| Index | Manual | Download | Source | Macros | Embedded word Case ins.
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 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 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 Pfelf

  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.

Input
  Pfelf is pointer to PFELF object.
Output
  FA and VA addresses of all SSS segments and groups are adjusted.
See also
  PgmLink PfelfLink PfelfxLink PfelfsoLink
Error
  Errors are reported with macro Msg.
Invokes
  ExpAlign PgmResizeGroups
Invoked by
  PfelfsoCompile

    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▲