summaryrefslogtreecommitdiffhomepage
path: root/elf.cpp
blob: 29233921f46ba7165ba8e17c252b9ea8848a2f1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "elf.h"

#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;

#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));
  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;

#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();

  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 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));
  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 = 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)
{
 std::vector<uint8_t> data;

 AddFileHeader(data, code);
 AddProgramHeader(data, code);

#ifdef PAD
 PadUpTo(data, PAD);
#endif

 data.insert(data.end(), code.begin(), code.end());
 
 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);

 File::setFile(path, data);
}

std::vector<uint8_t> Elf::Read(const std::filesystem::path& path)
{
 std::vector<uint8_t> result;

 // TODO

 return result;
}