Object RELOC describes one relocation of word, dword or qword memory variable in emitted code.
reloc PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32 INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules.
reloc HEAD ; Start of module interface.
Reloc 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.
RELOC objects are kept in Section.RelocBuffer. Important property of fixup is its .Org
which represents offset of the patched word/dword/qword from the beginning of segment.
The member .Section points to section or segment in whose .RelocBuffer
are the relocations kept at assembly time. It will be employed at link time for fixing up
.Org.
Evolution of reloc origin at assembly time:
D statement (
ExpEvalData), RELOC.Org is related
to data in one ordinal operand, which is 0 unless the data are duplicated.
RELOC record(s) are stored to the RelocBuffer provided for ExpEvalData.
D's operand (PseudoData
), origin in RelocBuffer is patched
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 $.
$.
Stm.RelocBuffer are patched by Stm.Offset
and stored to Sss.RelocBuffer of the section which is specified in
Stm.Section.
Evolution of reloc origin at combine time:
Evolution of reloc origin at link time:
Special reloc type relocDisp8
does not represent a real relocation but only a hint how to
decorate the scaled disp8*N in listing.
RELOC STRUC ; Relocation record.
.OrgLow D D ; Origin, i.e. offset of fixed memory object (word/dword/qword)
.OrgHigh D D ; relative from the beginning of the segment where the fixed object lies.
.Section D D ; ^SSS section or segment whose .EmitBuffer contains the fixed object.
.Status D D ; Relocation properties, see below.
.DispLow D D ; Target displacement to be added to the fixed object.
.DispHigh D D
.Target D D ; ^SSS representing section/segment which the target belongs to.
.Frame D D ; ^SSS representing assumed group/segment address used for addressing the target. 0=use .Target.
ENDSTRUC RELOC
relocTypeMask identifies the fundamental, format-independent relocation type.
relocWidthMask specifies if the relocated object is WORD|DWORD|QWORD.
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.
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.Disp by 1,4,5 and having the type fixed at 0x0004, but I preferred keeping the relocated DWORD unchanged.
; Fundamental relocation types.
relocPara = 0x0000_0001 ; Base relocation of paragraph address related to ImageBase.
relocAbsVA = 0x0000_0002 ; Absolute relocation of VA related to .Frame segment/group.
relocAbsRVA = 0x0000_0004 ; Absolute relocation of RVA related to .Frame segment.
relocRel = 0x0000_0008 ; Relative relocation of VA related to rIP.
relocFar = 0x0000_0010 ; Far absolute relocation (16+16 or 16+32).
relocTypeMask = 0x0000_0FFF ; Relocation type. Only one flag should be set.
; Correction of RIP-relative relocation.
relocRelDist = 0x0000_7000 ; Additional distance of RIP-relative relocation in 64bit mode (0..5).
; Evaluation of external symbol attributes postponed to the link time.
relocExtAttr = 0x000F_0000 ; DictAttr* (0..9) <<16. Synchronized with sssExtAttr.
; 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
; Miscellaneous properties.
relocResolved = 0x0080_0000 ; This relocation has been already resolved and should be ignored.
relocDisp8N = 0x7000_0000 ; Disp8*N shift factor 0..6. Valid only when relocDisp8 is set.
relocDisp8 = 0x8000_0000 ; Pseudorelocation, used to decorate dumped listing of Disp8*N (AVX instruction).
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
RelocCombine Procedure Relocation
MOV EBX,[%Relocation]
MOV ESI,[EBX+RELOC.Target] ; Segment in linked program.
TEST ESI
Msg cc=Z,'7727',0,[EBX+RELOC.OrgLow] ; Unresolved extern relocation at [!1S]:!2Hh.
JZ .90:
MOV EAX,[ESI+SSS.SegmPtr]
MOV [EBX+RELOC.Target],EAX
MOV ESI,[EBX+RELOC.Frame] ; Segment or group in linked program.
TEST ESI
JZ .80:
MOV EAX,[ESI+SSS.GroupPtr]
.80:MOV [EBX+RELOC.Target],EAX
.90:EndProcedure RelocCombine
RelocFixup Procedure Relocation
MOV ESI,[%Relocation]
JMP .10:
.E7924:Msg '7924',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Invalid relocation [!1S]:!2Hh.
JMP .90:
.10:; Fixup .Section and .Org of relocation ESI.
MOV ECX,[ESI+RELOC.Section]
JECXZ .E7924:
; Relocation ESI may belong to base program and then its .Section
; may refer to a sssSection rather than to a sssSegment.
; However, its offset is already related to the segment bottom.
JNSt [ECX+SSS.Status],sssSection,.30:
MOV ECX,[ECX+SSS.SegmPtr]
JECXZ .E7924:
.30:MOV EAX,[ECX+SSS.BottomLow] ; Bottom of old linked segment.
MOV EDX,[ECX+SSS.BottomHigh]
MOV ECX,[ECX+SSS.SegmPtr] ; Pointer to new base segment.
JECXZ .E7924:
SUB EAX,[ECX+SSS.BottomLow]
SBB EDX,[ECX+SSS.BottomHigh] ; EDX:EAX is now delta of relocated word/dword.
ADD [ESI+RELOC.OrgLow],EAX
ADC [ESI+RELOC.OrgHigh],EDX
MOV [ESI+RELOC.Section],ECX
; Fixup .Target and .Disp of relocation ESI.
MOV ECX,[ESI+RELOC.Target]
JECXZ .50: ; If the target is scalar.
JNSt [ECX+SSS.Status],sssSection,.40:
MOV ECX,[ECX+SSS.SegmPtr]
JECXZ .50:
.40:MOV EAX,[ECX+SSS.BottomLow]
MOV EDX,[ECX+SSS.BottomHigh]
MOV ECX,[ECX+SSS.SegmPtr]
JECXZ .50:
SUB EAX,[ECX+SSS.BottomLow]
SBB EDX,[ECX+SSS.BottomHigh]
ADD [ESI+RELOC.DispLow],EAX
ADC [ESI+RELOC.DispHigh],EDX
MOV [ESI+RELOC.Target],ECX
.50:; Fixup .Frame of relocation ESI.
MOV ECX,[ESI+RELOC.Frame]
JECXZ .90:
MOV ECX,[ECX+SSS.GroupPtr]
JECXZ .90:
MOV [ESI+RELOC.Frame],ECX
.90:EndProcedure RelocFixup
RelocSort Procedure Pgm
MOV EBX,[%Pgm]
ListGetFirst [EBX+PGM.SssList]
JZ .90:
.10:JNSt [EAX+SSS.Status],sssSegment,.80:
BufferRetrieve [EAX+SSS.RelocBuffer]
JECXZ .80: ; If there are no relocations in segment EAX.
PUSH EAX
LEA EDX,[ESI+ECX] ; End of RELOC array.
MOV EBX,ESI ; Temporary save ptr to RELOC block to EBX.
MOV EAX,ECX ; Temporary save size of RELOC block to EAX.
MOV EDI,SIZE#RELOC
.30: CMP ESI,EDX
JAE .70:
; Update frame of each relocation ESI.
MOV ECX,[ESI+RELOC.Target]
JECXZ .50:
MOV ECX,[ECX+SSS.GroupPtr]
JECXZ .50:
MOV ECX,[ECX+SSS.GroupPtr]
.50: MOV [ESI+RELOC.Frame],ECX
ADD ESI,EDI
JMP .30: ; The next relocation.
.70: CDQ ; EDX:EAX is now the size of RELOC array.
DIV EDI ; Get the number of RELOC records to EAX.
; Sort the RELOC array.
ShellSort EBX,EAX,EDI,MemberUpdate.SortByOrg::
POP EAX
.80:ListGetNext EAX ; The next segment.
JNZ .10:
.90:EndProcedure RelocSort
RelocUniq Procedure RelocBuffer
TempBuffer LocalVar
BufferRetrieve [%RelocBuffer]
JECXZ .90: ; Do nothing when it's empty.
Invoke EaBufferReserve::,RelocUniq
MOV [%TempBuffer],EAX
MOV EAX,ECX
MOV EBX,SIZE# RELOC
CDQ ; EDX:EAX is now the size of RELOC array.
DIV EBX ; Get the number of RELOC records to EAX.
LEA EDX,[ESI+ECX] ; EDX is now pointer to the end of array.
; Sort the RELOC array.
ShellSort ESI,EAX,EBX,MemberUpdate.SortByOrg::
; Copy unique records to TempBuffer.
.30:BufferStore [%TempBuffer],ESI,EBX ; Copy one unique record.
MOV EDI,ESI ; Remember in EDI the pointer to just stored record.
.40:ADD ESI,EBX ; The next record.
CMP ESI,EDX
JNB .80: ; If end of array was reached.
MOV ECX,EBX
PUSH ESI,EDI
REPE CMPSB
POP EDI,ESI
JE .40: ; Skip the record if it's duplicated.
JMP .30:
.80:;Copy TempBuffer to output.
BufferClear [%RelocBuffer]
BufferRetrieve [%TempBuffer]
BufferStore [%RelocBuffer],ESI,ECX
Invoke EaBufferRelease::,[%TempBuffer]
.90:EndProcedure RelocUniq
RelocResolveImage is invoked from PgmLinkImage
when an executable program image is linked.
RelocResolveImage will read all relocations (RELOC records) stored in
Segment.RelocBuffer and fixup their target in the emitted code, if possible.
The relocation is then marked as relocResolved.
If the image is in MZ format, unresolved paragraph relocations will be incorporated to the MZ executable image format later by PfmzCompile.
If the image is in PE|DLL format, absolute relocations
will be incorporated to [.reloc] section later by
PfpeBaserelocCreate.
In other executable formats any unresolved relocation reports E7727.
RELOC.Org
is fixed up according to relocation type.
Segment.RelocBuffer are then marked as relocResolved.
RelocResolveImage Procedure Segment, Program
SegmentBottomLow LocalVar ; RVA of target segment bottom.
SegmentBottomHigh LocalVar
FrameBottomLow LocalVar ; RVA of target group/segment bottom
FrameBottomHigh LocalVar ; which is assumed to be loaded at run time in segment register.
EmittedBottom LocalVar ; Pointer to bottom of emitted data (withing the contents of Segment.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.
MOV EBX,[%Segment]
; Mark borders of emitted contents.
BufferRetrieve [EBX+SSS.EmitBuffer]
LEA EAX,[ESI+ECX]
MOV [%EmittedBottom],ESI
MOV [%EmittedTop],EAX
; Walk through relocations.
BufferRetrieve [EBX+SSS.RelocBuffer]
TEST ECX
JZ .99: ; If there are no relocations in the segment, done.
; Resolve each relocation ESI in the loop .10: .. .90:.
.10:PUSH ECX
JSt [ESI+RELOC.Status],relocResolved|relocDisp8,.90: ; Skip if it's a decorating RELOC record only.
; First calculate %EmittedPtr to relocated word/dword/qword. It's width is specified by Reloc.Status.
MOV EAX,[ESI+RELOC.OrgLow] ; Offset of the fixed word/dword/qword relative to segment.Bottom.
MOV EDX,[ESI+RELOC.OrgHigh]
ADD EAX,[%EmittedBottom]
ADC EDX,0 ; Check if the relocated object lies inside emitted contents.
JNZ .E7920: ; Invalid fixup at [!1S]:!2Hh.
CMP EAX,[%EmittedTop]
JAE .E7920: ; Invalid fixup at [!1S]:!2Hh.
MOV [%EmittedPtr],EAX ; Pointer to relocated word/dword/qword within .EmitBuffer contents.
; Resolve relocation of target symbol.
MOV ECX,[ESI+RELOC.Target]
TEST ECX
JZ .30: ; If the target is scalar.
JNSt [ECX+SSS.Status],sssExtern,.30:
; Update relocation of external/imported symbol.
; Extern pseudosection ECX should refer with its .SymPtr to the corresponding public symbol.
MOV EDI,[ECX+SSS.SymPtr] ; Symbol of extern pseudosegment. It was put there in PgmLinkImage.
TEST EDI ; Properties of the matched public symbol EDI will be used instead of the external/imported one.
JZ .E7727: ; Unresolved extern relocation at [!1S]:!2Hh.
MOV EAX,[ESI+RELOC.Status]
AND EAX,relocExtAttr ; Postponed evaluation of attributes applied on external symbol.
JNZ .12:
MOV ECX,[EDI+SYM.Section]
JECXZ .12:
MOV EAX,[ECX+SSS.Status]
AND EAX,relocExtAttr
.12: SHR EAX,16 ; Convert relocDictAttr* to dictAttr*.
Dispatch EAX,dictAttrNONE,dictAttrPARA,dictAttrGROUP,dictAttrSEGMENT,dictAttrSECTION,dictAttrOFFSET
JMP .dictAttrNONE: ; Other attributes are ignored.
.dictAttrGROUP:
.dictAttrPARA:
MOV ECX,[EDI+SYM.Section] ; Segment or section of public symbol in base program.
SUB EAX,EAX
SUB EDX,EDX
MOV EDI,ECX
JECXZ .20: ; If external symbol is scalar.
MOV ECX,[ECX+SSS.SegmPtr]
JECXZ .20:
MOV EDI,[ECX+SSS.GroupPtr]
JMP .20:
.dictAttrSEGMENT:
.dictAttrSECTION:
MOV ECX,[EDI+SYM.Section] ; Segment or section of public symbol in base program.
SUB EAX,EAX
SUB EDX,EDX
MOV EDI,ECX
JMP .20:
.dictAttrOFFSET:
SUB ECX,ECX
JMP .18:
.dictAttrNONE:
MOV ECX,[EDI+SYM.Section] ; Segment or section of public symbol in base program.
JECXZ .18:
MOV ECX,[ECX+SSS.SegmPtr] ; Segment.Bottom is already elevated to the new VA in image.
.18: MOV EAX,[EDI+SYM.OffsetLow]
MOV EDX,[EDI+SYM.OffsetHigh]
MOV EDI,ECX ; Default frame of public symbol if it is in nongrouped segment.
JECXZ .20:
MOV EDI,[ECX+SSS.GroupPtr]
.20: MOV [ESI+RELOC.Target],ECX ; Update Target segment.
MOV [ESI+RELOC.Frame],EDI ; Update Frame group.
ADD [ESI+RELOC.DispLow],EAX ; Update Target displacement.
ADC [ESI+RELOC.DispHigh],EDX ; Update Target displacement.
.30: ; Common continuation of extern and standard symbols.
; Calculate %SegmentBottom of target segment.
MOV ECX,[ESI+RELOC.Target] ; Target segment. Zero when the target is absolute scalar address.
SUB EAX,EAX
CDQ
JECXZ .40: ; If scalar.
MOV ECX,[ECX+SSS.SegmPtr]
JECXZ .40:
MOV EAX,[ECX+SSS.BottomLow] ; SEGMENT#.
MOV EDX,[ECX+SSS.BottomHigh]
.40: MOV [%SegmentBottomLow],EAX
MOV [%SegmentBottomHigh],EDX
MOV [%FrameBottomLow],EAX ; Prepare frame for the case when equal to segment.
MOV [%FrameBottomHigh],EDX
; Calculate %FrameBottom of the group of target segment ECX. It equals to %SegmentBottom if no group.
JECXZ .50:
MOV ECX,[ECX+SSS.GroupPtr]
JECXZ .50:
JSt [ESI+RELOC.Status],relocPara,.43:
MOV EBX,[%Program]
XOR EDX,EDX
MOV EAX,[EBX+PGM.Pgmopt.Status]
CMP AL,pgmoptBIN ; When program format is BIN and relocation type not PARA#,
MOV EAX,EDX ; no base relocation is available, so FrameBottom will be 0.
JE .45:
.43: MOV EAX,[ECX+SSS.BottomLow]
MOV EDX,[ECX+SSS.BottomHigh]
.45: MOV [%FrameBottomLow],EAX
MOV [%FrameBottomHigh],EDX
.50: MOV EAX,[ESI+RELOC.Status] ; Perform the actual relocation ESI method.
MOV EDX,relocTypeMask
MOV EDI,[%EmittedPtr]
AND EDX,EAX ; EDX is now the relocation type.
; Select the relocation type.
Dispatch EDX,relocRel,relocAbsVA,relocAbsRVA,relocPara,relocFar
.relocResolved:
SetSt [ESI+RELOC.Status],relocResolved
JMP .90:
.relocPara: ; Absolute paragraph relocation.
; Relocated target word is increased by delta = (GROUP#Target)/16.
MOV EAX,[%FrameBottomLow]
MOV EDX,[%FrameBottomHigh]
SHRD EAX,EDX,4
ADD [EDI],AX ; The actual fixup with paragraph RVA.
MOV EBX,[%Program]
MOV EAX,[EBX+PGM.Pgmopt.Status]
CMP AL,pgmoptBIN
JE .relocResolved: ; This kind of relocation is resolved only if format=BIN.
JMP .90:
.relocFar: ; Far pointer relocation.
; Segment fixup delta value = (SEGMENT#Target) / 16.
; Offset fixup delta value = (SEGMENT#Target) \ 16 + RELOC.Disp
MOV EDX,[%SegmentBottomLow] ; RVA of the target segment.
MOV EAX,0x0000_000F
MOV ECX,2
AND EAX,EDX ; EAX is now RVA modulo 16.
ADD EAX,[ESI+RELOC.DispLow] ; If segment is unaligned, the remainder will be added to target displacement.
JSt [ESI+RELOC.Status],relocWidth16,.far16:
.far32:ADD [EDI],EAX ; The actual fixup of far dword offset.
MOV CL,4
JMP .farSeg:
.far16:ADD [EDI],AX ; The actual fixup of far word offset.
.farSeg:ADD EDI,ECX ; Make EDI point to the segment part of far address (add 2 or 4).
SHR EDX,4 ; EDX is now RVA/16.
ADD [EDI],DX ; The actual fixup of far segment paragraph address.
; Far relocation is not completely resolved yet, the segment part will be fixed up at load time.
; The reloc record ESI will be restructuralized from relocFar to relocPara.
SUB EAX,EAX
ADD [ESI+RELOC.OrgLow],ECX ; Make the origin point to paragraph address.
ADC [ESI+RELOC.OrgHigh],EAX
MOV [ESI+RELOC.DispLow],EAX
MOV [ESI+RELOC.DispHigh],EAX
MOVD [ESI+RELOC.Status],relocPara+relocWidth16
JMP .90:
.relocAbsRVA: ; Relocation of RVA.
MOV EBX,[%Program]
MOV ECX,[EBX+PGM.Pgmopt.ImageBaseLow]
MOV EDX,[EBX+PGM.Pgmopt.ImageBaseHigh]
NOT ECX
NOT EDX
ADD ECX,1
ADC EDX,0
JMP .relocAbs:
.relocAbsVA: ; Relocation of VA.
MOV EBX,[%Program]
SUB ECX,ECX
SUB EDX,EDX
.relocAbs: ; Absolute relocation.
; Fixup delta value = SEGMENT#Target - GROUP#Target + RELOC.Disp.
; GROUP#Target is 0 when MODEL=FLAT. EDX:ECX is -ImageBase if AbsRVA or 0 if AbsVA.
PUSH ECX,EDX
ADD ECX,[%FrameBottomLow]
; If the target frame is not paragraph-aligned, add the remainder to the target displacement.
AND ECX,0x0000_000F
ADD [ESI+RELOC.DispLow],ECX
ADC [ESI+RELOC.DispHigh],EDX
POP EDX,EAX
ADD EAX,[%SegmentBottomLow]
ADC EDX,[%SegmentBottomHigh]
JSt [EBX+PGM.Pgmopt.Status],pgmoptFLAT,.Frame0:
SUB EAX,[%FrameBottomLow]
SBB EDX,[%FrameBottomHigh]
.Frame0:
ADD EAX,[ESI+RELOC.DispLow]
ADC EDX,[ESI+RELOC.DispHigh] ; EDX:EAX is now fixup delta value.
JSt [ESI+RELOC.Status],relocWidth32,.Abs32:
JSt [ESI+RELOC.Status],relocWidth64,.Abs64:
.Abs16: ; Absolute word relocation.
ADD [EDI],AX ; The actual fixup.
JMP .relocResolved:
.Abs32: ; Absolute dword relocation.
ADD [EDI],EAX ; The actual fixup.
JMP .relocResolved:
.Abs64: ; Absolute qword relocation..
ADD [EDI+0],EAX ; The actual fixup.
ADC [EDI+4],EDX
JMP .relocResolved:
.relocRel: ; Self-relative relocation.
; Emitted relocated word/dword (Object) contains OFFSET#Target, or 0 if it was extern.
; Fixup delta value = SEGMENT#target - SEGMENT#Object - OFFSET#Object - SIZE#Object + RELOC.Disp.
MOV EBX,[%Segment]
MOV EAX,[%SegmentBottomLow]
MOV EDX,[%SegmentBottomHigh]
SUB EAX,[EBX+SSS.BottomLow]
SBB EDX,[EBX+SSS.BottomHigh]
SUB EAX,[ESI+RELOC.OrgLow]
SBB EDX,[ESI+RELOC.OrgHigh]
ADD EAX,[ESI+RELOC.DispLow]
ADC EDX,[ESI+RELOC.DispHigh]
MOV ECX,[ESI+RELOC.Status]
AND ECX,relocRelDist
SHR ECX,12 ; ECX is the size of imm+imm2 encoded in the instruction.
SUB EAX,ECX
SBB EDX,0 ; EDX:EAX is now the fixup delta value.
JSt [ESI+RELOC.Status],relocWidth16,.Rel16:
.Rel32:SUB EAX,4 ; SIZE#Object. ; Self-relative dword relocation.
SBB EDX,0
Invoke ExpWidthSigned::
CMP CL,expWidth4B
JA .E7922: ; Fixup increment out of 4GB range at [!1S]:!2Hh.
ADD [EDI],EAX ; The actual fixup.
JMP .relocResolved:
.Rel16:SUB EAX,2 ; SIZE#Object. ; Self-relative word relocation.
SBB EDX,0
Invoke ExpWidthSigned::
CMP CL,expWidth2B
JA .E7921: ; Fixup increment out of 64KB range at [!1S]:!2Hh.
ADD [EDI],AX ; The actual fixup.
JMP .relocResolved:
.E7727:Msg '7727',[%Segment],[ESI+RELOC.OrgLow] ; Unresolved extern relocation at [!1S]:!2Hh.
JMP .90:
.E7920:Msg '7920',[%Segment],[ESI+RELOC.OrgLow] ; Invalid fixup at [!1S]:!2Hh.
JMP .90:
.E7921:Msg '7921',[%Segment],[ESI+RELOC.OrgLow] ; Fixup increment out of 64KB range at [!1S]:!2Hh.
JMP .90:
.E7922:Msg '7922',[%Segment],[ESI+RELOC.OrgLow] ; Fixup increment out of 4GB range at [!1S]:!2Hh.
JMP .90:
.E7926:Msg '7926',[%Segment],[ESI+RELOC.OrgLow] ; Relocation offset out of 64KB range at [!1S]:!2Hh.
JMP .90:
.E7927:Msg '7927',[%Segment],[ESI+RELOC.OrgLow] ; Relocation offset out of 4GB range at [!1S]:!2Hh.
JMP .90:
.E7928:Msg '7928',[%Segment],[ESI+RELOC.OrgLow] ; Unaligned segment of relocation [!1S]:!2Hh.
; JMP .90:
.90:POP ECX
ADD ESI,SIZE#RELOC
SUB ECX,SIZE#RELOC
JA .10: ; The next relocation.
.99:EndProcedure RelocResolveImage
Segment.RelocBuffer and fixup their target in the emitted code
only if the relocation is relative to the same segment (relocRel).
relocResolved.RELOC.Org
is fixed up according to relocation type.
Segment.RelocBuffer are then marked as relocResolved.
RelocResolveObject Procedure Segment, Program
SegmentBottomLow LocalVar ; RVA of target segment bottom.
SegmentBottomHigh LocalVar
FrameBottomLow LocalVar ; RVA of target group/segment bottom
FrameBottomHigh LocalVar ; which is assumed to be loaded at run time in segment register.
EmittedBottom LocalVar ; Pointer to bottom of emitted data (withing the contents of Segment.EmitBuffer).
EmittedPtr LocalVar ; Relocated word/dword in emitted data. Always between EmittedBottom and EmittedTop.
EmittedTop LocalVar ; Pointer to top of emitted data.
MOV EBX,[%Segment]
; Mark borders of emitted contents.
BufferRetrieve [EBX+SSS.EmitBuffer]
LEA EAX,[ESI+ECX]
MOV [%EmittedBottom],ESI
MOV [%EmittedTop],EAX
; Walk through relocations.
BufferRetrieve [EBX+SSS.RelocBuffer]
TEST ECX
JZ .99: ; If there are no relocations in the segment, done.
; Resolve each relocation ESI in the loop .10: .. .90:.
.10:PUSH ECX
JSt [ESI+RELOC.Status],relocResolved|relocDisp8,.90: ; Skip if it's a decorating RELOC record only.
JNSt [EDI+RELOC.Status],relocRel,.90: ; Other than relative relocation are not resolvable yet,
; because final segments VA are not set when an linkable object file is compiled.
CMP [ESI+RELOC.Target],EBX
JNE .90: ; Only relative relocations within the same segment are resolvable here.
; First calculate %EmittedPtr to relocated word/dword/qword. It's width is specified by Reloc.Status.
MOV EAX,[ESI+RELOC.OrgLow] ; Offset of fixed word/dword/qword relative to segment.Bottom.
MOV EDX,[ESI+RELOC.OrgHigh]
ADD EAX,[%EmittedBottom]
ADC EDX,0
JNZ .E7920: ; Invalid fixup at [!1S]:!2Hh.
CMP EAX,[%EmittedTop]
JAE .E7920: ; Invalid fixup at [!1S]:!2Hh.
MOV [%EmittedPtr],EAX ; Pointer to relocated word/dword/qword within .EmitBuffer contents.
MOV ECX,[ESI+RELOC.Target] ; Resolve relocation of target symbol.
TEST ECX
JZ .30: ; If the target is scalar.
JNSt [ECX+SSS.Status],sssExtern,.30:
; Update relocation of external symbol.
; Extern pseudosection ECX should refer with its .SymPtr to the corresponding public symbol.
MOV EDI,[ECX+SSS.SymPtr] ; Symbol of extern pseudosegment. It was put there in PgmLinkImage.
TEST EDI ; Properties of the matched public symbol EDI will be used instead of the external/imported one.
JZ .E7727: ; Unresolved extern relocation at [!1S]:!2Hh.
MOV EAX,[ESI+RELOC.Status]
AND EAX,relocExtAttr ; Postponed evaluation of attributes applied on external symbol.
JNZ .12:
MOV ECX,[EDI+SYM.Section]
JECXZ .12:
MOV EAX,[ECX+SSS.Status]
AND EAX,relocExtAttr
.12: SHR EAX,16 ; Convert relocDictAttr* to dictAttr*.
Dispatch EAX,dictAttrNONE,dictAttrPARA,dictAttrGROUP,dictAttrSEGMENT,dictAttrSECTION,dictAttrOFFSET
JMP .dictAttrNONE: ; Other attributes are ignored.
.dictAttrGROUP:
.dictAttrPARA:
MOV ECX,[EDI+SYM.Section] ; Segment or section of public symbol in base program.
SUB EAX,EAX
SUB EDX,EDX
MOV EDI,ECX
JECXZ .20: ; If external symbol is scalar.
MOV ECX,[ECX+SSS.SegmPtr]
JECXZ .20:
MOV EDI,[ECX+SSS.GroupPtr]
JMP .20:
.dictAttrSEGMENT:
.dictAttrSECTION:
MOV ECX,[EDI+SYM.Section] ; Segment or section of public symbol in base program.
SUB EAX,EAX
SUB EDX,EDX
MOV EDI,ECX
JMP .20:
.dictAttrOFFSET:
SUB ECX,ECX
JMP .18:
.dictAttrNONE:
MOV ECX,[EDI+SYM.Section] ; Segment or section of public symbol in base program.
JECXZ .dictAttrOFFSET:
MOV ECX,[ECX+SSS.SegmPtr] ; Segment.Bottom is already elevated to the new VA in image.
.18: MOV EAX,[EDI+SYM.OffsetLow]
MOV EDX,[EDI+SYM.OffsetHigh]
MOV EDI,ECX ; Default frame of public symbol if it is in nongrouped segment.
JECXZ .20:
MOV EDI,[ECX+SSS.GroupPtr]
.20: MOV [ESI+RELOC.Target],ECX ; Update Target segment.
MOV [ESI+RELOC.Frame],EDI ; Update Frame group.
ADD [ESI+RELOC.DispLow],EAX ; Update Target displacement.
ADC [ESI+RELOC.DispHigh],EDX
.30: ; Common continuation of extern and standard symbols.
; Calculate %SegmentBottom of target segment.
MOV ECX,[ESI+RELOC.Target] ; Target segment. Zero when the target is absolute scalar address.
SUB EAX,EAX
CDQ
JECXZ .40: ; If scalar.
MOV ECX,[ECX+SSS.SegmPtr]
JECXZ .40:
MOV EAX,[ECX+SSS.BottomLow] ; SEGMENT#.
MOV EDX,[ECX+SSS.BottomHigh]
.40: MOV [%SegmentBottomLow],EAX
MOV [%SegmentBottomHigh],EDX
MOV [%FrameBottomLow],EAX ; Prepare frame for the case when equal to segment.
MOV [%FrameBottomHigh],EDX
; Calculate %FrameBottom of the group of target segment ECX. It equals to %SegmentBottom if no group.
JECXZ .50:
MOV ECX,[ECX+SSS.GroupPtr]
JECXZ .50:
JSt [ESI+RELOC.Status],relocPara,.43:
MOV EBX,[%Program]
XOR EDX,EDX
MOV EAX,[EBX+PGM.Pgmopt.Status]
CMP AL,pgmoptBIN ; When program format is BIN and relocation type not PARA#,
MOV EAX,EDX ; no base relocation is available, so FrameBottom will be 0.
JE .45:
.43: MOV EAX,[ECX+SSS.BottomLow]
MOV EDX,[ECX+SSS.BottomHigh]
.45: MOV [%FrameBottomLow],EAX
MOV [%FrameBottomHigh],EDX
.50: MOV EDI,[%EmittedPtr] ; Perform the actual relocation ESI method.
; Emitted relocated word/dword (Object) contains OFFSET#Target, or 0 if it was extern.
; Fixup delta value = SEGMENT#target - SEGMENT#Object - OFFSET#Object - SIZE#Object + RELOC.Disp.
MOV EBX,[%Segment]
MOV EAX,[%SegmentBottomLow]
MOV EDX,[%SegmentBottomHigh]
SUB EAX,[EBX+SSS.BottomLow]
SBB EDX,[EBX+SSS.BottomHigh]
SUB EAX,[ESI+RELOC.OrgLow]
SBB EDX,[ESI+RELOC.OrgHigh]
ADD EAX,[ESI+RELOC.DispLow]
ADC EDX,[ESI+RELOC.DispHigh]
MOV ECX,[ESI+RELOC.Status]
AND ECX,relocRelDist
SHR ECX,12 ; ECX is the size of imm+imm2 encoded in the instruction.
SUB EAX,ECX
SBB EDX,0 ; EDX:EAX is now the fixup delta value.
JSt [ESI+RELOC.Status],relocWidth16,.Rel16:
.Rel32:; Self-relative relocation of DWORD object.
SUB EAX,4 ; Size of disp32 (the relocated object).
SBB EDX,0
Invoke ExpWidthSigned::
CMP CL,expWidth4B
JA .E7922: ; Fixup increment out of 4GB range at [!1S]:!2Hh.
ADD [EDI],EAX ; The actual fixup.
JMP .relocResolved:
.Rel16: ; Self-relative relocation of WORD object.
SUB EAX,2 ; Size of disp16 (the relocated object).
SBB EDX,0
Invoke ExpWidthSigned::
CMP CL,expWidth2B
JA .E7921: ; Fixup increment out of 64KB range at [!1S]:!2Hh.
ADD [EDI],AX ; The actual fixup.
JMP .relocResolved:
.E7727:Msg '7727',[%Segment],[ESI+RELOC.OrgLow] ; Unresolved extern relocation at [!1S]:!2Hh.
JMP .90:
.E7920:Msg '7920',[%Segment],[ESI+RELOC.OrgLow] ; Invalid fixup at [!1S]:!2Hh.
JMP .90:
.E7921:Msg '7921',[%Segment],[ESI+RELOC.OrgLow] ; Fixup increment out of 64KB range at [!1S]:!2Hh.
JMP .90:
.E7922:Msg '7922',[%Segment],[ESI+RELOC.OrgLow] ; Fixup increment out of 4GB range at [!1S]:!2Hh.
JMP .90:
.E7926:Msg '7926',[%Segment],[ESI+RELOC.OrgLow] ; Relocation offset out of 64KB range at [!1S]:!2Hh.
JMP .90:
.E7927:Msg '7927',[%Segment],[ESI+RELOC.OrgLow] ; Relocation offset out of 4GB range at [!1S]:!2Hh.
JMP .90:
.E7928:Msg '7928',[%Segment],[ESI+RELOC.OrgLow] ; Unaligned segment of relocation [!1S]:!2Hh.
; JMP .90:
.relocResolved:
SetSt [ESI+RELOC.Status],relocResolved
.90:POP ECX
ADD ESI,SIZE#RELOC
SUB ECX,SIZE#RELOC
JA .10: ; The next relocation.
.99:EndProcedure RelocResolveObject
ENDPROGRAM reloc