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); } + |