| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# pfelfx.htm
Structures
Encodings
Procedures
PfelfxCompile
PfelfxPltGot
PfelfxLink
PfelfxLoadPgm

This EuroAssembler source pfelfx.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.

    pfelfx 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,pgm.htm,pgmopt.htm,reloc.htm,sss.htm,stm.htm,sym.htm

     pfelfx HEAD ; Start module interface.
    %LinPageSize    %SETA 4K ; Memory page size fixed at 1000h in 32bit Linux.

         ENDHEAD pfelfx

↑ PfelfxLoadPgm BasePgm, ObjBegin, ObjSize, FileNamePtr

  PfelfxLoadPgm reads the contents of one ELF file and converts it to structures of a fresh new program, which then will be stored on `BasePgm.ModulePgmList`.

  This procedure works with ELF types Relocatable, Executable and SharedObject in both 32bit and 64bit mode.

Input
  BasePgm is pointer to an existing PGM to which the object file is being linked/imported.
  ObjBegin is pointer to the contents of ELF file mapped in memory by the caller. It must start with PFELF_E_IDENT.
  ObjSize is number of bytes in the ELF object.
  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

    PfelfxLoadPgm Procedure BasePgm, ObjBegin, ObjSize, FileNamePtr
          Msg '8534',Dict_FormatELFX::,[%FileNamePtr] ; Format !1S of file "!2$" is not linkable.
        EndProcedure PfelfxLoadPgm

↑ PfelfxLink Pfelf

  PfelfxLink calculates size, alignment, virtual and file address of every program segment.

  It does not change the contents of `SSS.EmitBuffer, SSS.RelocBuffer`; the actual raw contents of segments is not concatenated into image here because relocations are not resolved yet.

Input
  Pfelf is pointer to PFELF object.
Output
  Segment and group addresses are adjusted.
Error
  Errors are reported with macro Msg.
See also
  PgmLink PfelfLink PfelfsoLink
Invokes
  ExpAlign PgmResizeGroups
Invoked by
  PfelfxCompile

    PfelfxLink Procedure Pfelf
    ArrayPtr     LocalVar ; Pointer into the array of DWORD pointers to SSS groups and segments (ELF programs and sections).
    ArrayEnd     LocalVar ; Behind the last pointer of the array.
    Size         LocalVar ; Virtual (emitted or reserved) segment size.
    FA           LocalVar ; Current file address when linked.
    VALow        LocalVar ; Current virtual address when linked, including ImageBase.
    VAHigh       LocalVar
    FileAlign    LocalVar ; PGMOPT.FileAlign.
    SectionAlign LocalVar ; PGMOPT.SectionAlign.
        MOV EDI,[%Pfelf]
        MOV EBX,[EDI+PFELF.Pgm]
        MOV EAX,[EBX+PGM.Pgmopt.FileAlign]
        MOV EDX,[EBX+PGM.Pgmopt.SectionAlign]
        MOV [%FileAlign],EAX
        MOV [%SectionAlign],EDX
        MOV ECX,[EDI+PFELF.HDRsEnd]
        MOV [%FA],ECX
        MOV EAX,[EBX+PGM.Pgmopt.ImageBaseLow]
        MOV EDX,[EBX+PGM.Pgmopt.ImageBaseHigh]
        MOV [%VALow],EAX
        MOV [%VAHigh],EDX
        BufferRetrieve [EBX+PGM.SegOrdBuffer]        ; Array of DWORD pointers to SSS.
        ADD ECX,ESI
        MOV [%ArrayPtr],ESI                          ; Prepare the main loop for all SSS objects.
        MOV [%ArrayEnd],ECX
    .10:MOV ESI,[%ArrayPtr]                          ; The main loop: Adjust FA and VA of all segments.
        CMP ESI,[%ArrayEnd]
        JNB .35:                                     ; End when all segments were linked.
        LODSD
        MOV [%ArrayPtr],ESI
        MOV EBX,EAX                                  ; EBX is the linked group or segment.
        CMPD [EBX+SSS.NameSize],0
        JZ .10:                                      ; Ignore the empty segment [] (ELF NULL section).
        ; Fork groups (ELF program headers) and segments (ELF sections).
        JSt [EBX+SSS.Status],sssSegment,.20:
        JNSt [EBX+SSS.Status],sssGroup,.10:

        ; Link the €ASM group EBX, also called "ELF program header".
        MOV EAX,[%VALow]                              ; A new [LOAD.*] group has different access flags, %VA rounds up by %LinPageSize.
        MOV EDX,[%VAHigh]
        Invoke ExpAlign::,EAX,%LinPageSize,0
        ADD EAX,ECX
        ADC EDX,0
        MOV [%VALow],EAX
        MOV [%VAHigh],EDX
        JMP .10:

    .20:; Link the €ASM segment EBX, also called "ELF section".
        SetSt [EBX+SSS.Status],sssLinked             ; This will tell relocation resolver that its VA is already fixed.
        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

        ; Compute segment's file address.
        MOV EAX,[%FA]                                ; Top FA of previous segment.
        MOV ECX,[EBX+SSS.Alignment]                  ; Segment's own alignment.
        JNSt [EBX+SSS.Purpose],sssPurposeDYNAMIC,.25:
        mov ecx,%LinPageSize
    .25:JSt [EBX+SSS.Purpose],sssPurposeElfMask,.30: ; PROGRAM FileAlign= is ignored for ELF-special sections .symtab, .strtab etc.
        CMP ECX,[%FileAlign]
        JAE .30:
        MOV ECX,[%FileAlign]                         ; PROGRAM FileAlign= applies to regular sections .text, .data etc.
    .30:Invoke ExpAlign::,EAX,ECX,0
        ADD EAX,ECX
        MOV [EBX+SSS.BottomFA],EAX
        BufferRetrieve [EBX+SSS.EmitBuffer]
        ADD EAX,ECX
        MOV [EBX+SSS.TopFA],EAX
        MOV [%FA],EAX
        ; Compute segment's memory address.
        MOV ECX,%LinPageSize-1                       ; 0x0000_0FFF
        AND ECX,[EBX+SSS.BottomFA]
        MOV EAX,[%VALow]
        MOV EDX,[%VAHigh]
        AND EAX,~(%LinPageSize-1)
        OR EAX,ECX                                   ; Make FA and VA congruent.
        MOV [EBX+SSS.BottomLow],EAX
        MOV [EBX+SSS.BottomHigh],EDX
        ADD EAX,[%Size]
        ADC EDX,0
        MOV [EBX+SSS.TopLow],EAX
        MOV [EBX+SSS.TopHigh],EDX
        MOV [%VALow],EAX
        MOV [%VAHigh],EDX
        JMP .10:

    .35:MOV EBX,[EDI+PFELF.Pgm]
        Invoke PgmResizeGroups::,EBX                 ; Update VA of groups by their segments.
        ; Special adjustment of group  [LOAD.HDR]
        MOV ECX,[EDI+PFELF.Sss.LOAD.HDR]
        JECXZ .40:
        MOV EAX,[EBX+PGM.Pgmopt.ImageBaseLow]
        MOV EDX,[EBX+PGM.Pgmopt.ImageBaseHigh]
        MOV [ECX+SSS.BottomLow],EAX
        MOV [ECX+SSS.BottomHigh],EDX
        MOVD [ECX+SSS.BottomFA],0
    .40:
        ; Special adjustment of group  [DYNAMIC] - copies FA and VA from segment [.dynamic].
        MOV ECX,[EDI+PFELF.Sss.dynamic]
        JECXZ .45:
        MOV ESI,[EDI+PFELF.Sss.DYNAMIC]
        MOV EAX,[ECX+SSS.BottomLow]
        MOV EDX,[ECX+SSS.BottomHigh]
        MOV [ESI+SSS.BottomLow],EAX
        MOV [ESI+SSS.BottomHigh],EDX
        MOV EAX,[ECX+SSS.TopLow]
        MOV EDX,[ECX+SSS.TopHigh]
        MOV [ESI+SSS.TopLow],EAX
        MOV [ESI+SSS.TopHigh],EDX
        MOV EAX,[ECX+SSS.BottomFA]
        MOV EDX,[ECX+SSS.TopFA]
        MOV [ESI+SSS.BottomFA],EAX
        MOV [ESI+SSS.TopFA],EDX
    .45:MOV ECX,16
        JSt [EDI+PFELF.Status],pfelfWidth64,.50:
        MOV CL,8
    .50:MOV [ESI+SSS.Alignment],ECX
        ; Special adjustment of group [PHDR] which covers PT_PHDR records only, FA starts at 40h (fixed), VA at ImageBase+40h. Size=%PHDRsize.
        MOV ESI,[EDI+PFELF.Sss.PHDR]
        TEST ESI
        JZ .70:
        MOV EAX,40h                              ; SIZE# PFELF_EHDR rounded up to 16.
        XOR EDX,EDX
        MOV [ESI+SSS.BottomFA],EAX
        MOV [ESI+SSS.TopFA],EAX
        ADD EAX,[EBX+PGM.Pgmopt.ImageBaseLow]
        ADC EDX,0
        MOV [ESI+SSS.BottomLow],EAX
        MOV [ESI+SSS.BottomHigh],EDX
        MOV [ESI+SSS.TopLow],EAX
        MOV [ESI+SSS.TopHigh],EDX
        PUSH ESI
          BufferRetrieve [EBX+PGM.SegOrdBuffer]
          SUB EDX,EDX
          SHR ECX,2
          JZ .65:
    .55:  LODSD
          JNSt [EAX+SSS.Status],sssGroup,.60:
          ADD EDX,[EDI+PFELF.PHDRSize]
    .60:  LOOP .55:
    .65:POP ESI                                  ; EDX is SIZE#[PHDR].
        ADD [ESI+SSS.TopFA],EDX
        ADD [ESI+SSS.TopLow],EDX
        ADCD [ESI+SSS.TopHigh],0
    .70: ; Special adjustment of group  [INTERP] - copies FA and VA from segment [.interp].
        MOV ECX,[EDI+PFELF.Sss.interp]
        JECXZ .90:
        MOV ESI,[EDI+PFELF.Sss.INTERP]
        MOV EAX,[ECX+SSS.BottomLow]
        MOV EDX,[ECX+SSS.BottomHigh]
        MOV [ESI+SSS.BottomLow],EAX
        MOV [ESI+SSS.BottomHigh],EDX
        MOV EAX,[ECX+SSS.TopLow]
        MOV EDX,[ECX+SSS.TopHigh]
        MOV [ESI+SSS.TopLow],EAX
        MOV [ESI+SSS.TopHigh],EDX
        MOV EAX,[ECX+SSS.BottomFA]
        MOV EDX,[ECX+SSS.TopFA]
        MOV [ESI+SSS.BottomFA],EAX
        MOV [ESI+SSS.TopFA],EDX
        MOVD [ESI+SSS.Alignment],1
    .90:EndProcedure PfelfxLink

↑ PfelfxCompile OutputStream, Pgm
  PfelfxCompile is a constructor of output 32bit or 64bit executable file for Linux.
Documented
  [ELF32], [ELF64].
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 PfelfShdr PfelfSssSeg PfelfSssTab PfelfsoDynamic PfelfsoHashTable PfelfsoSssDynTab PfelfxLink PfelfxPltGot PgmOrderSymbols PgmRelocResolve PgmStreamImage SssCreateGroup

    PfelfxCompile Procedure OutputStream, Pgm
    Pfelf      LocalVar Size=SIZE# PFELF             ; PFELF object.
        MOV EBX,[%Pgm]
        LEA EDI,[%Pfelf]
        Invoke PfelfCreate::,EDI,EBX
        Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"LOAD.HDR",8,0,sssPurposeRODATA
        MOV [EDI+PFELF.Sss.LOAD.HDR],EAX
        MOV [EAX+SSS.Alignment],%LinPageSize
        Invoke PfelfSssTab::,EDI,EAX                 ; Create ELF-special empty SSS segments [], [.symtab], [.strtab], [.shstrtab].
        JNSt [EDI+PFELF.Status],pfelfDynamic,.11:    ; Skip when none of linked modules is ELFSO (ELFX is being statically linked).
        Invoke PfelfsoSssDynTab::,EDI,EAX            ; Create ELFSO-special SSS segments: [.dynamic], [.dynsym], [.hash], [.dynstr], [.rel(a).dyn]. [.interp].
        Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"INTERP",6,0,sssPurposeINTERP
        MOV [EDI+PFELF.Sss.INTERP],EAX
        MOV [EAX+SSS.Alignment],1
    .11:                                             ; 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 .17:                                      ; Do not create [LOAD.CODE] group when no CODE/PLT segment exists.
        Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"LOAD.CODE",9,0,0
        MOV EDX,EAX
        MOV [EDX+SSS.Alignment],%LinPageSize
        MOV [EDI+PFELF.Sss.LOAD.CODE],EDX            ; EDX is the just created SSS group, i.e. ELF program segment.
    .13:LODSD                                        ; EAX is one of SSS segments which belongs to the group EDX.
        MOV [EAX+SSS.GroupPtr],EDX
        MOV EBX,[EAX+SSS.Alignment]
        CMP EBX,[EDX+SSS.Alignment]
        JBE .15:
        MOV [EDX+SSS.Alignment],EBX                  ; Group alignment = highest alignment of its segments.
    .15:LOOP .13:
    .17:BufferRetrieve [EDI+PFELF.Buffer.RODATA]
        SHR ECX,2
        JZ .23:                                      ; Do not create [LOAD.RODATA] group when no RODATA segment exists.
        MOV EBX,[EDI+PFELF.Pgm]
        Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"LOAD.RODATA",11,0,0
        MOV EDX,EAX
        MOV [EDX+SSS.Alignment],%LinPageSize
        MOV [EDI+PFELF.Sss.LOAD.RODATA],EDX
    .19:LODSD
        MOV [EAX+SSS.GroupPtr],EDX
        MOV EBX,[EAX+SSS.Alignment]
        CMP EBX,[EDX+SSS.Alignment]
        JBE .21:
        MOV [EDX+SSS.Alignment],%LinPageSize         ; Group alignment = highest alignment of its segments.
    .21:LOOP .19:
    .23:BufferRetrieve [EDI+PFELF.Buffer.DATA]
        SHR ECX,2
        JZ .29:                                      ; Do not create [LOAD.DATA] group when no DATA/GOT/BSS segment exists.
        MOV EBX,[EDI+PFELF.Pgm]
        Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"LOAD.DATA",9,0,0
        MOV EDX,EAX
        MOV [EDX+SSS.Alignment],%LinPageSize
        MOV [EDI+PFELF.Sss.LOAD.DATA],EDX
    .25:LODSD
        MOV [EAX+SSS.GroupPtr],EDX
        MOV EBX,[EAX+SSS.Alignment]
        CMP EBX,[EDX+SSS.Alignment]
        JBE .27:
        MOV [EDX+SSS.Alignment],EBX                  ; Group alignment = highest alignment of its segments.
    .27:LOOP .25:
    .29:MOV EBX,[EDI+PFELF.Pgm]
        JNSt [EDI+PFELF.Status],pfelfDynamic,.33:    ; Skip when none of linked modules is ELFSO (ELFX is being statically linked).
        Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"PHDR",4,0,sssPurposePHDR
        MOV [EDI+PFELF.Sss.PHDR],EAX
        Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"LOAD.DYNAMIC",12,0,sssPurposeDATA
        MOV [EDI+PFELF.Sss.LOAD.DYNAMIC],EAX
        MOV [EAX+SSS.Alignment],%LinPageSize
        Invoke SssCreateGroup::,[EBX+PGM.CurrentStm],=B"DYNAMIC",7,0,sssPurposeDYNAMIC
        MOV [EDI+PFELF.Sss.DYNAMIC],EAX
        mov [EAX+SSS.Alignment],%LinPageSize
        MOV ECX,16
        JSt [EDI+PFELF.Status],pfelfWidth64,.31:
        MOV CL,8
    .31:MOV ESI,[EDI+PFELF.Sss.dynamic]
        MOV [ESI+SSS.GroupPtr],EAX
        MOV [ESI+SSS.Alignment],ECX
    .33:MOV EBX,[EDI+PFELF.Pgm]
        ; All groups and segments are created now (but not their contents yet).
        ; Set the order of ELF special groups and segments into PGM.SegOrdBuffer.
        MOV ECX,[EDI+PFELF.Sss.PHDR]
        JECXZ .35:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [PHDR].
    .35:MOV ECX,[EDI+PFELF.Sss.INTERP]
        JECXZ .37:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [INTERP].
    .37: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 .39:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [.dynsym].
    .39:MOV ECX,[EDI+PFELF.Sss.rela.dyn]
        JECXZ .41:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [.rela.dyn].
    .41:MOV ECX,[EDI+PFELF.Sss.rela.plt]
        JECXZ .43:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [.rela.plt].
    .43:MOV ECX,[EDI+PFELF.Sss.hash]
        JECXZ .45:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [.hash].
    .45:MOV ECX,[EDI+PFELF.Sss.dynstr]
        JECXZ .47:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [.dynstr].
    .47:MOV ECX,[EDI+PFELF.Sss.interp]
        JECXZ .49:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [.interp].
    .49: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 .51:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [LOAD.CODE].
        BufferRetrieve [EDI+PFELF.Buffer.CODE]
        BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX                       ; [.text], [.plt] (all code sections).
    .51:MOV ECX,[EDI+PFELF.Sss.LOAD.RODATA]
        JECXZ .53:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [LOAD.RODATA].
        BufferRetrieve [EDI+PFELF.Buffer.RODATA]
        BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX                       ; [.rodata] (all read-only data sections).
    .53:MOV ECX,[EDI+PFELF.Sss.LOAD.DATA]
        JECXZ .55:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [LOAD.DATA].
        BufferRetrieve [EDI+PFELF.Buffer.DATA]
        BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX                       ; [.data], [.got], [.bss] (all data+bss sections).
    .55:MOV ECX,[EDI+PFELF.Sss.LOAD.DYNAMIC]
        JECXZ .57:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [LOAD.DYNAMIC].
        MOV EAX,[EDI+PFELF.Sss.dynamic]
        MOV [EAX+SSS.GroupPtr],ECX
        BufferStoreDword [EBX+PGM.SegOrdBuffer],EAX                      ; [.dynamic].
    .57:MOV ECX,[EDI+PFELF.Sss.DYNAMIC]
        JECXZ .59:
        BufferStoreDword [EBX+PGM.SegOrdBuffer],ECX                      ; [DYNAMIC].
    .59:BufferRetrieve [EBX+PGM.SegOrdBuffer]                            ; Enumerate and specify SSS.Segmindex of all ordered segments.
        SUB EDX,EDX                                                      ; EDX keeps SSS.SegmIndex.
        ADD ECX,ESI
    .61:CMP ESI,ECX
        JNB .63:
        LODSD
        JNSt [EAX+SSS.Status],sssSegment,.61:
        MOV [EAX+SSS.SegmIndex],EDX
        INC EDX
        JMP .61:
    .63:MOV ESI,[EDI+PFELF.Sss.rela.plt]
        MOV EDX,[EDI+PFELF.Sss.dynsym]
        TEST EDX
        JZ .65:
        MOV EAX,[EDX+SSS.SegmIndex]
        MOV [ESI+SSS.sh_link],EAX
    .65:MOV EDX,[EDI+PFELF.Sss.got]
        TEST EDX
        JZ .67:
        MOV EAX,[EDX+SSS.SegmIndex]
        MOV [ESI+SSS.sh_info],EAX
    .67:Invoke PgmOrderSymbols::,EBX                ; Put ^SYM dwords to Pgm.SymOrdBuffer. SYM.NameIndex and SYM.NameDynIndex are not set yet.
        ; Enumerate and specify SYM.NameIndex and SYM.NameDynIndex for symbols in PGM.SegOrdBuffer.
        BufferRetrieve [EBX+PGM.SymOrdBuffer]
        ADD ECX,ESI
        SUB EDX,EDX                                 ; EDX keeps SYM.NameIndex.
        SUB EBX,EBX                                 ; EBX keeps SYM.NameDynIndex.
    .69:CMP ESI,ECX
        JNB .71:
        LODSD
        MOV [EAX+SYM.NameIndex],EDX
        INC EDX
        JNSt [EAX+SYM.Status],symImport,.69:
        INC EBX
        MOV [EAX+SYM.NameDynIndex],EBX
        JMP .69:
    .71:; All SSS and SYM are indexed now.
        MOV EBX,[EDI+PFELF.Pgm]
        JNSt [EDI+PFELF.Status],pfelfDynamic,.73:    ; Skip when none of linked modules is ELFSO (ELFX is being statically linked).
        Invoke PfelfxPltGot,EDI                      ; Emit the contens of [.plt],[.got],[.rel(a).plt].
    .73:Invoke PfelfConvertSymbols,EDI,0             ; Convert €ASM symbols to PFELF_SYM in [.symtab], write their names to [.strtab]. Set SYM.NameIndex.
        JNSt [EDI+PFELF.Status],pfelfDynamic,.75:    ; Skip when none of linked modules is ELFSO (ELFX is being statically linked).
        Invoke PfelfConvertSymbols::,EDI,pfelfDyn    ; Convert €ASM symbols to PFELF_SYM in [.dynsym], write their names to [.dynstr]. Set SYM.NameDynIndex.
        Invoke PfelfsoHashTable::,EDI                ; Fill [.hash] SSS.EmitBuffer.
        Invoke PfelfsoDynamic::,EDI                  ; Fill [.dynamic] SSS.EmitBuffer.
        ; All SYM and SSS are indexed.
    .75:Invoke PfelfShdr::,EDI                       ; Create ELF section headers, pass 1.
        Invoke PfelfHdrsLink::,EDI                   ; Calculate PFELF.HDRsEnd.
        Invoke PfelfxLink,EDI                        ; Set VA, FA, sizes of all ELF "program segments" and "sections".
        JNSt [EDI+PFELF.Status],pfelfDynamic,.77:    ; Skip when none of linked modules is ELFSO (ELFX is being statically linked).
    .77:Invoke PgmRelocResolve::,[EDI+PFELF.Pgm]
        Invoke PfelfPhdr::,EDI
        Invoke PfelfEhdr::,EDI,pfelfExec             ; Create ELF file header.
        Invoke PfelfShdr::,EDI                       ; Create ELF section headers, pass 2.
        MOV EDX,[%OutputStream]
        Invoke PfelfHdrsStream::,EDI,EDX
        Invoke PgmStreamImage::,EBX,EDX
        Invoke PfelfDestroy::,EDI
       EndProcedure PfelfxCompile

↑ PfelfxPltGot Pfelf
  PfelfxPltGot is responsible for dynamic linking in ELFX executable.
  It is invoked when all sections and symbols are ordered and indexed but not linked yet.
  For each imported symbol in PGM.SymOrdBuffer it creates homonymous private symbols on PGM.SymList in ELF sections .plt and .got, resolves the imported symbol to symbol@plt, and emits records in SSS.EmitBuffer of [.plt] and [.got]. It also emits PFELF_REL* record in [.rel(a).plt].
Input
  Pfelf is Pfelf object.
Output
  EmitBuffer and RelocBuffer of [.plt],[.got],[.rel(a).plt].
Error
  Errors are reported with macro Msg.
Invokes
  SssUpdateByEmit
Invoked by
  PfelfxCompile

    PfelfxPltGot Procedure Pfelf
    SymPtr     LocalVar
    SymEnd     LocalVar
    Sym@impPtr LocalVar                              ; Original imported symbol in [sssImport]
    Sym@pltPtr LocalVar                              ; Homonymous copy in [.plt].
    Sym@gotPtr LocalVar                              ; Homonymous copy in [.got].
    DynIndex   LocalVar
        ClearLocalVar
        MOV EDI,[%Pfelf]
        MOV EBX,[EDI+PFELF.Pgm]
        BufferRetrieve [EBX+PGM.SymOrdBuffer]
        ADD ECX,ESI
        MOV [%SymPtr],ESI
        MOV [%SymEnd],ECX
    .10:MOV ESI,[%SymPtr]
        CMP ESI,[%SymEnd]
        JNB .90:
        LODSD
        MOV [%SymPtr],ESI
        JNSt [EAX+SYM.Status],symImport,.10:
        MOV [%Sym@impPtr],EAX
        MOV EBX,[EDI+PFELF.Pgm]
        ListStore [EBX+PGM.SymList],EAX              ; Create a homonymous symbol in [.got] as a copy of symbol EAX.
        MOV [%Sym@gotPtr],EAX
        MOV [EAX+SYM.Status],symPrivate              ; Rewrite some properties of both homonymous symbols.
        MOV [EAX+SYM.OffsetHigh],0
        ListStore [EBX+PGM.SymList],EAX              ; Create a homonymous symbol in [.plt].
        MOV [%Sym@pltPtr],EAX
        MOV EDX,[%Sym@impPtr]
        MOV [EDX+SYM.SymbPtr],EAX                    ; Redirect Sym@imp to Sym@plt to be relocated later.
        MOV ESI,[EDI+PFELF.Sss.plt]
        MOV [EAX+SYM.Section],ESI                    ; ESI=^SSS [.plt]
        BufferRetrieve [ESI+SSS.EmitBuffer]
        ADD ECX,6                                    ; Skip the size of "JMP symbol@got" emited it .plt
        MOV [EAX+SYM.OffsetLow],ECX                  ; Symbol@plt is ready.
        MOV EAX,[%Sym@gotPtr]
        MOV EDX,[EDI+PFELF.Sss.got]
        MOV [EAX+SYM.Section],EDX
        BufferRetrieve [EDX+SSS.EmitBuffer]          ; ECX=offset of symbol@got
        MOV [EAX+SYM.OffsetLow],ECX                  ; Symbol@got is ready.

        ; Create emited contents of [.plt]           ; EAX=^Sym@got
        MOV ESI,[EDI+PFELF.Sss.plt]
        BufferStoreWord  [ESI+SSS.EmitBuffer],0x25FF ; JMP sym@got,ADDR=REL
        BufferStoreDword [ESI+SSS.EmitBuffer],-4     ; This will be relocated to symbol@got
        BufferStoreByte  [ESI+SSS.EmitBuffer],0x68   ; PUSHQ imm
        MOV ECX,[EAX+SYM.NameDynIndex]
        DEC ECX
        BufferStoreDword [ESI+SSS.EmitBuffer],ECX
        BufferStoreByte  [ESI+SSS.EmitBuffer],0xE9   ; JMP .plt,ADDR=REL
        BufferStoreDword [ESI+SSS.EmitBuffer],-4     ; This will be relocated to the start of .plt

        ; Create relocation in .plt for JMP sym@got
        BufferNew [ESI+SSS.RelocBuffer],SIZE#RELOC,Zeroed=Yes
        MOV EBX,EAX                                  ; EBX=^RELOC
        MOV [EBX+RELOC.Section],ESI                  ; ESI=^SSS [.plt]
        BufferRetrieve [ESI+SSS.EmitBuffer]
        SUB ECX,14
        MOV [EBX+RELOC.OrgLow],ECX
        MOV [EBX+RELOC.Status],relocWidth32+relocRel
        MOV EDX,[EDI+PFELF.Sss.got]
        MOV EAX,[%Sym@gotPtr]
        MOV [EBX+RELOC.Symbol],EAX

        ; Create relocation in .plt for JMP .plt
        MOV ESI,[EDI+PFELF.Sss.plt]
        BufferNew [ESI+SSS.RelocBuffer],SIZE#RELOC,Zeroed=Yes
        MOV EBX,EAX                                  ; EBX=^RELOC
        MOV [EBX+RELOC.Section],ESI                  ; ESI=^SSS [.plt]
        ADD ECX,10
        MOV [EBX+RELOC.OrgLow],ECX
        MOV [EBX+RELOC.Status],relocWidth32+relocRel
        ;;MOV EAX,[%Sym@pltPtr]
        MOV ECX,[EDI+PFELF.Sss.plt]
        MOV EAX,[ECX+SSS.SymPtr]
        MOV [EBX+RELOC.Symbol],EAX
        ; Create emited contents of [.got]
        MOV ESI,[EDI+PFELF.Sss.got]
        BufferStoreQword [ESI+SSS.EmitBuffer],0

        ; Create relocation of address stored in .got
        BufferNew [ESI+SSS.RelocBuffer],SIZE#RELOC,Zeroed=Yes
        MOV EBX,EAX                                  ; EBX=^RELOC
        MOV [EBX+RELOC.Section],ESI                  ; ESI=^SSS [.got]
        MOV [EBX+RELOC.Status],relocWidth64+relocAbsVA
        BufferRetrieve [ESI+SSS.EmitBuffer]         ; ECX=offset of symbol@got
        SUB ECX,8
        MOV [EBX+RELOC.OrgLow],ECX
        MOV EAX,[%Sym@pltPtr]
        MOV [EBX+RELOC.Symbol],EAX

        ; Emit dynamic relocation PFELF_RELA* into [.rel(a).plt]
        MOV EDX,[EDI+PFELF.Sss.rela.plt]
        BufferRetrieve [EDX+SSS.EmitBuffer]           ; ECX=offset of PFELF_REL* record in .rel(a).plt
        BufferStoreQword [EDX+SSS.EmitBuffer],0       ; PFELF_RELA64.r_offset, will be relocated to symbol@got
        BufferStoreDword [EDX+SSS.EmitBuffer],pfelfR_X86_64_JUMP_SLOT ; PFELF_RELA64.r_info.low
        MOV EAX,[%Sym@gotPtr]
        BufferStoreDword [EDX+SSS.EmitBuffer],[EAX+SYM.NameDynIndex]  ; PFELF_RELA64.r_info.high
        BufferStoreQword [EDX+SSS.EmitBuffer],0       ; PFELF_RELA64.r_addend

        ; Create relocation of address in PFELF_RELA64.r_offset pointed to by ECX.
        BufferNew [EDX+SSS.RelocBuffer],SIZE# RELOC,Zeroed=Yes
        MOV EBX,EAX
        MOV [EBX+RELOC.OrgLow],ECX
        MOV [EBX+RELOC.Section],EDX
        MOV [EBX+RELOC.Status],relocWidth64+relocAbsVA
        MOV ECX,[%Sym@gotPtr]
        MOV [EBX+RELOC.Symbol],ECX
        JMP .10:
    .90:Invoke SssUpdateByEmit::,[EDI+PFELF.Sss.plt]
        Invoke SssUpdateByEmit::,[EDI+PFELF.Sss.got]
        Invoke SssUpdateByEmit::,[EDI+PFELF.Sss.rela.plt]
      EndProcedure PfelfxPltGot

      ENDPROGRAM pfelfx

▲Back to the top▲