1 // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <cstring>
6 #include <memory>
7 #include <string>
8 #include "common/common_funcs.h"
9 #include "common/common_types.h"
10 #include "common/file_util.h"
11 #include "common/logging/log.h"
12 #include "core/hle/kernel/code_set.h"
13 #include "core/hle/kernel/memory/page_table.h"
14 #include "core/hle/kernel/process.h"
15 #include "core/loader/elf.h"
16 #include "core/memory.h"
17
18 ////////////////////////////////////////////////////////////////////////////////////////////////////
19 // ELF Header Constants
20
21 // File type
22 enum ElfType {
23 ET_NONE = 0,
24 ET_REL = 1,
25 ET_EXEC = 2,
26 ET_DYN = 3,
27 ET_CORE = 4,
28 ET_LOPROC = 0xFF00,
29 ET_HIPROC = 0xFFFF,
30 };
31
32 // Machine/Architecture
33 enum ElfMachine {
34 EM_NONE = 0,
35 EM_M32 = 1,
36 EM_SPARC = 2,
37 EM_386 = 3,
38 EM_68K = 4,
39 EM_88K = 5,
40 EM_860 = 7,
41 EM_MIPS = 8
42 };
43
44 // File version
45 #define EV_NONE 0
46 #define EV_CURRENT 1
47
48 // Identification index
49 #define EI_MAG0 0
50 #define EI_MAG1 1
51 #define EI_MAG2 2
52 #define EI_MAG3 3
53 #define EI_CLASS 4
54 #define EI_DATA 5
55 #define EI_VERSION 6
56 #define EI_PAD 7
57 #define EI_NIDENT 16
58
59 // Sections constants
60
61 // Section types
62 #define SHT_NULL 0
63 #define SHT_PROGBITS 1
64 #define SHT_SYMTAB 2
65 #define SHT_STRTAB 3
66 #define SHT_RELA 4
67 #define SHT_HASH 5
68 #define SHT_DYNAMIC 6
69 #define SHT_NOTE 7
70 #define SHT_NOBITS 8
71 #define SHT_REL 9
72 #define SHT_SHLIB 10
73 #define SHT_DYNSYM 11
74 #define SHT_LOPROC 0x70000000
75 #define SHT_HIPROC 0x7FFFFFFF
76 #define SHT_LOUSER 0x80000000
77 #define SHT_HIUSER 0xFFFFFFFF
78
79 // Section flags
80 enum ElfSectionFlags {
81 SHF_WRITE = 0x1,
82 SHF_ALLOC = 0x2,
83 SHF_EXECINSTR = 0x4,
84 SHF_MASKPROC = 0xF0000000,
85 };
86
87 // Segment types
88 #define PT_NULL 0
89 #define PT_LOAD 1
90 #define PT_DYNAMIC 2
91 #define PT_INTERP 3
92 #define PT_NOTE 4
93 #define PT_SHLIB 5
94 #define PT_PHDR 6
95 #define PT_LOPROC 0x70000000
96 #define PT_HIPROC 0x7FFFFFFF
97
98 // Segment flags
99 #define PF_X 0x1
100 #define PF_W 0x2
101 #define PF_R 0x4
102 #define PF_MASKPROC 0xF0000000
103
104 typedef unsigned int Elf32_Addr;
105 typedef unsigned short Elf32_Half;
106 typedef unsigned int Elf32_Off;
107 typedef signed int Elf32_Sword;
108 typedef unsigned int Elf32_Word;
109
110 ////////////////////////////////////////////////////////////////////////////////////////////////////
111 // ELF file header
112
113 struct Elf32_Ehdr {
114 unsigned char e_ident[EI_NIDENT];
115 Elf32_Half e_type;
116 Elf32_Half e_machine;
117 Elf32_Word e_version;
118 Elf32_Addr e_entry;
119 Elf32_Off e_phoff;
120 Elf32_Off e_shoff;
121 Elf32_Word e_flags;
122 Elf32_Half e_ehsize;
123 Elf32_Half e_phentsize;
124 Elf32_Half e_phnum;
125 Elf32_Half e_shentsize;
126 Elf32_Half e_shnum;
127 Elf32_Half e_shstrndx;
128 };
129
130 // Section header
131 struct Elf32_Shdr {
132 Elf32_Word sh_name;
133 Elf32_Word sh_type;
134 Elf32_Word sh_flags;
135 Elf32_Addr sh_addr;
136 Elf32_Off sh_offset;
137 Elf32_Word sh_size;
138 Elf32_Word sh_link;
139 Elf32_Word sh_info;
140 Elf32_Word sh_addralign;
141 Elf32_Word sh_entsize;
142 };
143
144 // Segment header
145 struct Elf32_Phdr {
146 Elf32_Word p_type;
147 Elf32_Off p_offset;
148 Elf32_Addr p_vaddr;
149 Elf32_Addr p_paddr;
150 Elf32_Word p_filesz;
151 Elf32_Word p_memsz;
152 Elf32_Word p_flags;
153 Elf32_Word p_align;
154 };
155
156 // Symbol table entry
157 struct Elf32_Sym {
158 Elf32_Word st_name;
159 Elf32_Addr st_value;
160 Elf32_Word st_size;
161 unsigned char st_info;
162 unsigned char st_other;
163 Elf32_Half st_shndx;
164 };
165
166 // Relocation entries
167 struct Elf32_Rel {
168 Elf32_Addr r_offset;
169 Elf32_Word r_info;
170 };
171
172 ////////////////////////////////////////////////////////////////////////////////////////////////////
173 // ElfReader class
174
175 typedef int SectionID;
176
177 class ElfReader {
178 private:
179 char* base;
180 u32* base32;
181
182 Elf32_Ehdr* header;
183 Elf32_Phdr* segments;
184 Elf32_Shdr* sections;
185
186 u32* sectionAddrs;
187 bool relocate;
188 VAddr entryPoint;
189
190 public:
191 explicit ElfReader(void* ptr);
192
Read32(int off) const193 u32 Read32(int off) const {
194 return base32[off >> 2];
195 }
196
197 // Quick accessors
GetType() const198 ElfType GetType() const {
199 return (ElfType)(header->e_type);
200 }
GetMachine() const201 ElfMachine GetMachine() const {
202 return (ElfMachine)(header->e_machine);
203 }
GetEntryPoint() const204 VAddr GetEntryPoint() const {
205 return entryPoint;
206 }
GetFlags() const207 u32 GetFlags() const {
208 return (u32)(header->e_flags);
209 }
210 Kernel::CodeSet LoadInto(VAddr vaddr);
211
GetNumSegments() const212 int GetNumSegments() const {
213 return (int)(header->e_phnum);
214 }
GetNumSections() const215 int GetNumSections() const {
216 return (int)(header->e_shnum);
217 }
GetPtr(int offset) const218 const u8* GetPtr(int offset) const {
219 return (u8*)base + offset;
220 }
221 const char* GetSectionName(int section) const;
GetSectionDataPtr(int section) const222 const u8* GetSectionDataPtr(int section) const {
223 if (section < 0 || section >= header->e_shnum)
224 return nullptr;
225 if (sections[section].sh_type != SHT_NOBITS)
226 return GetPtr(sections[section].sh_offset);
227 else
228 return nullptr;
229 }
IsCodeSection(int section) const230 bool IsCodeSection(int section) const {
231 return sections[section].sh_type == SHT_PROGBITS;
232 }
GetSegmentPtr(int segment)233 const u8* GetSegmentPtr(int segment) {
234 return GetPtr(segments[segment].p_offset);
235 }
GetSectionAddr(SectionID section) const236 u32 GetSectionAddr(SectionID section) const {
237 return sectionAddrs[section];
238 }
GetSectionSize(SectionID section) const239 unsigned int GetSectionSize(SectionID section) const {
240 return sections[section].sh_size;
241 }
242 SectionID GetSectionByName(const char* name, int firstSection = 0) const; //-1 for not found
243
DidRelocate() const244 bool DidRelocate() const {
245 return relocate;
246 }
247 };
248
ElfReader(void * ptr)249 ElfReader::ElfReader(void* ptr) {
250 base = (char*)ptr;
251 base32 = (u32*)ptr;
252 header = (Elf32_Ehdr*)ptr;
253
254 segments = (Elf32_Phdr*)(base + header->e_phoff);
255 sections = (Elf32_Shdr*)(base + header->e_shoff);
256
257 entryPoint = header->e_entry;
258 }
259
GetSectionName(int section) const260 const char* ElfReader::GetSectionName(int section) const {
261 if (sections[section].sh_type == SHT_NULL)
262 return nullptr;
263
264 int name_offset = sections[section].sh_name;
265 const char* ptr = reinterpret_cast<const char*>(GetSectionDataPtr(header->e_shstrndx));
266
267 if (ptr)
268 return ptr + name_offset;
269
270 return nullptr;
271 }
272
LoadInto(VAddr vaddr)273 Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
274 LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
275
276 // Should we relocate?
277 relocate = (header->e_type != ET_EXEC);
278
279 if (relocate) {
280 LOG_DEBUG(Loader, "Relocatable module");
281 entryPoint += vaddr;
282 } else {
283 LOG_DEBUG(Loader, "Prerelocated executable");
284 }
285 LOG_DEBUG(Loader, "{} segments:", header->e_phnum);
286
287 // First pass : Get the bits into RAM
288 const VAddr base_addr = relocate ? vaddr : 0;
289
290 u64 total_image_size = 0;
291 for (unsigned int i = 0; i < header->e_phnum; ++i) {
292 const Elf32_Phdr* p = &segments[i];
293 if (p->p_type == PT_LOAD) {
294 total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
295 }
296 }
297
298 Kernel::PhysicalMemory program_image(total_image_size);
299 std::size_t current_image_position = 0;
300
301 Kernel::CodeSet codeset;
302
303 for (unsigned int i = 0; i < header->e_phnum; ++i) {
304 const Elf32_Phdr* p = &segments[i];
305 LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type,
306 p->p_vaddr, p->p_filesz, p->p_memsz);
307
308 if (p->p_type == PT_LOAD) {
309 Kernel::CodeSet::Segment* codeset_segment;
310 u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
311 if (permission_flags == (PF_R | PF_X)) {
312 codeset_segment = &codeset.CodeSegment();
313 } else if (permission_flags == (PF_R)) {
314 codeset_segment = &codeset.RODataSegment();
315 } else if (permission_flags == (PF_R | PF_W)) {
316 codeset_segment = &codeset.DataSegment();
317 } else {
318 LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i,
319 p->p_flags);
320 continue;
321 }
322
323 if (codeset_segment->size != 0) {
324 LOG_ERROR(Loader,
325 "ELF has more than one segment of the same type. Skipping extra "
326 "segment (id {})",
327 i);
328 continue;
329 }
330
331 const VAddr segment_addr = base_addr + p->p_vaddr;
332 const u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF;
333
334 codeset_segment->offset = current_image_position;
335 codeset_segment->addr = segment_addr;
336 codeset_segment->size = aligned_size;
337
338 std::memcpy(program_image.data() + current_image_position, GetSegmentPtr(i),
339 p->p_filesz);
340 current_image_position += aligned_size;
341 }
342 }
343
344 codeset.entrypoint = base_addr + header->e_entry;
345 codeset.memory = std::move(program_image);
346
347 LOG_DEBUG(Loader, "Done loading.");
348
349 return codeset;
350 }
351
GetSectionByName(const char * name,int firstSection) const352 SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const {
353 for (int i = firstSection; i < header->e_shnum; i++) {
354 const char* secname = GetSectionName(i);
355
356 if (secname != nullptr && strcmp(name, secname) == 0)
357 return i;
358 }
359 return -1;
360 }
361
362 ////////////////////////////////////////////////////////////////////////////////////////////////////
363 // Loader namespace
364
365 namespace Loader {
366
AppLoader_ELF(FileSys::VirtualFile file)367 AppLoader_ELF::AppLoader_ELF(FileSys::VirtualFile file) : AppLoader(std::move(file)) {}
368
IdentifyType(const FileSys::VirtualFile & file)369 FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) {
370 static constexpr u16 ELF_MACHINE_ARM{0x28};
371
372 u32 magic = 0;
373 if (4 != file->ReadObject(&magic))
374 return FileType::Error;
375
376 u16 machine = 0;
377 if (2 != file->ReadObject(&machine, 18))
378 return FileType::Error;
379
380 if (Common::MakeMagic('\x7f', 'E', 'L', 'F') == magic && ELF_MACHINE_ARM == machine)
381 return FileType::ELF;
382
383 return FileType::Error;
384 }
385
Load(Kernel::Process & process,Core::System & system)386 AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process,
387 [[maybe_unused]] Core::System& system) {
388 if (is_loaded) {
389 return {ResultStatus::ErrorAlreadyLoaded, {}};
390 }
391
392 std::vector<u8> buffer = file->ReadAllBytes();
393 if (buffer.size() != file->GetSize()) {
394 return {ResultStatus::ErrorIncorrectELFFileSize, {}};
395 }
396
397 const VAddr base_address = process.PageTable().GetCodeRegionStart();
398 ElfReader elf_reader(&buffer[0]);
399 Kernel::CodeSet codeset = elf_reader.LoadInto(base_address);
400 const VAddr entry_point = codeset.entrypoint;
401
402 // Setup the process code layout
403 if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), buffer.size()).IsError()) {
404 return {ResultStatus::ErrorNotInitialized, {}};
405 }
406
407 process.LoadModule(std::move(codeset), entry_point);
408
409 is_loaded = true;
410 return {ResultStatus::Success, LoadParameters{48, Core::Memory::DEFAULT_STACK_SIZE}};
411 }
412
413 } // namespace Loader
414