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 used in this source.
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
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