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 used in this source.
ea.htm,eaopt.htm,exp.htm,msg.htm,pf.htm,pfelfx.htm,pgm.htm,pgmopt.htm,reloc.htm,sss.htm,stm.htm,sym.htm
pfelf HEAD ; Start module interface.
; 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*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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
[], [.symtab], [.shstrtab], [.strtab].
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 reads the contents of one ELF file
and converts it to structures of a fresh new program, which then will be stored on
BasePgm.ModulePgmList.
This procedure works with ELF types Relocatable, Executable and SharedObject in both 32bit and 64bit mode.
BasePgm.ModulePgmList as a new
PGM structure.
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 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 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
Pfelf.Buffer.CODE,Pfelf.Buffer.RODATA,Pfelf.Buffer.DATA.
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
Pfelf.Buffer.PHDR.
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
Pfelf.Buffer.EHDR.pfelfRel, pfelfExec, pfelfDyn.
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
Pfelf.Buffer.SHDR.
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
[.symtab] | [.dynsym] segment of the linked program with PFELF_SYM symbols.
Pgm.SymOrdBuf in this order:0 (covert to [.symtab]+[.strtab]), or
pfelfDyn (convert to [.dynsym]+[.dynstr]+[.hash])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
the first non-local symbol.
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
JSt [EAX+SYM.Status],symSe|symImport|symExport|symGlobal|symPublic|symExtern,.40:
jmp .35: ; Only dynamic global symbols will be converted to [.dynsym].
;;; JNSt [%TabType],pfelfDyn,.40: ; All symbols will be converted to [.symtab].
JNSt [EAX+SYM.Status],symImport|symExport,.35: ; Only dynamic 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: ; Jump when symbol ESI is an absolute constant.
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: ; Jump when symbol ESI is an absolute constant (scalar).
JSt [ECX+SSS.Status],sssStructure,.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 calculates size, alignment and file address of each program segment. Virtual address is 0 for each ELF section.
It is invoked when the emited contents of all segments has been generated and their order was already established in
Pgm.OrdBuffer.
It assumes ImageBase=0 and EHDR,SHDR at the beginning of the output file, followed by emitted contents of the segments (ELF sections).
PfelfLink calculates segment virtual size as SSS.Top - SSS.Bottom for both initialized and uninitialized segments.
Segment file size is calculated from the size of Sss.EmitBuffer.
PfelfLink does not change the contents of SSS.EmitBuffer, SSS.RelocBuffer
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 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 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]
TEST ECX
JZ .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]
TEST ECX
JZ .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
.EHDR.e_phnum, .EHDR.e_phoff, .EHDR.e_shnum, EHDR.e_shoff, .HDRsEnd are updated.
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
PFELF.Buffer.EHDR, PFELF.Buffer.PHDR, PFELF.Buffer.SHDR
is aligned and stored to the Stream.
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