summaryrefslogtreecommitdiff
path: root/src/core/loader/elf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader/elf.cpp')
-rw-r--r--src/core/loader/elf.cpp318
1 files changed, 257 insertions, 61 deletions
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index f93354817..065601546 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string> 5#include <string>
6#include <memory>
6 7
7#include "common/common.h" 8#include "common/common.h"
8#include "common/file_util.h" 9#include "common/file_util.h"
@@ -12,6 +13,220 @@
12#include "core/loader/elf.h" 13#include "core/loader/elf.h"
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
14 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
15ElfReader::ElfReader(void *ptr) { 230ElfReader::ElfReader(void *ptr) {
16 base = (char*)ptr; 231 base = (char*)ptr;
17 base32 = (u32 *)ptr; 232 base32 = (u32 *)ptr;
@@ -29,28 +244,25 @@ const char *ElfReader::GetSectionName(int section) const {
29 if (sections[section].sh_type == SHT_NULL) 244 if (sections[section].sh_type == SHT_NULL)
30 return nullptr; 245 return nullptr;
31 246
32 int nameOffset = sections[section].sh_name; 247 int name_offset = sections[section].sh_name;
33 char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx); 248 char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
34 249
35 if (ptr) 250 if (ptr)
36 return ptr + nameOffset; 251 return ptr + name_offset;
37 else 252
38 return nullptr; 253 return nullptr;
39} 254}
40 255
41bool ElfReader::LoadInto(u32 vaddr) { 256bool ElfReader::LoadInto(u32 vaddr) {
42 DEBUG_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx); 257 DEBUG_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx);
43 258
44 // Should we relocate? 259 // Should we relocate?
45 bRelocate = (header->e_type != ET_EXEC); 260 relocate = (header->e_type != ET_EXEC);
46 261
47 if (bRelocate) 262 if (relocate) {
48 {
49 DEBUG_LOG(MASTER_LOG, "Relocatable module"); 263 DEBUG_LOG(MASTER_LOG, "Relocatable module");
50 entryPoint += vaddr; 264 entryPoint += vaddr;
51 } 265 } else {
52 else
53 {
54 DEBUG_LOG(MASTER_LOG, "Prerelocated executable"); 266 DEBUG_LOG(MASTER_LOG, "Prerelocated executable");
55 } 267 }
56 268
@@ -58,17 +270,14 @@ bool ElfReader::LoadInto(u32 vaddr) {
58 270
59 // First pass : Get the bits into RAM 271 // First pass : Get the bits into RAM
60 u32 segmentVAddr[32]; 272 u32 segmentVAddr[32];
273 u32 baseAddress = relocate ? vaddr : 0;
61 274
62 u32 baseAddress = bRelocate ? vaddr : 0; 275 for (int i = 0; i < header->e_phnum; i++) {
63
64 for (int i = 0; i < header->e_phnum; i++)
65 {
66 Elf32_Phdr *p = segments + i; 276 Elf32_Phdr *p = segments + i;
67 277
68 INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); 278 INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz);
69 279
70 if (p->p_type == PT_LOAD) 280 if (p->p_type == PT_LOAD) {
71 {
72 segmentVAddr[i] = baseAddress + p->p_vaddr; 281 segmentVAddr[i] = baseAddress + p->p_vaddr;
73 u32 writeAddr = segmentVAddr[i]; 282 u32 writeAddr = segmentVAddr[i];
74 283
@@ -78,27 +287,19 @@ bool ElfReader::LoadInto(u32 vaddr) {
78 u32 dstSize = p->p_memsz; 287 u32 dstSize = p->p_memsz;
79 u32 *s = (u32*)src; 288 u32 *s = (u32*)src;
80 u32 *d = (u32*)dst; 289 u32 *d = (u32*)dst;
81 for (int j = 0; j < (int)(srcSize + 3) / 4; j++) 290 for (int j = 0; j < (int)(srcSize + 3) / 4; j++) {
82 { 291 *d++ = (*s++);
83 *d++ = /*_byteswap_ulong*/(*s++);
84 }
85 if (srcSize < dstSize)
86 {
87 //memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss
88 } 292 }
89 INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz); 293 INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz);
90 } 294 }
91 } 295 }
92 296
93
94 INFO_LOG(MASTER_LOG, "Done loading."); 297 INFO_LOG(MASTER_LOG, "Done loading.");
95 return true; 298 return true;
96} 299}
97 300
98SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const 301SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const {
99{ 302 for (int i = firstSection; i < header->e_shnum; i++) {
100 for (int i = firstSection; i < header->e_shnum; i++)
101 {
102 const char *secname = GetSectionName(i); 303 const char *secname = GetSectionName(i);
103 304
104 if (secname != nullptr && strcmp(name, secname) == 0) 305 if (secname != nullptr && strcmp(name, secname) == 0)
@@ -107,25 +308,21 @@ SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const
107 return -1; 308 return -1;
108} 309}
109 310
110bool ElfReader::LoadSymbols() 311bool ElfReader::LoadSymbols() {
111{
112 bool hasSymbols = false; 312 bool hasSymbols = false;
113 SectionID sec = GetSectionByName(".symtab"); 313 SectionID sec = GetSectionByName(".symtab");
114 if (sec != -1) 314 if (sec != -1) {
115 {
116 int stringSection = sections[sec].sh_link; 315 int stringSection = sections[sec].sh_link;
117 const char *stringBase = (const char *)GetSectionDataPtr(stringSection); 316 const char *stringBase = (const char *)GetSectionDataPtr(stringSection);
118 317
119 //We have a symbol table! 318 //We have a symbol table!
120 Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); 319 Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
121 int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); 320 int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
122 for (int sym = 0; sym < numSymbols; sym++) 321 for (int sym = 0; sym < numSymbols; sym++) {
123 {
124 int size = symtab[sym].st_size; 322 int size = symtab[sym].st_size;
125 if (size == 0) 323 if (size == 0)
126 continue; 324 continue;
127 325
128 // int bind = symtab[sym].st_info >> 4;
129 int type = symtab[sym].st_info & 0xF; 326 int type = symtab[sym].st_info & 0xF;
130 327
131 const char *name = stringBase + symtab[sym].st_name; 328 const char *name = stringBase + symtab[sym].st_name;
@@ -144,42 +341,41 @@ bool ElfReader::LoadSymbols()
144 341
145namespace Loader { 342namespace Loader {
146 343
344/// AppLoader_ELF constructor
345AppLoader_ELF::AppLoader_ELF(std::string& filename) : is_loaded(false) {
346 this->filename = filename;
347}
348
349/// AppLoader_NCCH destructor
350AppLoader_ELF::~AppLoader_ELF() {
351}
352
147/** 353/**
148 * Loads an ELF file 354 * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
149 * @param filename String filename of ELF file
150 * @param error_string Pointer to string to put error message if an error has occurred 355 * @param error_string Pointer to string to put error message if an error has occurred
356 * @todo Move NCSD parsing out of here and create a separate function for loading these
151 * @return True on success, otherwise false 357 * @return True on success, otherwise false
152 */ 358 */
153bool Load_ELF(std::string& filename, std::string* error_string) { 359const ResultStatus AppLoader_ELF::Load() {
154 std::string full_path = filename; 360 INFO_LOG(LOADER, "Loading ELF file %s...", filename.c_str());
155 std::string path, file, extension;
156 SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
157#if EMU_PLATFORM == PLATFORM_WINDOWS
158 path = ReplaceAll(path, "/", "\\");
159#endif
160 File::IOFile f(filename, "rb");
161 361
162 if (f.IsOpen()) { 362 if (is_loaded)
163 u32 size = (u32)f.GetSize(); 363 return ResultStatus::ErrorAlreadyLoaded;
164 u8* buffer = new u8[size];
165 ElfReader* elf_reader = NULL;
166 364
167 f.ReadBytes(buffer, size); 365 File::IOFile file(filename, "rb");
168 366
169 elf_reader = new ElfReader(buffer); 367 if (file.IsOpen()) {
170 elf_reader->LoadInto(0x00100000); 368 u32 size = (u32)file.GetSize();
369 std::unique_ptr<u8[]> buffer(new u8[size]);
370 file.ReadBytes(&buffer[0], size);
171 371
172 Kernel::LoadExec(elf_reader->GetEntryPoint()); 372 ElfReader elf_reader(&buffer[0]);
173 373 elf_reader.LoadInto(0x00100000);
174 delete[] buffer; 374 Kernel::LoadExec(elf_reader.GetEntryPoint());
175 delete elf_reader;
176 } else { 375 } else {
177 *error_string = "Unable to open ELF file!"; 376 return ResultStatus::Error;
178 return false;
179 } 377 }
180 f.Close(); 378 return ResultStatus::Success;
181
182 return true;
183} 379}
184 380
185} // namespace Loader 381} // namespace Loader