#pragma once // ============================================================================ // elf.h - ELF format definitions // https://refspecs.linuxbase.org/elf/elf.pdf // https://gist.github.com/x0nu11byt3/bcb35c3de461e5fb66173071a2379779 // https://docs.oracle.com/cd/E19683-01/816-1386/6m7qcoblh/index.html // ============================================================================ #include /* ELF Types */ #pragma message("TODO: describe ELF types from specification") // ============================================================================ // =================================== ELF Header ============================= // ============================================================================ #define EI_NIDENT (16) /* e_ident offset (https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#ELF_header) */ #define EI_MAG0 0 #define EI_MAG1 1 #define EI_MAG2 2 #define EI_MAG3 3 #define EI_CLASS 4 #define EI_DATA 5 #define EI_VERSION 6 #define EI_OSABI 7 #define EI_ABIVERSION 8 #define EI_PAD 9 /* ELF Magic value */ #define ELF_MAGIC 0x464C457F // "\x7FELF" little-endian /* ELF Class */ #define ELFCLASS32 0x1 #define ELFCLASS64 0x2 /* Data format: or LSB(Least Significant Bit, little-endian) or MSB(Most Significant Bit, big-endian) */ #define ELFDATA2LSB 0x1 #define ELFDATA2MSB 0x2 /* ELF version */ #define ELFVERSION 0x1 /* Target ABI */ #define ELFABISYSTEMV 0x00 #define ELFABIHPUX 0x01 #define ELFABINETBSD 0x02 #define ELFABILINUX 0x03 #define ELFABIGNUHURD 0x04 #define ELFABISOLARIS 0x06 #define ELFABIAIX 0x07 #define ELFABIIRIX 0x08 #define ELFABIFREEBSD 0x09 #define ELFABITRU64 0x0A #define ELFABINM 0x0B #define ELFABIOPENBSD 0x0C #define ELFABIOPENVMS 0x0D #define ELFABINSKERNEL 0x0E #define ELFABIAROS 0x0F #define ELFABIFENIXOS 0x10 #define ELFABICLOUDABI 0x11 #define ELFABISTOPENVOS 0x12 /* ABI version */ #pragma message("TODO: do something with ABI version") /* Currently i don't use ABI version */ /* Object File Types, e_type field */ #define ET_NONE 0x0 /* Unknown */ #define ET_REL 0x1 /* Relocatable. (output of gcc -c). Contains sections + symbol tables + relocations. No program header */ #define ET_EXEC 0x2 /* Executable. Statically-linked executable with fixed virtual addresses. Has program headers. */ #define ET_DYN 0x3 /* Shared object. Shared library or PIE executable. Postitoin-independent, relocated at load time. */ #define ET_CORE 0x4 /* Core dump. Process memory image for post-mortem debugging */ #define ET_LOOS 0xFE00 /* Reserved inclusive range. Operating system specific */ #define ET_HIOS 0xFEFF /* Reserved inclusive range. Operating system specific */ #define ET_LOPROC 0xFF00 /* Reserved inclusive range. Processor specific */ #define ET_HIPROC 0xFFFF /* Reserved inclusive range. Processor specific */ /* Arch types, e_machine field */ #pragma message("TODO: add other architecture defines, copy from github") #define EM_X86 0x03 #define EM_X86_64 0x3E #define EM_ARM 0x28 /* up to Armv7/AArch32 */ #define EM_AARCH64 0xB7 /* Armv8/AArch64 */ /* Version value, e_version field */ #define EV_NONE 0x00 #define EV_CURRENT 0x01 #define EV_NUM 0x02 /* Other header fields: e_entry: Memory address of the entry point. e_phoff: Pointer to the start of the program header table. e_shoff: Pointer to the start of section header table. e_flags: Interpretation of this field depends on the target arch. e_ehsize: Contains the size of header (normally 64 bytes for 64-bit and 52 Bytes for 32-bit) e_phentsize: Contains the size of program header table entry. Or 0x20 (for 32-bit) or 0x38 (for 64-bit). e_phnum: Contains the number of entries in the program header table. e_shentsize: Contains the size of a section header table entry. Or 0x28 (for 32-bit) or 0x40 (for 64-bit) e_shnum: Contains the number of entries in the section header table. e_shstrndx: Contains index of the section header table entry, that contains the section names. */ /* ELF header (atm only for 64 bit) */ #pragma message("TODO: add elf header for 32 bit") struct Elf64_Ehdr { uint8_t e_ident[EI_NIDENT]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; uint64_t e_entry; uint64_t e_phoff; uint64_t e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; }; // ============================================================================ // =================================== Program Header ========================= // ============================================================================ /* Type, p_type field */ #define PT_NULL 0x00000000 /* Program header table entry unused */ #define PT_LOAD 0x00000001 /* Loadable segment */ #define PT_DYNAMIC 0x00000002 /* Dynamic linking information */ #define PT_INTERP 0x00000003 /* Interpreter information */ #define PT_NOTE 0x00000004 /* Auxiliary information */ #define PT_SHLIB 0x00000005 /* Reserved */ #define PT_PHDR 0x00000006 /* Segment containing program header table itself */ #define PT_TLS 0x00000007 /* Thread-Local Storage template */ #define PT_NUM 0x00000008 /* Number of defined types */ #define PT_LOOS 0x60000000 /* Reserved inclusive range. Operating system specific: */ #define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ #define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ #define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ #define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ #define PT_HISUNW 0x6fffffff #define PT_HIOS 0x6FFFFFFF /* Reserved inclusive range. Operating system specific end*/ #define PT_LOPROC 0x70000000 /* Reserved inclusive range. Processor specific */ #define PT_HIPROC 0x7FFFFFFF /* Reserved inclusive range. Processor specific */ /* Flags, p_flags 64-bit field */ #define PF_X 0x1 /* Executable segment */ #define PF_W 0x2 /* Writeable segment */ #define PF_R 0x4 /* Readable segment */ #define PF_MASKOS 0x0FF00000 /* OS-specific */ #define PF_MASKPROC 0xF0000000 /* Processor-specific */ /* Other Program Header fields: p_offset: Offset of the segment in the file image. p_vaddr: Virtual address of the segment in memory. p_paddr: On systems where physical address is relevant, reserved for segment's physical address. p_filesz: Size in bytes of the segment in the file image. May be 0. p_memsz: Size in bytes of the segment in memory. May be 0. p_flags: 32-bit flags (don't exist on 64 bit header) p_align: 0 and 1 specify no alignment. Otherwise should be a positive, integral power of 2, with p_vaddr equating p_offset modules p_align */ /* Elf64 Program Header */ struct Elf64_Phdr { uint32_t p_type; uint32_t p_flags; uint64_t p_offset; uint64_t p_vaddr; uint64_t p_paddr; uint64_t p_filesz; uint64_t p_memsz; uint64_t p_align; }; // ============================================================================ // =================================== Section Header ============================= // ============================================================================ /* Section Header Type, sh_type field */ #define SHT_NULL 0x0 /* Section header table entry unused. First entry in the section table must be SHT_NULL according the stanard */ #define SHT_PROGBITS 0x1 /* Program data */ #define SHT_SYMTAB 0x2 /* Symbol table */ #define SHT_STRTAB 0x3 /* String table */ #define SHT_RELA 0x4 /* Relocation entries with addends */ #define SHT_HASH 0x5 /* Symbol hash table */ #define SHT_DYNAMIC 0x6 /* Dynamic linking information */ #define SHT_NOTE 0x7 /* Notes */ #define SHT_NOBITS 0x8 /* Program space with no data (bss) */ #define SHT_REL 0x9 /* Relocation entries, no addends */ #define SHT_SHLIB 0x0A /* Reserved */ #define SHT_DYNSYM 0x0B /* Dynamic linker symbol table */ #define SHT_INIT_ARRAY 0x0E /* Array of constructors */ #define SHT_FINI_ARRAY 0x0F /* Array of destructors */ #define SHT_PREINIT_ARRAY 0x10 /* Array of pre-constructors */ #define SHT_GROUP 0x11 /* Section group */ #define SHT_SYMTAB_SHNDX 0x12 /* Extended section indices */ #define SHT_NUM 0x13 /* Number of defined types */ #define SHT_LOOS 0x60000000 /* Start OS-specific */ #define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ #define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ #define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ #define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ #define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ #define SHT_SUNW_move 0x6ffffffa #define SHT_SUNW_COMDAT 0x6ffffffb #define SHT_SUNW_syminfo 0x6ffffffc #define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ #define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ #define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ #define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ #define SHT_HIOS 0x6fffffff /* End OS-specific type */ #define SHT_LOPROC 0x70000000 /* Start of processor-specific */ #define SHT_HIPROC 0x7fffffff /* End of processor-specific */ #define SHT_LOUSER 0x80000000 /* Start of application-specific */ #define SHT_HIUSER 0x8fffffff /* End of application-specific */ /* Section Header flags, sh_flags field */ #define SHF_WRITE 0x1 /*Writable*/ #define SHF_ALLOC 0x2 /*Occupies memory during execution*/ #define SHF_EXECINSTR 0x4 /*Executable*/ #define SHF_MERGE 0x10 /*Might be merged*/ #define SHF_STRINGS 0x20 /*Contains null-terminated strings*/ #define SHF_INFO_LINK 0x40 /*'sh_info' contains SHT index*/ #define SHF_LINK_ORDER 0x80 /*Preserve order after combining*/ #define SHF_OS_NONCONFORMING 0x100 /*Non-standard OS specific handling required*/ #define SHF_GROUP 0x200 /*Section is member of a group*/ #define SHF_TLS 0x400 /*Section hold thread-local data*/ #define SHF_COMPRESSED 0x800 /*Section with compressed data*/ #define SHF_MASKOS 0x0FF00000 /*OS-specific*/ #define SHF_MASKPROC 0xF0000000 /*Processor-specific*/ #define SHF_ORDERED 0x4000000 /*Special ordering requirement (Solaris)*/ #define SHF_EXCLUDE 0x8000000 /*Section is excluded unless referenced or allocated (Solaris)*/ /* Other Section Header fields: sh_name: An offset to a string in the .shstrab section that represents the name of this section. Zero means no name. sh_addr: Virtual address of the section in memory, for sections that are loaded. sh_offset: Offset of the section in the file image. sh_size: Size in bytes of the section. May be 0. sh_link: Contains the section index of an associated section. This field is used for several purposes, depending on the type of section. sh_info: Contains extra information about the section. This field is used for several purposes, depending on the type of section. sh_addralign: Contains the required alignment of the section. This field must be a power of two. sh_entsize: Contains the size, in bytes, of each entry, for sections that contain fixed-size entries. Otherwise, this field contains zero. */ /* The most common ELF sections: .text - contains executable code. Packed with Read and Execute flags. Load only one times. Can't be changed. .data - initalized data. Read and Write flags. .rodata - initalized read only data. Read flag. .bss - unititlized data. Read and Write flags. other sections you can see here: https://gist.github.com/x0nu11byt3/bcb35c3de461e5fb66173071a2379779#sections Also, there is something like "group of sections" (readelf -g), but it's very rare. */ /* Elf64 Section Header */ struct Elf64_Shdr { uint32_t sh_name; uint32_t sh_type; uint64_t sh_flags; uint64_t sh_addr; uint64_t sh_offset; uint64_t sh_size; uint32_t sh_link; uint32_t sh_info; uint64_t sh_addralign; uint64_t sh_entsize; }; // ============================================================================ // =================================== Symbols ================================ // ============================================================================ // https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-79797/index.html #pragma message("TODO: do") /* Symbol fields: st_name: Symbol name st_info: Symbol type and binding. It is calculated using macros st_other: Symbol visibility. st_shndx: Section index. st_value: Symbol value. st_size: Symbol size; */ /* Symbol struct */ struct Elf64_Sym { uint32_t st_name; uint8_t st_info; uint8_t st_other; uint16_t st_shndx; uint64_t st_value; uint64_t st_size; }; // ============================================================================ // =================================== ELF Page size ========================== // ============================================================================ #define ELF_PAGE_SIZE 0x1000 #define ELF_PAGE_MASK (ELF_PAGE_SIZE - 1) // ============================================================================ // =================================== ELF Load Result ======================== // ============================================================================ // ATM it uses in efi_elf_parser.cpp /* Error codes for ElfLoadResult.error */ #define ELF_ERR_NONE 0 /* success */ #define ELF_ERR_FILE_TOO_SMALL 1 /* file smaller than ELF header */ #define ELF_ERR_INVALID_MAGIC 2 /* bad magic */ #define ELF_ERR_INVALID_CLASS 3 /* bad class */ #define ELF_ERR_INVALID_IDENT 4 /* bad ident */ #define ELF_ERR_INVALID_ARCH 5 /* bad machine */ #define ELF_ERR_INVALID_TYPE 6 /* bad type */ #define ELF_ERR_NO_LOAD_SEGS 7 /* no PT_LOAD segments found */ #define ELF_ERR_ALLOC_FAILED 8 /* AllocatePages failed (check efi_alloc_status) */ /* Elf Load Result object */ struct ElfLoadResult { uint64_t entry_point; uint64_t phys_base; uint64_t virt_base; uint64_t total_size; uint64_t efi_alloc_status; /* EFI_STATUS from AllocatePages, valid when error == ELF_ERR_ALLOC_FAILED */ uint8_t error; /* ELF_ERR_* code above */ bool success; };