Skip to content

Commit 19d44d6

Browse files
committed
Switch
1 parent e5661a7 commit 19d44d6

File tree

4 files changed

+83
-161
lines changed

4 files changed

+83
-161
lines changed

CMakeLists.txt

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -227,29 +227,31 @@ else ()
227227
# Not available for WASM
228228
enable_testing()
229229

230-
if (NOT "${FORCE_ELFLIB_STATIC}")
231-
find_package(LibElf)
232-
if ("${LibElf_FOUND}")
233-
include(CheckSymbolExists)
234-
check_symbol_exists(EM_RISCV "gelf.h" LIBELF_HAS_RISCV)
235-
if ("${LIBELF_HAS_RISCV}")
236-
# Turn non-cmake library into a cmake target
237-
add_library(libelf INTERFACE)
238-
target_link_libraries(libelf INTERFACE ${LIBELF_LIBRARY})
239-
target_include_directories(libelf INTERFACE ${LIBELF_INCLUDE_DIR})
240-
message(STATUS "Using system libelf")
241-
else ()
242-
message(STATUS "System libelf does not support RISC-V")
243-
set(LibElf_FOUND FALSE) # Force fallback
244-
endif ()
245-
endif ()
246-
endif ()
230+
# if (NOT "${FORCE_ELFLIB_STATIC}")
231+
# find_package(LibElf)
232+
# if ("${LibElf_FOUND}")
233+
# include(CheckSymbolExists)
234+
# check_symbol_exists(EM_RISCV "gelf.h" LIBELF_HAS_RISCV)
235+
# if ("${LIBELF_HAS_RISCV}")
236+
# # Turn non-cmake library into a cmake target
237+
# add_library(libelf INTERFACE)
238+
# target_link_libraries(libelf INTERFACE ${LIBELF_LIBRARY})
239+
# target_include_directories(libelf INTERFACE ${LIBELF_INCLUDE_DIR})
240+
# message(STATUS "Using system libelf")
241+
# else ()
242+
# message(STATUS "System libelf does not support RISC-V")
243+
# set(LibElf_FOUND FALSE) # Force fallback
244+
# endif ()
245+
# endif ()
246+
# endif ()
247247
endif ()
248248

249-
if ("${WASM}" OR "${FORCE_ELFLIB_STATIC}" OR NOT "${LibElf_FOUND}")
250-
message(STATUS "Using local libelf fallback.")
251-
add_subdirectory("external/libelf")
252-
endif ()
249+
# if ("${WASM}" OR "${FORCE_ELFLIB_STATIC}" OR NOT "${LibElf_FOUND}")
250+
# message(STATUS "Using local libelf fallback.")
251+
# add_subdirectory("external/libelf")
252+
# endif ()
253+
254+
add_subdirectory("external/libelfin")
253255

254256
# Detect Qt used qt version
255257
# Based on article https://www.steinzone.de/wordpress/how-to-support-both-qt5-and-qt6-using-cmake/

src/machine/CMakeLists.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ add_library(machine STATIC
7777
${machine_HEADERS})
7878
target_link_libraries(machine
7979
PRIVATE ${QtLib}::Core
80-
PUBLIC libelf)
80+
PUBLIC elf++ dwarf++)
81+
82+
target_include_directories(machine PUBLIC "${PROJECT_SOURCE_DIR}/external/libelfin")
8183

8284
if(NOT ${WASM})
8385
# Machine tests (not available on WASM)
@@ -181,7 +183,8 @@ if(NOT ${WASM})
181183
symboltable.h
182184
)
183185
target_link_libraries(program_loader_test
184-
PRIVATE ${QtLib}::Core ${QtLib}::Test libelf)
186+
PRIVATE ${QtLib}::Core ${QtLib}::Test elf++ dwarf++)
187+
target_include_directories(program_loader_test PRIVATE "${PROJECT_SOURCE_DIR}/external/libelfin")
185188
add_test(NAME program_loader COMMAND program_loader_test)
186189

187190

@@ -217,7 +220,8 @@ if(NOT ${WASM})
217220
machineconfig.cpp
218221
)
219222
target_link_libraries(core_test
220-
PRIVATE ${QtLib}::Core ${QtLib}::Test libelf)
223+
PRIVATE ${QtLib}::Core ${QtLib}::Test elf++ dwarf++)
224+
target_include_directories(core_test PRIVATE "${PROJECT_SOURCE_DIR}/external/libelfin")
221225
add_test(NAME core COMMAND core_test)
222226

223227
add_custom_target(machine_unit_tests

src/machine/programloader.cpp

Lines changed: 49 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <cerrno>
88
#include <cstring>
99
#include <exception>
10+
#include <fcntl.h>
11+
#include <unistd.h>
1012

1113
LOG_CATEGORY("machine.ProgramLoader");
1214

@@ -17,141 +19,83 @@ LOG_CATEGORY("machine.ProgramLoader");
1719

1820
using namespace machine;
1921

20-
ProgramLoader::ProgramLoader(const QString &file) : elf_file(file) {
21-
const GElf_Ehdr *elf_ehdr;
22-
// Initialize elf library
23-
if (elf_version(EV_CURRENT) == EV_NONE) {
24-
throw SIMULATOR_EXCEPTION(Input, "Elf library initialization failed", elf_errmsg(-1));
25-
}
26-
// Open source file - option QIODevice::ExistingOnly cannot be used on Qt
27-
// <5.11
28-
if (!elf_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) {
22+
ProgramLoader::ProgramLoader(const QString &file) {
23+
fd = open(file.toLocal8Bit().constData(), O_RDONLY | O_BINARY);
24+
if (fd < 0) {
2925
throw SIMULATOR_EXCEPTION(
3026
Input,
3127
QString("Can't open input elf file for reading (") + QString(file) + QString(")"),
3228
std::strerror(errno));
3329
}
34-
// Initialize elf
35-
if (!(this->elf = elf_begin(elf_file.handle(), ELF_C_READ, nullptr))) {
36-
throw SIMULATOR_EXCEPTION(Input, "Elf read begin failed", elf_errmsg(-1));
37-
}
38-
// Check elf kind
39-
if (elf_kind(this->elf) != ELF_K_ELF) {
40-
throw SIMULATOR_EXCEPTION(
41-
Input, "Invalid input file elf format, plain elf file expected", "");
42-
}
4330

44-
elf_ehdr = gelf_getehdr(this->elf, &this->hdr);
45-
if (!elf_ehdr) {
46-
throw SIMULATOR_EXCEPTION(Input, "Getting elf file header failed", elf_errmsg(-1));
31+
try {
32+
elf_file = elf::elf(elf::create_mmap_loader(fd));
33+
} catch (const std::exception &e) {
34+
close(fd);
35+
throw SIMULATOR_EXCEPTION(Input, "Elf library initialization failed", e.what());
4736
}
4837

49-
executable_entry = Address(elf_ehdr->e_entry);
50-
// Check elf file format, executable expected, nothing else.
51-
if (this->hdr.e_type != ET_EXEC) {
38+
const auto &hdr = elf_file.get_hdr();
39+
executable_entry = Address(hdr.entry);
40+
41+
if (hdr.type != elf::et::exec) {
5242
throw SIMULATOR_EXCEPTION(Input, "Invalid input file type", "");
5343
}
54-
// Check elf file architecture, of course only mips is supported.
55-
// Note: This also checks that this is big endian as EM_MIPS is suppose to
56-
// be: MIPS R3000 big-endian
57-
if (this->hdr.e_machine != EM_RISCV) {
44+
45+
if (hdr.machine != 243) { // EM_RISCV
5846
throw SIMULATOR_EXCEPTION(Input, "Invalid input file architecture", "");
5947
}
60-
// Check elf file class, only 32bit architecture is supported.
61-
int elf_class;
62-
if ((elf_class = gelf_getclass(this->elf)) == ELFCLASSNONE) {
63-
throw SIMULATOR_EXCEPTION(Input, "Getting elf class failed", elf_errmsg(-1));
64-
}
65-
// Get number of program sections in elf file
66-
if (elf_getphdrnum(this->elf, &this->n_secs)) {
67-
throw SIMULATOR_EXCEPTION(Input, "Elf program sections count query failed", elf_errmsg(-1));
68-
}
6948

70-
if (elf_class == ELFCLASS32) {
49+
if (hdr.ei_class == elf::elfclass::_32) {
7150
LOG("Loaded executable: 32bit");
7251
architecture_type = ARCH32;
73-
// Get program sections headers
74-
if (!(sections_headers.arch32 = elf32_getphdr(elf))) {
75-
throw SIMULATOR_EXCEPTION(Input, "Elf program sections get failed", elf_errmsg(-1));
76-
}
77-
// We want only LOAD sections so we create load_sections_indexes of those sections
78-
for (unsigned i = 0; i < n_secs; i++) {
79-
if (sections_headers.arch32[i].p_type != PT_LOAD) { continue; }
80-
indexes_of_load_sections.push_back(i);
81-
}
82-
} else if (elf_class == ELFCLASS64) {
52+
} else if (hdr.ei_class == elf::elfclass::_64) {
8353
LOG("Loaded executable: 64bit");
8454
architecture_type = ARCH64;
8555
WARN("64bit simulation is not fully supported.");
86-
// Get program sections headers
87-
if (!(sections_headers.arch64 = elf64_getphdr(elf))) {
88-
throw SIMULATOR_EXCEPTION(Input, "Elf program sections get failed", elf_errmsg(-1));
89-
}
90-
// We want only LOAD sections so we create load_sections_indexes of those sections
91-
for (unsigned i = 0; i < this->n_secs; i++) {
92-
if (sections_headers.arch64[i].p_type != PT_LOAD) { continue; }
93-
this->indexes_of_load_sections.push_back(i);
94-
}
95-
9656
} else {
97-
WARN("Unsupported elf class: %d", elf_class);
9857
throw SIMULATOR_EXCEPTION(
9958
Input,
10059
"Unsupported architecture type."
10160
"This simulator only supports 32bit and 64bit CPUs.",
10261
"");
10362
}
63+
64+
for (const auto &seg : elf_file.segments()) {
65+
if (seg.get_hdr().type == elf::pt::load) {
66+
load_segments.push_back(seg);
67+
}
68+
}
10469
}
10570

10671
ProgramLoader::ProgramLoader(const char *file) : ProgramLoader(QString::fromLocal8Bit(file)) {}
10772

10873
ProgramLoader::~ProgramLoader() {
109-
// Close elf
110-
elf_end(this->elf);
111-
// Close file
112-
elf_file.close();
74+
if (fd >= 0) {
75+
close(fd);
76+
}
11377
}
11478

11579
void ProgramLoader::to_memory(Memory *mem) {
116-
// Load program to memory (just dump it byte by byte)
117-
if (architecture_type == ARCH32) {
118-
for (size_t phdrs_i : this->indexes_of_load_sections) {
119-
uint32_t base_address = this->sections_headers.arch32[phdrs_i].p_vaddr;
120-
char *f = elf_rawfile(this->elf, nullptr);
121-
for (unsigned y = 0; y < this->sections_headers.arch32[phdrs_i].p_filesz; y++) {
122-
const auto buffer = (uint8_t)f[this->sections_headers.arch32[phdrs_i].p_offset + y];
123-
memory_write_u8(mem, base_address + y, buffer);
124-
}
125-
}
126-
} else if (architecture_type == ARCH64) {
127-
for (size_t phdrs_i : this->indexes_of_load_sections) {
128-
uint32_t base_address = this->sections_headers.arch64[phdrs_i].p_vaddr;
129-
char *f = elf_rawfile(this->elf, nullptr);
130-
for (unsigned y = 0; y < this->sections_headers.arch64[phdrs_i].p_filesz; y++) {
131-
const auto buffer = (uint8_t)f[this->sections_headers.arch64[phdrs_i].p_offset + y];
132-
memory_write_u8(mem, base_address + y, buffer);
133-
}
80+
for (const auto &seg : load_segments) {
81+
uint64_t base_address = seg.get_hdr().vaddr;
82+
const char *data = (const char *)seg.data();
83+
size_t filesz = seg.get_hdr().filesz;
84+
for (size_t i = 0; i < filesz; i++) {
85+
memory_write_u8(mem, base_address + i, (uint8_t)data[i]);
13486
}
13587
}
13688
}
13789

13890
Address ProgramLoader::end() {
139-
uint32_t last = 0;
140-
// Go trough all sections and found out last one
141-
if (architecture_type == ARCH32) {
142-
for (size_t i : this->indexes_of_load_sections) {
143-
Elf32_Phdr *phdr = &(this->sections_headers.arch32[i]);
144-
if ((phdr->p_vaddr + phdr->p_filesz) > last) { last = phdr->p_vaddr + phdr->p_filesz; }
145-
}
146-
} else if (architecture_type == ARCH64) {
147-
for (size_t i : this->indexes_of_load_sections) {
148-
Elf64_Phdr *phdr = &(this->sections_headers.arch64[i]);
149-
if ((phdr->p_vaddr + phdr->p_filesz) > last) { last = phdr->p_vaddr + phdr->p_filesz; }
91+
uint64_t last = 0;
92+
for (const auto &seg : load_segments) {
93+
uint64_t end_addr = seg.get_hdr().vaddr + seg.get_hdr().filesz;
94+
if (end_addr > last) {
95+
last = end_addr;
15096
}
15197
}
152-
return Address(last + 0x10); // We add offset so we are sure that also
153-
// pipeline is empty TODO propagate address
154-
// deeper
98+
return Address(last + 0x10);
15599
}
156100

157101
Address ProgramLoader::get_executable_entry() const {
@@ -160,42 +104,21 @@ Address ProgramLoader::get_executable_entry() const {
160104

161105
SymbolTable *ProgramLoader::get_symbol_table() {
162106
auto *p_st = new SymbolTable();
163-
Elf_Scn *scn = nullptr;
164-
GElf_Shdr shdr;
165-
Elf_Data *data;
166-
int count, ii;
167-
168-
elf_version(EV_CURRENT);
169-
170-
while (true) {
171-
if ((scn = elf_nextscn(this->elf, scn)) == nullptr) { return p_st; }
172-
gelf_getshdr(scn, &shdr);
173-
if (shdr.sh_type == SHT_SYMTAB) {
174-
/* found a symbol table, go print it. */
175-
break;
107+
for (const auto &sec : elf_file.sections()) {
108+
if (sec.get_hdr().type == elf::sht::symtab) {
109+
for (const auto &sym : sec.as_symtab()) {
110+
const auto &d = sym.get_data();
111+
p_st->add_symbol(sym.get_name().c_str(), d.value, d.size, d.info, d.other);
112+
}
176113
}
177114
}
178-
179-
data = elf_getdata(scn, nullptr);
180-
count = shdr.sh_size / shdr.sh_entsize;
181-
182-
/* retrieve the symbol names */
183-
for (ii = 0; ii < count; ++ii) {
184-
GElf_Sym sym;
185-
gelf_getsym(data, ii, &sym);
186-
p_st->add_symbol(
187-
elf_strptr(elf, shdr.sh_link, sym.st_name), sym.st_value, sym.st_size, sym.st_info,
188-
sym.st_other);
189-
}
190-
191115
return p_st;
192116
}
117+
193118
Endian ProgramLoader::get_endian() const {
194-
// Reading elf endian_id_byte according to the ELF specs.
195-
unsigned char endian_id_byte = this->hdr.e_ident[EI_DATA];
196-
if (endian_id_byte == ELFDATA2LSB) {
119+
if (elf_file.get_hdr().ei_data == elf::elfdata::lsb) {
197120
return LITTLE;
198-
} else if (endian_id_byte == ELFDATA2MSB) {
121+
} else if (elf_file.get_hdr().ei_data == elf::elfdata::msb) {
199122
return BIG;
200123
} else {
201124
throw SIMULATOR_EXCEPTION(
@@ -206,6 +129,7 @@ Endian ProgramLoader::get_endian() const {
206129
"");
207130
}
208131
}
132+
209133
ArchitectureType ProgramLoader::get_architecture_type() const {
210134
return architecture_type;
211135
}

src/machine/programloader.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
#include <QFile>
99
#include <cstdint>
10-
#include <gelf.h>
10+
#include <elf/elf++.hh>
1111
#include <qstring.h>
1212
#include <qvector.h>
1313

@@ -37,19 +37,11 @@ class ProgramLoader {
3737
ArchitectureType get_architecture_type() const;
3838

3939
private:
40-
QFile elf_file;
41-
Elf *elf;
42-
GElf_Ehdr hdr {}; // elf file header
43-
size_t n_secs {}; // number of sections in elf program header
40+
int fd;
41+
elf::elf elf_file;
4442
ArchitectureType architecture_type;
45-
46-
private:
47-
union {
48-
Elf32_Phdr *arch32;
49-
Elf64_Phdr *arch64;
50-
} sections_headers {};
51-
QVector<size_t> indexes_of_load_sections; // external index to sections_headers index
5243
Address executable_entry;
44+
std::vector<elf::segment> load_segments;
5345
};
5446

5547
} // namespace machine

0 commit comments

Comments
 (0)