-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathloader.cc
More file actions
133 lines (109 loc) · 4.17 KB
/
loader.cc
File metadata and controls
133 lines (109 loc) · 4.17 KB
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
/*
bare-metal ELF Loader for LEON3
- read elf
- map segments to memroy
- set cpu state
*/
#include <unicorn/unicorn.h>
#include <algorithm>
#include <cstdint>
#include <elfio/elfio.hpp>
#include <stdexcept>
#include <string>
#include <vector>
static inline uint64_t align_down(uint64_t x, uint64_t a) {
return x & ~(a - 1);
}
static inline uint64_t align_up(uint64_t x, uint64_t a) {
return (x + a - 1) & ~(a - 1);
}
static int prot_from_pflags(uint32_t pflags) {
int prot = 0;
if (pflags & PF_R) prot |= UC_PROT_READ;
if (pflags & PF_W) prot |= UC_PROT_WRITE;
if (pflags & PF_X) prot |= UC_PROT_EXEC;
return prot ? prot : UC_PROT_READ; // 至少可读
}
struct load_plan {
uint64_t entry;
uint64_t load_bias; // ET_EXEC: 0;ET_DYN: 由你选择
uint64_t min_vaddr; // 所有 PT_LOAD 的最小 vaddr
bool is_pie;
};
static load_plan analyze_elf(const ELFIO::elfio& r, uint64_t desired_base) {
if (r.get_type() != ET_EXEC && r.get_type() != ET_DYN)
throw std::runtime_error("unsupported e_type (expect ET_EXEC/ET_DYN)");
if (r.get_machine() != EM_SPARC /* && r.get_machine() != EM_SPARCV9 */)
throw std::runtime_error("unsupported e_machine");
const bool pie = (r.get_type() == ET_DYN);
uint64_t min_vaddr = UINT64_MAX;
for (const auto* seg : r.segments) {
if (seg->get_type() != PT_LOAD) continue;
min_vaddr = std::min<uint64_t>(min_vaddr, seg->get_virtual_address());
}
if (min_vaddr == UINT64_MAX) throw std::runtime_error("no PT_LOAD segments");
// 依据常见实现:按每段的 p_align 对齐基址,这里取 0x1000 作为页大小基准
const uint64_t page = 0x1000;
uint64_t load_bias = 0;
if (pie) {
load_bias = align_down(desired_base, page) - align_down(min_vaddr, page);
}
return {.entry = r.get_entry(),
.load_bias = load_bias,
.min_vaddr = min_vaddr,
.is_pie = pie};
}
static void map_segments_uc(uc_engine* uc, const ELFIO::elfio& r,
uint64_t load_bias) {
const uint64_t page = 0x1000;
for (const auto* seg : r.segments) {
if (seg->get_type() != PT_LOAD) continue;
uint64_t vaddr = seg->get_virtual_address() + load_bias;
uint64_t filesz = seg->get_file_size();
uint64_t memsz = seg->get_memory_size();
uint64_t p_align = std::max<uint64_t>(seg->get_align(), page);
uint64_t map_begin = align_down(vaddr, p_align);
uint64_t map_end = align_up(vaddr + memsz, page);
uint64_t map_size = map_end - map_begin;
int prot = prot_from_pflags(seg->get_flags());
uc_err err = uc_mem_map(uc, map_begin, map_size, prot);
if (err != UC_ERR_OK) throw std::runtime_error("uc_mem_map failed");
if (filesz) {
// 写入文件部分
uc_mem_write(uc, vaddr, seg->get_data(), filesz);
}
if (memsz > filesz) {
// 归零未初始化尾部(bss)
std::vector<uint8_t> zeros(memsz - filesz, 0);
uc_mem_write(uc, vaddr + filesz, zeros.data(), zeros.size());
}
}
}
static void map_stack_and_init_sp_sparc(uc_engine* uc,
uint64_t stack_top = 0x7fff0000,
uint64_t stack_size = 0x100000) {
uint64_t base = stack_top - stack_size;
if (uc_mem_map(uc, base, stack_size, UC_PROT_READ | UC_PROT_WRITE) !=
UC_ERR_OK)
throw std::runtime_error("map stack failed");
// SPARC: %o6 是栈指针寄存器别名
uint32_t sp = static_cast<uint32_t>(stack_top);
uc_reg_write(uc, UC_SPARC_REG_O6, &sp);
}
static void set_entry_sparc(uc_engine* uc, uint64_t entry) {
uint32_t pc = static_cast<uint32_t>(entry);
uint32_t npc = pc + 4;
uc_reg_write(uc, UC_SPARC_REG_PC, &pc);
uc_reg_write(uc, UC_SPARC_REG_nPC, &npc);
}
void load_elf_bare_metal_sparc(uc_engine* uc, const std::string& path,
uint64_t desired_base_for_pie = 0x400000) {
ELFIO::elfio r;
if (!r.load(path)) throw std::runtime_error("ELF load failed");
auto plan = analyze_elf(r, desired_base_for_pie);
map_segments_uc(uc, r, plan.load_bias);
map_stack_and_init_sp_sparc(uc);
const uint64_t entry = plan.entry + plan.load_bias;
set_entry_sparc(uc, entry);
// 至此可直接 uc_emu_start(uc, entry, 0, 0, 0)
}