#pragma once #include #include #include #include namespace Elf { // ELF 64 bit only #pragma pack(push, 1) struct FileHeader { enum { EI_MAG0 = 0, EI_MAG1, EI_MAG2, EI_MAG3, EI_CLASS, EI_DATA, EI_VERSION, EI_OSABI, EI_ABIVERSION, EI_PAD }; uint8_t e_ident[16]{ 0x7F, 0x45, 0x4C, 0x46, // .ELF 2, // 64 bit 1, // little endian 1, // Version: default == 1 0, // SysV, 3=Linux 0, // EI_ABIVERSION 0,0,0,0,0,0,0 // pad }; uint16_t e_type{0x02}; // ET_EXEC uint16_t e_machine{0x3E}; // AMD64 uint32_t e_version{1}; uint64_t e_entry{0x0000000000401000}; uint64_t e_phoff{0x40}; uint64_t e_shoff{}; // section header table offset uint32_t e_flags{}; uint16_t e_ehsize{0x40}; // size of this header uint16_t e_phentsize{0x38}; // size of program header uint16_t e_phnum{2}; // program headers: .text, .data uint16_t e_shentsize{0x40}; // size of section header uint16_t e_shnum{4}; // number of section headers uint16_t e_shstrndx{3}; // 1st section header contains section names }; // Segment struct ProgramHeader { uint32_t p_type{1}; // Loadable segment uint32_t p_flags{5}; // X=1 | W=2 | R=4 uint64_t p_offset{}; // offset in file uint64_t p_vaddr{0x401000}; // virtual address uint64_t p_paddr{0x401000}; // physical address, not really relevant uint64_t p_filesz{}; // size of segment in file, e.g. size of code uint64_t p_memsz{}; // size of segment in memory uint64_t p_align{}; // alignment }; struct SectionHeader { uint32_t sh_name{}; // offset of name in .shstrtab uint32_t sh_type{1}; // program data uint64_t sh_flags{6}; // ALLOC, EXE uint64_t sh_addr{0x401000}; // virtual address uint64_t sh_offset{}; uint64_t sh_size{}; // section size uint32_t sh_link{}; uint32_t sh_info{}; uint64_t sh_addralign{}; uint64_t sh_entsize{}; }; #pragma pack(pop) void Write(const std::filesystem::path& path, const std::vector& code, const std::vector& data); std::vector Read(const std::filesystem::path& path); }