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.
RELOC.Section=[CODE], RELOC.Org=0x0022, RELOC.Addend=0, RELOC.Symbol=Label, RELOC.Status=relocWidth16+relocAbsVA
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:
D
statement (see
ExpEvalData), RELOC.Org
is related
to the data emited by one ordinal operand, which is 0 unless the data are duplicated.
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.
Stm.RelocBuffer
, so the origin is now relative to $
.
RELOC.Org
still related to $
.
Stm.RelocBuffer
are elevated by Stm.Offset
and stored to Sss.RelocBuffer
of the section which is specified in
Stm.Section
.[.bss]
.
RELOC.Org
at marshal time:
RELOC.Org
at combine time:
RELOC.Org
at link time:
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
).
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.
The following tables show transformation of relocation types to
RELOC.Status
and back, together with their calculation methods:
Internal €ASM format | COFF, COFFD | ELF, ELFX, ELFSO | |
---|---|---|---|
RELOC.Statusreloc* | Calculation method |
PFCOFF_RELOCATION.TypeIMAGE_REL_I386_* |
PFELF_REL32.r_typepfelfR_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 |
Internal €ASM format | COFF, COFFD | ELF, ELFX, ELFSO | |
---|---|---|---|
RELOC.Statusreloc* | Calculation method |
PFCOFF_RELOCATION.TypeIMAGE_REL_AMD64_* |
PFELF_REL64.r_typepfelfR_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. INCLUDEHEAD \ ; Include headers of another modules used in this module. dict.htm, \ ea.htm, \ eaopt.htm, \ exp.htm, \ msg.htm, \ pf.htm, \ pgm.htm, \ pgmopt.htm, \ sss.htm, \ sym.htm, \ syswin.htm, \ ;;
reloc HEAD ; Start of module interface.
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
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 targetRELOC.Symbol
. relocAbsRVA = 0x0000_0004 ; Absolute relocation of RVA of the targetRELOC.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 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 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,MemberUpdate.SortByOrg:: ShellSort ESI,EBX,EDX,SortByOrg:: 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
.Org, .Section, .Addend, .Symbol
are updated.
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 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
Relocation.Org
is fixed up according to the relocation type.
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. ;.P6: ;TEST AL,0x0F ;Msg cc=NZ,'7928',ECX,[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Unaligned target segment [!1S] of relocation at [!2S]:!3Hh. 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 ; STC JZ .A9: ADD EAX,[EBX+SYM.OffsetLow] ADC EDX,[EBX+SYM.OffsetHigh] ; CLC .A9: RET ENDP1 .Abs: .90:EndProcedure RelocResolve
ENDPROGRAM reloc