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