This EuroAssembler source pfelfso.htm
generates output executable file in program format ELF as described in
[ELF32] and
[ELF64].
Section in ELF documentation is equivalent to €ASM SEGMENT.
Program in ELF documentation is equivalent to €ASM GROUP.
EUROASM NOWARN=2101 pfelfso 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. ea.htm, \ eaopt.htm, \ exp.htm, \ msg.htm, \ pf.htm, \ pfelf.htm, \ pfelfx.htm, \ pgm.htm, \ pgmopt.htm, \ reloc.htm, \ sss.htm, \ stm.htm, \ sym.htm, \ syswin.htm, \ ;;
pfelfso HEAD ; Start module interface.
ENDHEAD pfelfso
PfelfsoLoadPgm reads the contents of one ELFSO file
and converts it to structures of a fresh new program (module), which then will be stored on
BasePgm.ModulePgmList
.
This procedure works with ELF types Relocatable and SharedObject in both 32bit and 64bit mode. However SharedObject (format ELFSO) will be linked only statically; EuroAssembler doesn't support dynamic linking. PfelfsoLoadPgm is identical with PfelfLoadPgmLoad.
dso.sofil
BasePgm.ModulePgmList
as a new
PGM structure.PfelfsoLoadPgm Procedure BasePgm, ObjBegin, ObjSize, FileNamePtr Invoke PfelfLoadPgm::,[%BasePgm],[%ObjBegin],[%ObjSize],[%FileNamePtr] EndProcedure PfelfsoLoadPgm
PfelfsoHash Procedure StringPtr XOR EBX,EBX ; unsigned long hash = 0; MOV ESI,[%StringPtr] ; name - pointer to ASCIIZ symbol name. XOR EAX,EAX .10:LODSB ; AL = *name++ TEST EAX JZ .80: ; while (*name) SHL EBX,4 ; ADD EBX,EAX ; hash = (hash << 4) + *name ;>> MOV EDX,0xF000_0000 ; unsigned long g; (temporary variable). AND EDX,EBX ; (g = hash & 0xf000_0000) JZ .50: ; if (g) SHR EDX,24 ; (g >> 24) XOR EBX,EDX ; hash ^= (g >> 24); .50: ; https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-48031.html ; also described in Oracle is not used by GNU ld 2.34 ; NOT EDX ; ~g ; AND EBX,EDX ; hash &= ~g AND EBX,0x0FFF_FFFF ; ELF-64 doc. JMP .10: .80:MOV [%ReturnEAX],EBX ; return hash in EAX. EndProcedure PfelfsoHash
PfelfsoHashTable Procedure Pfelf SymSize LocalVar ; SIZE# PFELF_SYM (10h or 18h). DynSymPtr LocalVar ; Pointer to an array of PFELF_SYM records. DynSymEnd LocalVar ; Pointer behind the array. Strings LocalVar ; Pointer to the contens of [.dynstr] (ASCIIZ strings). StringsEnd LocalVar ; Pointer to the end of contens of [.dynstr]. NrOfSymbols LocalVar ; Number of dynamic symbols = number of hash chains. SymIndex LocalVar ; Index in symbol table (0..NrOfSymbols-1). NrOfBuckets = 3 ; Fixed number of hash buckets. MOV EDI,[%Pfelf] MOV EBX,[EDI+PFELF.Pgm] MOV ECX,SIZE# PFELF_SYM64 ; Initialize [%SymSize]. JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.10: MOV CL,SIZE# PFELF_SYM32 .10:MOV [%SymSize],ECX MOV EDX,[EDI+PFELF.Sss.dynstr] BufferRetrieve [EDX+SSS.EmitBuffer] ADD ECX,ESI MOV [%Strings],ESI MOV [%StringsEnd],ECX MOV EDX,[EDI+PFELF.Sss.dynsym] BufferRetrieve [EDX+SSS.EmitBuffer] MOV EAX,ECX ; Total size of ELF symbol table. ADD ECX,ESI MOV [%DynSymPtr],ESI MOV [%DynSymEnd],ECX MOV ECX,[EDX+SSS.SegmIndex] ; Index of [.dynsym]. XOR EDX,EDX MOV [%SymIndex],EDX DIVD [%SymSize] MOV [%NrOfSymbols],EAX MOV EDX,[EDI+PFELF.Sss.hash] MOV [EDX+SSS.sh_link],ECX ; [.hash] is associated with [.dynsym]. LEA ECX,[4*(1+1+NrOfBuckets)+4*EAX] ; Size of hash table in bytes. BufferResize [EDX+SSS.EmitBuffer],ECX ; Allocate ECX zeroed bytes on the buffer. BufferRetrieve [EDX+SSS.EmitBuffer] Invoke SssUpdateByEmit::,EDX MOV EDI,ESI ; EDI now points to the hash table allocated in SSS.EmitBuffer. MOV EAX,NrOfBuckets STOSD ; nbucket. MOV EAX,[%NrOfSymbols] STOSD ; nchain. JMP .30: .20:MOV ESI,[%DynSymPtr] ADD ESI,[%SymSize] MOV [%DynSymPtr],ESI .30:MOV ESI,[%DynSymPtr] ; ESI=^PFELF_SYM. CMP ESI,[%DynSymEnd] JNB .90: MOV EAX,[ESI+PFELF_SYM64.st_name] ; Offset .sh_name is identical for both 32 and 64. ADD EAX,[%Strings] CMP EAX,[%StringsEnd] JNB .20: ; Skip if PFELF_SYM if malformed. Invoke PfelfsoHash,EAX MOV EBX,EAX ; Hash value. MOV ECX,NrOfBuckets XOR EDX,EDX DIV ECX ; EDX is now bucket index 0,1,2. EDI=^bucket[0]. MOV EAX,[%SymIndex] INCD [%SymIndex] MOV ECX,[EDI+4*EDX] ; Load the current index from bucket. TEST ECX ; Is the bucket free? JNZ .40: MOV [EDI+4*EDX],EAX ; Put symbol index to the bucket. JMP .20: ; The next PFELF_SYM. .40:CMPD [EDI+4*NrOfBuckets+4*ECX],0 ; Is the chain free? JNE .50: MOV [EDI+4*NrOfBuckets+4*ECX],EAX ; Put symbol index to the chain. JMP .20: .50:MOV ECX,[EDI+4*NrOfBuckets+4*ECX] ; Load the current index from chain. JMP .40: .90:EndProcedure PfelfsoHashTable
PfelfsoLink calculates size, file address and virtual address of every program segment.
It is invoked when the emited contents of all segments has been generated and their order was already established by
PgmOrderSegments in Pgm.OrdBuffer
.
It assumes ImageBase=0 and EHDR,PHDR,SHDR at the beginning of the output file, followed by segments emitted contents.
PfelfsoLink calculates segment virtual size as SSS.Top - SSS.Bottom
for both initialized and uninitialized segments.
Segment file size is calculated from the size of Sss.EmitBuffer.
PfelfsoLink does not change the contents of SSS.EmitBuffer, SSS.RelocBuffer
;
the actual raw contents of regular segments is not concatenated into image here because relocations are not resolved yet.
PfelfsoLink Procedure Pfelf ArrayPtr LocalVar ; Pointer to the array of DWORD pointers to SSS groups and segments. ArrayEnd LocalVar ; Behind the last pointer. Size LocalVar ; Virtual (emitted or reserved) segment size. PHDRsize LocalVar ; Size of one ELF program header (20h or 38h). SHDRsize LocalVar ; Size of one ELF section header (28h or 40h). FA LocalVar ; Current file address. VALow LocalVar ; Current virtual address. VAHigh LocalVar ; FileAlign LocalVar ; Effective file alignment. SectionAlign LocalVar ; Effective section alignment. MOV EDI,[%Pfelf] MOV EBX,[EDI+PFELF.Pgm] MOV EAX,SIZE# PFELF_PHDR64 MOV EDX,SIZE# PFELF_SHDR64 JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.10: MOV AL,SIZE# PFELF_PHDR32 MOV DL,SIZE# PFELF_SHDR32 .10:MOV [%PHDRsize],EAX MOV [%SHDRsize],EDX BufferRetrieve [EBX+PGM.SegOrdBuffer] ; Prepare array of DWORD pointers to SSS. ADD ECX,ESI MOV [%ArrayPtr],ESI MOV [%ArrayEnd],ECX MOV EAX,[EBX+PGM.Pgmopt.ImageBaseLow] ; ImageBase=0 in ELFSO. MOV EDX,[EBX+PGM.Pgmopt.ImageBaseHigh] ADD EAX,[EDI+PFELF.HDRsEnd] ; Calculate headers size where to start linking at. ADC EDX,0 MOV [%FA],EAX MOV [%VALow],EAX MOV [%VAHigh],EDX .20:MOV ESI,[%ArrayPtr] ; Read pointers to sorted groups and segments. CMP ESI,[%ArrayEnd] JNB .80: ; End when all groups and segments were linked. LODSD MOV [%ArrayPtr],ESI MOV EBX,EAX SetSt [EBX+SSS.Status],sssLinked ; Tell RelocResolve that segments are linked. JNSt [EBX+SSS.Status],sssGroup,.40: ; Link the €ASM group EBX. Each group has different access rights, thus alignment must be at least %LinPageSize. CMP EBX,[EDI+PFELF.Sss.LOAD.HDR] JE .20: ; This ELF "program" is already linked. MOV ECX,[EBX+SSS.Alignment] ; EBX=^SSS.sssGroup (ELF "program"). ;; JNSt [EBX+SSS.Purpose],sssPurposeCODE|sssPurposeRODATA|sssPurposeGOT|sssPurposeDATA|sssPurposeBSS|sssPurposeDYNAMIC, .30: JNSt [EBX+SSS.Purpose],sssPurposeCODE|sssPurposeRODATA|sssPurposeDATA, .30: CMP ECX,%LinPageSize JAE .30: MOV ECX,%LinPageSize ; LOAD groups alignment in DSO is at least %LinPageSize (0x1000). .30:MOV EAX,[%VALow] MOV EDX,[%VAHigh] push ecx Invoke ExpAlign::,EAX,ECX,0 ADD EAX,ECX ADC EDX,0 MOV [EBX+SSS.BottomLow],EAX MOV [EBX+SSS.BottomHigh],EDX MOV [%VALow],EAX MOV [%VAHigh],EDX pop ecx Invoke ExpAlign::,[%FA],ECX,0 ADD [%FA],ECX JMP .20: .40:JNSt [EBX+SSS.Status],sssSegment,.20: ; Link the segment EBX. CMPD [EBX+SSS.NameSize],0 ; EBX=^SSS.sssSegment (ELF "section"). JZ .20: ; Skip the empty NULL segment []. .45:; Compute effective alignment of segment EBX. MOV ECX,[EBX+SSS.Alignment] ; ECX is segment's own alignment. MOV [%FileAlign],ECX MOV [%SectionAlign],ECX MOV EAX,[EBX+SSS.TopLow] ; Compute segment size in memory. MOV EDX,[EBX+SSS.TopHigh] SUB EAX,[EBX+SSS.BottomLow] SBB EDX,[EBX+SSS.BottomHigh] Msg cc=NZ,'8525',EBX ; Size of segment [!1S] exceeded 4 GB. MOV [%Size],EAX MOV ESI,EAX ; Compute segment's file address. MOV EDX,[%FA] ; (Perhaps unaligned) FA of the previous segment's Top. Invoke ExpAlign::,EDX,[%FileAlign],0 ; Returns ECX=alignment stuff size following the headers|previous segment contents. ADD ECX,EDX MOV [EBX+SSS.BottomFA],ECX ; Aligned FA of this segment. JNSt [EBX+SSS.Status],sssNotBSS,.55: ; Skip when EDI is BSS segment. ADD ECX,ESI ; Add %Size in the file. .55:MOV [EBX+SSS.TopFA],ECX MOV [%FA],ECX ; Unaligned FA of the next segment. ; Compute segment's virtual address. MOV EAX,[%VALow] ; Compute segment's absolute virtual address. MOV EDX,[%VAHigh] ; EDX:EAX is unaligned VA of the top of previous segment. MOV ECX,[%SectionAlign] .60:Invoke ExpAlign::,EAX,ECX,0 ; Returns ECX=alignment stuff size following previous segment contents. ADD EAX,ECX ADC EDX,0 MOV ECX,%LinPageSize-1 ; 0x0000_0FFF. AND ECX,[EBX+SSS.BottomFA] AND EAX,~(%LinPageSize-1) ; 0xFFFF_F000. OR EAX,ECX ; Make VA and FA congruent by %LinPageSize. MOV [EBX+SSS.BottomLow],EAX MOV [EBX+SSS.BottomHigh],EDX ADD EAX,ESI ; Add virtual %Size. ADC EDX,0 MOV [EBX+SSS.TopLow],EAX MOV [EBX+SSS.TopHigh],EDX MOV [%VALow],EAX ; Unaligned VA of the next segment. MOV [%VAHigh],EDX JMP .20: ; Go to link the next segment. .80:Invoke PgmResizeGroups::,[EDI+PFELF.Pgm] ; Update FA and VA of regular groups by their segments. MOV EDX,[%Pfelf] MOV EDI,[EDX+PFELF.Sss.LOAD.HDR] ; Special treatment of group LOAD.HDR. XOR EAX,EAX MOV [EDI+SSS.BottomLow],EAX MOV [EDI+SSS.BottomHigh],EAX MOV [EDI+SSS.BottomFA],EAX MOV EDI,[EDX+PFELF.Sss.DYNAMIC] ; Special treatment of group DYNAMIC. MOV ESI,[EDX+PFELF.Sss.dynamic] MOV EAX,[ESI+SSS.BottomLow] MOV EDX,[ESI+SSS.BottomHigh] MOV [EDI+SSS.BottomLow],EAX MOV [EDI+SSS.BottomHigh],EDX MOV EAX,[ESI+SSS.TopLow] MOV EDX,[ESI+SSS.TopHigh] MOV [EDI+SSS.TopLow],EAX MOV [EDI+SSS.TopHigh],EDX MOV EAX,[ESI+SSS.BottomFA] MOV EDX,[ESI+SSS.TopFA] MOV [EDI+SSS.BottomFA],EAX MOV [EDI+SSS.TopFA],EDX MOV EDX,[%Pfelf] MOV ECX,16 JSt [EDX+PFELF.Status],pfelfWidth64,.87: MOV CL,8 .87:MOV [EDI+SSS.Alignment],ECX .90:EndProcedure PfelfsoLink
[%DynamicSSS].EmitBuffer
with dynamic table entries (2*DWORD or 2*QWORD each).
[%DynStrSSS].EmitBuffer
should be already filled with names of dynamic symbols.PfelfsoDynamic Procedure Pfelf DSOPtr LocalVar ; Pointer to DWORD Ptr+Size pairs of DSO NEEDED module name strings. Kept in PGM.DSONameBuffer]. DSOEnd LocalVar ; End of Ptr+Size pairs. dynamicRelocBuf LocalVar ; ^SSS.RelocBUFFER of [.dynamic]. dynamicEmitBuf LocalVar ; ^SSS.EmitBUFFER of [.dynamic]. dynstrBuf LocalVar ; ^SSS.EmitBUFFER of [.dynstr]. ; dynstrBuf is not cleared here, it was filled by PfelfConvertSymbols ; and PFELF.dynstrSize specifies the total size of dynamic symbol names. MOV EDI,[%Pfelf] MOV ESI,[EDI+PFELF.Sss.dynamic] MOV EBX,[EDI+PFELF.Sss.dynstr] MOV EAX,[EBX+SSS.SegmIndex] MOV [ESI+SSS.sh_link],EAX ; PFELF_SHDR.sh_link of .dynamic section uses strings from .dynstr section. MOV EDX,[ESI+SSS.EmitBuffer] MOV EAX,[ESI+SSS.RelocBuffer] MOV [%dynamicEmitBuf],EDX MOV [%dynamicRelocBuf],EAX MOV EDX,[EBX+SSS.EmitBuffer] MOV [%dynstrBuf],EDX MOV EBX,[EDI+PFELF.Pgm] ; DT_NEEDED. BufferRetrieve [EBX+PGM.DSONameBuffer] JECXZ .16: ADD ECX,ESI MOV [%DSOPtr],ESI MOV [%DSOEnd],ECX .10:MOV ESI,[%DSOPtr] CMP ESI,[%DSOEnd] JNB .16: LODSD MOV EDI,EAX LODSD MOV EDX,EAX ; EDI,EDX is the needed DSO module name string. MOV [%DSOPtr],ESI BufferRetrieve [%dynstrBuf] ; ECX is now the future offset of NEEDED module name in [.dynamicstr]. BufferStore [%dynstrBuf],EDI,EDX BufferStoreByte [%dynstrBuf],0 MOV EDI,[%dynamicEmitBuf] JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.12: BufferStoreDword EDI,pfelfDT_NEEDED BufferStoreDword EDI,ECX ; DYNAMIC.d_val=offset of NEEDED file in [.dynamicstr] section. JMPS .10: .12:BufferStoreQword EDI,pfelfDT_NEEDED BufferStoreQword EDI,ECX ; DYNAMIC.d_val=offset of NEEDED file in [.dynamicstr] section. .14:JMP .10: .16:; DT_RUNPATH. MOV EDI,[%Pfelf] MOV ECX,[Ea.Eaopt.RunPathSize::] JECXZ .22: ; If no RUNPATH. MOV EAX,ECX BufferRetrieve [%dynstrBuf] MOV EDX,ECX ; Future offset of RUNPATH module name in [.dynstr]. BufferStore [%dynstrBuf],[Ea.Eaopt.RunPathPtr::],EAX BufferStoreByte [%dynstrBuf],0 JSt [EDI+PFELF.Status],pfelfWidth64,.18: BufferStoreDword [%dynamicEmitBuf],pfelfDT_RUNPATH BufferStoreDword [%dynamicEmitBuf],EDX ; DYNAMIC.d_val=offset of RunPath in [.dynstr] section. JMPS .22: .18:BufferStoreQword [%dynamicEmitBuf],pfelfDT_RUNPATH BufferStoreQword [%dynamicEmitBuf],EDX ; DYNAMIC.d_val=offset of RunPath in [.dynstr] section. .22: ; DT_HASH MOV EDX,[EDI+PFELF.Sss.hash] JSt [EDI+PFELF.Status],pfelfWidth64,.24: BufferStoreDword [%dynamicEmitBuf],pfelfDT_HASH CALL .Reloc: BufferStoreDword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr=VA of segment [.hash]. JMPS .26: .24:BufferStoreQword [%dynamicEmitBuf],pfelfDT_HASH CALL .Reloc: BufferStoreQword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr=VA of segment [.hash]. .26:; DT_STRTAB. MOV EDX,[EDI+PFELF.Sss.dynstr] JSt [EDI+PFELF.Status],pfelfWidth64,.28: BufferStoreDword [%dynamicEmitBuf],pfelfDT_STRTAB CALL .Reloc: BufferStoreDword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr=VA of segment [dynstr]. JMPS .30: .28:BufferStoreQword [%dynamicEmitBuf],pfelfDT_STRTAB CALL .Reloc: BufferStoreQword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr=VA of segment [dynstr]. .30:; DT_SYMTAB. MOV EDX,[EDI+PFELF.Sss.dynsym] JSt [EDI+PFELF.Status],pfelfWidth64,.32: BufferStoreDword [%dynamicEmitBuf],pfelfDT_SYMTAB CALL .Reloc: BufferStoreDword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr=VA of segment [.dynsym]. JMPS .34: .32:BufferStoreQword [%dynamicEmitBuf],pfelfDT_SYMTAB CALL .Reloc: BufferStoreQword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr=VA of segment [.dynsym]. .34:; DT_STRSZ. BufferRetrieve [%dynstrBuf] JSt [EDI+PFELF.Status],pfelfWidth64,.36: BufferStoreDword [%dynamicEmitBuf],pfelfDT_STRSZ BufferStoreDword [%dynamicEmitBuf],ECX ; DYNAMIC.d_val=size of segment [.dynstr]. JMPS .38: .36:BufferStoreQword [%dynamicEmitBuf],pfelfDT_STRSZ BufferStoreQword [%dynamicEmitBuf],ECX ; DYNAMIC.d_val=size of segment [.dynstr]. .38:; DT_SYMENT. JSt [EDI+PFELF.Status],pfelfWidth64,.40: BufferStoreDword [%dynamicEmitBuf],pfelfDT_SYMENT BufferStoreDword [%dynamicEmitBuf],SIZE#PFELF_SYM32 ; DYNAMIC.d_val=size of one [.dynsym] entry. JMPS .42: .40:BufferStoreQword [%dynamicEmitBuf],pfelfDT_SYMENT BufferStoreQword [%dynamicEmitBuf],SIZE#PFELF_SYM64 ; DYNAMIC.d_val=size of one [.dynsym] entry. .42:MOV EDX,[EDI+PFELF.Sss.rela.dyn] TEST EDX JZ .54: ; When no dynamic relocations are present. ; DT_RELA, DT_RELASZ, DT_RELAENT, DT_RELACOUNT BufferRetrieve [EDX+SSS.EmitBuffer] ; ECX=size of all PFELF_REL* records in .rel(a).dyn JSt [EDI+PFELF.Status],pfelfWidth64,.54: BufferStoreDword [%dynamicEmitBuf],pfelfDT_REL CALL .Reloc: BufferStoreDword [%dynamicEmitBuf],0 BufferStoreDword [%dynamicEmitBuf],pfelfDT_RELSZ BufferStoreDword [%dynamicEmitBuf],ECX BufferStoreDword [%dynamicEmitBuf],pfelfDT_RELENT BufferStoreDword [%dynamicEmitBuf],SIZE# PFELF_REL32 .54:; DT_RELSZ + DT_JMPREL. MOV EDX,[EDI+PFELF.Sss.rela.plt] TEST EDX JZ .58: ; When no dynamic relocations are present. BufferRetrieve [EDX+SSS.EmitBuffer] JSt [EDI+PFELF.Status],pfelfWidth64,.56: BufferStoreDword [%dynamicEmitBuf],pfelfDT_PLTRELSZ BufferStoreDword [%dynamicEmitBuf],ECX ; DYNAMIC.d_val = size of [.rel.plt]. BufferStoreDword [%dynamicEmitBuf],pfelfDT_JMPREL CALL .Reloc: BufferStoreDword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr = SEGMENT# [.rel.plt]. JMPS .58: .56:BufferStoreQword [%dynamicEmitBuf],pfelfDT_PLTRELSZ BufferStoreQword [%dynamicEmitBuf],ECX ; DYNAMIC.d_val = size of [rela.plt]. BufferStoreQword [%dynamicEmitBuf],pfelfDT_JMPREL CALL .Reloc: BufferStoreQword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr = SEGMENT# [.rela.plt]. .58:; DT_PLTGOT. MOV EDX,[EDI+PFELF.Sss.got] TEST EDX JZ .76: ; When no dynamic relocations are present. JSt [EDI+PFELF.Status],pfelfWidth64,.60: BufferStoreDword [%dynamicEmitBuf],pfelfDT_PLTGOT CALL .Reloc: BufferStoreDword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr=VA of segment [.got]. JMPS .76: .60:BufferStoreQword [%dynamicEmitBuf],pfelfDT_PLTGOT CALL .Reloc: BufferStoreQword [%dynamicEmitBuf],0 ; DYNAMIC.d_ptr=VA of segment [.got]. .76:; DT_BIND_NOW. JSt [EDI+PFELF.Status],pfelfWidth64,.78: BufferStoreDword [%dynamicEmitBuf],pfelfDT_BIND_NOW BufferStoreDword [%dynamicEmitBuf],0 ; DYNAMIC.d_val=ignored. BufferStoreDword [%dynamicEmitBuf],pfelfDT_FLAGS_1 BufferStoreDword [%dynamicEmitBuf],pfelfDF_1_NOW + pfelfDF_TEXTREL JMPS .80: .78:BufferStoreQword [%dynamicEmitBuf],pfelfDT_BIND_NOW BufferStoreQword [%dynamicEmitBuf],0 ; DYNAMIC.d_val=ignored. BufferStoreQword [%dynamicEmitBuf],pfelfDT_FLAGS BufferStoreQword [%dynamicEmitBuf],pfelfDF_BIND_NOW ;;;;;;;;;;;;;; + pfelfDF_TEXTREL BufferStoreQword [%dynamicEmitBuf],pfelfDT_FLAGS_1 BufferStoreQword [%dynamicEmitBuf],pfelfDF_1_NOW ; DYNAMIC.d_val=1 (bind now). .80: ; DT_NULL. BufferStoreQword [%dynamicEmitBuf],pfelfDT_NULL ; DYNAMIC.p_tag=DT_NULL, terminate Dynamic table. BufferStoreQword [%dynamicEmitBuf],0 Invoke SssUpdateByEmit::,[EDI+PFELF.Sss.dynamic] Invoke SssUpdateByEmit::,[EDI+PFELF.Sss.dynstr] .Reloc: PROC1 ; Write RELOC record to %dynamicEmitBuf. ; Input: EDI=^PFELF, EDX=target ^SSS PUSHAD BufferNew [%dynamicRelocBuf],SIZE# RELOC, Zeroed=Yes MOV EBX,EAX MOV ECX,[EDI+PFELF.Sss.dynamic] MOV [EBX+RELOC.Section],ECX BufferRetrieve [%dynamicEmitBuf] MOV [EBX+RELOC.OrgLow],ECX MOV EAX,[EDX+SSS.SymPtr] ; Symbol associated with the target segment. MOV [EBX+RELOC.Symbol],EAX MOV [EBX+RELOC.Status],relocWidth32+relocAbsVA POPAD RET ENDP1 .Reloc: .90:EndProcedure PfelfsoDynamic
[.dynamic], [.dynsym], [.hash], [.dynstr], [.rel(a).dyn]. [.interp]
.PfelfsoSssDynTab Procedure Pfelf, Group MOV EDI,[%Pfelf] MOV EBX,[EDI+PFELF.Pgm] MOV EDX,[%Group] ListNew [EBX+PGM.SssList],Zeroed=yes ; Create SSS [.dynamic]. MOV ESI,EAX MOV [EDI+PFELF.Sss.dynamic],ESI SetSt [ESI+SSS.Status],sssSegment+sssUsed+sssNotBSS MOV [ESI+SSS.NamePtr],=B".dynamic" MOV [ESI+SSS.NameSize],8 MOV [ESI+SSS.Purpose],sssPurposeDYNAMIC BufferCreate [EBX+PGM.Pool],Size=1K MOV [ESI+SSS.EmitBuffer],EAX BufferCreate [EBX+PGM.Pool],Size=1K MOV [ESI+SSS.RelocBuffer],EAX MOV EAX,16 JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.40: MOV AL,8 .40:MOV [ESI+SSS.Alignment],EAX Invoke SymCreateSe::,ESI,EBX ListNew [EBX+PGM.SssList],Zeroed=yes ; Create SSS [.dynsym]. MOV ESI,EAX MOV [EDI+PFELF.Sss.dynsym],ESI SetSt [ESI+SSS.Status],sssSegment+sssUsed+sssNotBSS MOV [ESI+SSS.NamePtr],=B".dynsym" MOV [ESI+SSS.NameSize],7 MOV [ESI+SSS.GroupPtr],EDX MOV [ESI+SSS.Purpose],sssPurposeSYMBOLS BufferCreate [EBX+PGM.Pool],Size=1K MOV [ESI+SSS.EmitBuffer],EAX BufferCreate [EBX+PGM.Pool],Size=1K MOV [ESI+SSS.RelocBuffer],EAX MOV EAX,8 JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.50: MOV AL,16 .50:MOV [ESI+SSS.Alignment],EAX Invoke SymCreateSe::,ESI,EBX ListNew [EBX+PGM.SssList],Zeroed=yes ; Create SSS [.dynstr]. MOV ESI,EAX MOV [EDI+PFELF.Sss.dynstr],ESI SetSt [ESI+SSS.Status],sssSegment+sssUsed+sssNotBSS MOV [ESI+SSS.NamePtr],=B".dynstr" MOV [ESI+SSS.NameSize],7 MOV [ESI+SSS.GroupPtr],EDX MOV [ESI+SSS.Purpose],sssPurposeSTRINGS MOV [ESI+SSS.Alignment],1 BufferCreate [EBX+PGM.Pool],Size=1K MOV [ESI+SSS.EmitBuffer],EAX Invoke SymCreateSe::,ESI,EBX ListNew [EBX+PGM.SssList],Zeroed=yes ; Create SSS [.hash]. MOV ESI,EAX MOV [EDI+PFELF.Sss.hash],ESI SetSt [ESI+SSS.Status],sssSegment+sssUsed+sssNotBSS MOV [ESI+SSS.NamePtr],=B".hash" MOV [ESI+SSS.NameSize],5 MOV [ESI+SSS.GroupPtr],EDX MOV [ESI+SSS.Purpose],sssPurposeHASH BufferCreate [EBX+PGM.Pool],Size=512 MOV [ESI+SSS.EmitBuffer],EAX MOV [ESI+SSS.Alignment],4 Invoke SymCreateSe::,ESI,EBX JNSt [EDI+PFELF.Status],pfelfDynamic,.90: ListNew [EBX+PGM.SssList],Zeroed=yes ; Create and fill SSS [.interp] only if the created DSO links other DSOs. MOV ESI,EAX MOV [EDI+PFELF.Sss.interp],EAX SetSt [ESI+SSS.Status],sssSegment+sssUsed+sssNotBSS MOV [ESI+SSS.NamePtr],=B".interp" MOV [ESI+SSS.NameSize],7 MOV [ESI+SSS.GroupPtr],EDX MOV [ESI+SSS.Purpose],sssPurposeINTERP MOV [ESI+SSS.Alignment],1 MOV ECX,[Ea.Eaopt.InterpreterSize::] INC ECX BufferCreate [EBX+PGM.Pool],Size=ECX MOV [ESI+SSS.EmitBuffer],EAX MOV [ESI+SSS.TopLow],ECX DEC ECX MOV ESI,[Ea.Eaopt.InterpreterPtr::] BufferStore EAX,ESI,ECX BufferStoreByte EAX,0 .90:EndProcedure PfelfsoSssDynTab
PfelfsoCompile Procedure OutputStream, Pgm Pfelf LocalVar Size=SIZE# PFELF ; PFELF object. MOV EBX,[%Pgm] LEA EDI,[%Pfelf] Invoke PfelfCreate::,EDI,EBX ; Create groups and segments for ELF-special sections. Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"LOAD.HDR",8,0,sssPurposeRODATA MOV [EDI+PFELF.Sss.LOAD.HDR],EAX Invoke PfelfSssTab::,EDI,EAX ; Create ELF-special empty SSS segments [], [.symtab], [.strtab], [.shstrtab]. Invoke PfelfsoSssDynTab,EDI,EAX ; Create ELFSO-special SSS segments: [.dynamic], [.dynsym], [.hash], [.dynstr], [.interp]. Invoke PfelfRelaCreate::,EDI ; Create segments [.rel(a)name] for each segment with relocations. ;Create groups of regular segments. Invoke PfelfSssSeg::,EDI ; Fill PFELF.Buffer.CODE/RODATA/DATA with pointers to segments. BufferRetrieve [EDI+PFELF.Buffer.CODE] SHR ECX,2 JZ .15: ; Do not create [LOAD.CODE] group when no CODE/PLT segment exists. Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"LOAD.CODE",9,sssGroup,sssPurposeCODE+sssPurposePLT MOV EDX,EAX MOV [EDX+SSS.Alignment],%LinPageSize MOV [EDI+PFELF.Sss.LOAD.CODE],EDX .10:LODSD MOV [EAX+SSS.GroupPtr],EDX LOOP .10: .15:BufferRetrieve [EDI+PFELF.Buffer.RODATA] SHR ECX,2 JZ .25: ; Do not create [LOAD.RODATA] group when no RODATA segment exists. Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"LOAD.RODATA",11,sssGroup,sssPurposeRODATA MOV EDX,EAX MOV [EDX+SSS.Alignment],%LinPageSize MOV [EDI+PFELF.Sss.LOAD.RODATA],EDX .20:LODSD MOV [EAX+SSS.GroupPtr],EDX LOOP .20: .25:BufferRetrieve [EDI+PFELF.Buffer.DATA] Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"LOAD.DATA",9,sssGroup,sssPurposeDATA+sssPurposeBSS+sssPurposeGOT+sssPurposeDYNAMIC MOV EDX,EAX MOV [EDX+SSS.Purpose],sssPurposeDATA MOV [EDX+SSS.Alignment],%LinPageSize MOV [EDI+PFELF.Sss.LOAD.DATA],EDX SHR ECX,2 JZ .35: ; Do not create [LOAD.DATA] group when no DATA/GOT/BSS/DYNAMIC segment exists. .30:LODSD MOV [EAX+SSS.GroupPtr],EDX LOOP .30: .35:Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"DYNAMIC",7,0,sssPurposeDYNAMIC MOV [EDI+PFELF.Sss.DYNAMIC],EAX MOV ECX,16 JSt [EDI+PFELF.Status],pfelfWidth64,.38: MOV CL,8 .38:MOV ESI,[EDI+PFELF.Sss.dynamic] ; Order groups and segments. ; Order ELF special groups and segments. BufferStoreDword [EBX+PGM.SegOrdBuffer],[EDI+PFELF.Sss.LOAD.HDR] ; [LOAD.HDR]. BufferStoreDword [EBX+PGM.SegOrdBuffer],[EDI+PFELF.Sss] ; [] (NULL section). BufferStoreDword [EBX+PGM.SegOrdBuffer],[EDI+PFELF.Sss.symtab] ; [.symtab]. MOV ECX,[EDI+PFELF.Sss.dynsym] JECXZ .43: BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX ; [.dynsym]. .43:Invoke SssFindByPurpose::,sssSegment,sssPurposeRELOC,sssDontCare,0,EBX,[EDI+PFELF.Buffer] BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX .45:MOV ECX,[EDI+PFELF.Sss.hash] JECXZ .46: BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX ; [.hash]. .46:MOV ECX,[EDI+PFELF.Sss.dynstr] JECXZ .47: BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX ; [.dynstr]. .47:BufferStoreDword [EBX+PGM.SegOrdBuffer],[EDI+PFELF.Sss.strtab] ; [.strtab]. BufferStoreDword [EBX+PGM.SegOrdBuffer],[EDI+PFELF.Sss.shstrtab] ; [.shstrtab]. MOV ECX,[EDI+PFELF.Sss.LOAD.CODE] JECXZ .50: BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX ; [LOAD.CODE]. BufferRetrieve [EDI+PFELF.Buffer.CODE] BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX ; [.text] (all code sections). .50:MOV ECX,[EDI+PFELF.Sss.LOAD.RODATA] JECXZ .55: BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX ; [LOAD.RODATA]. BufferRetrieve [EDI+PFELF.Buffer.RODATA] BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX ; [.rodata] (all read-only data sections). .55:MOV ECX,[EDI+PFELF.Sss.LOAD.DATA] JECXZ .65: BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX ; [LOAD.DATA]. BufferRetrieve [EDI+PFELF.Buffer.DATA] BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX ; [.data] (all data+got+bss sections). .65:MOV ECX,[EDI+PFELF.Sss.DYNAMIC] JECXZ .70: BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX ; [DYNAMIC]. .70:; Enumerate and index all ordered segments. BufferRetrieve [EBX+PGM.SegOrdBuffer] SUB EDX,EDX ; SSS.SegmIndex. ADD ECX,ESI .75:CMP ESI,ECX JNB .80: LODSD JNSt [EAX+SSS.Status],sssSegment,.75: MOV [EAX+SSS.SegmIndex],EDX INC EDX JMP .75: .80:; Index all symbols, ordered by their type and name. Invoke PgmOrderSymbols::,EBX ; Create contents of ELF-special sections. Invoke PfelfConvertSymbols::,EDI,0 ; Convert €ASM symbols to PFELF_SYM in [.symtab], write their names to [.strtab]. Invoke PfelfConvertSymbols::,EDI,pfelfDyn ; Convert €ASM symbols to PFELF_SYM in [.dynsym], write their names to [.dynstr]. Invoke PfelfRelaConvert::,EDI ; Convert relocations form regular segments into [.rel(a)name].EmitBuffer. Invoke PfelfsoHashTable,EDI ; Fill [.hash] SSS.EmitBuffer. Invoke PfelfsoDynamic,EDI ; Fill [.dynamic] SSS.EmitBuffer. ; All SYM and SSS are indexed. Invoke PfelfShdr::,EDI ; Create ELF section headers, pass 1. Invoke PfelfHdrsLink::,EDI ; Calculate PFELF.HDRsEnd. Invoke PfelfsoLink,EDI ; Set VA, FA, sizes of all ELF "program segments" and "sections". Invoke PgmSymResolve::,EBX ; Match external symbols to statically linked public symbols. BufferRetrieve [EBX+PGM.SegOrdBuffer] ADD ECX,ESI .81:CMP ESI,ECX JNB .88: LODSD JNSt [EAX+SSS.Status],sssSegment,.81: JSt [EAX+SSS.Purpose],sssPurposeRegular,.81: ; Do not resolve relocations in reg.sections yet (.text, .data...). Invoke SssRelocResolve::,EAX,EBX ; Resolve .symtab, .dynsym, .dynamic. JMP .81: .88:Invoke PfelfEhdr::,EDI,pfelfDyn Invoke PfelfPhdr::,EDI Invoke PfelfShdr::,EDI ; Flush the output. MOV EDX,[%OutputStream] Invoke PfelfHdrsStream::,EDI,EDX Invoke PgmStreamImage::,EBX,EDX Invoke PfelfDestroy::,EDI EndProcedure PfelfsoCompile
ENDPROGRAM pfelfso