diff options
| author | Roland Reichwein <mail@reichwein.it> | 2020-03-28 22:27:01 +0100 | 
|---|---|---|
| committer | Roland Reichwein <mail@reichwein.it> | 2020-03-28 22:27:01 +0100 | 
| commit | ee18ec019ef6f0ef9d7cd3b4cf0314291814cab0 (patch) | |
| tree | 5f23e0bce52e24c3c04825ad008ec74a5e722a1c | |
| parent | 7fdcbd50a35c17e8ea7d88fbcaa3080ee44351b3 (diff) | |
Add ELF handling (WIP)
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | bnf.h | 2 | ||||
| -rw-r--r--[-rwxr-xr-x] | cppbnf.cpp | 0 | ||||
| -rw-r--r-- | elf.cpp | 89 | ||||
| -rw-r--r-- | elf.h | 64 | ||||
| -rw-r--r-- | file.cpp | 46 | ||||
| -rw-r--r-- | file.h | 15 | ||||
| -rw-r--r-- | minicc.h | 2 | ||||
| -rw-r--r-- | test-elf.cpp | 24 | 
9 files changed, 239 insertions, 4 deletions
| @@ -56,6 +56,7 @@ SRC=\      test-minicc.cpp \      elf.cpp \      test-elf.cpp \ +    file.cpp \      googletest/src/gtest-all.cpp \      googlemock/src/gmock-all.cpp @@ -7,8 +7,6 @@  #include <utility>  #include <vector> -using namespace std::string_literals; -  using BNF = std::unordered_map<std::string, std::vector<std::vector<std::string>>>;  std::unordered_map<std::string, std::set<std::string>> Reverse(BNF bnf); // unused now, remove? diff --git a/cppbnf.cpp b/cppbnf.cpp index 4f0b758..4f0b758 100755..100644 --- a/cppbnf.cpp +++ b/cppbnf.cpp @@ -1 +1,90 @@  #include "elf.h" + +#include "file.h" + +//#include <boost/endian/conversion.hpp> + +#include <cstring> + +// 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; + +  size_t old_size {data.size()}; +  data.resize(old_size + sizeof(fh)); +  std::memcpy(data.data() + old_size, reinterpret_cast<void*>(&fh), sizeof(fh)); + } + + void AddProgramHeader(std::vector<uint8_t>& data, const std::vector<uint8_t>& code) + { +  Elf::ProgramHeader ph; + +  ph.p_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader); +  ph.p_filesz = code.size(); +  ph.p_memsz = code.size(); + +  size_t old_size {data.size()}; +  data.resize(old_size + sizeof(ph)); +  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) + { +  Elf::SectionHeader sh; + +  sh.sh_name = 0; // offset in section +  sh.sh_size = code.size(); +  sh.sh_type = 1; // program + +  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 AddSectionHeaderSectionNames(std::vector<uint8_t>& data, const std::vector<uint8_t>& code) + { +  Elf::SectionHeader sh; + +  sh.sh_name = 0; // offset in section +  sh.sh_size = 16; +  sh.sh_type = 3; // section names +  sh.sh_flags = 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 Elf::Write(const std::filesystem::path& path, const std::vector<uint8_t>& code) +{ + std::vector<uint8_t> data; + + AddFileHeader(data, code); + AddProgramHeader(data, code); + + data.insert(data.end(), code.begin(), code.end()); +  + std::string section_names(".text\0.shstrtab\0", 16); + 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()); + + AddSectionHeaderText(data, code); + AddSectionHeaderSectionNames(data, code); + + File::setFile(path, data); +} + +std::vector<uint8_t> Elf::Read(const std::filesystem::path& path) +{ + std::vector<uint8_t> result; + + // TODO + + return result; +} @@ -1,22 +1,82 @@  #pragma once -#pragma pack(push, 1) +#include <bit> +#include <cstdint> +#include <filesystem> +#include <vector>  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 +  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{0x00000112}; // EXEC_P, HAS_SYMS, D_PAGED + 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  }; +// 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{0x0}; // 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  };  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{0x1000}; + 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<uint8_t>&); +std::vector<uint8_t> Read(const std::filesystem::path& path);  } -#pragma pack(pop) + diff --git a/file.cpp b/file.cpp new file mode 100644 index 0000000..5e17d1a --- /dev/null +++ b/file.cpp @@ -0,0 +1,46 @@ +#include "file.h" + +#include "minicc.h" + +#include <fstream> + +namespace fs = std::filesystem; + +std::vector<uint8_t> File::getFile(const fs::path& filename) +{ + std::ifstream file(filename.string(), std::ios::in | std::ios::binary | std::ios::ate); + + if (file.is_open()) { +  std::ifstream::pos_type fileSize = file.tellg(); +  file.seekg(0, std::ios::beg); + +  std::vector<uint8_t> bytes(fileSize, 0); +  file.read(reinterpret_cast<char*>(bytes.data()), fileSize); + +  return bytes; + + } else { +  throw std::runtime_error("Opening "s + filename.string() + " for reading"); + } +} + +void File::setFile(const fs::path& filename, const std::string& s) +{ + File::setFile(filename, s.data(), s.size()); +} + +void File::setFile(const fs::path& filename, const char* data, size_t size) +{ + std::ofstream file(filename.string(), std::ios::out | std::ios::binary); + if (file.is_open()) { +  file.write(data, size); + } else { +  throw std::runtime_error("Opening "s + filename.string() + " for writing"); + } +} + +void File::setFile(const fs::path& filename, const std::vector<uint8_t>& data) +{ + File::setFile(filename, reinterpret_cast<const char*>(data.data()), data.size()); +} + @@ -0,0 +1,15 @@ +#pragma once + +#include <cstdint> +#include <filesystem> +#include <string> +#include <vector> + +namespace File { + +std::vector<uint8_t> getFile(const std::filesystem::path& filename); +void setFile(const std::filesystem::path& filename, const std::string& s); +void setFile(const std::filesystem::path& filename, const char* data, size_t size); +void setFile(const std::filesystem::path& filename, const std::vector<uint8_t>& data); + +} @@ -5,6 +5,8 @@  #include <string>  #include <iostream> +using namespace std::string_literals; +  using index_t = size_t;  std::vector<std::string> split(std::string s); diff --git a/test-elf.cpp b/test-elf.cpp index d1aebd3..dba220e 100644 --- a/test-elf.cpp +++ b/test-elf.cpp @@ -12,10 +12,12 @@  #include <map>  #include <memory>  #include <string> +#include <system_error>  #include <utility>  #include <vector>  using namespace std::string_literals; +namespace fs = std::filesystem;  class ElfTest: public ::testing::Test  { @@ -25,10 +27,32 @@ protected:   }   ~ElfTest() {   } + fs::path TempFilename(){return "tempfile.txt";} + + void SetUp(){ +  std::error_code ec; +  fs::remove(TempFilename(), ec); + } + void TearDown(){ +  std::error_code ec; +  //fs::remove(TempFilename(), ec); + }  }; +#if 0  TEST_F(ElfTest, read) {  } +#endif  TEST_F(ElfTest, write) { + Elf::Write(TempFilename(), +            { +            0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, // mov    $0x3c,%rax     # syscall 60 +            0x48, 0x31, 0xff,                         // xor    %rdi,%rdi      # exit code 0 +            0x0f, 0x05                                // syscall +            }); + + ASSERT_TRUE(fs::exists(TempFilename())); + ASSERT_GT(fs::file_size(TempFilename()), 0);  } + | 
