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