summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2020-03-28 22:27:01 +0100
committerRoland Reichwein <mail@reichwein.it>2020-03-28 22:27:01 +0100
commitee18ec019ef6f0ef9d7cd3b4cf0314291814cab0 (patch)
tree5f23e0bce52e24c3c04825ad008ec74a5e722a1c
parent7fdcbd50a35c17e8ea7d88fbcaa3080ee44351b3 (diff)
Add ELF handling (WIP)
-rw-r--r--Makefile1
-rw-r--r--bnf.h2
-rw-r--r--[-rwxr-xr-x]cppbnf.cpp0
-rw-r--r--elf.cpp89
-rw-r--r--elf.h64
-rw-r--r--file.cpp46
-rw-r--r--file.h15
-rw-r--r--minicc.h2
-rw-r--r--test-elf.cpp24
9 files changed, 239 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index aff378e..d11ffe6 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/bnf.h b/bnf.h
index 9244b4d..148b6d1 100644
--- a/bnf.h
+++ b/bnf.h
@@ -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
diff --git a/elf.cpp b/elf.cpp
index c94f2f5..9a835ff 100644
--- a/elf.cpp
+++ b/elf.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;
+}
diff --git a/elf.h b/elf.h
index 0b47fb6..9d1ba69 100644
--- a/elf.h
+++ b/elf.h
@@ -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());
+}
+
diff --git a/file.h b/file.h
new file mode 100644
index 0000000..bc49305
--- /dev/null
+++ b/file.h
@@ -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);
+
+}
diff --git a/minicc.h b/minicc.h
index 861a30a..5a5f5d8 100644
--- a/minicc.h
+++ b/minicc.h
@@ -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);
}
+