-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathelfloader.cpp
146 lines (120 loc) · 4.44 KB
/
elfloader.cpp
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
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "elfloader.h"
#include "rv_memory.h"
#define ELF_RISCV_MACHINE 243
template<typename T>
auto offset_ptr(const void *data, size_t offset = 0)
{
return reinterpret_cast<const T*>(reinterpret_cast<const uint8_t*>(data)+offset);
}
uint8_t elf_segment::protection() const
{
uint8_t prot_flags = 0;
if ((segment_->p_flags & PF_R) == PF_R) {
prot_flags |= RV_MEMORY_R;
}
if ((segment_->p_flags & PF_W) == PF_W) {
prot_flags |= RV_MEMORY_W;
}
if ((segment_->p_flags & PF_X) == PF_X) {
prot_flags |= RV_MEMORY_X;
}
return prot_flags;
}
bool elf_loader::check_magic(const Elf32_Ehdr *hdr) const
{
return hdr->e_ident[EI_MAG0] == ELFMAG0 &&
hdr->e_ident[EI_MAG1] == ELFMAG1 &&
hdr->e_ident[EI_MAG2] == ELFMAG2 &&
hdr->e_ident[EI_MAG3] == ELFMAG3;
}
elf_loader::~elf_loader()
{
}
void elf_loader::load()
{
// load target ELF into memory
struct stat st;
if (stat(filename_.c_str(), &st) == -1) {
throw std::runtime_error("stat() failed");
}
buffer_.resize(st.st_size);
int fd = open(filename_.c_str(), O_RDONLY);
if (fd == -1) {
throw std::runtime_error("open() failed");
}
ssize_t bytes_read = read(fd, buffer_.data(), st.st_size);
close(fd);
if (bytes_read == -1 || bytes_read != st.st_size) {
throw std::runtime_error("read() failed");
}
const uint8_t*const buf = buffer_.data();
fprintf(stderr, "[i] checking ELF file...\n");
// check elf magic
header_ = offset_ptr<Elf32_Ehdr>(buf);
if (!check_magic(header_)) {
throw std::runtime_error("invalid ELF file");
}
// ensure this is a 32bit executable
if (header_->e_ident[EI_CLASS] != ELFCLASS32) {
throw std::runtime_error("only 32bit ELFs supported");
}
// ensure RISC-V machine
if (header_->e_machine != ELF_RISCV_MACHINE) {
throw std::runtime_error("invalid e_machine, only RISC-V supported");
}
// store program headers into segments_ array for easy access
if (header_->e_phnum == 0) {
throw std::runtime_error("invalid ELF, at least one program header required");
}
fprintf(stderr, "[i] loading program segments...\n");
auto *phdr = offset_ptr<Elf32_Phdr>(header_, header_->e_phoff);
for (size_t i = 0; i < header_->e_phnum; ++i) {
// we care only about PT_LOAD, since these segments are actually mapped
// for now, we ignore the protection flag
if (phdr->p_type == PT_LOAD) {
fprintf(stderr, "[i] segment %d - vaddr: 0x%08x, vsize: %d\n", i, phdr->p_vaddr, phdr->p_memsz);
segments_.emplace_back(phdr);
}
phdr = offset_ptr<Elf32_Phdr>(phdr, header_->e_phentsize);
}
fprintf(stderr, "[i] loading symbols...\n");
// first we need to locate the symbol table within the sections
auto *shdr = offset_ptr<Elf32_Shdr>(header_, header_->e_shoff);
for (size_t i = 0; i < header_->e_shnum; ++i) {
if (shdr->sh_type == SHT_SYMTAB) {
symbol_table_ = shdr;
}
sections_.push_back(shdr);
shdr = offset_ptr<Elf32_Shdr>(shdr, header_->e_shentsize);
}
if (sections_.empty()) {
throw std::runtime_error("missing sections");
}
if (symbol_table_ == nullptr) {
throw std::runtime_error("missing symbol table");
}
uint32_t num_syms = symbol_table_->sh_size / symbol_table_->sh_entsize;
fprintf(stderr, "[i] found %d symbols...\n", num_syms);
// scan all the symbol table and build a "name" => "address" map
auto *psym = offset_ptr<Elf32_Sym>(header_, symbol_table_->sh_offset);
auto strtable = offset_ptr<const char>(header_, sections_[symbol_table_->sh_link]->sh_offset);
for (uint32_t i = 0; i < num_syms; ++i) {
// first of all, we're interested only in GLOBAL symbols of type STT_FUNC
// note: st_name IS NOT a pointer to a string, but an index into the string table
if (psym->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)) {
// now lookup name
auto sym_name = offset_ptr<const char>(strtable, psym->st_name);
symbols_.emplace(sym_name, psym->st_value);
}
psym = offset_ptr<Elf32_Sym>(psym, symbol_table_->sh_entsize);
}
fprintf(stderr, "[i] entry point at 0x%08x\n", entry_point());
}