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.
; 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 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
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 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 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] 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
.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