diff options
| -rw-r--r-- | elf.cpp | 69 | ||||
| -rw-r--r-- | elf.h | 14 | ||||
| -rw-r--r-- | test-elf.cpp | 2 | 
3 files changed, 72 insertions, 13 deletions
| @@ -2,17 +2,25 @@  #include "file.h" +// TODO  //#include <boost/endian/conversion.hpp>  #include <cstring> +// We need at least 4096 bytes aligment. Otherwise we get segfaults at startup +#define PAD 0x1000 +  // Helper Functions  namespace {   void AddFileHeader(std::vector<uint8_t>& data, const std::vector<uint8_t>& code)   {    Elf::FileHeader fh; -  fh.e_shoff = sizeof(fh) + sizeof(Elf::ProgramHeader) + code.size() + 16; +#ifdef PAD +  fh.e_shoff = PAD + code.size() + 17; +#else +  fh.e_shoff = sizeof(fh) + sizeof(Elf::ProgramHeader) + code.size() + 17; +#endif    size_t old_size {data.size()};    data.resize(old_size + sizeof(fh)); @@ -23,7 +31,12 @@ namespace {   {    Elf::ProgramHeader ph; +#ifdef PAD +  ph.p_offset = PAD; +  ph.p_align = PAD; +#else    ph.p_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader); +#endif    ph.p_filesz = code.size();    ph.p_memsz = code.size(); @@ -32,13 +45,35 @@ namespace {    std::memcpy(data.data() + old_size, reinterpret_cast<void*>(&ph), sizeof(ph));   } - void AddSectionHeaderText(std::vector<uint8_t>& data, const std::vector<uint8_t>& code) + void AddSectionHeaderNull(std::vector<uint8_t>& data, const std::vector<uint8_t>& code)   {    Elf::SectionHeader sh;    sh.sh_name = 0; // offset in section +  sh.sh_size = 0; +  sh.sh_type = 0; // <null> +  sh.sh_flags = 0; +  sh.sh_addr = 0; +  sh.sh_offset = 0; + +  size_t old_size {data.size()}; +  data.resize(old_size + sizeof(sh)); +  std::memcpy(data.data() + old_size, reinterpret_cast<void*>(&sh), sizeof(sh)); + } +  + void AddSectionHeaderText(std::vector<uint8_t>& data, const std::vector<uint8_t>& code) + { +  Elf::SectionHeader sh; + +  sh.sh_name = 1; // offset in section    sh.sh_size = code.size();    sh.sh_type = 1; // program +#ifdef PAD +  sh.sh_offset = PAD; +#else +  sh.sh_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader); +#endif +  sh.sh_addralign = 1;    size_t old_size {data.size()};    data.resize(old_size + sizeof(sh)); @@ -49,15 +84,30 @@ namespace {   {    Elf::SectionHeader sh; -  sh.sh_name = 0; // offset in section -  sh.sh_size = 16; +  sh.sh_name = 7; // offset in section +  sh.sh_size = 17;    sh.sh_type = 3; // section names    sh.sh_flags = 0; +  sh.sh_addr = 0; +#ifdef PAD +  sh.sh_offset = PAD + code.size(); +#else +  sh.sh_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader) + code.size(); +#endif +  sh.sh_addralign = 1;    size_t old_size {data.size()};    data.resize(old_size + sizeof(sh));    std::memcpy(data.data() + old_size, reinterpret_cast<void*>(&sh), sizeof(sh));   } + + void PadUpTo(std::vector<uint8_t>& data, size_t size) + { +  if (data.size() < size) { +   data.resize(size); +  } else +   throw std::runtime_error("Padding not possible. Too many bytes already."); + }  }  void Elf::Write(const std::filesystem::path& path, const std::vector<uint8_t>& code) @@ -67,13 +117,21 @@ void Elf::Write(const std::filesystem::path& path, const std::vector<uint8_t>& c   AddFileHeader(data, code);   AddProgramHeader(data, code); +#ifdef PAD + PadUpTo(data, PAD); +#endif +   data.insert(data.end(), code.begin(), code.end()); - std::string section_names(".text\0.shstrtab\0", 16); + std::string section_names("\0.text\0.shstrtab\0", 17); + if (section_names.size() != 17) +  throw std::runtime_error("Bad size"); +   size_t old_size {data.size()};   data.resize(old_size + section_names.size());   std::memcpy(data.data() + old_size, section_names.data(), section_names.size()); + AddSectionHeaderNull(data, code);   AddSectionHeaderText(data, code);   AddSectionHeaderSectionNames(data, code); @@ -88,3 +146,4 @@ std::vector<uint8_t> Elf::Read(const std::filesystem::path& path)   return result;  } + @@ -29,7 +29,7 @@ struct FileHeader    2, // 64 bit    1, // little endian    1, // Version: default == 1 -  3, // Linux +  0, // SysV, 3=Linux    0, // EI_ABIVERSION    0,0,0,0,0,0,0 // pad   }; @@ -39,13 +39,13 @@ struct FileHeader   uint64_t e_entry{0x0000000000401000};   uint64_t e_phoff{0x40};   uint64_t e_shoff{}; // section header table offset - uint32_t e_flags{0x00000112}; // EXEC_P, HAS_SYMS, D_PAGED + 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{1}; // 1 program header   uint16_t e_shentsize{0x40}; // size of section header - uint16_t e_shnum{2}; // number of section headers - uint16_t e_shstrndx{1}; // 1st section header contains section names + uint16_t e_shnum{3}; // number of section headers + uint16_t e_shstrndx{2}; // 1st section header contains section names  };  // Segment @@ -53,12 +53,12 @@ struct ProgramHeader  {   uint32_t p_type{1}; // Loadable segment   uint32_t p_flags{5}; // X=1 | W=2 | R=4 - uint64_t p_offset{0x0}; // offset in file + 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{0}; // alignment + uint64_t p_align{}; // alignment  };  struct SectionHeader @@ -67,7 +67,7 @@ struct SectionHeader   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{0x1000}; + uint64_t sh_offset{};   uint64_t sh_size{}; // section size   uint32_t sh_link{};   uint32_t sh_info{}; diff --git a/test-elf.cpp b/test-elf.cpp index dba220e..d3fa9a9 100644 --- a/test-elf.cpp +++ b/test-elf.cpp @@ -49,7 +49,7 @@ TEST_F(ElfTest, write) {              {              0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, // mov    $0x3c,%rax     # syscall 60              0x48, 0x31, 0xff,                         // xor    %rdi,%rdi      # exit code 0 -            0x0f, 0x05                                // syscall +            0x0f, 0x05,                               // syscall              });   ASSERT_TRUE(fs::exists(TempFilename())); | 
