EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

pfelfso.htm
Structures
Encodings
Procedures
PfelfsoCompile
PfelfsoDynamic
PfelfsoHash
PfelfsoHashTable
PfelfsoLink
PfelfsoLoadPgm

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 BasePgm, ObjBegin, ObjSize, FileNamePtr

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.

Input
BasePgm is pointer to an existing PGM to which the object file is being linked/imported.
ObjBegin is pointer to the contents of ELFSO file mapped in memory by the caller. It must start with PFELF_E_IDENT.
ObjSize is number of bytes in the ELFSO object (filesize of the dso.so fil
FileNamePtr is pointer to zero-terminated object file name (used in error reports).
Output
Loaded program is stored on BasePgm.ModulePgmList as a new PGM structure.
Error
Errors are reported with macro Msg.
Invoked from
PfLoad
Invokes
PfelfLoadPgm
PfelfsoLoadPgm Procedure BasePgm, ObjBegin, ObjSize, FileNamePtr
  Invoke PfelfLoadPgm::,[%BasePgm],[%ObjBegin],[%ObjSize],[%FileNamePtr]
 EndProcedure PfelfsoLoadPgm
↑ PfelfsoHash StringPtr
PfelfsoHash computes hash of one ASCIIZ name pointed by StringPtr.
C-Algorithm
class="PRE">unsigned long pfelfsoHash(const unsigned char *name) {unsigned long hash = 0, g; while (*name) {hash = (hash << 4) + *name++; if (g = hash & 0xf000_0000) hash ^= (g >> 24); hash &= 0x0FFF_FFFF; hash &= ~g; used by Oracle but not in ld 2.34 }return hash; }
Manual
[ELF32],[ELF64]
Input
StringPtr is pointer to zero-terminated string (symbol name).
Output
EAX= the hash value.
Error
-
Invoked by
PfelfsoHashTable
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 Pfelf
PfelfsoHashTable fills SSS.EmitBuffer [.hash] with the contents of hash table for all global symbols stored in [.dynsym].EmitBuffer.
Manual
[ELF32],[ELF64]
Input
Pfelf is pointer to PFELF object.
Output
SSS.EmitBuffer of [.hash] is filled with hash table. SSS.Top is updated.
Error
Errors are reported with macro Msg.
Invoked by
PfelfsoCompile PfelfxCompile
Invokes
PfelfsoHash SssUpdateByEmit
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 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
↑ PfelfsoDynamic Pfelf
PfelfsoDynamic fills [%DynamicSSS].EmitBuffer with dynamic table entries (2*DWORD or 2*QWORD each).
[%DynStrSSS].EmitBuffer should be already filled with names of dynamic symbols.
Manual
[ELF32],[ELF64] Oracle guide
Input
Pfelf is pointer to PFELF object.
Output
EmitBuffer of PFELF.Sss.dynamic] is filled with Dynamic table, RelocBuffer with relocations.
Error
Errors are reported with macro Msg.
Invoked by
PfelfsoCompile PfelfxCompile
Invokes
SssUpdateByEmit
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
↑ PfelfsoSssDynTab Pfelf, Group
PfelfsoSssDynTab creates six ELF-dynamic-special empty SSS segments: [.dynamic], [.dynsym], [.hash], [.dynstr], [.rel(a).dyn]. [.interp].
Input
Pfelf is pointer to PFELF object.
Group is pointer to SSS sss.Group to be assigned to all created segments. It may be 0.
Output
Special SSS segments are stored on Pfelf.Pgm.SssList.
Error
Errors are reported with macro Msg.
See also
PfelfSssTab
Invoked by
PfelfsoCompile PfelfxCompile
Invokes
SymCreateSe
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 OutputStream, Pgm
PfelfsoCompile is a constructor of output 32bit or 64bit Dynamically Shared Object in ELF file format.
Input
OutputStream is pointer to a STREAM for the output file contents.
Pgm is pointer to PGM representing completely assembled and combined program.
Output
OutputStream is filled with output file contents.
Error
Errors are reported with macro Msg.
Invoked from
PfOutput
Invokes
PfelfConvertSymbols PfelfCreate PfelfDestroy PfelfEhdr PfelfHdrsLink PfelfHdrsStream PfelfPhdr PfelfRelaConvert PfelfRelaCreate PfelfShdr PfelfSssSeg PfelfSssTab PfelfsoDynamic PfelfsoHashTable PfelfsoLink PfelfsoSssDynTab PgmOrderSymbols PgmStreamImage PgmSymResolve SssCreateGroup SssFindByPurpose SssRelocResolve
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

▲Back to the top▲