| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# reloc.htm
Classes
RELOC
Relocation types
I386 (32bit)
X86_64 (64bit)
Encodings
RelocEnc
Procedures
RelocCombine
RelocPurge
RelocRelocInBuffer
RelocReportUnresolved
RelocResolve

Structure RELOC describes relocation in storage unit, which is a word, dword or qword memory variable in emitted code|data. The address, which the instruction refers to, is called target.

Relocations loaded at link-time from object files in formats OMF, COFF, ELF are converted by PfformatLoad to this united internal structure RELOC, which does not depend on CPU architecture (AMD64, x86, v86) neither on object-file format.

RELOC objects are kept in `SSS.RelocBuffer`. Their properties are:
`RELOC.Status` specifies the type of relocation and the size of relocated storage unit.
`RELOC.Org` represents the offset of the storage unit from the beginning of its section|segment, which is identified by `RELOC.Section` (P).
`RELOC.Symbol` specifies the target. It points to SYM representing the bottom of (perhaps external) segment or group (frame).
`RELOC.Addend` represents addend (A) to the value (R) in storage unit, which was left in instruction encoding by the assembler at asm-time (and which is pointed to by `RELOC.Org` ). Addend will be added to the storage unit when the relocation is resolved.
Frame of absolute relocation is the target's segment|group bottom, addend is zero.
Frame of relative relocation is RIP, i.e. address of the following instruction. Addend is the difference between the address of storage unit and RIP, for instance -2 when a word unit is relocated and this word is the last field of JMPN in 16bit mode.

Example of absolute relocation
  |[CODE] |[CODE] SEGMENT WIDTH=16 | ... |0021:BA[0000] | MOV DX,Label ; Load DX with the offset of external symbol Label.
  `RELOC.Section=[CODE], RELOC.Org=0x0022, RELOC.Addend=0, RELOC.Symbol=Label, RELOC.Status=relocWidth16+relocAbsVA`

Example of relative relocation
  |[.text] |[.text] SEGMENT WIDTH=64 | ... |00000012:48C705(00000000)23010000 | MOV [QData],0x123,DATA=QWORD,ADDR=REL ; Store immeditate constant to an external variable QData.
  `RELOC.Section=[.text], RELOC.Org=0x00000015, RELOC.Addend=-8, RELOC.Symbol=QData, RELOC.Status=relocWidth64+relocRel`

Addend is 0 in absolute relocations. In relative relocations it is the negative distance between RELOC.Org and the start of the next instruction (rIP). Addend may be modified later in RelocResolve

Relocation of FAR pointers uses two RELOC records (one for the offset, other for the paragraph address of target).

For the relation between symbols and segments in €ASM see SymSssBinding.

RELOC records are created by €ASM at asm-time by IiFlush when a machine instruction is assembled, and by ExpEvalData or ExpStoreInstr when a data definition is assembled.
RELOC record are also created at link-time when OMF|COFF|ELF object files are loaded.

Relative intrasection relocations (iiRelocDispRIP and iiRelocImmRIP) are resolved immediately in IiFlush.
Relative intrasegment relocations and absolute relocations of scalars are resolved in RelocResolve when sections are marshaled to their segment.
Other relocations between segments and external symbols are resolved by the linker of executable formats (PfformatCompile) or they are converted and stored in object output files.

Evolution of `RELOC.Org` in multiple data definition (e.g. `DD 2*DWORD aPointer`) at assembly time:

- When an address symbol is referred as a data value in ordinal operand of `D` statement (see ExpEvalData), `RELOC.Org` is related to the data emited by one ordinal operand, which is 0 unless the data are duplicated.
  RELOC record(s) are stored to the RelocBuffer provided for ExpEvalData.
- After assembly of each `D`'s operand (see PseudoData ), origin in RelocBuffer is elevated by the size of so far emitted data, giving offset relative to the start of the statement.
  Reloc record is then stored to `Stm.RelocBuffer` , so the origin is now relative to `$`.
- After StmExecute the assembled data are listed by StmListing, `RELOC.Org` still related to `$`.
- Finally, data are flushed to the section using StmFlush . Records from `Stm.RelocBuffer` are elevated by `Stm.Offset` and stored to `Sss.RelocBuffer` of the section which is specified in `Stm.Section`.

Example
  aData D D 5, 2*D aBssSymbol ; EuroAssembler creates two RELOC records with origins 4 and 8 in Stm.RelocBuffer. ; Origins will be elevated to OFFSET#aData+4, OFFSET#aData+8 in StmFlush. ; RELOC.Symbol points to symbol .bss representing the bottom of target segment `[.bss]`.

Evolution of `RELOC.Org` at marshal time:

- At the end of the last pass are all sections marshaled (linked) to their base segment, symbols are elevated by the section offset. Relocations are then resolved by RelocResolve, if possible.

Evolution of `RELOC.Org` at combine time:

- Sections no longer exist at combine time. Symbols from combined public segments are elevated in SssCombine.

Evolution of `RELOC.Org` at link time:

- When the segments are linked to an executable image and their VA is fixed, relocations are resolved by RelocResolve. If the program is in linkable object format (OMF, COFF, ELF), unresolved relocations are converted and stored in the appropriate format to the output file.

### Calculation method shortcuts:

A represents the value left by the compiler in relocated storage unit (word|dword|qword). It is visible in the dump column of program listing.
The process of resolving a relocation will replace A with the new relocated value R.

B represents the base address at which a shared object has been loaded into memory during execution. Generally, a shared object is built with a zero-base virtual address, but the execution address will be different. In €ASM it is specified by `PROGRAM ImageBase=`.

G represents the offset into the global offset table at which the relocation entry’s symbol will reside during execution.

GOT represents the VA (virtual address) of the global offset table.

L represents the place (section offset or address) of the Procedure Linkage Table entry for a symbol.

O represents the offset of the target symbol, whose index resides in the relocation entry, from the bottom of its segment. It becomes VA when the segment is finally linked to executable image.

P represents VA of the storage unit (word|dword|qword) which is being relocated (computed using `PFELF_REL.r_offset` alias `RELOC.Org+SEGMENT#RELOC.Section`.

R is the final value which will be written to the storage unit instead of A as the result of resolving the relocation. This value is visible in debugger and in hexadecimal dump of output file.

S represents the value (VA) of the target symbol, whose index resides in the relocation entry, i.e. `RELOC.Symbol` (its offset + bottom of its segment). When the symbol is scalar, its segment is NULL and S is its absolute value.

V is number of bytes (`0..5`) betweeen the end of relocated word|dword|qword and start of the next instruction (rIP). It is nonzero only when the relocated storage unit is not the last field in instruction encoding, e.g. in `ADCD [Symbol],0x11` assembled as `8315[00000000]11` is V=1, W=4.

W represents the width of the relocated storage unit (word|dword|qword) in bytes, i.e. `2|4|8`.

Z represents the size of the symbol whose index resides in the relocation entry (SIZE# of `RELOC.Symbol`).

### Calculation of A by compilers

If the relocation is absolute:
A=O, i.e. offset of target or its absolute value.

If the relocation is relative, compilers compute this value according to the output format:
A=0 in COFF Microsoft format,
A=B-P-W-V in COFFD DJ GPP format,
A=-W-V in ELF format.

### Calculation of R by linkers

The following tables show transformation of relocation types to `RELOC.Status` and back, together with their calculation methods:

Relocation types for machine i386 (PROGRAM WIDTH=32)
Internal €ASM format | COFF, COFFD | ELF, ELFX, ELFSO
--- | --- | ---
RELOC.Status `reloc*` | Calculation method | PFCOFF_RELOCATION.Type `IMAGE_REL_I386_*` | PFELF_REL32.r_type `pfelfR_386_*`
`None` | R=A | 0 `ABSOLUTE` | 0|5 `NONE|COPY`
`Width16+AbsVA` | R=S+A | 1 `DIR16` |
`Width16+Rel` | R=S-P+A | 2 `REL16` |
`Width32+AbsVA` | R=S+A | 6 `DIR32` | 1 `32`
`Width32+AbsRVA` | R=S-B+A | 7 `DIR32NB` |
`Width32+Rel` | R=S-P | 20 `REL32` |
`Width32+Rel+COFFD` | R=S+A | 20 `REL32` |
`Width32+Rel+ELF` | R=S-P+A |  | 2 `PC32`
`Width32+GOT` | R=G-P+A |  | 3 `GOT32`
`Width32+PLT` | R=L-P+A |  | 4 `PLT32`
`Width32+Sym` | R=S |  | 6|7 `GLOB_DAT|JMP_SLOT`
`Width32+Dyn` | R=B+A |  | 8 `RELATIVE`
`Width32+GOToff` | R=S-GOT+A |  | 9 `GOTOFF`
`Width32+GOTrel` | R=GOT-P+A |  | 10 `GOTPC`

Relocation types for machine x86-64 (PROGRAM WIDTH=64)
Internal €ASM format | COFF, COFFD | ELF, ELFX, ELFSO
--- | --- | ---
RELOC.Status `reloc*` | Calculation method | PFCOFF_RELOCATION.Type `IMAGE_REL_AMD64_*` | PFELF_REL64.r_type `pfelfR_X86_64_*`
`None` | R=A | 0 `ABSOLUTE` | 0|5 `NONE|COPY`
`Width64+AbsVA` | R=S+A | 1 `ADDR64` | 1 `64`
`Width32+AbsVA` | R=S+A | 2 `ADDR32` | 10 `32`
`Width32+AbsRVA` | R=S-B+A | 3 `ADDR32NB` |
`Width32+Rel` | R=S-P+A | 4 `REL32` | 2 `PC32`
`Width32+Rel+RelDist1` | R=S-P+V+A | 5 `REL32_1` |
`Width32+Rel+RelDist2` | R=S-P+V+A | 6 `REL32_2` |
`Width32+Rel+RelDist3` | R=S-P+V+A | 7 `REL32_3` |
`Width32+Rel+RelDist4` | R=S-P+V+A | 8 `REL32_4` |
`Width32+Rel+RelDist5` | R=S-P+V+A | 9 `REL32_5` |
`Width32+GOT` | R=G+A |  | 3 `GOT32`
`Width32+PLT` | R=L-P+A |  | 4 `PLT32`
`Width64+Sym` | R=S |  | 6|7 `GLOB_DAT|JMP_SLOT`
`Width64+Dyn` | R=B+A |  | 8 `RELATIVE`
`Width64+GOToff` | R=S-GOT+A |  | 25 `GOTOFF64`
`Width32+GOTrel` | R=GOT-P+A |  | 26 `GOTPC32`

          euroasm nowarn=2101
    reloc PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32
          INCLUDEHEAD euroasm.htm, \  Interface (structures, symbols and macros) of other modules used in this source.
                      dict.htm,ea.htm,eaopt.htm,exp.htm,msg.htm,pf.htm,pgm.htm,pgmopt.htm,sss.htm,sym.htm

     reloc HEAD  ; Start of module interface.

↑ RELOC

  Relocation record used internally by EuroAssembler describes one relocation, i.e. a WORD, DWORD or QWORD in emitted code/data which needs to be patched at link-time or at load-time.

  Special reloc type `relocDisp8` does not represent a real relocation but only a hint how to decorate the scaled disp8*N in listing, if nonzero. Other bits in RELOC.Status should be zero when disp8*N is used.

    RELOC STRUC  ; Relocation record.
    .OrgLow     D D ; P: Origin, i.e. offset of fixed memory object (word|dword|qword)
    .OrgHigh    D D ;   relative from the beginning of the section which hosts the fixed object.
    .Section    D D ; ^SSS section or segment whose .EmitBuffer contains the fixed object.
    .Status     D D ; Relocation properties, see below.

    .AddendLow  D D ; A: Value to be added to the relocated word|dword|qword.
    .AddendHigh D D
    .Symbol     D D ; ^SYM representing the bottom of target's segment or an external symbol.
                D D ; not used
            ENDSTRUC RELOC ; SIZE# RELOC = 32 = 20h

↑ RelocEnc
  Encoding of flags used in RELOC.Status.
  `relocTypeMask` identifies the fundamental, format-independent relocation type.
  `relocWidthMask` specifies if the relocated object is WORD|DWORD|QWORD (W).
  `relocExtAttr` is used when attribute is applied to an external object, and its evaluation needs to be postponed to the link-time.
  `relocRelDist` specifies an additional distance of the relocated object in 64bit mode (V). It is nonzero when the relocated DWORD displacement in instruction encoding is followed by immediate value, for instance `MOV [MemoryVar],ImmConstant`. In this case RIP is not only an address of relocated DWORD displacement+4, but it is must be enlarged by the value in relocRelDist (usually 1,4,5). The corresponding PFCOFF_RELOCATION.Type is then 0x0005,0x0008,0x0009.

  > Some other linkers keep PFCOFF_RELOCATION.Type at fixed value 0x0004 (IMAGE_REL_AMD64_REL32) and decrement the relocated object in COFF text by 1,4,5 instead.
  > €ASM could also achieve this with decrementing RELOC.Addend by 1,4,5 and having the type fixed at 0x0004, but I preferred keeping the relocated DWORD unchanged in COFF object code.

                                 ; Fundamental relocation types.
    relocNone      = 0x0000_0000 ; No relocation, same as relocResolved.
    relocPara      = 0x0000_0001 ; Base relocation of paragraph address related to ImageBase.
    relocAbsVA     = 0x0000_0002 ; Absolute relocation of  VA of the target RELOC.Symbol.
    relocAbsRVA    = 0x0000_0004 ; Absolute relocation of RVA of the target RELOC.Symbol.
    relocRel       = 0x0000_0008 ; Relative relocation of  VA related to rIP. May be set together with relocELF,relocCOFFD.
    relocFar       = 0x0000_0010 ; Far absolute relocation (16+16 or 16+32).
                   ; 0x0000_0020 ; Reserved.
    relocSym       = 0x0000_0040 ; Related to the symbol.
    relocDyn       = 0x0000_0080 ; Related to the runtime ImageBase of shared object.
    relocPLT       = 0x0000_0100 ; Adressed via Procedure Linkage Table.
    relocGOT       = 0x0000_0200 ; Related to the Global Offset Table.
    relocGOToff    = 0x0000_0400 ; Adressed via entry in Global Offset Table.
    relocGOTrel    = 0x0000_0800 ; Relative relocation addressed via GOT.
                   ; 0x0000_1000 ; Reserved.
                   ; 0x0000_2000 ; Reserved.
    relocTypeMask  = 0x0000_3FFF ; Relocation type. Only one flag may be set.
    relocCOFFD     = 0x0000_4000 ; Relocation was loaded from COFFD (DJ GPP) module.
    relocELF       = 0x0000_8000 ; Relocation was loaded from ELF module.
                                 ; Evaluation of external symbol attributes postponed to the link time.
    relocExtAttr   = 0x000F_0000 ; DictAttr* (0..9) synchronized with expExtAttr.
                                 ; W: Width of relocated object.
    relocWidth16   = 0x0010_0000 ;  WORD in memory is relocated.
    relocWidth32   = 0x0020_0000 ; DWORD in memory is relocated.
    relocWidth64   = 0x0040_0000 ; QWORD in memory is relocated.
    relocWidthMask = relocWidth16|relocWidth32|relocWidth64
                                 ; V: correction of RIP-relative relocation.
    relocRelDist   = 0x0700_0000 ; Additional distance of RIP-relative relocation in 64bit mode (0..5).
                                 ; Miscellaneous properties.
    relocDisp8N    = 0x7000_0000 ; Disp8*N shift factor 1..6. Pseudorelocation used to decorate dumped listing.
    relocResolved  = 0x8000_0000 ; This relocation has been already resolved and should be ignored.
    relocIgnore    = relocResolved | relocDisp8N ; Do not relocate anything.

      ENDHEAD reloc ; End of module interface.

↑ RelocRelocInBuffer Buffer, Delta
  RelocRelocInBuffer will relocate origin of each RELOC record in Buffer by Delta.
Input
  Buffer is pointer to BUFFER which should contain zero or more RELOC objects.
  Delta is signed 32bit integer which will be added to .Org of each RELOC object in the buffer.
Output
  The contents of Buffer is changed.
Error
  -
Invoked by
  PfomfLoadDataBlock PfomfLoadModule

    RelocRelocInBuffer Procedure Buffer,Delta
        BufferRetrieve [%Buffer]
        JECXZ .90:
        MOV EAX,[%Delta]
        MOV EBX,SIZE#RELOC
        CDQ
    .10:ADD [ESI+RELOC.OrgLow],EAX
        ADC [ESI+RELOC.OrgHigh],EDX
        ADD ESI,EBX
        SUB ECX,EBX
        JA .10:
    .90:EndProcedure RelocRelocInBuffer

↑ RelocPurge Pgm
  RelocPurge sorts relocations in all segments of a given Pgm by their RELOC.Org ascending and then removes resolved and duplicated records.
  It is invoked at link time, after PgmCombine and SssCreateImplicit.
Input
  Pgm is pointer to the linked PGM.
Output
  Relocations in all segments are purged and sorted.
Error
  -
Expands
  ShellSort
Invoked by
  PfOutput
Invokes
  EaBufferRelease EaBufferReserve

    RelocPurge    Procedure Pgm
    TopOrig LocalVar                          ; Pointer to the original top of RelocBuffer (behind the last RELOC record).
    Top     LocalVar                          ; Pointer to the current top of RelocBuffer (behind the last RELOC record).
    TempBuf LocalVar                          ; ^Temporary buffer for relocations.
        Invoke EaBufferReserve::,%^PROC
        MOV [%TempBuf],EAX
        MOV EBX,[%Pgm]
        MOV EDX,SIZE# RELOC
        ListGetFirst [EBX+PGM.SssList]
        JZ .90:
    .10:JNSt [EAX+SSS.Status],sssSegment,.80:
        XOR EBX,EBX                           ; Counter of RELOC records in %TempBuf.
        BufferClear [%TempBuf]
        BufferRetrieve [EAX+SSS.RelocBuffer]
        ADD ECX,ESI
    .20:CMP ESI,ECX
        JNB .40:                              ; If there are no more relocations in segment EAX.
        JSt [ESI+RELOC.Status],relocIgnore,.30:
        BufferStore [%TempBuf],ESI,EDX
        INC EBX
    .30:ADD ESI,EDX
        JMP .20:
    .40:BufferClear [EAX+SSS.RelocBuffer]
        BufferRetrieve [%TempBuf]             ; Sort the array of EBX records.
        ShellSort ESI,EBX,EDX,MemberSortByOrg::
        BufferRetrieve [%TempBuf]             ; Omit duplicated relocations.
        ADD ECX,ESI                           ; ESI..ECX is an array of sorted RELOC records.
    .50:CMP ESI,ECX
        JNB .80:
        BufferStore [EAX+SSS.RelocBuffer],ESI,EDX
    .60:LEA EDI,[ESI+EDX]                     ; The next records following ESI.
        CMP EDI,ECX
        JNB .80:
        Compare ESI,EDX,EDI,EDX               ; Compare, preserving all GPR.
        MOV ESI,EDI
        JE .60:
        JMP .50:
    .80:ListGetNext EAX ; The next segment.
        JNZ .10:
    .90:Invoke EaBufferRelease::,[%TempBuf]
        EndProcedure RelocPurge

↑ RelocCombine Relocation, BaseProg
  RelocCombine will update the Relocation in BasePgm when segments and symbols have already been combined to the base program.
  Intrasegment relative relocation between public homonymous segments is finally resolved here.
Input
  Relocation points to RELOC object in the base program, as it was copied from linked module.
  BaseProg is pointer to a PGM which it is linked to.
Output
  Relocation members `.Org, .Section, .Addend, .Symbol` are updated.
Error
  -
Invoked by
  PgmCombine

    RelocCombine Procedure Relocation, BaseProg
        MOV EBX,[%Relocation]
        MOV ECX,[EBX+RELOC.Status]
        JSt ECX,relocIgnore,.90:
        ; Update RELOC.Section:RELOC.Org, i.e. position of the relocated storage unit (word|dword).
        MOV ESI,[EBX+RELOC.Section]                  ; ^SSS where the relocated object is located.
        MOV EAX,[ESI+SSS.BottomLow]                  ; Bottom of its combined segment might have been elevated.
        MOV EDX,[ESI+SSS.BottomHigh]
        MOV EDI,[ESI+SSS.SegmPtr]
        SUB EAX,[EDI+SSS.BottomLow]
        SBB EDX,[EDI+SSS.BottomHigh]
        ADD [EBX+RELOC.OrgLow],EAX
        ADC [EBX+RELOC.OrgHigh],EDX
        MOV [EBX+RELOC.Section],EDI
        AND ECX,relocTypeMask
        Dispatch ECX,relocAbsVA,relocAbsRVA,relocRel
        JMP .90:

    .relocRel:
        MOV EDI,[EBX+RELOC.Symbol]
        TEST EDI
        JZ .90:
        MOV ECX,[EDI+SYM.Section]
        JECXZ .90:
        MOV EAX,[ECX+SSS.BottomLow]
        MOV EDX,[ECX+SSS.BottomHigh]
        MOV EDI,[EDI+SYM.SymbPtr]
        TEST EDI
        JZ .90:
        MOV ECX,[EDI+SYM.Section]
        JECXZ .90:
        SUB EAX,[ECX+SSS.BottomLow]
        SBB EDX,[ECX+SSS.BottomHigh]
        ADD [EBX+RELOC.AddendLow],EAX
        ADC [EBX+RELOC.AddendHigh],EDX
        MOV [EBX+RELOC.Symbol],EDI
        JMP .90:

    .relocAbsRVA:
    .relocAbsVA:
        MOV ECX,[EBX+RELOC.Symbol]
        JECXZ .90:
        MOV EDI,[ECX+SYM.Section]
        TEST EDI
        JZ .90:
        MOV EAX,[EDI+SSS.BottomLow]
        MOV EDX,[EDI+SSS.BottomHigh]
        ADD [EBX+RELOC.AddendLow],EAX
        ADC [EBX+RELOC.AddendHigh],EDX
    .90:
       EndProcedure RelocCombine

↑ RelocReportUnresolved Pgm
  Procedure reports warning W3835 Relocation at [!1S]:!2H is not resolvable in this program format for each unresolved relocation left in program %Pgm.
Input
  Pgm points to a linked PGM
Output
  -
Error
  W3835 if any relocation if left unresolved.
Invoked by
  PfbinCompile PfbootCompile PfcomCompile PfmzCompile

    RelocReportUnresolved Procedure Pgm
        MOV EBX,[%Pgm]
        BufferRetrieve [EBX+PGM.SegOrdBuffer]               ; ESI,ECX is now an array of pointers to SSS.
        SAR ECX,2
        JZ .90:
    .10:LODSD
        JNSt [EAX+SSS.Status],sssSegment,.80:
        PUSH ECX,ESI
          BufferRetrieve [EAX+SSS.RelocBuffer]
          JECXZ .70:
    .20:  MOV EAX,[ESI+RELOC.Status]
          JSt EAX,relocResolved|relocIgnore,.60:
          JSt EAX,relocAbsVA,.E7733:
          JSt EAX,relocRel  ,.E7734:
    .E7735: Msg '7735',EAX,[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Relocation type 0x!1W at [!2S]:!3H is not resolvable in this program format.
          JMPS .60:
    .E7733: Msg '7733',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Absolute relocation at [!2S]:!3H is not resolvable in this program format.
          JMPS .60:
    .E7734: Msg '7734',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Relative relocation at [!2S]:!3H is not resolvable in this program format.
    .60:  ADD ESI,SIZE# RELOC
          SUB ECX,SIZE# RELOC
          JA .20:
    .70:POP ESI,ECX
    .80:LOOP .10:
    .90:EndProcedure RelocReportUnresolved

↑ RelocResolve Relocation, BaseProgram
  RelocResolve will try to resolve one relocation.
  It is invoked when an executable program is combined and linked, external symbols resolved and virtual segment addresses fixed in image.
Input
  Relocation = ^RELOC.
  BaseProgram is pointer to PGM.
Output
  Data or code in SSS.EmitBuffer is modified: emited relocable Word/Dword/Fword pointed to by `Relocation.Org` is fixed up according to the relocation type.
  Resolved relocation in is then marked as relocResolved.
Error
  -
Invoked by
  SssRelocResolve

    RelocResolve Procedure Relocation, BaseProgram
    EmittedBottom      LocalVar ; Pointer to the bottom of emitted data (withing the contents of SSS.EmitBuffer).
    EmittedPtr         LocalVar ; Pointer to the relocated word|dword in emitted data. Always between %EmittedBottom and %EmittedTop.
    EmittedTop         LocalVar ; Pointer to the top of emitted data.
    Pgmopt             LocalVar ; Program format and model (cache copy of Program.Pgmopt.Status).
         MOV EBX,[%BaseProgram]
         MOV EAX,[EBX+PGM.Pgmopt.Status]
         MOV [%Pgmopt],EAX
         MOV ESI,[%Relocation]
         MOV EAX,[ESI+RELOC.Section]
         BufferRetrieve [EAX+SSS.EmitBuffer]         ; Mark borders of emitted contents.
         ADD ECX,ESI
         MOV [%EmittedBottom],ESI
         MOV [%EmittedTop],ECX
         MOV ESI,[%Relocation]
    .20: MOV EDI,[ESI+RELOC.Status]
         JSt EDI,relocIgnore,.90:                    ; If relocation ESI is already resolved or if its a Disp8*N decoration.
         JNSt EDI,relocWidthMask,.E7920:             ; Invalid fixup at [!1S]:!2Hh.
         MOV EBX,[ESI+RELOC.Symbol]                  ; Target symbol of the relocation ESI.
         TEST EBX
         JNZ .30:
         MOV EAX,pgmoptFormatMask
         AND EAX,[%Pgmopt]
         Dispatch AL,pgmoptBIN,pgmoptBOOT
         JMP .90:
    .pgmoptBIN:
    .pgmoptBOOT:                                     ; Formats which allow absolute scalar target.
         SetSt [ESI+RELOC.Status],relocResolved
         JMP .50:
    .30: MOV ECX,[EBX+SYM.SymbPtr]                   ; Is the external symbol EBX really resolved to public symbol ECX?
         JECXZ .40:
         MOV [ESI+RELOC.Symbol],ECX                  ; Replace external target EBX with its resolved public/PLT symbol ECX.
         MOV EBX,ECX
    .40: MOV ECX,[EBX+SYM.Section]
         MOV EAX,relocExtAttr
         MOV EDX,ECX                                 ; Prepare registers for handlers of postponed attribute evaluation.
         AND EAX,EDI
         JZ .dictAttrNONE:
         SHR EAX,16                                  ; Convert relocExtAttr to dictAttr* (1..9).
         Dispatch AL,dictAttrOFFSET,dictAttrSECTION,dictAttrSEGMENT,dictAttrGROUP,dictAttrPARA,dictAttrSIZE,dictAttrTYPE
         JMP .dictAttrNONE:                          ; Target symbol is not attributed.
         ; Attribute dispatching: EBX=^SYM target (never 0), ECX=EDX=^SSS of target symbol (0 when scalar), ESI=^RELOC.
    .Scalar:
         XOR EBX,EBX
         JMP .50:
    .dictAttrSECTION:
         JECXZ .Scalar:
         JSt [EBX+SYM.Status],symSe,.dictAttrNONE:
    .D2: MOV EAX,[EDX+SSS.SymPtr]                     ; Replace the target symbol with section's bottom symbol (symSe).
         MOV [ESI+RELOC.Symbol],EAX
         JMP .dictAttrNONE:
    .dictAttrSEGMENT:
         JECXZ .Scalar:
         MOV ECX,[EDX+SSS.SegmPtr]
         JECXZ .D2:
         MOV EDX,ECX
         JMP .D2:                                     ; Replace the target symbol with segment's bottom symbol (symSe).
    .dictAttrGROUP:
         JECXZ .Scalar:
         MOV ECX,[EDX+SSS.SegmPtr]
         JECXZ .D2:
         MOV EDX,ECX
         MOV ECX,[EDX+SSS.GroupPtr]
         JECXZ .D2:
         MOV EDX,ECX
         JMP .D2:                                     ; Replace the target symbol with group's bottom symbol (symSe).
    .dictAttrPARA:
         RstSt [ESI+RELOC.Status],relocTypeMask
         SetSt [ESI+RELOC.Status],relocPara
         JMP .dictAttrGROUP:                          ; Replace the target symbol with group's bottom symbol (symSe).
    .dictAttrOFFSET:
         MOV EAX,[EBX+SYM.OffsetLow]
         JMP .D4:

    .dictAttrTYPE:
         MOV EAX,[EBX+SYM.Status]
         AND EAX,symTypeMask
         JMP .D4:
    .dictAttrSIZE:
         MOV EAX,[EBX+SYM.Size]
    .D4: XOR EDX,EDX
         ADD [ESI+RELOC.AddendLow],EAX
         ADC [ESI+RELOC.AddendHigh],EDX
         MOV [ESI+RELOC.Symbol],EDX
    .dictAttrNONE:
         MOV EDI,[ESI+RELOC.Status]
         MOV EBX,[ESI+RELOC.Symbol]
         XOR ECX,ECX
         TEST EBX                                    ; EBX=0 when the target is scalar.
         JZ .50:
         MOV ECX,[EBX+SYM.Section]
         ; EBX=^SYM of target (0 when ExtAttr resolved to scalar), ECX=^SSS of target symbol (0 when scalar),  ESI=^RELOC, EDI=RELOC.Status
    .50: MOV EAX,[ESI+RELOC.AddendLow]
         MOV EDX,[ESI+RELOC.AddendHigh]
         AND EDI,relocTypeMask
         Dispatch EDI,relocRel,relocAbsVA,relocFar,relocPara,relocAbsRVA
    .E7735:Msg '7735',EDI,[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Relocation type 0x!1W at [!2S]:!3H is not resolvable in this program format.
         JMP .90::
    .E7925: Msg '7925',EBX,[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Unresolved relocation of symbol "!1S" at [!2S]:!3Hh.
         JMP .90::
    .E7920: Msg '7920',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Invalid fixup at [!1S]:!2Hh.
         JMP .90::
    .E7927: Msg '7927',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Relocation offset out of 4GB range at [!1S]:!2Hh.
         JMP .90::

    .relocRel: ; Relative relocation is resolvable if target segment ECX=[ESI+RELOC.Section] or if both are sssLinked.
        MOV EDI,[ESI+RELOC.Section]
        CMP ECX,EDI
        JE .R2:                                              ; Resolve if intrasegment relative relocation.
        JNSt [%Pgmopt],pgmoptImage,.90:                ; Do not resolve when this format may be combined and linked into image later.
        TEST EBX
        JZ .R4:
        JNSt [EDI+SSS.Status],sssLinked,.90::          ; Ignore when this segment is not linked yet.
        JECXZ .R2:                                           ; Scalar target segment is treated as sssLinked.
        JNSt [ECX+SSS.Status],sssLinked,.90::          ; Ignore when target segment is not linked yet.
    .R2:SetSt [ESI+RELOC.Status],relocResolved
        ADD EAX,[EBX+SYM.OffsetLow]
        ADC EDX,[EBX+SYM.OffsetHigh]
        JECXZ .R4:
        ADD EAX,[ECX+SSS.BottomLow]
        ADC EDX,[ECX+SSS.BottomHigh]
    .R4:SUB EAX,[ESI+RELOC.OrgLow]
        SBB EDX,[ESI+RELOC.OrgHigh]
        MOV ECX,[ESI+RELOC.Section]
        SUB EAX,[ECX+SSS.BottomLow]
        SBB EDX,[ECX+SSS.BottomHigh]
        JMP .Apply:

    .relocAbsRVA:  ; ImageBase absolute relocation is resolvable only if target segment is sssLinked.
         MOV EDI,[%BaseProgram]
         SUB EAX,[EDI+PGM.Pgmopt.ImageBaseLow]
         SBB EDX,[EDI+PGM.Pgmopt.ImageBaseHigh]
    .relocAbsVA:   ; Absolute relocation is resolvable only if target segment ECX is sssLinked or none (scalar).
         CALL .Abs:
         JC .90::
         SetSt [ESI+RELOC.Status],relocResolved
         JMP .Apply:

    .relocFar:  ; Far relocation is resolvable only if target segment is sssLinked.
                ; It is resolved in two parts: as relocAbsVA (relocWidth16|relocWidth32) and then as relocPara (relocWidth16).
         CALL .Abs:
         JC .90::
         JMP .Apply:                                 ; Apply the relocation of offset portion, then continue with relocPara.

    .relocPara:  ; Frame of paragraph relocation is the group (if exists) or the segment of target.
         JECXZ .P2:
         JNSt [ECX+SSS.Status],sssLinked,.90:: ; Ignore when the target segment ECX is not linked yet.
         MOV EBX,[ECX+SSS.SymPtr]
         MOV ECX,[ECX+SSS.GroupPtr]
         JECXZ .P2:
         MOV EBX,[ECX+SSS.SymPtr]
    .P2: MOV [ESI+RELOC.Symbol],EBX
         TEST EBX
         JZ .P3:
         MOV ECX,[EBX+SYM.Section]
         CMPB [%Pgmopt],pgmoptMZ                     ; Paragraph relocation in MZ executable will be fixed-up by the DOS loader.
         JE .P4:                                     ; relocPara will be finally resolved in PfmzCompile.
    .P3: SetSt [ESI+RELOC.Status],relocResolved      ; Formats BIN, BOOT, COM are fixed-up here to the absolute paragraph address.
    .P4: JECXZ .Apply:
         JSt [%Pgmopt],pgmoptFLAT,.Apply:            ; Let segment part 0 in FLAT model.
         ADD EAX,[ECX+SSS.BottomLow]
         ADC EDX,[ECX+SSS.BottomHigh]
         JNZ .E7927:                                 ; Relocation offset out of 4GB range at [!1S]:!2Hh.
         SHR EAX,4                                   ; Convert linear address to the paragraph address.
         ;JMP .Apply:
    .Apply:                                          ; Add EDX:EAX to the relocated object identified at ESI+RELOC.Org.
         MOV EDI,[ESI+RELOC.OrgLow]
         MOV ECX,[ESI+RELOC.OrgHigh]
         ADD EDI,[%EmittedBottom]                    ; EDI=pointer to the relocated object in emitted code.
         ADC ECX,0
         JNZ .E7927:                                 ; Relocation offset out of 4GB range at [!1S]:!2Hh.
         MOV ECX,[ESI+RELOC.Status]
         MOV EBX,ECX
         AND ECX,relocWidthMask
         SHR ECX,19                                  ; Convert relocWidth to the object size 2,4,8.
         ADD ECX,EDI
         CMP ECX,[%EmittedTop]                       ; Check if RELOC.Org is within the emitted code.
         JA .E7920:                                  ; Invalid fixup at [!1S]:!2Hh.
         JNSt EBX,relocWidth64,.W32:
         ADD [EDI+0],EAX
         ADC [EDI+4],EDX
         JMP .60:
    .W32:JNSt EBX,relocWidth32,.W16:
         ADD [EDI],EAX
         JMP .60:
    .W16:JNSt EBX,relocWidth16,.60:                  ; Ignore relocations with undefined width.
         ADD [EDI],AX
    .60: JNSt [ESI+RELOC.Status],relocFar,.90::
         ADD [ESI+RELOC.OrgLow],2                    ; Offset part of FAR relocation was resolved. Change relocFar to unresolved 16bit relocPara.
         JNSt [ESI+RELOC.Status],relocWidth32,.70:
         ADD [ESI+RELOC.OrgLow],2                    ; Only when relocFar is 16:32 bits.
    .70: RstSt [ESI+RELOC.Status],relocFar+relocWidth32+relocWidth64
         SetSt [ESI+RELOC.Status],relocPara+relocWidth16 ; Change relocFar to relocPara.
         JMP .20:                                    ; Resolve the same relocFar record once again, this time as relocPara.

    .Abs:PROC1  ; Input: ESI=^RELOC; EBX=^SYM; ECX=^SSS; EDX:EAX=addend. Output: CF=not resolvable; EDX:EAX updated, ready to apply; EDI clobbered.
         JECXZ .A5:                                  ; Resolvable if EBX is a scalar symbol.
         JSt [ECX+SSS.Status],sssLinked,.A1:
         STC                                         ; Do not resolve when target segment is not linked yet.
         JMP .A9:
    .A1: JSt [%Pgmopt],pgmoptFLAT,.A3:               ; Use VA (segment bottom) instead of SVA in FLAT model.
         MOV EDI,[ECX+SSS.GroupPtr]                  ; Frame whose PARA# is assumed in segment register.
         TEST EDI
         JNZ .A2:
         MOV EDI,[ECX+SSS.BottomLow]                 ; Bottom of segment ECX is used as the addressing frame.
         AND EDI,0x0000_000F
         ADD EAX,EDI
         ADC EDX,0
         JMP .A5:
    .A2: SUB EAX,[EDI+SSS.BottomLow]
         SBB EDX,[EDI+SSS.BottomHigh]
         MOV EDI,[EDI+SSS.BottomLow]                 ; Bottom of group EDI is used as the addressing frame.
         AND EDI,0x0000_000F                         ; Correction when the relocation frame assumed in segment register was not OWORD aligned.
         ADD EAX,EDI
         ADC EDX,0
    .A3: ADD EAX,[ECX+SSS.BottomLow]
         ADC EDX,[ECX+SSS.BottomHigh]
    .A5: TEST EBX
         JZ .A9:
         ADD EAX,[EBX+SYM.OffsetLow]
         ADC EDX,[EBX+SYM.OffsetHigh]
    .A9: RET
         ENDP1 .Abs:
    .90:EndProcedure RelocResolve

     ENDPROGRAM reloc

▲Back to the top▲