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 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.
BasePgm.ModulePgmList as a new
PGM structure.
PfelfxLoadPgm Procedure BasePgm, ObjBegin, ObjSize, FileNamePtr
      Msg '8534',Dict_FormatELFX::,[%FileNamePtr] ; Format !1S of file "!2$" is not linkable.
    EndProcedure PfelfxLoadPgm
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.
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 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 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