#pragma once #include #include #include #include #include #include namespace types::elf { using elf32_addr_t = uint32_t; using elf32_off_t = uint32_t; using elf64_addr_t = uint64_t; using elf64_off_t = uint64_t; constexpr elf32_addr_t ELF32_STACK_BOTTOM = 0xbffff000; constexpr elf32_off_t ELF32_STACK_SIZE = 8 * 1024 * 1024; constexpr elf32_addr_t ELF32_STACK_TOP = ELF32_STACK_BOTTOM - ELF32_STACK_SIZE; constexpr int ELF_LOAD_FAIL_NORETURN = 0x114514; struct PACKED elf32_header { // 0x7f, "ELF" char magic[4]; enum : uint8_t { FORMAT_32 = 1, FORMAT_64 = 2, } format; enum : uint8_t { ENDIAN_LITTLE = 1, ENDIAN_BIG = 2, } endian; // should be 1 uint8_t _version1; enum : uint8_t { ABI_SYSTEM_V = 0x00, // TODO: ABI_LINUX = 0x03, } abi; uint8_t abi_version; uint8_t _reserved[7]; enum : uint16_t { ET_NONE = 0x00, ET_REL = 0x01, ET_EXEC = 0x02, ET_DYN = 0x03, ET_CORE = 0x04, ET_LOOS = 0xfe00, ET_HIOS = 0xfeff, ET_LOPROC = 0xff00, ET_HIPROC = 0xffff, } type; enum : uint16_t { ARCH_NONE = 0x00, ARCH_X86 = 0x03, ARCH_ARM = 0x28, ARCH_IA64 = 0x32, ARCH_X86_64 = 0x3e, ARCH_ARM64 = 0xb7, ARCH_RISCV = 0xf3, } arch; // should be 1 uint32_t _version2; // entry address elf32_addr_t entry; // program header table offset elf32_off_t phoff; // section header table offset elf32_off_t shoff; // architecture dependent flags uint32_t flags; // elf header size uint16_t ehsize; // program header table entry size uint16_t phentsize; // program header table entries number uint16_t phnum; // section header table entry size uint16_t shentsize; // section header table entries number uint16_t shnum; // section header table entry index that contains section names uint16_t shstrndx; }; struct PACKED elf32_program_header_entry { enum : uint32_t { PT_NULL = 0x00, PT_LOAD = 0x01, PT_DYNAMIC = 0x02, PT_INTERP = 0x03, PT_NOTE = 0x04, PT_SHLIB = 0x05, PT_PHDR = 0x06, PT_TLS = 0x07, PT_LOOS = 0x60000000, PT_HIOS = 0x6fffffff, PT_LIPROC = 0x70000000, PT_HIPROC = 0x7fffffff, } type; elf32_off_t offset; elf32_addr_t vaddr; elf32_addr_t paddr; elf32_off_t filesz; elf32_off_t memsz; // segment dependent enum : uint32_t { PF_X = 0x1, PF_W = 0x2, PF_R = 0x4, } flags; // 0 and 1 for no alignment, otherwise power of 2 uint32_t align; }; struct PACKED elf32_section_header_entry { elf32_off_t sh_name; enum : uint32_t { SHT_NULL = 0x00, SHT_PROGBITS = 0x01, SHT_RELA = 0x04, SHT_DYNAMIC = 0x06, SHT_NOTE = 0x07, SHT_NOBITS = 0x08, SHT_REL = 0x09, SHT_DYNSYM = 0x0b, SHT_INIT_ARRAY = 0x0e, SHT_FINI_ARRAY = 0x0f, SHT_PREINIT_ARRAY = 0x0f, } sh_type; enum : uint32_t { SHF_WRITE = 0x01, SHF_ALLOC = 0x02, SHF_EXECINSTR = 0x04, } sh_flags; elf32_addr_t sh_addr; elf32_off_t sh_offset; elf32_off_t sh_size; uint32_t sh_link; uint32_t sh_info; elf32_off_t sh_addralign; elf32_off_t sh_entsize; }; struct elf32_load_data { fs::dentry_pointer exec_dent; const std::vector& argv; const std::vector& envp; uintptr_t ip; uintptr_t sp; }; // TODO: environment variables int elf32_load(elf32_load_data& data); struct PACKED elf64_header { // 0x7f, "ELF" char magic[4]; enum : uint8_t { FORMAT_32 = 1, FORMAT_64 = 2, } format; enum : uint8_t { ENDIAN_LITTLE = 1, ENDIAN_BIG = 2, } endian; // should be 1 uint8_t _version1; enum : uint8_t { ABI_SYSTEM_V = 0x00, // TODO: ABI_LINUX = 0x03, } abi; uint8_t abi_version; uint8_t _reserved[7]; enum : uint16_t { ET_NONE = 0x00, ET_REL = 0x01, ET_EXEC = 0x02, ET_DYN = 0x03, ET_CORE = 0x04, ET_LOOS = 0xfe00, ET_HIOS = 0xfeff, ET_LOPROC = 0xff00, ET_HIPROC = 0xffff, } type; enum : uint16_t { ARCH_NONE = 0x00, ARCH_X86 = 0x03, ARCH_ARM = 0x28, ARCH_IA64 = 0x32, ARCH_X86_64 = 0x3e, ARCH_ARM64 = 0xb7, ARCH_RISCV = 0xf3, } arch; // should be 1 uint32_t _version2; // entry address elf64_addr_t entry; // program header table offset elf64_off_t phoff; // section header table offset elf64_off_t shoff; // architecture dependent flags uint32_t flags; // elf header size uint16_t ehsize; // program header table entry size uint16_t phentsize; // program header table entries number uint16_t phnum; // section header table entry size uint16_t shentsize; // section header table entries number uint16_t shnum; // section header table entry index that contains section names uint16_t shstrndx; }; struct PACKED elf64_program_header_entry { enum : uint32_t { PT_NULL = 0x00, PT_LOAD = 0x01, PT_DYNAMIC = 0x02, PT_INTERP = 0x03, PT_NOTE = 0x04, PT_SHLIB = 0x05, PT_PHDR = 0x06, PT_TLS = 0x07, PT_LOOS = 0x60000000, PT_HIOS = 0x6fffffff, PT_LIPROC = 0x70000000, PT_HIPROC = 0x7fffffff, } type; // segment dependent enum : uint32_t { PF_X = 0x1, PF_W = 0x2, PF_R = 0x4, } flags; elf64_off_t offset; elf64_addr_t vaddr; elf64_addr_t paddr; elf64_off_t filesz; elf64_off_t memsz; // 0 and 1 for no alignment, otherwise power of 2 uint64_t align; }; struct PACKED elf64_section_header_entry { uint32_t sh_name; enum : uint32_t { SHT_NULL = 0x00, SHT_PROGBITS = 0x01, SHT_RELA = 0x04, SHT_DYNAMIC = 0x06, SHT_NOTE = 0x07, SHT_NOBITS = 0x08, SHT_REL = 0x09, SHT_DYNSYM = 0x0b, SHT_INIT_ARRAY = 0x0e, SHT_FINI_ARRAY = 0x0f, SHT_PREINIT_ARRAY = 0x0f, } sh_type; enum : uint64_t { SHF_WRITE = 0x01, SHF_ALLOC = 0x02, SHF_EXECINSTR = 0x04, } sh_flags; elf64_addr_t sh_addr; elf64_off_t sh_offset; elf64_off_t sh_size; uint32_t sh_link; uint32_t sh_info; elf64_off_t sh_addralign; elf64_off_t sh_entsize; }; struct elf64_load_data { fs::dentry_pointer exec_dent; std::vector argv; std::vector envp; unsigned long ip; unsigned long sp; }; } // namespace types::elf