EuroAssembler Index Manual Download Source Macros


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.
INCLUDEHEAD  \  ; Include headers of another modules used in this module.
ea.htm,      \
eaopt.htm,   \
exp.htm,     \
msg.htm,     \
pf.htm,      \
pfelf.htm,   \
pgm.htm,     \
pgmopt.htm,  \
reloc.htm,   \
sss.htm,     \
stm.htm,     \
sym.htm,     \
syswin.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 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],EBX                   ; Group alignment = highest alignment of its segments.
    mov [EDX+SSS.Alignment],%LinPageSize
.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 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                      ; [.dynstr].
.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▲