EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

pfelf.htm
Structures
PFELF
PFELF_DYN32
PFELF_DYN64
PFELF_E_IDENT
PFELF_EHDR32
PFELF_EHDR64
PFELF_PHDR32
PFELF_PHDR64
PFELF_REL32
PFELF_REL64
PFELF_RELA32
PFELF_RELA64
PFELF_SHDR32
PFELF_SHDR64
PFELF_SYM32
PFELF_SYM64
Encodings
PfelfEncodings
Procedures
PfelfCompile
PfelfConvertSymbols
PfelfCreate
PfelfDestroy
PfelfEhdr
PfelfHdrsLink
PfelfHdrsStream
PfelfLink
PfelfLoadPgm
PfelfPhdr
PfelfRelaCreate
PfelfRelaConvert
PfelfShdr
PfelfSssTab
PfelfSssSeg

This EuroAssembler source pfelf.htm generates output linkable object file in program format ELF as described in [ELF32] and [ELF64].

Section in ELF documentation is equivalent to €ASM SEGMENT.
Segment in ELF documentation is equivalent to €ASM GROUP or module.

      EUROASM NOWARN=2101
pfelf 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,      \
pfelfx.htm,  \
pgm.htm,     \
pgmopt.htm,  \
reloc.htm,   \
sss.htm,     \
stm.htm,     \
sym.htm,     \
syswin.htm,  \
;;
 pfelf HEAD ; Start module interface.
↑ PfelfEncodings
Boolean flags and attributes used in ELF structure members.
Documented
[SystemV].

; PFELF_E_IDENT.e_class
pfelfClass32    = 1    ; 32bit object.
pfelfClass64    = 2    ; 64bit object.

; PFELF_E_IDENT.e_osabi
pfelfOSABI_NONE    = 0
pfelfOSABI_SYSV    = 0
pfelfOSABI_HPUX    = 1
pfelfOSABI_NETBSD  = 2
pfelfOSABI_LINUX   = 3
pfelfOSABI_GNU     = 3
pfelfOSABI_SOLARIS = 6
pfelfOSABI_AIX     = 7
pfelfOSABI_FREEBSD = 9
pfelfOSABI_OPENBSD = 12
pfelfOSABI_OPENVMS = 13

; PFELF_EHDR.e_type
pfelfRel        = 1    ; Relocatable object file.
pfelfExec       = 2    ; Executable file.
pfelfDyn        = 3    ; Shared object file.

; PFELF_EHDR.e_machine
pfelfMachine386 = 0x0003 ; Intel x86.
pfelfMachineX64 = 0x003E ; Intel x86_64.

; PFELF_SHDR.sh_type
pfelfSHT_NULL     =  0
pfelfSHT_PROGBITS =  1
pfelfSHT_SYMTAB   =  2
pfelfSHT_STRTAB   =  3
pfelfSHT_RELA     =  4
pfelfSHT_HASH     =  5
pfelfSHT_DYNAMIC  =  6
pfelfSHT_NOTE     =  7
pfelfSHT_NOBITS   =  8
pfelfSHT_REL      =  9
pfelfSHT_SHLIB    = 10
pfelfSHT_DYNSYM   = 11

; PFELF_SHDR.sh_flags
pfelfSHF_WRITE     = 0x0000_0001 ; Section contains writeble data.
pfelfSHF_ALLOC     = 0x0000_0002 ; Section will be allocated and readable.
pfelfSHF_EXECINSTR = 0x0000_0004 ; Section contains executable instructions.

; PFELF_SYM.st_info as sum of pfelfSTT* and pfelfSTB*.
pfelfSTT_NOTYPE    = 0x00 ; Symbol is scalar.
pfelfSTT_OBJECT    = 0x01 ; Symbol represents data object.
pfelfSTT_FUNC      = 0x02 ; Symbol represents function/procedure which requires PLT in SO format.
pfelfSTT_SECTION   = 0x03 ; Symbol represents section identified by PFELF_SYM.st_shndx.
pfelfSTT_FILE      = 0x04 ; Symbol represents source file.
pfelfSTB_LOCAL     = 0x00 ; Symbol has standard private scope.
pfelfSTB_GLOBAL    = 0x10 ; Symbol is public.
pfelfSTB_WEAK      = 0x20 ; Symbol is public if no other linked object file defines it.

; PFELF_SYM.st_shndx special values.
pfelfSHN_UNDEF     = 0x0000 ; Symbol is external.
pfelfSHN_ABS       = 0xFFF1 ; Symbol is scalar.
pfelfSHN_COMMON    = 0xFFF2 ; Symbol represents a common block not allocated yet in linking.

; PFELF_REL32.r_info LSB:
; Relocation type flag          val width calculation
pfelfR_386_NONE               =  0 ;  -   none
pfelfR_386_32                 =  1 ; 32   S + A
pfelfR_386_PC32               =  2 ; 32   S + A - P
pfelfR_386_GOT32              =  3 ; 32   G + A - P
pfelfR_386_PLT32              =  4 ; 32   L + A - P
pfelfR_386_COPY               =  5 ;  -   none
pfelfR_386_GLOB_DAT           =  6 ; 32   S
pfelfR_386_JMP_SLOT           =  7 ; 32   S
pfelfR_386_RELATIVE           =  8 ; 32   B + A
pfelfR_386_GOTOFF             =  9 ; 32   S + A - GOT
pfelfR_386_GOTPC              = 10 ; 32   GOT + A -P
; PFELF_RELA64.r_info LSDW:
pfelfR_X86_64_NONE            =  0 ;  -   none
pfelfR_X86_64_64              =  1 ; 64   S + A
pfelfR_X86_64_PC32            =  2 ; 32   S + A - P
pfelfR_X86_64_GOT32           =  3 ; 32   G + A
pfelfR_X86_64_PLT32           =  4 ; 32   L + A - P
pfelfR_X86_64_COPY            =  5 ;  -   none
pfelfR_X86_64_GLOB_DAT        =  6 ; 64   S
pfelfR_X86_64_JUMP_SLOT       =  7 ; 64   S
pfelfR_X86_64_RELATIVE        =  8 ; 64   B + A
pfelfR_X86_64_GOTPCREL        =  9 ; 32   G + GOT + A - P
pfelfR_X86_64_32              = 10 ; 32   S + A   ; Field is zero-extended to 64 bits.
pfelfR_X86_64_32S             = 11 ; 32   S + A   ; Field is sign-extended to 64 bits.
pfelfR_X86_64_16              = 12 ; 16   S + A
pfelfR_X86_64_PC16            = 13 ; 16   S + A - P
pfelfR_X86_64_8               = 14 ;  8   S + A
pfelfR_X86_64_PC8             = 15 ;  8   S + A - P
pfelfR_X86_64_DTPMOD64        = 16 ; 64
pfelfR_X86_64_DTPOFF64        = 17 ; 64
pfelfR_X86_64_TPOFF64         = 18 ; 64
pfelfR_X86_64_TLSGD           = 19 ; 32
pfelfR_X86_64_TLSLD           = 20 ; 32
pfelfR_X86_64_DTPOFF32        = 21 ; 32
pfelfR_X86_64_GOTTPOFF        = 22 ; 32
pfelfR_X86_64_TPOFF32         = 23 ; 32
pfelfR_X86_64_PC64            = 24 ; 64   S + A - P
pfelfR_X86_64_GOTOFF64        = 25 ; 64   S + A - GOT
pfelfR_X86_64_GOTPC32         = 26 ; 32   GOT + A - P
pfelfR_X86_64_SIZE32          = 32 ; 32   Z + A
pfelfR_X86_64_SIZE64          = 33 ; 64   Z + A
pfelfR_X86_64_GOTPC32_TLSDESC = 34 ; 32
pfelfR_X86_64_TLSDESC_CALL    = 35 ;  -
pfelfR_X86_64_TLSDESC         = 36 ; 64*2
pfelfR_X86_64_IRELATIVE       = 37 ; 64   indirect (B + A)

; For calculation shortcuts (S,A,GOT etc) see reloc.htm.
;
; The SYSTEM V architecture uses only PFELF_REL32 relocation entries,
; the field to be relocated holds the addend.
;
; The AMD64 ABI architectures uses only PFELF_RELA64 relocation entries
; with explicit addends. The .r_addend member serves as the relocation addend.

; PFELF_PHDR.p_type
pfelfPT_NULL    = 0 ; Unused entry.
pfelfPT_LOAD    = 1 ; Loadable segment.
pfelfPT_DYNAMIC = 2 ; Dynamic linking tables.
pfelfPT_INTERP  = 3 ; Program interpreter path name.
pfelfPT_NOTE    = 4 ; Note sections.
pfelfPT_SHLIB   = 5 ; Reserved.
pfelfPT_PHDR    = 6 ; Program header table.

; PFELF_PHDR.p_flags
pfelfPF_X       = 0x0001 ; Execute permission.
pfelfPF_W       = 0x0002 ; Write permission.
pfelfPF_R       = 0x0004 ; Read permission.

; PFELF_DYN.d_tag, see Dynamic Section
pfelfDT_BIND_NOW = 24
pfelfDT_DEBUG    = 21
pfelfDT_FLAGS    = 30
pfelfDT_FLAGS_1  = 0x6FFFFFFB
pfelfDT_GNU_HASH = 0x6FFFFEF5
pfelfDT_HASH     =  4
pfelfDT_JMPREL   = 23
pfelfDT_NEEDED   =  1
pfelfDT_NULL     =  0
pfelfDT_PLTGOT   =  3
pfelfDT_PLTREL   = 20
pfelfDT_PLTRELSZ =  2
pfelfDT_REL      = 17
pfelfDT_RELA     =  7
pfelfDT_RELAENT  =  9
pfelfDT_RELASZ   =  8
pfelfDT_RELENT   = 19
pfelfDT_RELSZ    = 18
pfelfDT_RPATH    = 15
pfelfDT_RUNPATH  = 29
pfelfDT_SONAME   = 14
pfelfDT_STRSZ    = 10
pfelfDT_STRTAB   =  5
pfelfDT_SYMENT   = 11
pfelfDT_SYMTAB   =  6
pfelfDT_TEXTREL  = 22

pfelfDF_1_NOW    = 1
pfelfDF_BIND_NOW = 8
pfelfDF_TEXTREL  = 4

; Flags used in PFELF.Status.
pfelfFormatELF   = 0x0000_0001 ; Compiled format is object ELF file for static linking.
pfelfFormatELFX  = 0x0000_0002 ; Compiled format is executable ELF file.
pfelfFormatELFSO = 0x0000_0004 ; Compiled format is object ELF file for dynamic linking (DSO).
pfelfDynamic     = 0x0000_0400 ; Compiled ELFX links at least one DSO.
pfelfTEXTREL     = 0x0000_0100 ; Relocations in non-writeable section(s) exist in DSO.
pfelfWidth32     = 0x0200_0000 ; Compiled format is 32bit.
pfelfWidth64     = 0x0400_0000 ; Compiled format is 64bit.
↑ PFELF
Object of this structure is a set of temporary parameters used for compiling ELF-based file formats.
It is constructed in Pfelf*Compile and its pointer is delivered to other methods as the parameter.
PFELF        STRUC
                  ; +00h.   Pointers to BUFFER for non-section components:
.Buffer           D DWORD ; Temporary buffer used by SssFindByPurpose.
.Buffer.EHDR      D DWORD ; ELF file header.
.Buffer.PHDR      D DWORD ; ELF program headers.
.Buffer.SHDR      D DWORD ; ELF section headers.
                  ; +10h.   Values of EHDR members.
.EHDR.e_phoff     D DWORD ; Program headers offset (FA).
.EHDR.e_shoff     D DWORD ; Section headers offset (FA).
.EHDR.e_phnum     D DWORD ; Number of program header entries.
.EHDR.e_shnum     D DWORD ; Number of section header entries.
                  ; +20h.   Pointers to  SSS groups (ELF "program sections").
.Sss.LOAD.HDR     D DWORD ; €ASM group of ELF LOAD program segment loading EHDR,PHDR,SHDR and ELF-special sections.
.Sss.LOAD.CODE    D DWORD ; €ASM group of ELF LOAD program segment loading .text and .plt.
.Sss.LOAD.RODATA  D DWORD ; €ASM group of ELF LOAD program segment loading .rodata.
.Sss.LOAD.DATA    D DWORD ; €ASM group of ELF LOAD program segment loading .data, .got and .bss.
.Sss.LOAD.DYNAMIC D DWORD ; €ASM group of ELF LOAD program segment loading .dynamic section.
.Sss.DYNAMIC      D DWORD ; €ASM group of ELF DYNAMIC program segment.
.Sss.PHDR         D DWORD ; €ASM group of ELF PHDR program segment which covers PHDR records.
.Sss.INTERP       D DWORD ; €ASM group of ELF INTERP program segment, which covers .interp.
                          ; Pointers to BUFFER for DWORD pointers to SSS segments.
.Buffer.CODE      D DWORD ; Buffer for pointers to executable segments (purpose CODE, PLT).
.Buffer.RODATA    D DWORD ; Buffer for pointers to read-only data segments (purpose RODATA).
.Buffer.DATA      D DWORD ; Buffer for pointers to read-write segments (purpose DATA, GOT, BSS).
                          ; Pointers to SSS with ELF-specific sections.
.Sss              D DWORD ; €ASM segment [] (an empty NULL ELF section).
.Sss.symtab       D DWORD ; €ASM segment [.symtab] (static symbol table).
.Sss.strtab       D DWORD ; €ASM segment [.strtab] (names of symbols).
.Sss.shstrtab     D DWORD ; €ASM segment [.shstrtab] (names of sections).
.Sss.interp       D DWORD ; €ASM segment [.interp] (name of dynamic runtime linker).
.Sss.dynsym       D DWORD ; €ASM segment [.dynsym] (dynamic symbol table).
.Sss.hash         D DWORD ; €ASM segment [.hash] (hashtable of dynamic symbol names).
.Sss.dynstr       D DWORD ; €ASM segment [.dynstr] (names of dynamic symbols, needed files, runpath).
.Sss.dynamic      D DWORD ; €ASM segment [.dynamic] (information for dynamic linker).
.Sss.plt          D DWORD ; €ASM segment [.plt] (Procedure Linkage Table).
.Sss.got          D DWORD ; €ASM segment [.got] (Global Offset Table).
.Sss.rela.dyn     D DWORD ; €ASM segment [.rel.dyn] or [.rela.dyn] (relocations in DSO).
.Sss.rela.plt     D DWORD ; €ASM segment [.rel.plt] or [.rela.plt] (relocations in PLT).
                          ; Miscellaneous data:
.Status           D DWORD ; See PFELF flags
.Pgm              D DWORD ; Pointer to PGM of the compiled program.
.relSize          D DWORD ; Size of one PFELF_REL* record (08h/10h/0Ch*18h).
.symSize          D DWORD ; Size of one PFELF_SYM* record (10h/18h).
.dynstrSize       D DWORD ; Size of names in dynamic symbol section before NEEDED and RUNPATH are appended to [.dynstr].
.PHDRSize         D DWORD ; Size of PFELF_PHDR (20h or 38h).
.HDRsEnd          D DWORD ; End of the last header from EHDR,PHDR,SHDR (FA).
             ENDSTRUC PFELF
↑ PFELF_E_IDENT
Substructure used in ELF file header as a member PFELF_EHDR.e_ident
PFELF_E_IDENT STRUC        ; Identical for 32bit and 64bit versions.
 .e_mag0       D BYTE 0x7F ; Magic number.
 .e_mag        D BYTE 'ELF'; Format identificator.
 .e_class      D BYTE pfelfClass%^WIDTH ; pfelfClass32 or pfelfClass64, specified by %^Width.
 .e_data       D BYTE 1    ; 1=Little Endian, 2=Big Endian.
 .e_version    D BYTE 1    ; ELF format version. Specified by %^MajorImageVersion=1.
 .e_osabi      D BYTE 0    ; System V ABI.
 .e_abiversion D BYTE 0    ; SystemV ABI 3rd edition.
 .e_pad        D 7*BYTE 0  ; Not used.
 ENDSTRUC PFELF_E_IDENT    ; SIZE# PFELF_IDENT = 16 = 10h.
↑ PFELF_EHDR32
32bit ELF File Header. Always located at FA=0.
PFELF_EHDR32 STRUC
 .e_ident      D PFELF_E_IDENT,.e_class=pfelfClass32 ; See above.
               ; +10h.
 .e_type       D  WORD ; Object file type. 1=linkable, 2=executable, 3=shared object.
 .e_machine    D  WORD ; Machine type. 0x0003=x86
 .e_version    D DWORD ; Object file version. Specified by %^MajorLinkerVersion=1.
 .e_entry      D DWORD ; Entry point VA, specified by %^Entry=.
 .e_phoff      D DWORD ; Program headers offset (FA).
               ; +20h.
 .e_shoff      D DWORD ; Section headers offset (FA).
 .e_flags      D DWORD ; Processor specific flags, always 0.
 .e_ehsize     D  WORD ; ELF header size = 52.
 .e_phentsize  D  WORD ; Size of one program header entry = 32 = 20h.
 .e_phnum      D  WORD ; Number of program header entries.
 .e_shentsize  D  WORD ; Size of one section header entry = 40 = 28h.
               ; +30h.
 .e_shnum      D  WORD ; Number of section header entries.
 .e_shstrndx   D  WORD ; Section name string table index.
 ENDSTRUC PFELF_EHDR32 ; SIZE# PFELF_EHDR32 = 52 = 34h.
↑ PFELF_EHDR64
64bit ELF File Header. Always located at FA=0.
PFELF_EHDR64 STRUC
 .e_ident      D PFELF_E_IDENT,.e_class=pfelfClass64 ; See above.
               ; +10h.
 .e_type       D  WORD ; Object file type. 1=linkable, 2=executable, 3=shared object.
 .e_machine    D  WORD ; Machine type. 0x003E=x86_64.
 .e_version    D DWORD ; Object file version. Specified by %^MajorLinkerVersion=1.
 .e_entry      D QWORD ; Entry point VA, specified by %^Entry=.
               ; +20h.
 .e_phoff      D QWORD ; Program headers offset (FA).
 .e_shoff      D QWORD ; Section headers offset (FA).
               ; +30h.
 .e_flags      D DWORD ; Processor specific flags, always 0.
 .e_ehsize     D  WORD ; ELF header size = 64.
 .e_phentsize  D  WORD ; Size of one program header entry = 56 = 38h.
 .e_phnum      D  WORD ; Number of program header entries.
 .e_shentsize  D  WORD ; Size of one section header entry = 64 = 40h.
 .e_shnum      D  WORD ; Number of section header entries.
 .e_shstrndx   D  WORD ; Section name string table index.
 ENDSTRUC PFELF_EHDR64 ; SIZE# PFELF_EHDR64 = 64 = 040h.
↑ PFELF_PHDR32
32bit ELF program (€ASM group) header.
PFELF_PHDR32 STRUC
 .p_type       D DWORD ; Type of segment. 1=loadable 2=dynamic 3=interpreter etc.
 .p_offset     D DWORD ; FA of group.
 .p_vaddr      D DWORD ; VA of group.
 .p_paddr      D DWORD ; Reserved, copy of p_vaddr.
               ; +10h.
 .p_filesz     D DWORD ; Group size in file.
 .p_memsz      D DWORD ; Group size in memory.
 .p_flags      D DWORD ; Group attributes. 1=exec  2=write  4=read.
 .p_align      D DWORD ; Group alignment, specified by %^SectionAlign for regular purposes.
 ENDSTRUC PFELF_PHDR32 ; SIZE# PFELF_PHDR32 = 32 = 20h.
↑ PFELF_PHDR64
64bit ELF program (€ASM group) header.
PFELF_PHDR64 STRUC
 .p_type       D DWORD ; Type of segment. 1=loadable 2=dynamic 3=interpreter etc.
 .p_flags      D DWORD ; Group attributes. 1=exec  2=write  4=read.
 .p_offset     D QWORD ; FA of group.
               ; +10h.
 .p_vaddr      D QWORD ; VA of group.
 .p_paddr      D QWORD ; Reserved, copy of p_vaddr.
               ; +20h.
 .p_filesz     D QWORD ; Group size in file.
 .p_memsz      D QWORD ; Group size in memory.
               ; +30h.
 .p_align      D QWORD ; Group alignment, specified by %^SectionAlign for regular purposes.
 ENDSTRUC PFELF_PHDR64 ; SIZE# PFELF_PHDR64 = 56 = 38h.
↑ PFELF_SHDR32
32bit ELF section header.
PFELF_SHDR32 STRUC
 .sh_name      D DWORD ; Section name (offset in string table section .shstrtab).
 .sh_type      D DWORD ; Section type. See %^PURPOSE: 1=PROGBITS, 2=SYMTAB, 3=STRTAB etc.
 .sh_flags     D DWORD ; Section attributes. 1=writeable, 2=allocated(readable), 4=executable.
 .sh_addr      D DWORD ; VA in memory.
               ; +10h.
 .sh_offset    D DWORD ; FA in file.
 .sh_size      D DWORD ; Size of section.
 .sh_link      D DWORD ; Link to other section, see above.
 .sh_info      D DWORD ; Miscellaneous information, see above.
               ; +20h.
 .sh_addralign D DWORD ; Section FA alignment. Specified by SEGMENT ALIGN=.
 .sh_entsize   D DWORD ; Size of entries, if the section has table.
 ENDSTRUC PFELF_SHDR32 ; SIZE# PFELF_SHDR32 = 40 = 28h.
↑ PFELF_SHDR64
64bit ELF section header.
PFELF_SHDR64 STRUC
 .sh_name      D DWORD ; Section name (offset in string table section .shstrtab).
 .sh_type      D DWORD ; Section type. See %^PURPOSE: 1=PROGBITS, 2=SYMTAB, 3=STRTAB etc.
 .sh_flags     D QWORD ; Section attributes. Section attributes. 1=writeable, 2=allocated(readable), 4=executable.
               ; +10h.
 .sh_addr      D QWORD ; VA in memory.
 .sh_offset    D QWORD ; FA in file.
               ; +20h.
 .sh_size      D QWORD ; Size of section.
 .sh_link      D DWORD ; Link to other section, see above.
 .sh_info      D DWORD ; Miscellaneous information, see above.
               ; +30h.
 .sh_addralign D QWORD ; Section FA alignment. Specified by SEGMENT ALIGN=.
 .sh_entsize   D QWORD ; Size of entries, if the section has table.
 ENDSTRUC PFELF_SHDR64 ; SIZE# PFELF_SHDR64 64 = 40h.
↑ PFELF_SYM32
32bit ELF symbol table.
PFELF_SYM32 STRUC
 .st_name      D DWORD ; Symbol name (offset in string table section .strtab).
 .st_value     D DWORD ; Symbol value/offset.
 .st_size      D DWORD ; Symbol size.
 .st_info      D BYTE  ; Bind and type, see above: 0=LOCAL 1=OBJECT 2=FUNC 3=SECTION 4=FILE 10=GLOBAL
 .st_other     D BYTE  ; Reserved.
 .st_shndx     D  WORD ; Index of section where the symbol belongs.
 ENDSTRUC PFELF_SYM32  ; SIZE# PFELF_SYM32 = 16 = 10h.
↑ PFELF_SYM64
64bit ELF symbol table.
PFELF_SYM64 STRUC
 .st_name      D DWORD ; Symbol name (offset in string table section .strtab).
 .st_info      D  BYTE ; Bind and type, see above: 0=LOCAL 1=OBJECT 2=FUNC 3=SECTION 4=FILE 10=GLOBAL
 .st_other     D  BYTE ; Reserved.
 .st_shndx     D  WORD ; Index of section where the symbol belongs.
 .st_value     D QWORD ; Symbol value/offset.
               ; +10h.
 .st_size      D QWORD ; Symbol size.
 ENDSTRUC PFELF_SYM64 ; SIZE# PFELF_SYM64 = 24 = 18h.
↑ PFELF_REL32
32bit ELF relocation without addend.
PFELF_REL32 STRUC
 .r_offset     D DWORD ; Address of reference (of DWORD with addend which is updated).
 .r_info       D DWORD ; Relocation type (in LSB) and symbol index (in bits 8..31).
 ENDSTRUC PFELF_REL32  ; SIZE# PFELF_REL32 = 8.
↑ PFELF_REL64
64bit ELF relocation without addend.
PFELF_REL64 STRUC
 .r_offset     D QWORD ; Address of reference (of DWORD/QWORD with addend which is updated).
 .r_info       D QWORD ; Relocation type (in low DWORD) and symbol index (in high DWORD).
 ENDSTRUC PFELF_REL64  ; SIZE# PFELF_REL64 = 16 = 10h.
↑ PFELF_RELA32
32bit ELF relocation with addend.
PFELF_RELA32 STRUC
 .r_offset     D DWORD ; Address of reference (of DWORD which is updated).
 .r_info       D DWORD ; Relocation type (in LSB) and symbol index (in bits 8..31).
 .r_addend     D DWORD ; Value to be added to the D|WORD which is fixed-up.
 ENDSTRUC PFELF_RELA32 ; SIZE# PFELF_RELA32 = 12 = 0Ch.
↑ PFELF_RELA64
64bit ELF relocation with addend.
PFELF_RELA64 STRUC
 .r_offset     D QWORD ; Address of reference (of DWORD/QWORD which is updated).
 .r_info       D QWORD ; Relocation type (in low DWORD) and symbol index (in high DWORD).
 .r_addend     D QWORD ; Value to be added to the Q|D|WORD which is fixed-up.
 ENDSTRUC PFELF_RELA64 ; SIZE# PFELF_RELA64 = 24 = 18h.
↑ PFELF_DYN32
32bit ELF Dynamic structure.
PFELF_DYN32 STRUC
 .d_tag        D DWORD   ; Dynamic element type.
 .d_val        D 0*DWORD ; Dynamic element value, aliased by pointer.
 .d_ptr        D DWORD   ; Dynamic element pointer.
    ENDSTRUC PFELF_DYN32 ; SIZE# PFELF_DYN32 = 8
↑ PFELF_DYN64
64bit ELF Dynamic structure.
PFELF_DYN64 STRUC
 .d_tag        D QWORD   ; Dynamic element type.
 .d_val        D 0*QWORD ; Dynamic element value, aliased by pointer.
 .d_ptr        D QWORD   ; Dynamic element pointer.
    ENDSTRUC PFELF_DYN64 ; SIZE# PFELF_DYN64 = 16 = 10h.
 ENDHEAD pfelf  ; End of module interface.
↑ PfelfCompile OutputStream, Pgm
is constructor of output 32bit or 64bit statically linkable module in ELF format.
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
PfDrectveCreate PfelfConvertSymbols PfelfCreate PfelfDestroy PfelfEhdr PfelfHdrsLink PfelfHdrsStream PfelfLink PfelfRelaConvert PfelfRelaCreate PfelfShdr PfelfSssSeg PfelfSssTab PgmOrderSymbols PgmStreamImage PgmSymResolve SssCreateGroup SssFindByPurpose
PfelfCompile Procedure OutputStream, Pgm
Pfelf LocalVar Size=SIZE# PFELF                  ; PFELF object.
    MOV EBX,[%Pgm]                               ; Initialization.
    LEA EDI,[%Pfelf]
    Invoke PfelfCreate::,EDI,EBX                 ; Initialize helper object PFELF.
    Invoke PfelfSssTab::,EDI,EAX                  ; Create ELF-special empty SSS segments [], [.symtab], [.strtab], [.shstrtab].
;Create groups of regular segments.
    Invoke PfelfSssSeg,EDI                        ; Fill PFELF.Buffer.CODE/RODATA/DATA with pointers to regular 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,0,0
    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,0,0
    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]
    SHR ECX,2
    JZ .35:                                       ; Do not create [LOAD.DATA] group when no DATA/GOT/BSS segment exists.
    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
.30:LODSD
    MOV [EAX+SSS.GroupPtr],EDX
    LOOP .30:
.35:Invoke PfDrectveCreate::,[EDI+PFELF.Pgm]     ; Create NOTE segment [.drectve] when imported|exported symbols exist.
    Invoke PfelfRelaCreate,EDI                   ; Create segments [.rel(a)name] for each segment with relocations.
    ; Order groups and segments.
    BufferStoreDword [EBX+PGM.SegOrdBuffer],[EDI+PFELF.Sss]          ; [] (NULL section).
    BufferStoreDword [EBX+PGM.SegOrdBuffer],[EDI+PFELF.Sss.symtab]   ; [.symtab].
    Invoke SssFindByPurpose::,sssSegment,sssPurposeRELOC,sssNotBSS,0,EBX,[EDI+PFELF.Buffer]
    BufferRetrieve [EDI+PFELF.Buffer]
    BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX                       ; [.rel(a)name] (all reloc sections).
    Invoke SssFindByPurpose::,sssSegment,sssPurposeDRECTVE,sssNotBSS,0,EBX,[EDI+PFELF.Buffer]
    BufferRetrieve [EDI+PFELF.Buffer]
    JECXZ .41:
    BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX                       ; [.rel(a)name] (all .drectv sections).
.41:BufferStoreDword [EBX+PGM.SegOrdBuffer],[EDI+PFELF.Sss.strtab]   ; [.strtab].
    BufferStoreDword [EBX+PGM.SegOrdBuffer],[EDI+PFELF.Sss.shstrtab] ; [.shstrtab].
    BufferRetrieve [EDI+PFELF.Buffer.CODE]
    BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX                       ; [.text]  (all code sections).
    BufferRetrieve [EDI+PFELF.Buffer.RODATA]
    BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX                       ; [.rodata]  (all read-only data sections).
    BufferRetrieve [EDI+PFELF.Buffer.DATA]
    BufferStore [EBX+PGM.SegOrdBuffer],ESI,ECX                       ; [.data]  (all data+bss sections).
    ; Enumerate and index all ordered segments.
    BufferRetrieve [EBX+PGM.SegOrdBuffer]       ; Assign an index for all ordered segments.
    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:Invoke PgmSymResolve::,EBX                   ; Match external symbols to statically linked public symbols.
    Invoke PgmOrderSymbols::,EBX                 ; Index all symbols, ordered by their type and name.
    Invoke PfelfConvertSymbols,EDI,0             ; Convert €ASM symbols to PFELF_SYM in [.symtab], write their names to [.strtab].
    Invoke PfelfRelaConvert,EDI                  ; Convert relocations form regular segments into [.rel(a)name].EmitBuffer.
    Invoke PfelfShdr::,EDI                       ; Create ELF section headers, pass 1.
    Invoke PfelfHdrsLink::,EDI                   ; Calculate PFELF.HDRsEnd.
    Invoke PfelfLink,EDI                         ; Set VA, FA, sizes of all ELF "program segments" and "sections".
    Invoke PfelfEhdr::,EDI,pfelfRel              ; 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 PfelfCompile
↑ PfelfSssTab Pfelf, Group
PfelfSssTab creates four empty ELF-special SSS segments [], [.symtab], [.shstrtab], [.strtab].
Input
Pfelf is pointer to PFELF object.
Group is pointer to ^SSS sssGroup wich should be assigned to all created segments. May be 0.
Output
Special SSS segments are stored on Pfelf.Pgm.SssList.
Error
Errors are reported with macro Msg.
See also
PfelfsoSssDynTab
Invoked by
PfelfCompile PfelfsoCompile PfelfxCompile
Invokes
SymCreateSe
PfelfSssTab Procedure Pfelf, Group
    MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    MOV EDX,[%Group]
    ListNew [EBX+PGM.SssList],Zeroed=yes         ; Create SSS [] - empty segment without name, required in ELF section header.
    MOV ESI,EAX
    MOV [EDI+PFELF.Sss],ESI
    SetSt [ESI+SSS.Status],sssSegment+sssUsed
    ListNew [EBX+PGM.SssList],Zeroed=yes         ; Create SSS [.symtab]
    MOV ESI,EAX
    MOV [EDI+PFELF.Sss.symtab],ESI
    SetSt [ESI+SSS.Status],sssSegment+sssUsed+sssNotBSS
    MOV [ESI+SSS.NamePtr],=B".symtab"
    MOV [ESI+SSS.NameSize],7
    MOV [ESI+SSS.GroupPtr],EDX
    MOV [ESI+SSS.Purpose],sssPurposeSYMBOLS
    MOV EAX,8
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.20:
    MOV AL,16
.20:MOV [ESI+SSS.Alignment],EAX
    BufferCreate [EBX+PGM.Pool],Size=1K
    MOV [ESI+SSS.EmitBuffer],EAX
    BufferCreate [EBX+PGM.Pool],Size=1K
    MOV [ESI+SSS.RelocBuffer],EAX
    Invoke SymCreateSe::,ESI,EBX
    ListNew [EBX+PGM.SssList],Zeroed=yes         ; Create SSS  [.strtab]
    MOV ESI,EAX
    MOV [EDI+PFELF.Sss.strtab],ESI
    SetSt [ESI+SSS.Status],sssSegment+sssUsed+sssNotBSS
    MOV [ESI+SSS.NamePtr],=B".strtab"
    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=512
    MOV [ESI+SSS.EmitBuffer],EAX
    Invoke SymCreateSe::,ESI,EBX
    ListNew [EBX+PGM.SssList],Zeroed=yes         ; Create SSS  [.shstrtab]
    MOV ESI,EAX
    MOV [EDI+PFELF.Sss.shstrtab],ESI
    SetSt [ESI+SSS.Status],sssSegment+sssUsed+sssNotBSS
    MOV [ESI+SSS.NamePtr],=B".shstrtab"
    MOV [ESI+SSS.NameSize],9
    MOV [ESI+SSS.GroupPtr],EDX
    MOV [ESI+SSS.Purpose],sssPurposeSTRINGS
    MOV [ESI+SSS.Alignment],1
    BufferCreate [EBX+PGM.Pool],Size=256
    MOV [ESI+SSS.EmitBuffer],EAX
EndProcedure PfelfSssTab
↑ PfelfLoadPgm BasePgm, ObjBottom, ObjSize, FileNamePtr

PfelfLoadPgm 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.
ObjBottom 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 mapped ELF file.
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
EaBufferRelease EaBufferReserve EaFs2Id PfDrectveDestroy PgmoptSetLinkProp SssCreateExtern SssFindByIndex SymFindByIndex
Invoked by
PfelfsoLoadPgm
PfelfLoadPgm Procedure BasePgm, ObjBottom, ObjSize, FileNamePtr
EmitBottom     LocalVar ; Pointer to the raw emitted contents of segment whose pointers are relocated.
EmitTop        LocalVar ; Pointer to the end of the raw contents.
ObjProgress    LocalVar ; FA where E7771 was detected.
ObjTop         LocalVar ; Pointer behind the mapped file.
RelSize        LocalVar ; Size of one ELF REL|RELA record.
RelBottom      LocalVar ; Pointer to the raw contents of .rel(a) section in memory.
RelocBuf       LocalVar ; ^BUFFER fo RELOC records.
RelocSss       LocalVar ; ^SSS to which the relocations apply.
RelTop         LocalVar ; Pointer to the end of the raw contents of .rel(a) section.
SectIndex      LocalVar ; Ordinal number of section|symbol in ELF file.
ShdrBottom     LocalVar ; Pointer to the start of mapped section headers.
ShdrTop        LocalVar ; Pointer to the end of mapped section headers.
ShdrSize       LocalVar ; Size of one SHDR (28h or 40h).
ShInfo         LocalVar ; SHDR.sh_info.
ShLink         LocalVar ; SHDR.sh_link.
ShStrTabBottom LocalVar ; Pointer to the raw contents of .shstrtab section.
ShStrTabTop    LocalVar ; Pointer to the end of .shstrtab contents.
StrTabEnd      LocalVar ; Pointer to the end of .strtab contents.
StrTabPtr      LocalVar ; Pointer to the raw contents of .strtab section.
SymSize        LocalVar ; Size of one PFELF_SYM record (10h or 18h).
SymIndex       LocalVar ; Ordinal number of symbol in PGM.SymList.
SymTabBottom   LocalVar ; Pointer to the raw contents of .symtab section.
SymTabTop      LocalVar ; Pointer to the end of .symtab contents.
SymSection     LocalVar ; ^SSS with SYM.Section.
SymShndx       LocalVar ; PFELF_SYM.st_shndx - index of section where the symbol belongs.
SymInfo        LocalVar ; DH=symbol bind 10=GLOBAL 20=WEAK; DL=symbol type: 0=LOCAL 1=OBJECT 2=FUNC 3=SECTION 4=FILE.
Entry          LocalVar ; Entry VA, should be 0 in ELF and ELFSO format.
StackOrg       LocalVar ; ESP at the entry of this Procedure PfelfLoadPgm.
     MOV [%StackOrg],ESP
     MOV EAX,[%ObjBottom]
     ADD EAX,[%ObjSize]
     MOV [%ObjTop],EAX
     MOV EBX,[%BasePgm]
     ; Create loaded module in format PGM. Some properties are inherited from %BasePgm.
     ListNew [EBX+PGM.ModulePgmList],Zeroed=Yes
     MOV ESI,[EBX+PGM.CurrentStm]
     MOV ECX,[EBX+PGM.LinePtr]
     MOV EDX,[EBX+PGM.Pool]
     MOV EBX,EAX                                 ; EBX is now the new loaded module ^PGM.
     MOV [EBX+PGM.CurrentStm],ESI
     MOV [EBX+PGM.LinePtr],ECX
     MOV [EBX+PGM.Pool],EDX
     ListCreate EDX,SIZE#SSS
     MOV [EBX+PGM.SssList],EAX
     ListCreate EDX,SIZE#SYM
     MOV [EBX+PGM.SymList],EAX
     MOV EDI,[%FileNamePtr]                      ; Create module name.
     GetLength$ EDI                              ; EDI,ECX is file name string. Remove path.
     MOV EDX,ECX
     LEA ESI,[EDI+ECX-1]
     STD
.010:LODSB ; Read the string backward.
     CMP AL,'/'
     JE .020:
     CMP AL,'\'
     JE .020:
     CMP AL,':'
     LOOPNE .010:
.020:CLD
     LEA ESI,[EDI+ECX]
     SUB EDX,ECX                                 ; ESI,EDX is now the file name without path.
     PUSH EBX
       MOV EBX,[%BasePgm]
       PoolStore [EBX+PGM.Pool],ESI,EDX          ; Make it permanent in BasePgm.Pool.
       MOV ESI,EAX
     POP EBX                                     ; Resore pointer to module PGM.
     MOV EDI,[EBX+PGM.DSONameBuffer]
     TEST EDI
     JNZ .025:
     BufferCreate [EBX+PGM.Pool],Size=64         ; Remove DSONameBuffer?
     MOV [EBX+PGM.DSONameBuffer],EAX
     MOV EDI,EAX
.025:BufferStoreDword EDI,ESI
     BufferStoreDword EDI,EDX
     LEA EDI,[ESI+EDX]                           ; Remove extension (usually .o) or .so).
.030:DEC EDI
     CMP EDI,ESI
     JNA .050:
     CMPB [EDI],'.'
     JNE .030:
.040:SUB EDI,ESI
     JNZ .055:
.050:MOV EDI,EDX                                 ; When file name has no extension, use it as is.
.055:; ESI,EDI is now file name without path and without extension, it will be used as the module name.
     Invoke EaBufferReserve::,PfelfLoadPgm
     Invoke EaFs2Id::,ESI,EDI,EAX                ; Replace nonalphanum with underscores.
     BufferRetrieve EAX
     Invoke EaBufferRelease::,EAX
     PoolStore [EBX+PGM.Pool],ESI,ECX            ; Make the module name nonvolatile.
     MOV [EBX+PGM.NamePtr],EAX
     MOV [EBX+PGM.NameSize],ECX
; Empty PGM module EBX is now prepared. Examine ELF file header.
     MOV ESI,[%ObjBottom]
     MOVD [%ObjProgress],PFELF_EHDR64.e_type
     MOV DL,[ESI+PFELF_EHDR64.e_type]            ; Module type (ELF, ELFX, ELFSO).
     XOR EAX,EAX
     Dispatch DL,pfelfRel,pfelfExec,pfelfDyn
     JMP .E7771:                                 ; ELF file "!1$" is corrupted at offset 0x!2H.
.pfelfDyn:MOV AL,pgmoptELFSO
     JMP .060:
.pfelfExec: MOV AL,pgmoptELFX
     JMP .058:
.pfelfRel:  MOV AL,pgmoptELF                     ; pgmoptELF=12.
.058:
    ;;;; MOVD [EBX+PGM.DSONameBuffer],0             ; NonDSO file is not NEEDED in dynamic section, abort its buffer.

.060:Invoke PgmoptSetLinkProp::,EAX              ; Set Pgmopt.Status properties to EAX.
     MOVD [%ObjProgress],PFELF_EHDR64.e_ident.e_class
     MOV DL,[ESI+PFELF_EHDR64.e_ident.e_class]
     MOV EDI,[%BasePgm]
     MOVD [%ObjProgress],PFELF_EHDR64.e_machine
     Dispatch DL,pfelfClass32,pfelfClass64
.E7776:Msg '7776'                                ; ELF section .symtab not found.
     JMPS .Er:
.E7771:Msg '7771',[%FileNamePtr],[%ObjProgress]  ; ELF file "!1$" is corrupted at offset 0x!2H.
.Er:MOV EDI,[%BasePgm]
     ListRemove [EDI+PGM.ModulePgmList],EBX      ; Delete the unsuccesfully loaded module
     MOV ESP,[%StackOrg]                         ;  and abort this procedure, ignoring current stack level.
     JMP .399:
.E7721:Msg '7721',EBX,[%BasePgm]                 ; Cannot link 32bit module "%1S" to 64bit program "!2S".
     JMP .Er:
.E7722:Msg '7722',EBX,[%BasePgm]                 ; Cannot link 64bit module "%1S" to 32bit program "!2S".
     JMP .Er:
     ; ESI is pointer to PFELF_EHDR (file header).
.pfelfClass32:SetSt EAX,pgmoptWidth32
     MOVD [%ShdrSize],SIZE# PFELF_SHDR32
     MOVD [%SymSize],SIZE# PFELF_SYM32
     JSt [EDI+PGM.Pgmopt.Status],pgmoptWidth64,.E7721:
     MOV ECX,[ESI+PFELF_EHDR32.e_entry]
     MOV [%Entry],ECX
     MOV EDI,[ESI+PFELF_EHDR32.e_shoff]
     MOVZX ECX,[ESI+PFELF_EHDR32.e_shnum]
     MOVZX EDX,[ESI+PFELF_EHDR32.e_shstrndx]
     CMP [ESI+PFELF_EHDR32.e_machine],pfelfMachine386
     JMP .070:
.pfelfClass64:SetSt EAX,pgmoptWidth64
     MOVD [%ShdrSize],SIZE# PFELF_SHDR64
     MOVD [%SymSize],SIZE# PFELF_SYM64
     JSt [EDI+PGM.Pgmopt.Status],pgmoptWidth32,.E7722:
     MOV ECX,[ESI+PFELF_EHDR64.e_entry+0]
     MOV [%Entry],ECX
     MOV EDI,[ESI+PFELF_EHDR64.e_shoff]
     MOVZX ECX,[ESI+PFELF_EHDR64.e_shnum]       ; Number of SHDR entries.
     MOVZX EDX,[ESI+PFELF_EHDR64.e_shstrndx]
     CMP [ESI+PFELF_EHDR64.e_machine],pfelfMachineX64
.070:JNE .E7771:
     MOV [EBX+PGM.Pgmopt.Status],EAX             ; Set program width and link properties.
     ADD EDI,ESI

     ; EDI is FA of the first PFELF_SHDR (section headers)
     MOV [%ShdrBottom],EDI                       ; FA of array of ECX section headers mapped in memory.
     MOV EAX,[%ShdrSize]
     PUSH EDX
       MUL ECX                                   ; ECX=EHDR.e_shnum, number of section headers.
     POP EDX                                     ; EDX=EHDR.e_shstrndx.
     ADD EAX,EDI
     MOV [%ShdrTop],EAX
     ; Find .shstrtab section with index EDX.
     MOV EAX,[%ShdrSize]
     MUL EDX
     ADD EDI,EAX                                 ; EDI is now ^PFELF_SHDR of section .shstrtab in memory.
     JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.080:
     MOVD [%ObjProgress],PFELF_EHDR32.e_shstrndx
     MOV EAX,[EDI+PFELF_SHDR32.sh_offset]
     MOV ECX,[EDI+PFELF_SHDR32.sh_size]
     JMP .090:
.080:MOVD [%ObjProgress],PFELF_EHDR64.e_shstrndx
     MOV EAX,[EDI+PFELF_SHDR64.sh_offset]
     MOV ECX,[EDI+PFELF_SHDR64.sh_size]
.090:ADD EAX,ESI
     MOV [%ShStrTabBottom],EAX
     ADD ECX,EAX                                 ; EAX..ECX is now memory-mapped contents of .shstrtab.
     MOV [%ShStrTabTop],ECX
     CMP ECX,[%ObjTop]
     JA .E7771:
     ; %ShdrBottom..%ShdrTop is array of PFELF_SHDR records.
     MOV ESI,[%ShdrBottom]

     ; Sections pass 1: convert regular emitting sections to SSS segments
     ;             and store them on PGM.SssList of the loaded module EBX.
     MOVD [%SectIndex],0                         ; Ordinal number of section header, it goes to SSS.SegmIndex.
.110:CMP ESI,[%ShdrTop]
     JNB .190:                                   ; End of pass 1.
     MOV EAX,ESI
     SUB EAX,[%ObjBottom]
     MOV [%ObjProgress],EAX
     MOV EDX,[ESI+PFELF_SHDR64.sh_type]          ; Works for both 32 and 64bit.
     Dispatch DL,pfelfSHT_PROGBITS,pfelfSHT_NOBITS,pfelfSHT_NOTE
     JMP .180:                                   ; Ignore sections of other types.
.pfelfSHT_NOTE:                                  ; Used as [.drectve] for linker directives.
.pfelfSHT_PROGBITS:                              ; Regular CODE, RODATA, DATA segment.
.pfelfSHT_NOBITS:                                ; Regular BSS segment.
     ListNew [EBX+PGM.SssList],Zeroed=yes        ; Create SSS.
     MOV EDI,EAX                                 ; ^SSS.
     MOV [EDI+SSS.SegmPtr],EAX
     MOV EAX,[%SectIndex]
     MOV [EDI+SSS.SegmIndex],EAX                 ; Section header index in ELF file.
     ; Section name.
     MOV EAX,[ESI+PFELF_SHDR64.sh_name]          ; Index in string table (common for SHDR32 and SHDR64).
     ADD EAX,[%ShStrTabBottom]
     CMP EAX,[%ShStrTabTop]
     JA .E7771:
     GetLength$ EAX
     PoolStore [EBX+PGM.Pool],EAX,ECX
     MOV [EDI+SSS.NamePtr],EAX
     MOV [EDI+SSS.NameSize],ECX                  ; SSS.Name.
     ; Section status.
     MOV EAX,sssSegment+sssPublic                ; SSS.Status.
     CMP DL,pfelfSHT_NOBITS
     JE .120:
     OR EAX,sssNotBSS
.120:MOV EDX,pgmoptWidthMask
     AND EDX,[EBX+PGM.Pgmopt.Status]
     OR EAX,EDX                                  ; SSS width inherits PGM width.
     MOV [EDI+SSS.Status],EAX

     ; Section purpose. .sh_name, .sh_type and .sh_flags are identical for 32 and 64bit version.
     MOV EDX,sssPurposeDRECTVE
     CMPD [ESI+PFELF_SHDR64.sh_type],pfelfSHT_NOTE
     JE .130:
     MOV EDX,sssPurposeCODE                      ; SSS.Purpose is determined by access rights in SHDR.eh_flags.
     JSt  [ESI+PFELF_SHDR64.sh_flags],pfelfSHF_EXECINSTR,.130: ; [.text], [.plt].
     JNSt [ESI+PFELF_SHDR64.sh_flags],pfelfSHF_ALLOC,.130:
     MOV EDX,sssPurposeBSS
     JNSt [EDI+SSS.Status],sssNotBSS,.130:
     MOV EDX,sssPurposeDATA                      ; [.data], [.got].
     JSt [ESI+PFELF_SHDR64.sh_flags],pfelfSHF_WRITE,.130:
     MOV EDX,sssPurposeRODATA                    ; [.rodata].
.130:MOV [EDI+SSS.Purpose],EDX                   ; SSS.Purpose specifies acces rights RWX.
     ; Virtual address, size, alignment.
     PUSH EBX
       JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.140:
       MOV EAX,[ESI+PFELF_SHDR32.sh_addr]
       SUB EDX,EDX
       MOV ECX,[ESI+PFELF_SHDR32.sh_size]
       MOV EBX,[ESI+PFELF_SHDR32.sh_addralign]
       JMP .150:
.140:  MOV EAX,[ESI+PFELF_SHDR64.sh_addr+0]
       MOV EDX,[ESI+PFELF_SHDR64.sh_addr+4]
       MOV ECX,[ESI+PFELF_SHDR64.sh_size+0]
       MOV EBX,[ESI+PFELF_SHDR64.sh_addralign+0]
.150:  MOV [EDI+SSS.BottomLow],EAX
       MOV [EDI+SSS.BottomHigh],EDX
       ADD EAX,ECX
       ADC EDX,0
       MOV [EDI+SSS.TopLow],EAX
       MOV [EDI+SSS.TopHigh],EDX
       MOV [EDI+SSS.Alignment],EBX
     POP EBX                                     ; Restore loaded module ^PGM.
     ; Section raw contents.
     JNSt [EDI+SSS.Status],sssNotBSS,.180:       ; There's no raw contents in BSS.
     BufferCreate [EBX+PGM.Pool],Size=ECX
     MOV [EDI+SSS.EmitBuffer],EAX
     BufferCreate [EBX+PGM.Pool],Size=8K
     MOV [EDI+SSS.RelocBuffer],EAX
     JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.160:
     MOV EAX,[ESI+PFELF_SHDR32.sh_offset]
     JMP .170:
.160:MOV EAX,[ESI+PFELF_SHDR64.sh_offset+0]
.170:ADD EAX,[%ObjBottom]
     LEA EDX,[EAX+ECX]                           ; EAX,ECX now specifies the raw contents of the section EDI.
     CMP EDX,[%ObjTop]
     JA .E7771:
     BufferStore [EDI+SSS.EmitBuffer],EAX,ECX
.180:INCD [%SectIndex]
     ADD ESI,[%ShdrSize]                         ; Convert the next regular section.
     JMP .110:

.190:; %ShdrBottom..%ShdrTop is array of PFELF_SHDR records.
     ; Sections pass 2: find ELF section .symtab and its .strtab
     MOV ESI,[%ShdrBottom]
.203:CMP ESI,[%ShdrTop]
     JNB .E7776:                                 ; ELF section .symtab not found.
     CMPD [ESI+PFELF_SHDR64.sh_type],pfelfSHT_SYMTAB  ; Works for both 32 and 64bit.
     JE .205:
     ADD ESI,[%ShdrSize]
     JMP .203:
.205:JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.207: ; ESI is SHDR .symtab.
      MOV EAX,[ESI+PFELF_SHDR32.sh_offset]
      MOV ECX,[ESI+PFELF_SHDR32.sh_size]
      MOV EDX,[ESI+PFELF_SHDR32.sh_link]
      JMP .209:
.207: MOV EAX,[ESI+PFELF_SHDR64.sh_offset]
      MOV ECX,[ESI+PFELF_SHDR64.sh_size]
      MOV EDX,[ESI+PFELF_SHDR64.sh_link]
.209: ADD EAX,[%ObjBottom]
      MOV [%SymTabBottom],EAX
      ADD EAX,ECX
      MOV [%SymTabTop],EAX
      ; Find ELF section .strtab by index EDX.
      MOV EAX,[%ShdrSize]
      MUL EDX
      ADD EAX,[%ShdrBottom]
      CMP EAX,[%ShdrTop]
      JNB .E7771:                               ; ELF file "!1$" is corrupted at offset 0x!2H.
      MOV ESI,EAX
      SUB EAX,[%ObjBottom]
      MOV [%ObjProgress],EAX
      CMP [ESI+PFELF_SHDR64.sh_type],pfelfSHT_STRTAB
      JNE .E7771:                                ; ELF file "!1$" is corrupted at offset 0x!2H.
      JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.2A1:
      MOV EAX,[ESI+PFELF_SHDR32.sh_offset]
      MOV ECX,[ESI+PFELF_SHDR32.sh_size]
      JMP .2A3:
.2A1: MOV EAX,[ESI+PFELF_SHDR64.sh_offset+0]
      MOV ECX,[ESI+PFELF_SHDR64.sh_size+0]
.2A3: ADD EAX,[%ObjBottom]
      MOV [%StrTabPtr],EAX
      ADD EAX,ECX
      MOV [%StrTabEnd],EAX

     ; Convert static ELF symbols from %SymTabBottom..%SymTabEnd into SYM symbols
     ;              and store them on PGM.SymList of the loaded module EBX in the loop .210: .. .290:.
     ; Ordinal number in ELF symbol table goes to SYM.NameIndex.
     MOVD [%SymIndex],0
     MOV ESI,[%SymTabBottom]
.210:CMP ESI,[%SymTabTop]
     JNB .290:                                  ; When all symbols are converted.
     MOV EAX,ESI
     SUB EAX,[%ObjBottom]
     MOV [%ObjProgress],EAX
     MOVD [%SymSection],0
     JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.242:
     MOV ECX,[ESI+PFELF_SYM32.st_info]           ; .st_info,.st_other,.st_shndx.
     JMP .246:
.242:MOV ECX,[ESI+PFELF_SYM64.st_info]           ; .st_info,.st_other,.st_shndx.
.246:TEST ECX
     JZ .278:                                    ; Ignore NUL symbol.
     MOVZX EDX,CL                                ; EDX=symbol bind and type 0=LOCAL 1=OBJECT 2=FUNC 3=SECTION 4=FILE 10h=GLOBAL 20h=WEAK
     SHR ECX,16                                  ; ECX=section index.
     MOV [%SymShndx],ECX
     MOV DH,DL
     AND DX,0xF00F                               ; DH=symbol bind, DL=symbol type.
     MOV [%SymInfo],EDX
     CMP DL,pfelfSTT_FILE
     JE .278:                                    ; Ignore FILE symbol.
     ; Other than NUL and FILE type ELF symbols will be converted to €ASM symbols.
     ListNew [EBX+PGM.SymList],Zeroed=yes        ; Create an empty SYM record.
     MOV EDI,EAX                                 ; ^SYM.
     MOV EAX,[%SymIndex]                         ; PFELF_SYM ordinal.
     MOV [EDI+SYM.NameIndex],EAX
     MOV EAX,[ESI+PFELF_SYM64.st_name]
     ADD EAX,[%StrTabPtr]
     CMP EAX,[%StrTabEnd]
     JNB .E7771:
     GetLength$ EAX                              ; Namesize of the symbol stored in .strtab.
     PoolStore [EBX+PGM.Pool],EAX,ECX
     MOV [EDI+SYM.NamePtr],EAX
     MOV [EDI+SYM.NameSize],ECX
     JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.247:
     MOV EAX,[ESI+PFELF_SYM32.st_value]
     XOR EDX,EDX                                 ; Zero extend pointer to EDX:EAX.
     CMPD [%SymShndx],pfelfSHN_ABS
     JNE .2D6:                                   ; When the symbol is scalar,
     CDQ                                         ;   sign-extend its value to EDX:EAX.
.2D6:MOV ECX,[ESI+PFELF_SYM32.st_size]
     JMPS .248:
.247:MOV EAX,[ESI+PFELF_SYM64.st_value+0]
     MOV EDX,[ESI+PFELF_SYM64.st_value+4]
     MOV ECX,[ESI+PFELF_SYM64.st_size+0]
.248:MOV [EDI+SYM.Size],ECX
     MOV ECX,[%SymShndx]                         ; Restore ELF section index.
     CMP ECX,pfelfSHN_ABS
     JE    .2C1:                                ; Symbol is scalar.
     JECXZ .2C1:                                ; Symbol is undefined (external).
     PUSH EAX                                   ; Otherwise it is defined in section with index ECX.
       Invoke SssFindByIndex::,ECX,EBX
       MOV ECX,EAX
       MOV [%SymSection],EAX
     POP EAX                                    ; Restore symbol value (offset) EDX:EAX. ECX is ^SSS of symbol's segment.
     JC .2C1:                                   ; If SSS not found, treat it as scalar.
.2C0:SUB EAX,[ECX+SSS.BottomLow]                ; ELFSO symbol might be already linked, i.e. offset elevated by its segment.
     SBB EDX,[ECX+SSS.BottomHigh]               ; ELF segments are not linked, their Bottom=0.
.2C1:MOV [EDI+SYM.OffsetLow],EAX
     MOV [EDI+SYM.OffsetHigh],EDX
     MOV EAX,[%SymSection]
     MOV [EDI+SYM.Section],EAX
     MOV EDX,[%SymInfo]                          ; DH=symbol bind 10h=GLOBAL 20h=WEAK; DL=symbol type: 0=LOCAL 1=OBJECT 2=FUNC 3=SECTION 4=FILE.
     TEST DH,pfelfSTB_GLOBAL|pfelfSTB_WEAK
     JNZ .2C5:
     TEST EAX
     JNZ .2C5:
     ; EDI is symSe of ELF-special section .strtab, .symtab, .dynamic, .hash etc. It will be discarded.
     ListRemove [EBX+PGM.SymList],EDI
     JMP .278:

.2C5:MOV EAX,'A'                                 ; EAX used for construction of SYM.Status.
     CMP ECX,pfelfSHN_ABS
     JNE .249:
     MOV AL,'N'                                  ; Symbol is scalar.
.249:CMP DL,pfelfSTT_OBJECT
     JNE .251:
     CMP AL,'N'
     JNE .251:
     MOV ECX,[EDI+SYM.Size]
     JECXZ .251:
     Dispatch CL,0n1,0n2,0n4,0n8,0n16,0n32,0n64
     JMPS .251:
.0n1:MOV AL,'B'
     JMPS .251:
.0n2:MOV AL,'W'
     JMPS .251:
.0n4:MOV AL,'D'
     JMPS .251:
.0n8:MOV AL,'Q'
     JMPS .251:
.0n16:MOV AL,'O'
     JMPS .251:
.0n32:MOV AL,'Y'
     JMPS .251:
.0n64:MOV AL,'Z'
.251: CMP DL,pfelfSTT_FUNC
      JNE .253:
      SetSt EAX,symProc
.253: CMP DL,pfelfSTT_SECTION
      JNE .254:
      SetSt EAX,symSe
      MOV ECX,[%SymSection]
      JECXZ .254:
      MOV [ECX+SSS.SymPtr],EDI
.254: CMPD [%SymShndx],pfelfSHN_UNDEF            ; Symbol is external?
      JNE .255:
      SetSt EAX,symExtern
.255: TEST DH,pfelfSTB_WEAK
      JZ .257:
      SetSt EAX,symWeak
.257: TEST DH,pfelfSTB_GLOBAL
      JZ .259:
      CMPD [%SymShndx],pfelfSHN_UNDEF            ; Symbol is external?
      JE .259:
      SetSt EAX,symPublic
.259: MOV [EDI+SYM.Status],EAX
      JNSt EAX,symExtern, .278:
      ; When an external symbol was loaded, its requires its extern pseudosegment.
      Invoke SssCreateExtern::,EDI,EBX
.278: INCD [%SymIndex]
      ADD ESI,[%SymSize]
      JMP .210:                                  ; The next ELF symbol.

.290: Invoke PfDrectveDestroy::,EBX               ; Process the contents of [.drectve] segment, if exists.
; Sections pass 4: Convert ELF relocations to RELOC
;              and store them to SSS.RelocBuffer of their segments.
     ; %ShdrBottom..%ShdrTop is array of PFELF_SHDR records.
     MOV ESI,[%ShdrBottom]
.300:CMP ESI,[%ShdrTop]    ; Convert each ELF SHT_REL(A) section in the loop .300: .. .395:.
     JNB .399:
     PUSH ESI              ; Save pointer in mapped SHDR.
       MOV EAX,ESI
       SUB EAX,[%ObjBottom]
       MOV [%ObjProgress],EAX
       MOV EDX,[ESI+PFELF_SHDR64.sh_type]        ; SHDR32.sh_type=SHDR64.sh_type.
       Dispatch DL,pfelfSHT_REL,pfelfSHT_RELA
       JMP .395:                                 ; Ignore sections of other types in this pass.
.pfelfSHT_RELA:
       SetSt [EBX+PGM.Pgmopt.Status],pgmoptRelWithAddend
       MOV EAX,SIZE# PFELF_RELA64
       JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.305:
       MOV EAX,SIZE# PFELF_RELA32
       JMP .305:
.pfelfSHT_REL:
       RstSt [EBX+PGM.Pgmopt.Status],pgmoptRelWithAddend
       MOV EAX,SIZE# PFELF_REL64
       JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.305:
       MOV EAX,SIZE# PFELF_REL32
.305:  MOV [%RelSize],EAX
       JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.310:
       MOV EAX,[ESI+PFELF_SHDR32.sh_link]
       MOV ECX,[ESI+PFELF_SHDR32.sh_info]
       MOV [%ShLink],EAX
       MOV [%ShInfo],ECX
       MOV EDI,[ESI+PFELF_SHDR32.sh_offset]
       MOV ECX,[ESI+PFELF_SHDR32.sh_size]
       JMP .315:
.310:  MOV EAX,[ESI+PFELF_SHDR64.sh_link]
       MOV ECX,[ESI+PFELF_SHDR64.sh_info]
       MOV [%ShLink],EAX
       MOV [%ShInfo],ECX
       MOV EDI,[ESI+PFELF_SHDR64.sh_offset]
       MOV ECX,[ESI+PFELF_SHDR64.sh_size]
.315:  ADD EDI,[%ObjBottom]
       ADD ECX,EDI
       MOV [%RelBottom],EDI
       MOV [%RelTop],ECX
       CMP ECX,[%ObjTop]
       JA .E7771:
       ; [%ShInfo] specifies index of section to which relocations apply ([.text], [.data], [.rodata]).
       Invoke SssFindByIndex::,[%ShInfo],EBX
       JC .E7771:
       MOV [%RelocSss],EAX
       MOV EDX,[EAX+SSS.RelocBuffer]
       MOV [%RelocBuf],EDX                       ; Buffer where converted RELOC records will be stored.
       BufferRetrieve [EAX+SSS.EmitBuffer]       ; ESI,ECX contains emitted contents of the relocated section.
       ADD ECX,ESI
       MOV [%EmitBottom],ESI
       MOV [%EmitTop],ECX
       MOV ESI,[%RelBottom]                      ; [%RelBottom]..[%RelTop] is an array of PFELF_REL* records.
.330:  CMP ESI,[%RelTop]                         ; Convert each relocation ESI in the loop .330: .. .380:.
       JNB .395:
       BufferNew [%RelocBuf],SIZE# RELOC,Zeroed=Yes
       MOV EDI,EAX                               ; ESI=^REL(A)   EDI=^RELOC.
       JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.345:
       MOV EAX,[ESI+PFELF_REL32.r_offset]
       SUB EDX,EDX
       JMP .350:
.345:  MOV EAX,[ESI+PFELF_REL64.r_offset+0]
       MOV EDX,[ESI+PFELF_REL64.r_offset+4]
.350:  MOV [EDI+RELOC.OrgLow],EAX
       MOV [EDI+RELOC.OrgHigh],EDX
       MOV EAX,[%RelocSss]                       ; Segment of all relocated storage units.
       MOV [EDI+RELOC.Section],EAX
       JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.355:
       MOV ECX,[ESI+PFELF_REL32.r_info]
       MOV EDX,ECX
       AND EDX,0x0000_00FF                       ; .r_type.
       SHR ECX,8                                 ; .r_sym.
       JMP .360:
.355:  MOV EDX,[ESI+PFELF_REL64.r_info+0]        ; .r_type.
       MOV ECX,[ESI+PFELF_REL64.r_info+4]        ; .r_sym.
.360:  Invoke SymFindByIndex::,ECX,EBX
       Msg cc=C,'7777',ECX                       ; Symbol nr.!$D not found in ELF section .symtab.
       MOV [EDI+RELOC.Symbol],EAX
       ; Convert r_type DL to RELOC.Status in ECX.
       XOR ECX,ECX
       PUSHD .RelDispatched:                        ; Prepare the return address from Dispatch.
       JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.365:
       Dispatch DL,pfelfR_386_32,pfelfR_386_PC32,pfelfR_386_GOT32,pfelfR_386_PLT32,  \  Relocation types in ELF32.
                   pfelfR_386_GLOB_DAT,pfelfR_386_JMP_SLOT,pfelfR_386_RELATIVE,      \
                   pfelfR_386_GOTOFF,pfelfR_386_GOTPC,pfelfR_386_NONE,pfelfR_386_COPY
       JMP .E7731:                               ; Unsupported relocation type 0x!1B at [!2S]:!3Hh.
.365:  Dispatch DL,pfelfR_X86_64_PC32, pfelfR_X86_64_64,pfelfR_X86_64_GOT32,pfelfR_X86_64_PLT32,pfelfR_X86_64_32,\ Relocation types in ELF64.
                   pfelfR_X86_64_32S,pfelfR_X86_64_GLOB_DAT,pfelfR_X86_64_JUMP_SLOT,         \
                   pfelfR_X86_64_RELATIVE,pfelfR_X86_64_GOTOFF64,pfelfR_X86_64_GOTPC32,      \
                   pfelfR_X86_64_COPY,pfelfR_X86_64_NONE
.E7731:Msg '7731',EDX,[EDI+RELOC.Section],[EDI+RELOC.OrgLow] ; Unsupported relocation type 0x!1B at [!2S]:!3Hh.
       RET                                       ; Ignore this REL.
.pfelfR_X86_64_32:
.pfelfR_X86_64_32S:
.pfelfR_386_32:
       OR  ECX,relocWidth32 | relocAbsVA
       RET
.pfelfR_386_PC32:
.pfelfR_X86_64_PC32:
       OR  ECX,relocWidth32 | relocRel
       RET
.pfelfR_X86_64_GOT32:
.pfelfR_386_GOT32:
       OR  ECX,relocWidth32 | relocGOT
       RET
.pfelfR_X86_64_PLT32:
.pfelfR_386_PLT32:
       OR  ECX,relocWidth32 | relocPLT
       RET
.pfelfR_386_GLOB_DAT:
.pfelfR_386_JMP_SLOT:
       OR  ECX,relocWidth32 | relocSym
       RET
.pfelfR_386_RELATIVE:
       OR  ECX,relocWidth32 | relocDyn
       RET
.pfelfR_386_GOTOFF:
       OR  ECX,relocWidth32 | relocGOToff
       RET
.pfelfR_X86_64_GOTPC32:
.pfelfR_386_GOTPC:
       OR  ECX,relocWidth32 | relocGOTrel
       RET
.pfelfR_X86_64_64:
       OR  ECX,relocWidth64 | relocAbsVA
       RET
.pfelfR_X86_64_JUMP_SLOT:
.pfelfR_X86_64_GLOB_DAT:
       OR  ECX,relocWidth64 | relocSym
       RET
.pfelfR_X86_64_RELATIVE:
       OR  ECX,relocWidth64 | relocDyn
       RET
.pfelfR_X86_64_GOTOFF64:
       OR  ECX,relocWidth64 | relocGOToff
       RET
.pfelfR_386_COPY:
.pfelfR_386_NONE:
.pfelfR_X86_64_COPY:
.pfelfR_X86_64_NONE:
       OR ECX,relocResolved
       RET
.RelDispatched:
       MOV [EDI+RELOC.Status],ECX
       JNSt [EBX+PGM.Pgmopt.Status],pgmoptRelWithAddend,.386:
       JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.382:
       MOV EAX,[ESI+PFELF_RELA32.r_addend]
       CDQ
       JMP .384:
.382:  MOV EAX,[ESI+PFELF_RELA64.r_addend+0]
       MOV EDX,[ESI+PFELF_RELA64.r_addend+4]
.384:  ADD [EDI+RELOC.AddendLow],EAX
       ADC [EDI+RELOC.AddendHigh],EDX
.386:  MOV ECX,[EDI+RELOC.Symbol]
       JECXZ .388:
       MOV EAX,[ECX+SYM.OffsetLow]
       MOV EDX,[ECX+SYM.OffsetHigh]
       SUB [EDI+RELOC.AddendLow],EAX
       SBB [EDI+RELOC.AddendHigh],EDX
.388:  ADD ESI,[%RelSize]
       JMP .330:                              ; The next REL(A) record.
.395:POP ESI
     ADD ESI,[%ShdrSize]
     JMP .300:                                ; The next .rel* section.
.399:; Sections pass 3 - unlink VA of ELFSO sections, as they will be statically combined to the base program.
     ListGetFirst [EBX+PGM.SssList]
     JZ .3E9:
.3E1:MOV EDI,EAX
     MOV EAX,[EDI+SSS.BottomLow]
     MOV EDX,[EDI+SSS.BottomHigh]
     SUB [EDI+SSS.TopLow],EAX
     SBB [EDI+SSS.TopHigh],EDX
     XOR EAX,EAX
     MOV [EDI+SSS.BottomLow],EAX
     MOV [EDI+SSS.BottomHigh],EAX
     ListGetNext EDI
     JNZ .3E1:
.3E9:
    EndProcedure PfelfLoadPgm
↑ PfelfCreate PfelfPtr, PgmPtr
PfelfCreate is a constructor of PFELF object.
Input
PfelfPtr is a pointer to PFELF object allocated by the caller.
PgmPtr is pointer to PGM representing the completely assembled and combined program.
Output
-
Error
Errors are reported with macro Msg.
Invoked by
PfelfCompile PfelfsoCompile PfelfxCompile
Invokes
EaBufferReserve
PfelfCreate Procedure PfelfPtr, PgmPtr
    MOV ESI,[%PfelfPtr]
    XOR EAX,EAX
    MOV EDI,ESI
    MOV ECX,SIZE# PFELF / 4
    REP STOSD                                    ; Clear the PFELF object.
    MOV EBX,[%PgmPtr]
    MOV [ESI+PFELF.Pgm],EBX
    MOV EAX,[EBX+PGM.Pgmopt.Status]
    MOV EDX,SIZE# PFELF_SYM64
    SAL EDX,16
    MOV  DX,SIZE# PFELF_RELA64
    MOV ECX,SIZE# PFELF_PHDR64
    JSt EAX,pgmoptWidth64,.06:
    MOV EDX,SIZE# PFELF_SYM32
    SAL EDX,16
    MOV DX,SIZE# PFELF_REL32
    MOV CL,SIZE# PFELF_PHDR32
.06:MOV [ESI+PFELF.relSize],DX
    SAR EDX,16
    MOV [ESI+PFELF.symSize],EDX
    MOV [ESI+PFELF.PHDRSize],ECX
    MOV ECX,EAX
    AND EAX,pgmoptWidthMask
    AND ECX,pgmoptFormatMask
    OR [ESI+PFELF.Status],EAX
    MOV EAX,pfelfFormatELF
    CMP CL,pgmoptELF
    JE .10:
    MOV EAX,pfelfFormatELFX
    CMP CL,pgmoptELFX
    JE .10:
    MOV EAX,pfelfFormatELFSO
    CMP CL,pgmoptELFSO
    JNE .20:
.10:OR [ESI+PFELF.Status],EAX
.20:Invoke EaBufferReserve::,%^PROC              ; Create a temporary buffer.
    MOV [ESI+PFELF.Buffer],EAX
    Invoke EaBufferReserve::,%^PROC              ; Create ELF-headers buffers/
    MOV [ESI+PFELF.Buffer.EHDR],EAX
    Invoke EaBufferReserve::,%^PROC
    MOV [ESI+PFELF.Buffer.PHDR],EAX
    Invoke EaBufferReserve::,%^PROC
    MOV [ESI+PFELF.Buffer.SHDR],EAX
    Invoke EaBufferReserve::,%^PROC
    MOV [ESI+PFELF.Buffer.CODE],EAX
    Invoke EaBufferReserve::,%^PROC
    MOV [ESI+PFELF.Buffer.RODATA],EAX
    Invoke EaBufferReserve::,%^PROC
    MOV [ESI+PFELF.Buffer.DATA],EAX
   EndProcedure PfelfCreate
↑ PfelfDestroy PfelfPtr
PfelfCreate is a destructor of PFELF object.
Input
PfelfPtr is a pointer to PFELF object allocated by the caller.
Output
-
Error
Errors are reported with macro Msg.
Invoked by
PfelfCompile PfelfsoCompile PfelfxCompile
Invokes
EaBufferRelease
PfelfDestroy Procedure PfelfPtr
     LEA ESI,[%PfelfPtr]
     Invoke EaBufferRelease::,[ESI+PFELF.Buffer.DATA]
     Invoke EaBufferRelease::,[ESI+PFELF.Buffer.RODATA]
     Invoke EaBufferRelease::,[ESI+PFELF.Buffer.CODE]
     Invoke EaBufferRelease::,[ESI+PFELF.Buffer.SHDR]
     Invoke EaBufferRelease::,[ESI+PFELF.Buffer.PHDR]
     Invoke EaBufferRelease::,[ESI+PFELF.Buffer.EHDR]
     Invoke EaBufferRelease::,[ESI+PFELF.Buffer]
    EndProcedure PfelfDestroy
↑ PfelfSssSeg Pfelf
PfelfSssSeg selects SSS segments from Pfelf.Pgm.SssList by purpose and stores pointers to them in Pfelf.Buffer.CODE,Pfelf.Buffer.RODATA,Pfelf.Buffer.DATA.
Input
Pfelf is pointer to PFELF object.
Output
Buffers in Pfelf object are filled.
Error
Errors are reported with macro Msg.
Invoked by
PfelfCompile PfelfsoCompile PfelfxCompile
Invokes
SssFindByPurpose
PfelfSssSeg Procedure Pfelf
    MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    MOV EDX,[EDI+PFELF.Buffer.CODE]
    BufferClear EDX
    Invoke SssFindByPurpose::,sssSegment,sssPurposeCODE,sssNotBSS,0,EBX,[EDI+PFELF.Buffer]
    BufferRetrieve [EDI+PFELF.Buffer]
    BufferStore EDX,ESI,ECX
    Invoke SssFindByPurpose::,sssSegment,sssPurposePLT,sssNotBSS,0,EBX,[EDI+PFELF.Buffer]
    BufferRetrieve [EDI+PFELF.Buffer]
    BufferStore EDX,ESI,ECX
    MOV EDX,[EDI+PFELF.Buffer.RODATA]
    BufferClear EDX
    Invoke SssFindByPurpose::,sssSegment,sssPurposeRODATA,sssNotBSS,0,EBX,[EDI+PFELF.Buffer]
    BufferRetrieve [EDI+PFELF.Buffer]
    BufferStore EDX,ESI,ECX
    MOV EDX,[EDI+PFELF.Buffer.DATA]
    BufferClear EDX
    Invoke SssFindByPurpose::,sssSegment,sssPurposeDATA,sssNotBSS,0,EBX,[EDI+PFELF.Buffer]
    BufferRetrieve [EDI+PFELF.Buffer]
    BufferStore EDX,ESI,ECX
    Invoke SssFindByPurpose::,sssSegment,sssPurposeGOT,sssNotBSS,0,EBX,[EDI+PFELF.Buffer]
    BufferRetrieve [EDI+PFELF.Buffer]
    BufferStore EDX,ESI,ECX
    Invoke SssFindByPurpose::,sssSegment,sssPurposeDYNAMIC,sssNotBSS,0,EBX,[EDI+PFELF.Buffer]
    BufferRetrieve [EDI+PFELF.Buffer]
    BufferStore EDX,ESI,ECX
    Invoke SssFindByPurpose::,sssSegment,sssPurposeBSS,sssDontCare,0,EBX,[EDI+PFELF.Buffer]
    BufferRetrieve [EDI+PFELF.Buffer]
    BufferStore EDX,ESI,ECX
  EndProcedure PfelfSssSeg
↑ PfelfPhdr Pfelf
PfelfPhdr converts every €ASM sssGroup SSS to records PFELF_PHDR and stores them in Pfelf.Buffer.PHDR.
The groups are already ordered in Pfelf.Pgm.SegOrdBuffer.
Input
Pfelf is pointer to PFELF object.
Output
Pfelf.Buffer.PHDR is filled with ELF program header records.
Error
Errors are reported with macro Msg.
Invoked by
PfelfsoCompile PfelfxCompile
PfelfPhdr Procedure Pfelf
OrdBufPtr  LocalVar                             ; Ptr to an array of pointers to SSS objects.
OrdBufEnd  LocalVar                             ; Ptr to the end ot array.
    MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    BufferClear [EDI+PFELF.Buffer.PHDR]
    BufferRetrieve [EBX+PGM.SegOrdBuffer]
    ADD ECX,ESI
    MOV [%OrdBufPtr],ESI
    MOV [%OrdBufEnd],ECX
.10:MOV ESI,[%OrdBufPtr]
    CMP ESI,[%OrdBufEnd]
    JNB .90:
    LODSD
    MOV [%OrdBufPtr],ESI
    JNSt [EAX+SSS.Status],sssGroup,.10:
    MOV ESI,EAX                                  ; Each sssGroup ESI will create one PHDR record.
.15:MOV ECX,SIZE# PFELF_PHDR64
    JSt [EDI+PFELF.Status],pfelfWidth64,.17:
    MOV CL,SIZE# PFELF_PHDR32
.17:BufferNew [EDI+PFELF.Buffer.PHDR],ECX,Zeroed=Yes
    MOV EBX,EAX                                  ; EBX=^PHDR, yet empty.
.18:MOV EAX,[ESI+SSS.BottomLow]                  ; Virtual address. EBX=^empty PHDR, ESI=sssGroup.
    MOV EDX,[ESI+SSS.BottomHigh]
.19:JSt [EDI+PFELF.Status],pfelfWidth64,.20:
    MOV [EBX+PFELF_PHDR32.p_vaddr],EAX
    MOV [EBX+PFELF_PHDR32.p_paddr],EAX
    JMP .30:
.20:MOV [EBX+PFELF_PHDR64.p_vaddr+0],EAX
    MOV [EBX+PFELF_PHDR64.p_vaddr+4],EDX
    MOV [EBX+PFELF_PHDR64.p_paddr+0],EAX
    MOV [EBX+PFELF_PHDR64.p_paddr+4],EDX
.30:MOV EAX,[ESI+SSS.TopLow]                     ; File offset + virtual size.
    MOV EDX,[ESI+SSS.TopHigh]
    SUB EAX,[ESI+SSS.BottomLow]
    SBB EDX,[ESI+SSS.BottomHigh]                 ; EDX:EAX is virtual size.
    MOV ECX,[ESI+SSS.BottomFA]
    JSt [EDI+PFELF.Status],pfelfWidth64,.40:
    MOV [EBX+PFELF_PHDR32.p_memsz],EAX
    MOV [EBX+PFELF_PHDR32.p_offset],ECX
    MOV EAX,[ESI+SSS.TopFA]
    SUB EAX,ECX
    MOV [EBX+PFELF_PHDR32.p_filesz],EAX
    JMP .50:
.40:MOV [EBX+PFELF_PHDR64.p_memsz+0],EAX
    MOV [EBX+PFELF_PHDR64.p_memsz+4],EDX
    MOV [EBX+PFELF_PHDR64.p_offset+0],ECX
    MOV EAX,[ESI+SSS.TopFA]
    SUB EAX,ECX
    MOV [EBX+PFELF_PHDR64.p_filesz+0],EAX
.50:XOR EDX,EDX                                  ; Default PHDR.p_flags: none.
    XOR EAX,EAX                                  ; Default PHDR.p_type = PT_NULL.
    MOV ECX,[ESI+SSS.Alignment]                  ; Default PHDR.p_align is SSS.Alignment.
    MOV ESI,[ESI+SSS.Purpose]                    ; Specify PHDR type, access flags and alignment by SSS.Purpose.
    PUSHD .Dispatched:                           ; Prepare return address from dispatching.
pur %FOR PHDR,CODE,RODATA,DATA,GOT,PLT,BSS,DRECTVE,DYNAMIC,INTERP
      JSt ESI,sssPurpose%pur,.sssPurpose%pur:    ; Dispatch PHDR by purpose.
    %ENDFOR pur
    RET                                          ; Continue at the label .Dispatched: with EAX=p_type, EDX=p_flags, ECX=p_align.
.sssPurposePHDR:
    MOV AL,pfelfPT_PHDR
    MOV ECX,8
    RET
.sssPurposeRODATA:
    MOV AL,pfelfPT_LOAD
    MOV DL,pfelfPF_R
    RET
.sssPurposeDRECTVE:
    MOV AL,pfelfPT_NOTE
    RET
.sssPurposePLT:
.sssPurposeCODE:
    MOV AL,pfelfPT_LOAD
    MOV DL,pfelfPF_R + pfelfPF_X
    RET
.sssPurposeDATA:
.sssPurposeGOT:
.sssPurposeBSS:
    MOV AL,pfelfPT_LOAD
    MOV DL,pfelfPF_R + pfelfPF_W
    RET
.sssPurposeINTERP:
    MOV AL,pfelfPT_INTERP
    MOV DL,pfelfPF_R
    RET
.sssPurposeDYNAMIC:
    MOV AL,pfelfPT_DYNAMIC
    MOV DL,pfelfPF_R + pfelfPF_W
    RET
.Dispatched:
    MOV [EBX+PFELF_PHDR64.p_type],EAX            ; PHDR64.p_type == PHDR32.p_type.
    JSt [EDI+PFELF.Status],pfelfWidth64,.60:
    MOV [EBX+PFELF_PHDR32.p_flags],EDX
    MOV [EBX+PFELF_PHDR32.p_align],ECX
    JMP .10:
.60:MOV [EBX+PFELF_PHDR64.p_flags],EDX
    MOV [EBX+PFELF_PHDR64.p_align+0],ECX
    JMP .10:
.90:EndProcedure PfelfPhdr
↑ PfelfEhdr Pfelf, e_type
PfelfEhdr creates PFELF_EHDR in Pfelf.Buffer.EHDR.
Input
Pfelf is pointer to PFELF object.
e_type is one of pfelfRel, pfelfExec, pfelfDyn.
Output
Pfelf.Buffer.PHDR is filled with ELF program header records.
Error
Errors are reported with macro Msg.
Invoked by
PfelfCompile PfelfsoCompile PfelfxCompile
Invokes
PgmGetEntryAddress
PfelfEhdr Procedure Pfelf, e_type
    MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    MOV EDX,[EDI+PFELF.Buffer.EHDR]
    BufferClear EDX
    MOV ECX,SIZE# PFELF_EHDR64
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.20:
    MOV ECX,SIZE# PFELF_EHDR32
.20:BufferNew EDX,ECX,Zeroed=Yes
    MOV EDI,EAX
    ; EHDR members common for 32bit and 64bit variant: .e_ident, .e_type, .e_machine, .e_version
    MOVD [EDI+PFELF_EHDR64.e_ident.e_mag0],0x464C457F ; ELF format identification.
    MOV ECX,pfelfClass64
    MOV EAX,pfelfMachineX64
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.30:
    MOV CL,pfelfClass32
    MOV AL,pfelfMachine386
.30:MOV [EDI+PFELF_EHDR64.e_ident.e_class],CL    ; E_IDENT.e_class
    MOV [EDI+PFELF_EHDR64.e_machine],AX
    MOVB [EDI+PFELF_EHDR64.e_ident.e_data],1     ; E_IDENT.e_data=1 (little endian).
    MOV ECX,[EBX+PGM.Pgmopt.MajorImageVersion]
    MOV [EDI+PFELF_EHDR64.e_ident.e_version],CL  ; E_IDENT.e_version=%^MajorImageVersion (default=1).
    MOV EDX,[%e_type]
    MOV [EDI+PFELF_EHDR64.e_type],DL
    MOV ECX,[EBX+PGM.Pgmopt.MajorLinkerVersion]  ; EHDR.e_version=%^MajorLinkerVersion (default=1).
    MOV [EDI+PFELF_EHDR64.e_version],CX
    Invoke PgmGetEntryAddress::,EBX              ; Returns Entry VA in EDX:EAX.
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.40:
    MOV [EDI+PFELF_EHDR32.e_entry],EAX
    JMPS .50:
.40:MOV [EDI+PFELF_EHDR64.e_entry+0],EAX
    MOV [EDI+PFELF_EHDR64.e_entry+4],EDX
.50:MOV ESI,[%Pfelf]
    MOV EAX,[ESI+PFELF.EHDR.e_phnum]
    MOV EDX,[ESI+PFELF.EHDR.e_shnum]
    MOV ECX,[ESI+PFELF.EHDR.e_phoff]
    MOV ESI,[ESI+PFELF.EHDR.e_shoff]
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.70:
    ; EHDR32.
    MOV [EDI+PFELF_EHDR32.e_phnum],AX
    MOV [EDI+PFELF_EHDR32.e_shnum],DX
    MOV [EDI+PFELF_EHDR32.e_phoff],ECX
    MOV [EDI+PFELF_EHDR32.e_shoff],ESI
    MOV [EDI+PFELF_EHDR32.e_ehsize],SIZE# PFELF_EHDR32    ; 0x0034.
    MOV [EDI+PFELF_EHDR32.e_phentsize],SIZE# PFELF_PHDR32 ; 0x0020.
    MOV [EDI+PFELF_EHDR32.e_shentsize],SIZE# PFELF_SHDR32 ; 0x0028.
    MOV EDX,[%Pfelf]
    MOV ECX,[EDX+PFELF.Sss.shstrtab]
    JECXZ .90:
    MOV EAX,[ECX+SSS.SegmIndex]
    MOV [EDI+PFELF_EHDR32.e_shstrndx],EAX
.60:JMP .90:
.70:; EHDR64.                                      ; EDX:EAX=program entry symbol value or 0 when none.
    MOV [EDI+PFELF_EHDR64.e_phnum],AX
    MOV [EDI+PFELF_EHDR64.e_shnum],DX
    MOV [EDI+PFELF_EHDR64.e_phoff+0],ECX
    MOV [EDI+PFELF_EHDR64.e_shoff+0],ESI
    MOV [EDI+PFELF_EHDR64.e_ehsize],SIZE# PFELF_EHDR64    ; 0x0040.
    MOV [EDI+PFELF_EHDR64.e_phentsize],SIZE# PFELF_PHDR64 ; 0x0038.
    MOV [EDI+PFELF_EHDR64.e_shentsize],SIZE# PFELF_SHDR64 ; 0x0040.
    MOV EDX,[%Pfelf]
    MOV ECX,[EDX+PFELF.Sss.shstrtab]
    JECXZ .90:
    MOV EAX,[ECX+SSS.SegmIndex]
    MOV [EDI+PFELF_EHDR64.e_shstrndx],EAX
.90:EndProcedure PfelfEhdr
↑ PfelfShdr Pfelf
PfelfShdr converts segments ordered on Pgm.SegmOrdBuffer to PFELF_SHDR32 or PFELF_SHDR64 object stored to Pfelf.Buffer.SHDR.
Input
Pfelf is pointer to PFELF object.
Output
SHDR objects are stored to Pfelf.Buffer.SHDR, their names to Pfelf.Sss.shstrtab.EmitBuffer.
Error
-
Invoked by
PfelfCompile PfelfsoCompile PfelfxCompile
PfelfShdr Procedure Pfelf
NameBuf    LocalVar                               ; ^BUFFER for ELF section names = [.shstrtab].EmitBuffer.
ShdrSize   LocalVar                               ; SIZE# PFELF_SHDR (28h or 40h).
OrdBufPtr  LocalVar                               ; Pointer inside array of pointers to SSS.
OrdBufEnd  LocalVar                               ; Pointer to the end of array.
ShdrBottom LocalVar                               ; ^PFELF_SHDR - pointer to the bottom of ELF section headers.
ShdrPtr    LocalVar                               ; ^PFELF_SHDR - pointer to the current ELF section header.
   MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    MOV ECX,[EDI+PFELF.Sss.shstrtab]
    MOV EDX,[ECX+SSS.EmitBuffer]
    MOV [%NameBuf],EDX
    BufferClear EDX
    BufferStoreByte EDX,0
    BufferClear [EDI+PFELF.Buffer.SHDR]
    MOV ECX,SIZE# PFELF_SHDR64
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.10:
    MOV CL,SIZE# PFELF_SHDR32
.10:MOV [%ShdrSize],ECX
    BufferRetrieve [EBX+PGM.SegOrdBuffer]
    ADD ECX,ESI
    MOV [%OrdBufPtr],ESI
    MOV [%OrdBufEnd],ECX
.20:MOV ESI,[%OrdBufPtr]
    CMP ESI,[%OrdBufEnd]
    JNB .80:
    LODSD                                        ; Load pointer to SSS.
    MOV [%OrdBufPtr],ESI
    BufferRetrieve [%NameBuf]                    ; Size of %NameBuf in ECX will be SHDR.sh_name.
    MOV ESI,EAX
    JNSt [ESI+SSS.Status],sssSegment,.20:        ; Skip groups.
    MOV EDI,[%Pfelf]
    BufferNew [EDI+PFELF.Buffer.SHDR],[%ShdrSize],Zeroed=Yes  ; Allocate ELF section header.
    MOV EDI,EAX                                  ; Convert ESI=^SSS to EDI=^PFELF_SHDR.
    MOV [%ShdrBottom],EAX
    CMPD [ESI+SSS.NameSize],0
    JZ .20:                                      ; Leave [] section header blank.
    ; SHDR.sh_name, SHDR.type, SHDR.flags are identical properties in PFELF_SHDR32 and PFELF_SHDR64.
    MOV [EDI+PFELF_SHDR64.sh_name],ECX
    BufferStore [%NameBuf],[ESI+SSS.NamePtr],[ESI+SSS.NameSize]
    BufferStoreByte [%NameBuf],0
    MOV EDX,[ESI+SSS.Purpose]
    MOV EDI,[ESI+SSS.NamePtr]                    ; Pointer to section name used to distinguish purpose of spec.section.
    MOV ECX,[ESI+SSS.NameSize]
    MOV EDI,[EDI+1]                              ; Omit '.' and load EDI with first 4 characters of section name.
.30:XOR EAX,EAX                                  ; AH will be dispatched to SHDR.sh_flags, AL to SHDR.sh_type.
    XOR ECX,ECX                                  ; CH will be dispatched to SHDR64.sh_entsize, CL to SHDR32.sh_entsize.
    PUSHD .Dispatched:                           ; Specify return address from dispatching.
pur %FOR %SssPurposeList{17..}                   ; Omit PECOFF special purposes.
      TEST EDX,sssPurpose%pur
      JZ .P%.:
      CALL .sssPurpose%pur:                      ; Prepare flags in AH,AL,CH,CL.
      .P%.:
     %ENDFOR pur
     RET                                         ; Continue at .Dispatched:
    ; Subprocedures which set AH=SHDR.sh_flags, AL=SHDR.sh_type, CH=SHDR64.sh_entsize, CL=SHDR32.sh_entsize.
.sssPurposePLT:
    MOV CL,4
    MOV CH,16
    OR AH,pfelfSHF_WRITE
.sssPurposeCODE:
    MOV AL,pfelfSHT_PROGBITS
    OR  AH,pfelfSHF_ALLOC+pfelfSHF_EXECINSTR
    RET
.sssPurposeDRECTVE:
    MOV AL,pfelfSHT_NOTE
    RET
.sssPurposePHDR:
    RET
.sssPurposeGOT:
    MOV CL,4
    MOV CH,8
.sssPurposeDATA:
    MOV AL,pfelfSHT_PROGBITS
    OR  AH,pfelfSHF_ALLOC+pfelfSHF_WRITE
    RET
.sssPurposeSTACK:
.sssPurposeBSS:
    MOV AL,pfelfSHT_NOBITS
    OR  AH,pfelfSHF_ALLOC+pfelfSHF_WRITE
    RET
.sssPurposeLITERAL:
.sssPurposeRODATA:
    MOV AL,pfelfSHT_PROGBITS
    OR  AH,pfelfSHF_ALLOC
    RET
.sssPurposeSYMBOLS:
    MOV CL,SIZE# PFELF_SYM32
    MOV CH,SIZE# PFELF_SYM64
    MOV AL,pfelfSHT_SYMTAB
    CMP EDI,'dyns'                               ; [.dynsym] ?
    JNE .Ret:
    MOV AL,pfelfSHT_DYNSYM
    OR  AH,pfelfSHF_ALLOC
.Ret:RET
.sssPurposeDYNAMIC:
    MOV CL,SIZE# PFELF_DYN32
    MOV CH,SIZE# PFELF_DYN64
    MOV AL,pfelfSHT_DYNAMIC
    OR  AH,pfelfSHF_ALLOC+pfelfSHF_WRITE
    RET
.sssPurposeINTERP:
    MOV AL,pfelfSHT_PROGBITS
    OR  AH,pfelfSHF_ALLOC
    RET
.sssPurposeSTRINGS:
    MOV AL,pfelfSHT_STRTAB
    CMP EDI,'dyns'                               ; [.dynstr] ?
    JNE .Ret:
    MOV AH,pfelfSHF_ALLOC
    RET
.sssPurposeRELOC:
    OR  AH,pfelfSHF_ALLOC
    MOV AL,pfelfSHT_REL
    MOV CL,SIZE# PFELF_REL32
    MOV CH,SIZE# PFELF_REL64
    CMP EDI,'rela'                               ; [.rela.Name] ?
    JNE .Ret:
    MOV CL,SIZE# PFELF_RELA32
    MOV CH,SIZE# PFELF_RELA64
    MOV AL,pfelfSHT_RELA
    RET
.sssPurposeHASH:
    MOV CL,4
    MOV CH,4
    MOV AL,pfelfSHT_HASH
    OR  AH,pfelfSHF_ALLOC
    RET
.Dispatched:  ; Return from subprocedures which have set AH=SHDR.sh_flags, AL=SHDR.sh_type, CH=SHDR64.sh_entsize, CL=SHDR32.sh_entsize.
    MOV EDI,[%ShdrBottom]
    MOV [EDI+PFELF_SHDR64.sh_type],AL            ; Identical member of SHDR64 and SHDR32.
    MOV [EDI+PFELF_SHDR64.sh_flags],AH           ; Identical member of SHDR64 and SHDR32.
    MOV EAX,[ESI+SSS.TopLow]
    MOV EDX,[ESI+SSS.TopHigh]
    SUB EAX,[ESI+SSS.BottomLow]
    SBB EDX,[ESI+SSS.BottomHigh]                 ; SHDR.sh_size
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.70:
    ; PFELF_SHDR32 members.
    MOV [EDI+PFELF_SHDR32.sh_size],EAX
    TEST EDX
    Msg cc=NZ,'8515',ESI                         ; Size of segment [!1S] exceeds 4 GB.
    MOV [EDI+PFELF_SHDR32.sh_entsize],CL
    MOV EAX,[ESI+SSS.BottomLow]
    MOV ECX,[ESI+SSS.BottomFA]
    MOV EDX,[ESI+SSS.Alignment]
    MOV [EDI+PFELF_SHDR32.sh_addr],EAX
    MOV [EDI+PFELF_SHDR32.sh_offset],ECX
    MOV [EDI+PFELF_SHDR32.sh_addralign],EDX
    MOV EAX,[ESI+SSS.sh_link]
    MOV EDX,[ESI+SSS.sh_info]
    MOV [EDI+PFELF_SHDR32.sh_link],EAX
    MOV [EDI+PFELF_SHDR32.sh_info],EDX
    JMP .20:
.70:; PFELF_SHDR64 members.
    MOV [EDI+PFELF_SHDR64.sh_size+0],EAX
    MOV [EDI+PFELF_SHDR64.sh_size+4],EDX
    MOV [EDI+PFELF_SHDR64.sh_entsize],CH
    MOV [EDI+PFELF_SHDR64.sh_offset+0],ECX
    MOV EDX,[ESI+SSS.Alignment]
    MOV [EDI+PFELF_SHDR64.sh_addralign+0],EDX
    MOV EAX,[ESI+SSS.BottomLow]
    MOV EDX,[ESI+SSS.BottomHigh]
    MOV ECX,[ESI+SSS.BottomFA]
    MOV [EDI+PFELF_SHDR64.sh_addr+0],EAX
    MOV [EDI+PFELF_SHDR64.sh_addr+4],EDX
    MOV [EDI+PFELF_SHDR64.sh_offset+0],ECX
    MOV EAX,[ESI+SSS.sh_link]
    MOV EDX,[ESI+SSS.sh_info]
    MOV [EDI+PFELF_SHDR64.sh_link],EAX
    MOV [EDI+PFELF_SHDR64.sh_info],EDX
    JMP .20:
.80:MOV EDX,[%Pfelf]                       ; Update VA of [.shstrtab] by emitted data.
    MOV EDI,[EDX+PFELF.Sss.shstrtab]
    BufferRetrieve [EDI+SSS.EmitBuffer]
    MOV EAX,[EDI+SSS.BottomLow]
    MOV EDX,[EDI+SSS.BottomHigh]
    ADD EAX,ECX
    ADC EDX,0
    MOV [EDI+SSS.TopLow],EAX
    MOV [EDI+SSS.TopHigh],EDX
  EndProcedure PfelfShdr
↑ PfelfConvertSymbols Pfelf, TabType
populates the [.symtab] | [.dynsym] segment of linked program with PFELF_SYM symbols.
PfelfConvertSymbols creates PFELF_SYM records STN_UNDEFX, STT_FILE and then it converts other symbols from Pgm.SymOrdBuf in this order:
  1. STN_UNDEFX empty NUL symbol
  2. STT_FILE with the name of source file
  3. STT_SECTION for each regular program section
  4. STB_LOCAL for each private symbol in Pgm (not when TabType=pfelfDyn)
  5. STB_GLOBAL for each public, extern, exported or imported symbol in Pgm
Input
Pfelf is pointer to PFELF object,
TableType is either 0 (covert to [.symtab]+[.strtab]), or pfelfDyn (convert to [.dynsym]+[.dynstr]+[.hash])
Output

PFELF_SYM records are stored in SSS.EmitBuffer of segment [.symtab] | [.dynsym], their names are stored in SSS.EmitBuffer of segment [.strtab] | [.dynstr].

SYM.NameIndex | SYM.NameDynIndex of converted symbols is updated.
Segments with sssPurposeRegular create PFELF_SYM with STT_SECTION type, their SSS.NameIndex is updated.
SSS.sh_info of segment [.symtab]|[.dynsym] is updated with the index of first non-local symbol.

Error
Errors are reported with macro Msg.
Invoked by
PfelfCompile PfelfsoCompile PfelfxCompile
Invokes
SssUpdateByEmit
PfelfConvertSymbols Procedure Pfelf, TabType
SymOrd  LocalVar                                 ; Zero-based ordinal number of the symbol in [.symtab]. Also SYM.NameIndex or SYM.NameDynIndex.
SymSss  LocalVar                                 ; ^SSS [.symtab] or [.dynsym].
StrSss  LocalVar                                 ; ^SSS [.strtab] or [.dynstr].
SymPtr  LocalVar                                 ; Pointer to an array of pointers to SYM.
SymEnd  LocalVar                                 ; End of the array.
Sym     LocalVar                                 ; ^SYM.
SymBuf  LocalVar                                 ; ^SSS.EmitBuffer for PFELF_SYM records.
NameBuf LocalVar                                 ; ^SSS.EmitBuffer for ASCIIZ symbol names.
    MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    BufferRetrieve [EBX+PGM.SymOrdBuffer]
    ADD ECX,ESI
    MOV [%SymPtr],ESI
    MOV [%SymEnd],ECX                            ; %SymPtr..%SymEnd is an array of pointers to SYM in the right order.
    JSt [%TabType],pfelfDyn,.15:
    MOV ESI,[EDI+PFELF.Sss.symtab]
    MOV EDX,[EDI+PFELF.Sss.strtab]
    JMP .20:
.15:MOV ESI,[EDI+PFELF.Sss.dynsym]
    MOV EDX,[EDI+PFELF.Sss.dynstr]
.20:MOV [%SymSss],ESI
    MOV [%StrSss],EDX
    MOV EAX,[EDX+SSS.SegmIndex]
    MOV [ESI+SSS.sh_link],EAX                    ; Symbol section ESI uses names from string table EDX.
    MOV ECX,[ESI+SSS.EmitBuffer]
    MOV EAX,[EDX+SSS.EmitBuffer]
    MOV [%NameBuf],EAX
    BufferStoreByte EAX,0                        ; Initialize [.strtab] or [.dynstr] with NULL symbol name.
    MOV [%SymBuf],ECX
    BufferNew ECX,[EDI+PFELF.symSize],Zeroed=Yes          ; Create NULL PFELF_SYM.
    MOVD [%SymOrd],1
    JSt [%TabType],pfelfDyn,.35:
    BufferNew ECX,[EDI+PFELF.symSize],Zeroed=Yes          ; Create STT_FILE SYM of source file.
    BufferRetrieve [%NameBuf]                    ; ECX=1.
    MOV [EAX+PFELF_SYM64.st_name],ECX            ; Offset of .st_name is identical for PFELF_SYM32 and PFELF_SYM64.
    LEA EDX,[Ea.SrcFile.Name::]
    ADD EDX,[Ea.SrcFile.NameOffs::]
    GetLength$ EDX                               ; EDX,ECX is now source file name without path.
    INC ECX                                      ; Zero terminated.
    BufferStore [%NameBuf],EDX,ECX
    MOV EDX,pfelfSTB_LOCAL+pfelfSTT_FILE + pfelfSHN_ABS<<16  ; >>
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.25:
    MOV [EAX+PFELF_SYM32.st_info],EDX            ; Store .st_info, .st_other, .st_shndx.
    JMP .30:
.25:MOV [EAX+PFELF_SYM64.st_info],EDX            ; Store .st_info, .st_other, .st_shndx.
.30:INCD [%SymOrd]                               ; Skip NUL and FILE ELF symbols.
.35:MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    MOV ESI,[%SymPtr]                            ; The main loop through symbols.  EDI=^PFELF
    CMP ESI,[%SymEnd]
    JNB .90:                                     ; End when no more symbols are left.
    LODSD                                        ; EAX=^SYM.
    MOV [%SymPtr],ESI
    MOV [%Sym],EAX
    JNSt [%TabType],pfelfDyn,.40:                ; All symbols will be converted to [.symtab].
    JNSt [EAX+SYM.Status],symImport|symExport,.35: ; Only dynamically global symbols will be converted to [.dynsym].
.40:BufferNew [%SymBuf],[EDI+PFELF.symSize],Zeroed=Yes
    MOV EDI,EAX                                  ; EDI=^PFELF_SYM.
    BufferRetrieve [%NameBuf]
    MOV [EDI+PFELF_SYM64.st_name],ECX            ; PFELF_SYM64.st_name=PFELF_SYM32.st_name.
    MOV ESI,[%Sym]                               ; Restore ESI=^SYM.
    BufferStore [%NameBuf],[ESI+SSS.NamePtr],[ESI+SSS.NameSize]
    BufferStoreByte [%NameBuf],0                 ; Zero-terminate the name in [.strtab] or [.dynstr].
    JNSt [ESI+SYM.Status],symExplScopeMask,.43:  ; Skip local and section symbols.
    MOV EDX,[%SymSss]                            ; Converting GLOBAL symbol. EDX=^[.symtab] or ^[.dynsym].
    CMPD [EDX+SSS.sh_info],0
    JNE .43:                                     ; Symbol table .sh_info wasn't established yet?
    MOV EAX,[%SymOrd]
    MOV [EDX+SSS.sh_info],EAX                    ; Index of the first global symbol.
.43:XOR EAX,EAX
    XOR EDX,EDX
    MOV ECX,[ESI+SYM.Section]
    JECXZ .45:
    MOV EAX,[ECX+SSS.BottomLow]
    MOV EDX,[ECX+SSS.BottomHigh]
.45:ADD EAX,[ESI+SYM.OffsetLow]
    ADC EDX,[ESI+SYM.OffsetHigh]
    MOV ECX,[%SymOrd]
    JSt [%TabType],pfelfDyn,.48:
    MOV [ESI+SYM.NameIndex],ECX
    JMPS .49:
.48:INC ECX
    MOV [ESI+SYM.NameDynIndex],ECX
    DEC ECX
.49:INC ECX
    MOV [%SymOrd],ECX
    MOV ECX,[ESI+SYM.Section]
    JECXZ .50:
    MOV ECX,[ECX+SSS.SegmIndex]
    JMP .55:
.50:MOV CX,pfelfSHN_ABS                          ; 0xFFF1 - scalar symbol special index.
.55:PUSH EBX
      MOV EBX,[%Pfelf]
      JSt [EBX+PFELF.Status],pfelfWidth64,.60:
      MOV [EDI+PFELF_SYM32.st_shndx],CX
      MOV [EDI+PFELF_SYM32.st_value],EAX
      JMP .65:
.60:  MOV [EDI+PFELF_SYM64.st_shndx],CX
      MOV [EDI+PFELF_SYM64.st_value+0],EAX
      MOV [EDI+PFELF_SYM64.st_value+4],EDX
.65:POP EBX                                       ; Restore ^PGM.
    MOV ECX,[ESI+SYM.Status]
    MOV DL,pfelfSTT_FUNC
    JSt ECX,symProc,.70:
    CMP CL,'I'
    JE .70:
    MOV DL,pfelfSTT_SECTION
    JSt ECX,symSe,.70:
    MOV DL,pfelfSTT_NOTYPE
    CMP CL,'A'
    JE .70:
    CMP CL,'N'
    JE .70:
    CMP CL,0
    JE .70:
    CMP CL,'?'
    JE .70:
    MOV DL,pfelfSTT_OBJECT                        ; Undispatched data types 'B','W','D','Q' etc.
.70:JNSt ECX,symScopeMask,.80:
    JNSt ECX,symWeak,.75:
    OR DL,pfelfSTB_WEAK
    JMP .80:
.75:OR DL,pfelfSTB_GLOBAL
.80:MOV EAX,[ESI+SYM.Size]
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.85:
    MOV [EDI+PFELF_SYM32.st_size],EAX
    MOV [EDI+PFELF_SYM32.st_info],DL
    JMP .86:
.85:MOV [EDI+PFELF_SYM64.st_size+0],EAX
    MOV [EDI+PFELF_SYM64.st_info],DL
.86:
    ; Create relocation of symbol address.
    MOV EDI,[%Pfelf]
    MOV EAX,[%Sym]
    JSt [EAX+SYM.Status],symImport,.35:
    MOV EDX,[%SymSss]                              ; [.symtab] or [.dynsym]
    BufferRetrieve [EDX+SSS.EmitBuffer]            ; ECX=offset behind the just emitted PFELF_SYM
    BufferNew [EDX+SSS.RelocBuffer],SIZE# RELOC,Zeroed=Yes
    MOV EBX,EAX
    MOV [EBX+RELOC.Section],EDX
    JNSt [EDI+PFELF.Status],pfelfWidth64,.87:
    MOV EAX,relocWidth64+relocAbsVA
    SUB ECX,SIZE# PFELF_SYM64 - PFELF_SYM64.st_value
    JMPS .88:
.87:MOV EAX,relocWidth32+relocAbsVA
    SUB ECX,SIZE# PFELF_SYM32 - PFELF_SYM32.st_value
.88:MOV [EBX+RELOC.Status],EAX
    MOV [EBX+RELOC.OrgLow],ECX
    MOV ECX,[%Sym]
    MOV [EBX+RELOC.Symbol],ECX
    MOV EAX,[ECX+SYM.OffsetLow]
    MOV EDX,[ECX+SYM.OffsetHigh]
    SUB [EBX+RELOC.AddendLow],EAX
    SBB [EBX+RELOC.AddendHigh],EDX
    JMP .35
.90:Invoke SssUpdateByEmit::,[%StrSss]
    Invoke SssUpdateByEmit::,[%SymSss]
    JNSt [%TabType],pfelfDyn,.99:
    BufferRetrieve [%NameBuf]
    MOV EDI,[%Pfelf]
    MOV [EDI+PFELF.dynstrSize],ECX
.99:EndProcedure PfelfConvertSymbols
PfelfLink 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.
SHDRsize     LocalVar ; Size of one ELF section header (28h or 40h).
FA           LocalVar ; Current file address.
FileAlign    LocalVar ; Effective file alignment.
    MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    MOV EDX,SIZE# PFELF_SHDR64
    JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.10:
    MOV DL,SIZE# PFELF_SHDR32
.10: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 ELF.
    ADD EAX,[EDI+PFELF.HDRsEnd]                  ; Calculate headers size to start linking at.
    MOV [%FA],EAX
.20:MOV ESI,[%ArrayPtr]
    CMP ESI,[%ArrayEnd]
    JNB .80:                                     ; End when all segments were linked.
    LODSD
    MOV [%ArrayPtr],ESI
    MOV EDI,EAX
    SetSt [EDI+SSS.Status],sssLinked             ; Tell RelocResolve that segments are linked.
.40:JNSt [EDI+SSS.Status],sssSegment,.20:
    CMPD [EDI+SSS.NameSize],0                    ; EDI=^SSS.sssSegment (ELF "section").
    JZ .20:                                      ; Skip the empty NULL segment [].
    MOV ECX,[EDI+SSS.Alignment]                  ; ECX is segment's own alignment.
    JNSt [EDI+SSS.Purpose],sssPurposeRegular,.50:
    CMP ECX,[EBX+PGM.Pgmopt.FileAlign]
    JAE .50:
    MOV ECX,[EBX+PGM.Pgmopt.FileAlign]
.50:MOV [%FileAlign],ECX
; Link the segment EDI.
    MOV EAX,[EDI+SSS.TopLow]                     ; Compute segment size in memory.
    MOV EDX,[EDI+SSS.TopHigh]
    SUB EAX,[EDI+SSS.BottomLow]
    SBB EDX,[EDI+SSS.BottomHigh]
    Msg cc=NZ,'8525',EDI                         ; 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 [EDI+SSS.BottomFA],ECX                   ; Aligned FA of this segment.
    JNSt [EDI+SSS.Status],sssNotBSS,.55:         ; Skip when EDI is BSS segment.
    ADD ECX,ESI                                  ; Add %Size in the file.
.55:MOV [EDI+SSS.TopFA],ECX
    MOV [%FA],ECX                                ; Unaligned FA of the next segment.
    JMP .20:                                     ; Go to link the next segment.

.80:Invoke PgmResizeGroups::,EBX                 ; Update FA and VA of groups by their segments.
    MOV EDX,[%Pfelf]                             ; [LOAD.HDR] and [LOAD.DYNAMIC] were resized incorrectly.
    MOV EDI,[EDX+PFELF.Sss.LOAD.HDR]             ; Pseudogroup for segments [], [.symtab], [.rel(a)name], [.strtab], [.shstrtab].
    TEST EDI
    JZ .90:
    XOR EAX,EAX
    MOV [EDI+SSS.BottomLow],EAX
    MOV [EDI+SSS.BottomHigh],EAX
    MOV [EDI+SSS.BottomFA],EAX
.90:EndProcedure PfelfLink
↑ PfelfRelaCreate Pfelf
PfelfRelaCreate creates an empty SSS segment [.rel(a)name] for each SSS segment [ name] which has at least one relocation in its .RelocBuffer.
Input
Pfelf is pointer to PFELF object.
Output
SSS segment(s) named [.rel(a)name] are created in %Pfelf.Pgm with sssPurposeRELOC.
Error
Errors are reported with macro Msg.
Invoked by
PfelfCompile PfelfsoCompile
PfelfRelaCreate Procedure Pfelf
RegularSss LocalVar ; ^SSS [name].
RelaSss    LocalVar ; ^SSS [.rel(a)name].
    MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    ListGetFirst [EBX+PGM.SssList]
.10:MOV [%RegularSss],EAX
    JNSt [EAX+SSS.Status],sssSegment,.80:
    BufferRetrieve [EAX+SSS.RelocBuffer]
    JNA .80:
    ListNew [EBX+PGM.SssList],Zeroed=Yes         ; Create a new SSS segment.
    MOV [%RelaSss],EAX
    MOV ESI,EAX                                  ; SSS [.rel(a).name].
    SetSt [ESI+SSS.Status],sssSegment+sssNotBSS+sssPublic
    SetSt [ESI+SSS.Purpose],sssPurposeRELOC
    MOVD [ESI+SSS.Alignment],8
    BufferClear [EDI+PFELF.Buffer]               ; Temporary buffer for construction .rel(a).name.
    BufferStore [EDI+PFELF.Buffer],=B'.rel',4
    JNSt [EDI+PFELF.Status],pfelfWidth64,.20:
    BufferStoreByte [EDI+PFELF.Buffer],'a'
.20:MOV EAX,[%RegularSss]
    BufferStore [EDI+PFELF.Buffer],[EAX+SSS.NamePtr],[EAX+SSS.NameSize]
    BufferRetrieve [EDI+PFELF.Buffer]
    PoolStore [EBX+PGM.Pool],ESI,ECX
    MOV ESI,[%RelaSss]
    MOV [ESI+SSS.NamePtr],EAX                    ; [.rel(a).name].
    MOV [ESI+SSS.NameSize],ECX
    MOV EAX,[%RegularSss]
    MOV [ESI+SSS.sh_info],EAX                    ; Temporarity store ^SSS [name], which will be replaced with .SegmIndex after PfelfLink.
.80:ListGetNext [%RegularSss]
    JNZ .10:
   EndProcedure PfelfRelaCreate
↑ PfelfRelaConvert Pfelf
PfelfRelaConvert copies all unresolved RELOC relocations from regular SSS segments ([.name]) and converts those RELOC record to the format PFELF_REL* and stores it to [.rel(a) name].EmitBuffer.
Input
Pfelf is pointer to PFELF object.
Output
[.rel(a).name] SSS segment is updated for each SSS with relocations.
Error
Errors are reported with macro Msg.
Invoked by
PfelfCompile PfelfsoCompile
Invokes
SssUpdateByEmit
PfelfRelaConvert Procedure Pfelf
RegularSss LocalVar ; ^SSS [name].
RelaSss    LocalVar ; ^SSS [.rel(a)name].
RelaBuffer LocalVar ; ^SSS [.rel(a)name].EmitBuffer.
RelocPtr   LocalVar ; Pointer to an array of RELOC records.
RelocEnd   LocalVar ; Pointer to the end of input RELOC array.
EmitPtr    LocalVar ; Pointer to the contents of %RegularSss.EmitBuffer.
EmitEnd    LocalVar ; Pointer to the end of %RegularSss.EmitBuffer.
    MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    ListGetFirst [EBX+PGM.SssList]
.10:MOV [%RelaSss],EAX
    JNSt [EAX+SSS.Status],sssSegment,.85:
    JNSt [EAX+SSS.Purpose],sssPurposeRELOC,.85:
    MOV EDX,[EAX+SSS.sh_info]                    ; ^SSS [name] temporarily stored there by PfelfRelaCreate.
    TEST EDX
    JZ .85:
    MOV [%RegularSss],EDX
    MOV ECX,[EDX+SSS.SegmIndex]
    MOV [EAX+SSS.sh_info],ECX                    ; Replace with index.
    MOV ECX,[EDI+PFELF.Sss.symtab]
    JECXZ .15:
    MOV ECX,[ECX+SSS.SegmIndex]
.15:MOV [EAX+SSS.sh_link],ECX
    BufferRetrieve [EDX+SSS.RelocBuffer]
    JNA .85:
    MOV [%RelocPtr],ESI
    MOV [%RelocEnd],ESI
    ADD [%RelocEnd],ECX
    MOV ESI,EAX                                  ; SSS [.rel(a).name].
    MOV EBX,[EDI+PFELF.Pgm]
    BufferCreate [EBX+PGM.Pool],Size=ECX
    MOV [ESI+SSS.EmitBuffer],EAX
    MOV [%RelaBuffer],EAX
.20:MOV ESI,[%RelocPtr]                          ; Convert ESI=^RELOC to PFELF_REL*.
    CMP ESI,[%RelocEnd]
    JNB .80:
    JSt [ESI+RELOC.Status],relocIgnore,.70:
    BufferNew [%RelaBuffer],[EDI+PFELF.relSize],Zeroed=Yes
    MOV EBX,EAX                                  ; Convert ESI=^RELOC to EBX=^PFELF_REL32.
    JSt [EDI+PFELF.Status],pfelfWidth64,.50:

    ; PFELF_REL32 needs to add RELOC.Addend to the relocated DWORD object in emitted code.
    MOV EAX,[ESI+RELOC.OrgLow]
    MOV ECX,[ESI+RELOC.Section]
    JECXZ .E7732:                                ; Relocation type 0x!1W at [!2S]:!3H is out of range.
    BufferRetrieve [ECX+SSS.EmitBuffer]          ; ESI,ECX is the emitted contents.
    CMP EAX,ECX
    JNB .E7732:                                  ; Relocation type 0x!1W at [!2S]:!3H is out of range.
    LEA ECX,[ESI+EAX]                            ; Pointer to the relocated DWORD object.
    MOV ESI,[%RelocPtr]
    XOR EAX,EAX
    XOR EDX,EDX
    XCHG EAX,[ESI+RELOC.AddendLow]               ; Apply EDX:EAX=RELOC.Addend to the emitted object.
    XCHG EDX,[ESI+RELOC.AddendHigh]
    JNSt [ESI+RELOC.Status],relocWidth32,.25:
    ADD [ECX],EAX
    JMPS .35:
.25:JNSt [ESI+RELOC.Status],relocWidth64,.30:
    ADD [ECX+0],EAX
    ADC [ECX+4],EDX
    JMPS .35:
.30:JNSt [ESI+RELOC.Status],relocWidth16,.35:
    ADD [ECX],AX
.35:MOV ECX,[ESI+RELOC.Section]
    MOV EAX,[ESI+RELOC.OrgLow]
    ADD EAX,[ECX+SSS.BottomLow]
    MOV [EBX+PFELF_REL32.r_offset],EAX
    MOV ECX,[ESI+RELOC.Symbol]
    JECXZ .E7738:
    MOV ECX,[ECX+SYM.NameIndex]
    SHL ECX,8                                    ; Target symbol index in bits 8..31.
    MOV EDX,[ESI+RELOC.Status]
    JSt EDX,relocWidth16|relocWidth64,.E7730:    ; Unsupported !1Dbit relocation type 0x!2W at [!3S]:!4Hh.
    MOV CL,pfelfR_386_32                         ; 1.
    JSt EDX,relocAbsVA,.40:
    MOV CL,pfelfR_386_PC32                       ; 2.
    JSt EDX,relocRel,.40:
    MOV CL,pfelfR_386_GOT32                      ; 3.
    JSt EDX,relocGOT,.40:
    MOV CL,pfelfR_386_PLT32                      ; 4.
    JSt EDX,relocPLT,.40:
    MOV CL,pfelfR_386_GLOB_DAT                   ; 6.
    JSt EDX,relocSym,.40:
    MOV CL,pfelfR_386_RELATIVE                   ; 8.
    JSt EDX,relocDyn,.40:
    MOV CL,pfelfR_386_GOTOFF                     ; 9.
    JSt EDX,relocGOToff,.40:
    MOV CL,pfelfR_386_GOTPC                      ; 10.
    JSt EDX,relocGOTrel,.40:
    MOV CL,0
.40:MOV [EBX+PFELF_REL32.r_info],ECX             ; PFELF_REL32 at EBX is done.
    JMP .70:
.E7730:MOV EDX,[ESI+RELOC.Status]
    MOVZX ECX,DX                                  ; relocTypeMask.
    AND EDX,relocWidthMask
    SHR EDX,16
    Msg '7730',EDX,ECX,[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Unsupported !1Dbit relocation type 0x!2W at [!3S]:!4Hh.
    JMP .70:
.E7732:                                          ; Unsupported !1Dbit relocation type 0x!2W at [!3S]:!4Hh.
    MOV ESI,[%RelocPtr]
    MOV EDX,[ESI+RELOC.Status]
    MOVZX ECX,DX                                 ; relocTypeMask.
    AND EDX,relocWidthMask
    SHR EDX,16
    Msg '7730',EDX,ECX,[ESI+RELOC.Section],[ESI+RELOC.OrgLow]
    JMP .70:                                     ; The next RELOC.
.E7738:Msg '7738',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Missing target symbol of relocation at [!1S]:!2Hh.
    JMP .70:
.50: ; PFELF_RELA64 has its own Addend field.
    MOV EAX,[ESI+RELOC.OrgLow]
    MOV EDX,[ESI+RELOC.OrgHigh]
    MOV ECX,[ESI+RELOC.Section]
    JECXZ .55:
    ADD EAX,[ECX+SSS.BottomLow]
    ADC EDX,[ECX+SSS.BottomHigh]
.55:MOV [EBX+PFELF_RELA64.r_offset+0],EAX
    MOV [EBX+PFELF_RELA64.r_offset+4],EDX
    MOV EAX,[ESI+RELOC.AddendLow]
    MOV EDX,[ESI+RELOC.AddendHigh]
    MOV [EBX+PFELF_RELA64.r_addend+0],EAX
    MOV [EBX+PFELF_RELA64.r_addend+4],EDX
    MOV ECX,[ESI+RELOC.Symbol]                   ; Construct PFELF_RELA64.r_info.
    JECXZ .E7738:                                ; Missing target symbol of relocation at [!1S]:!2Hh.
    MOV ECX,[ECX+SYM.NameIndex]
    MOV EDX,[ESI+RELOC.Status]
    JSt EDX,relocWidth16,.E7730:                 ; Unsupported !1Dbit relocation type 0x!2W at [!3S]:!4Hh.
    JSt EDX,relocWidth64,.60:
    MOV EAX,pfelfR_X86_64_32                     ; 10
    JSt EDX,relocAbsVA,.65:
    MOV AL,pfelfR_X86_64_PC32                    ; 2.
    JSt EDX,relocRel,.65:
    MOV AL,pfelfR_X86_64_GOT32                   ; 3.
    JSt EDX,relocGOT,.65:
    MOV AL,pfelfR_X86_64_PLT32                   ; 4.
    JSt EDX,relocPLT,.65:
    MOV AL,pfelfR_X86_64_GOTPC32                 ; 26.
    JSt EDX,relocGOTrel,.65:
    MOV AL,pfelfR_X86_64_NONE                    ; 0.
    JMP .65:
.60:MOV EAX,pfelfR_X86_64_64                     ; 1.
    JSt EDX,relocAbsVA,.65:
    MOV AL,pfelfR_X86_64_JUMP_SLOT               ; 7.
    JSt EDX,relocSym,.65:
    MOV AL,pfelfR_X86_64_RELATIVE                ; 8.
    JSt EDX,relocDyn,.65:
    MOV AL,pfelfR_X86_64_GOTOFF64                ; 25.
    JSt EDX,relocGOToff,.65:
    MOV AL,pfelfR_X86_64_NONE                    ; 0.
.65:MOV [EBX+PFELF_RELA64.r_info+0],EAX
    MOV [EBX+PFELF_RELA64.r_info+4],ECX
.70:ADDD [%RelocPtr],SIZE# RELOC
    JMP .20:                                     ; The next RELOC.
.80:Invoke SssUpdateByEmit::,[%RelaSss]
.85:ListGetNext [%RelaSss]
    JNZ .10:                                     ; The next regular segment.
   EndProcedure PfelfRelaConvert
PfelfHdrsLink Procedure Pfelf
PHDRlen LocalVar
SHDRlen LocalVar
OrdEnd  LocalVar
    MOV EDI,[%Pfelf]
    MOV EBX,[EDI+PFELF.Pgm]
    BufferRetrieve [EBX+PGM.SegOrdBuffer]
    ADD ECX,ESI
    MOV [%OrdEnd],ECX
    SUB ECX,ECX                                  ; PHDR counter.
    SUB EDX,EDX                                  ; SHDR counter.
.10:CMP ESI,[%OrdEnd]
    JNB .30:
    LODSD
    JNSt [EAX+SSS.Status],sssGroup,.20:
    INC ECX
.20:JNSt [EAX+SSS.Status],sssSegment,.10:
    INC EDX
    JMP .10:
.30:MOV [EDI+PFELF.EHDR.e_phnum],ECX
    MOV [EDI+PFELF.EHDR.e_shnum],EDX
    MOV ECX,SIZE# PFELF_EHDR64 << 16 +SIZE# PFELF_SHDR64 << 8 + SIZE# PFELF_PHDR64 ; >>>>
    JSt [EDI+PFELF.Status],pfelfWidth64,.40:
    MOV ECX,SIZE# PFELF_EHDR32 << 16 +SIZE# PFELF_SHDR32 << 8 + SIZE# PFELF_PHDR32 ; >>>>
.40:MOVZX EAX,CH                                 ; Size of one section header entry.
    MUL [EDI+PFELF.EHDR.e_shnum]
    MOV [%SHDRlen],EAX                           ; Total length of SHDRs in bytes.
    MOVZX EAX,CL
    MUL [EDI+PFELF.EHDR.e_phnum]
    MOV [%PHDRlen],EAX                           ; Total length of PHDRs in bytes.
    SHR ECX,16                                   ; ECX=Size of PFELF_EHDR (34h or 40h).
    MOV ESI,ECX                                  ; ESI=Current unaligned FA.
    MOV CL,8                                     ; ECX=PHDR alignment in 64 bits.
    MOV EDX,16                                   ; EDX=SHDR alignment in 64 bits.
    JSt [EDI+PFELF.Status],pfelfWidth64,.45:
    XCHG ECX,EDX                                 ; 32 bits.
.45:TEST EAX                                     ; Is PHDR present?
    JZ .50:                                      ; Skip if not.
    Invoke ExpAlign::,ESI,ECX,0                  ; Return alignment bytes in ECX.
    ADD ESI,ECX                                  ; ESI is aligned FA of PHDRs.
    MOV [EDI+PFELF.EHDR.e_phoff],ESI
    ADD ESI,EAX
.50:Invoke ExpAlign::,ESI,EDX,0                  ; Return alignment bytes in ECX.
    ADD ESI,ECX                                  ; ESI is aligned FA of SHDRs.
    MOV [EDI+PFELF.EHDR.e_shoff],ESI
    ADD ESI,[%SHDRlen]
    MOV [EDI+PFELF.HDRsEnd],ESI                  ; Unaligned size of HDRs.
   EndProcedure PfelfHdrsLink
↑ PfelfHdrsStream Pfelf, Stream
PfelfHdrsStream will store ELF headers (EHDR, PHDR, SHDR) to an empty Stream.
Input
Pfelf is pointer to PFELF object.
Stream is pointer to an output memory STREAM.
Output
Contents of buffers in PFELF members PFELF.Buffer.EHDR, PFELF.Buffer.PHDR, PFELF.Buffer.SHDR is aligned and stored to the Stream.
Error
Errors are reported with macro Msg.
Invoked by
PfelfCompile PfelfsoCompile PfelfxCompile
Invokes
EaStreamAlign
PfelfHdrsStream Procedure Pfelf, Stream
    MOV EDI,[%Pfelf]
    MOV EDX,[%Stream]
    BufferRetrieve [EDI+PFELF.Buffer.EHDR]
    StreamStore EDX,ESI,ECX                     ; ELF file header.
    MOV EAX,8                                   ; PHDR64 alignment.
    MOV EBX,16                                  ; SHDR64 alignment.
    JSt [EDI+PFELF.Status],pfelfWidth64,.20:
    XCHG EAX,EBX                                ; 32 bits.
.20:BufferRetrieve [EDI+PFELF.Buffer.PHDR]
    JECXZ .30:                                  ; Skip when ELF program headers PHDR are not present.
    Invoke EaStreamAlign::, EDX,EAX,0
    StreamStore EDX,ESI,ECX                     ; ELF program headers.
.30:Invoke EaStreamAlign::, EDX,EBX,0
    BufferRetrieve [EDI+PFELF.Buffer.SHDR]
    StreamStore EDX,ESI,ECX                     ; ELF section headers.
   EndProcedure PfelfHdrsStream
  ENDPROGRAM pfelf

▲Back to the top▲