summaryrefslogtreecommitdiff
path: root/src/core/loader/elf.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2014-06-25 09:46:14 -0400
committerGravatar bunnei2014-06-25 09:46:14 -0400
commit469fe42fad01fc45e454e6acfa413eeae92e587e (patch)
tree4cf876688cc2d03d34512f8f1a25bc26d853f1fb /src/core/loader/elf.cpp
parentMerge pull request #7 from archshift/travis-osx (diff)
parentLoader: Refactored loading functions to only read data from binary if called. (diff)
downloadyuzu-469fe42fad01fc45e454e6acfa413eeae92e587e.tar.gz
yuzu-469fe42fad01fc45e454e6acfa413eeae92e587e.tar.xz
yuzu-469fe42fad01fc45e454e6acfa413eeae92e587e.zip
Merge pull request #22 from bunnei/loader-improvements
Refactor loader code and add preliminary NCCH support
Diffstat (limited to 'src/core/loader/elf.cpp')
-rw-r--r--src/core/loader/elf.cpp370
1 files changed, 370 insertions, 0 deletions
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
new file mode 100644
index 000000000..76c9d6d54
--- /dev/null
+++ b/src/core/loader/elf.cpp
@@ -0,0 +1,370 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <string>
6#include <memory>
7
8#include "common/common.h"
9#include "common/file_util.h"
10#include "common/symbols.h"
11
12#include "core/mem_map.h"
13#include "core/loader/elf.h"
14#include "core/hle/kernel/kernel.h"
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// ELF Header Constants
18
19// File type
20enum ElfType {
21 ET_NONE = 0,
22 ET_REL = 1,
23 ET_EXEC = 2,
24 ET_DYN = 3,
25 ET_CORE = 4,
26 ET_LOPROC = 0xFF00,
27 ET_HIPROC = 0xFFFF,
28};
29
30// Machine/Architecture
31enum ElfMachine {
32 EM_NONE = 0,
33 EM_M32 = 1,
34 EM_SPARC = 2,
35 EM_386 = 3,
36 EM_68K = 4,
37 EM_88K = 5,
38 EM_860 = 7,
39 EM_MIPS = 8
40};
41
42// File version
43#define EV_NONE 0
44#define EV_CURRENT 1
45
46// Identification index
47#define EI_MAG0 0
48#define EI_MAG1 1
49#define EI_MAG2 2
50#define EI_MAG3 3
51#define EI_CLASS 4
52#define EI_DATA 5
53#define EI_VERSION 6
54#define EI_PAD 7
55#define EI_NIDENT 16
56
57// Magic number
58#define ELFMAG0 0x7F
59#define ELFMAG1 'E'
60#define ELFMAG2 'L'
61#define ELFMAG3 'F'
62
63// Sections constants
64
65// Section types
66#define SHT_NULL 0
67#define SHT_PROGBITS 1
68#define SHT_SYMTAB 2
69#define SHT_STRTAB 3
70#define SHT_RELA 4
71#define SHT_HASH 5
72#define SHT_DYNAMIC 6
73#define SHT_NOTE 7
74#define SHT_NOBITS 8
75#define SHT_REL 9
76#define SHT_SHLIB 10
77#define SHT_DYNSYM 11
78#define SHT_LOPROC 0x70000000
79#define SHT_HIPROC 0x7FFFFFFF
80#define SHT_LOUSER 0x80000000
81#define SHT_HIUSER 0xFFFFFFFF
82
83// Section flags
84enum ElfSectionFlags
85{
86 SHF_WRITE = 0x1,
87 SHF_ALLOC = 0x2,
88 SHF_EXECINSTR = 0x4,
89 SHF_MASKPROC = 0xF0000000,
90};
91
92// Segment types
93#define PT_NULL 0
94#define PT_LOAD 1
95#define PT_DYNAMIC 2
96#define PT_INTERP 3
97#define PT_NOTE 4
98#define PT_SHLIB 5
99#define PT_PHDR 6
100#define PT_LOPROC 0x70000000
101#define PT_HIPROC 0x7FFFFFFF
102
103typedef unsigned int Elf32_Addr;
104typedef unsigned short Elf32_Half;
105typedef unsigned int Elf32_Off;
106typedef signed int Elf32_Sword;
107typedef unsigned int Elf32_Word;
108
109////////////////////////////////////////////////////////////////////////////////////////////////////
110// ELF file header
111
112struct Elf32_Ehdr {
113 unsigned char e_ident[EI_NIDENT];
114 Elf32_Half e_type;
115 Elf32_Half e_machine;
116 Elf32_Word e_version;
117 Elf32_Addr e_entry;
118 Elf32_Off e_phoff;
119 Elf32_Off e_shoff;
120 Elf32_Word e_flags;
121 Elf32_Half e_ehsize;
122 Elf32_Half e_phentsize;
123 Elf32_Half e_phnum;
124 Elf32_Half e_shentsize;
125 Elf32_Half e_shnum;
126 Elf32_Half e_shstrndx;
127};
128
129// Section header
130struct Elf32_Shdr {
131 Elf32_Word sh_name;
132 Elf32_Word sh_type;
133 Elf32_Word sh_flags;
134 Elf32_Addr sh_addr;
135 Elf32_Off sh_offset;
136 Elf32_Word sh_size;
137 Elf32_Word sh_link;
138 Elf32_Word sh_info;
139 Elf32_Word sh_addralign;
140 Elf32_Word sh_entsize;
141};
142
143// Segment header
144struct Elf32_Phdr {
145 Elf32_Word p_type;
146 Elf32_Off p_offset;
147 Elf32_Addr p_vaddr;
148 Elf32_Addr p_paddr;
149 Elf32_Word p_filesz;
150 Elf32_Word p_memsz;
151 Elf32_Word p_flags;
152 Elf32_Word p_align;
153};
154
155// Symbol table entry
156struct Elf32_Sym {
157 Elf32_Word st_name;
158 Elf32_Addr st_value;
159 Elf32_Word st_size;
160 unsigned char st_info;
161 unsigned char st_other;
162 Elf32_Half st_shndx;
163};
164
165// Relocation entries
166struct Elf32_Rel {
167 Elf32_Addr r_offset;
168 Elf32_Word r_info;
169};
170
171////////////////////////////////////////////////////////////////////////////////////////////////////
172// ElfReader class
173
174typedef int SectionID;
175
176class ElfReader {
177private:
178 char *base;
179 u32 *base32;
180
181 Elf32_Ehdr *header;
182 Elf32_Phdr *segments;
183 Elf32_Shdr *sections;
184
185 u32 *sectionAddrs;
186 bool relocate;
187 u32 entryPoint;
188
189public:
190 ElfReader(void *ptr);
191 ~ElfReader() { }
192
193 u32 Read32(int off) const { return base32[off >> 2]; }
194
195 // Quick accessors
196 ElfType GetType() const { return (ElfType)(header->e_type); }
197 ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
198 u32 GetEntryPoint() const { return entryPoint; }
199 u32 GetFlags() const { return (u32)(header->e_flags); }
200 bool LoadInto(u32 vaddr);
201 bool LoadSymbols();
202
203 int GetNumSegments() const { return (int)(header->e_phnum); }
204 int GetNumSections() const { return (int)(header->e_shnum); }
205 const u8 *GetPtr(int offset) const { return (u8*)base + offset; }
206 const char *GetSectionName(int section) const;
207 const u8 *GetSectionDataPtr(int section) const {
208 if (section < 0 || section >= header->e_shnum)
209 return nullptr;
210 if (sections[section].sh_type != SHT_NOBITS)
211 return GetPtr(sections[section].sh_offset);
212 else
213 return nullptr;
214 }
215 bool IsCodeSection(int section) const {
216 return sections[section].sh_type == SHT_PROGBITS;
217 }
218 const u8 *GetSegmentPtr(int segment) {
219 return GetPtr(segments[segment].p_offset);
220 }
221 u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; }
222 int GetSectionSize(SectionID section) const { return sections[section].sh_size; }
223 SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found
224
225 bool DidRelocate() {
226 return relocate;
227 }
228};
229
230ElfReader::ElfReader(void *ptr) {
231 base = (char*)ptr;
232 base32 = (u32 *)ptr;
233 header = (Elf32_Ehdr*)ptr;
234
235 segments = (Elf32_Phdr *)(base + header->e_phoff);
236 sections = (Elf32_Shdr *)(base + header->e_shoff);
237
238 entryPoint = header->e_entry;
239
240 LoadSymbols();
241}
242
243const char *ElfReader::GetSectionName(int section) const {
244 if (sections[section].sh_type == SHT_NULL)
245 return nullptr;
246
247 int name_offset = sections[section].sh_name;
248 char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
249
250 if (ptr)
251 return ptr + name_offset;
252
253 return nullptr;
254}
255
256bool ElfReader::LoadInto(u32 vaddr) {
257 DEBUG_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx);
258
259 // Should we relocate?
260 relocate = (header->e_type != ET_EXEC);
261
262 if (relocate) {
263 DEBUG_LOG(MASTER_LOG, "Relocatable module");
264 entryPoint += vaddr;
265 } else {
266 DEBUG_LOG(MASTER_LOG, "Prerelocated executable");
267 }
268 INFO_LOG(MASTER_LOG, "%i segments:", header->e_phnum);
269
270 // First pass : Get the bits into RAM
271 u32 segment_addr[32];
272 u32 base_addr = relocate ? vaddr : 0;
273
274 for (int i = 0; i < header->e_phnum; i++) {
275 Elf32_Phdr *p = segments + i;
276 INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr,
277 p->p_filesz, p->p_memsz);
278
279 if (p->p_type == PT_LOAD) {
280 segment_addr[i] = base_addr + p->p_vaddr;
281 memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz);
282 INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", segment_addr[i],
283 p->p_memsz);
284 }
285 }
286 INFO_LOG(MASTER_LOG, "Done loading.");
287 return true;
288}
289
290SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const {
291 for (int i = firstSection; i < header->e_shnum; i++) {
292 const char *secname = GetSectionName(i);
293
294 if (secname != nullptr && strcmp(name, secname) == 0)
295 return i;
296 }
297 return -1;
298}
299
300bool ElfReader::LoadSymbols() {
301 bool hasSymbols = false;
302 SectionID sec = GetSectionByName(".symtab");
303 if (sec != -1) {
304 int stringSection = sections[sec].sh_link;
305 const char *stringBase = (const char *)GetSectionDataPtr(stringSection);
306
307 //We have a symbol table!
308 Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
309 int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
310 for (int sym = 0; sym < numSymbols; sym++) {
311 int size = symtab[sym].st_size;
312 if (size == 0)
313 continue;
314
315 int type = symtab[sym].st_info & 0xF;
316
317 const char *name = stringBase + symtab[sym].st_name;
318
319 Symbols::Add(symtab[sym].st_value, name, size, type);
320
321 hasSymbols = true;
322 }
323 }
324
325 return hasSymbols;
326}
327
328////////////////////////////////////////////////////////////////////////////////////////////////////
329// Loader namespace
330
331namespace Loader {
332
333/// AppLoader_ELF constructor
334AppLoader_ELF::AppLoader_ELF(const std::string& filename) : is_loaded(false) {
335 this->filename = filename;
336}
337
338/// AppLoader_NCCH destructor
339AppLoader_ELF::~AppLoader_ELF() {
340}
341
342/**
343 * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
344 * @param error_string Pointer to string to put error message if an error has occurred
345 * @todo Move NCSD parsing out of here and create a separate function for loading these
346 * @return True on success, otherwise false
347 */
348ResultStatus AppLoader_ELF::Load() {
349 INFO_LOG(LOADER, "Loading ELF file %s...", filename.c_str());
350
351 if (is_loaded)
352 return ResultStatus::ErrorAlreadyLoaded;
353
354 File::IOFile file(filename, "rb");
355
356 if (file.IsOpen()) {
357 u32 size = (u32)file.GetSize();
358 std::unique_ptr<u8[]> buffer(new u8[size]);
359 file.ReadBytes(&buffer[0], size);
360
361 ElfReader elf_reader(&buffer[0]);
362 elf_reader.LoadInto(0x00100000);
363 Kernel::LoadExec(elf_reader.GetEntryPoint());
364 } else {
365 return ResultStatus::Error;
366 }
367 return ResultStatus::Success;
368}
369
370} // namespace Loader