1 // Copyright (c) 2012- PPSSPP Project.
2
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
11
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18 #include <atomic>
19
20 #include "Common/StringUtils.h"
21 #include "Common/Thread/ParallelLoop.h"
22
23 #include "Core/MemMap.h"
24 #include "Core/Reporting.h"
25 #include "Core/ThreadPools.h"
26 #include "Core/MIPS/MIPSTables.h"
27 #include "Core/ELF/ElfReader.h"
28 #include "Core/Debugger/MemBlockInfo.h"
29 #include "Core/Debugger/SymbolMap.h"
30 #include "Core/HLE/sceKernelMemory.h"
31 #include "Core/HLE/sceKernelModule.h"
32
GetSectionName(int section) const33 const char *ElfReader::GetSectionName(int section) const {
34 if (sections[section].sh_type == SHT_NULL)
35 return nullptr;
36
37 int nameOffset = sections[section].sh_name;
38 if (nameOffset < 0 || (size_t)nameOffset >= size_) {
39 ERROR_LOG(LOADER, "ELF: Bad name offset %d in section %d (max = %d)", nameOffset, section, (int)size_);
40 return nullptr;
41 }
42 const char *ptr = (const char *)GetSectionDataPtr(header->e_shstrndx);
43
44 if (ptr)
45 return ptr + nameOffset;
46 else
47 return nullptr;
48 }
49
addrToHiLo(u32 addr,u16 & hi,s16 & lo)50 void addrToHiLo(u32 addr, u16 &hi, s16 &lo)
51 {
52 lo = (addr & 0xFFFF);
53 u32 naddr = addr - lo;
54 hi = naddr>>16;
55 u32 test = (hi<<16) + lo;
56 if (test != addr)
57 {
58 WARN_LOG_REPORT(LOADER, "HI16/LO16 relocation failure?");
59 }
60 }
61
LoadRelocations(const Elf32_Rel * rels,int numRelocs)62 bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) {
63 std::vector<u32> relocOps;
64 relocOps.resize(numRelocs);
65
66 DEBUG_LOG(LOADER, "Loading %i relocations...", numRelocs);
67 std::atomic<int> numErrors;
68 numErrors.store(0);
69
70 ParallelRangeLoop(&g_threadManager, [&](int l, int h) {
71 for (int r = l; r < h; r++) {
72 u32 info = rels[r].r_info;
73 u32 addr = rels[r].r_offset;
74
75 int type = info & 0xf;
76
77 // Often: 0 = code, 1 = data.
78 int readwrite = (info >> 8) & 0xff;
79 if (readwrite >= (int)ARRAY_SIZE(segmentVAddr)) {
80 if (numErrors < 10) {
81 ERROR_LOG_REPORT(LOADER, "Bad segment number %i", readwrite);
82 }
83 numErrors++;
84 continue;
85 }
86
87 addr += segmentVAddr[readwrite];
88
89 // It appears that misaligned relocations are allowed.
90 if (((addr & 3) && type != R_MIPS_32) || !Memory::IsValidAddress(addr)) {
91 if (numErrors < 10) {
92 WARN_LOG_REPORT(LOADER, "Suspicious address %08x, skipping reloc, type = %d", addr, type);
93 } else if (numErrors == 10) {
94 WARN_LOG(LOADER, "Too many bad relocations, skipping logging");
95 }
96 numErrors++;
97 continue;
98 }
99
100 relocOps[r] = Memory::ReadUnchecked_Instruction(addr, true).encoding;
101 }
102 }, 0, numRelocs, 128);
103
104 ParallelRangeLoop(&g_threadManager, [&](int l, int h) {
105 for (int r = l; r < h; r++) {
106 VERBOSE_LOG(LOADER, "Loading reloc %i (%p)...", r, rels + r);
107 u32 info = rels[r].r_info;
108 u32 addr = rels[r].r_offset;
109
110 int type = info & 0xf;
111 int readwrite = (info >> 8) & 0xff;
112 int relative = (info >> 16) & 0xff;
113
114 if (readwrite >= (int)ARRAY_SIZE(segmentVAddr)) {
115 continue;
116 }
117
118 addr += segmentVAddr[readwrite];
119 if (((addr & 3) && type != R_MIPS_32) || !Memory::IsValidAddress(addr)) {
120 continue;
121 }
122
123 u32 op = relocOps[r];
124
125 const bool log = false;
126 //log=true;
127 if (log) {
128 DEBUG_LOG(LOADER, "rel at: %08x info: %08x type: %i", addr, info, type);
129 }
130 u32 relocateTo = segmentVAddr[relative];
131
132 switch (type) {
133 case R_MIPS_32:
134 if (log)
135 DEBUG_LOG(LOADER, "Full address reloc %08x", addr);
136 //full address, no problemo
137 op += relocateTo;
138 break;
139
140 case R_MIPS_26: //j, jal
141 //add on to put in correct address space
142 if (log)
143 DEBUG_LOG(LOADER, "j/jal reloc %08x", addr);
144 op = (op & 0xFC000000) | (((op & 0x03FFFFFF) + (relocateTo >> 2)) & 0x03FFFFFF);
145 break;
146
147 case R_MIPS_HI16: //lui part of lui-addiu pairs
148 {
149 if (log)
150 DEBUG_LOG(LOADER, "HI reloc %08x", addr);
151
152 u32 cur = (op & 0xFFFF) << 16;
153 u16 hi = 0;
154 bool found = false;
155 for (int t = r + 1; t < numRelocs; t++) {
156 if ((rels[t].r_info & 0xF) == R_MIPS_LO16) {
157 u32 corrLoAddr = rels[t].r_offset + segmentVAddr[readwrite];
158 if (log) {
159 DEBUG_LOG(LOADER, "Corresponding lo found at %08x", corrLoAddr);
160 }
161 if (Memory::IsValidAddress(corrLoAddr)) {
162 s16 lo = (s16)relocOps[t];
163 cur += lo;
164 cur += relocateTo;
165 addrToHiLo(cur, hi, lo);
166 found = true;
167 break;
168 } else {
169 ERROR_LOG(LOADER, "Bad corrLoAddr %08x", corrLoAddr);
170 }
171 }
172 }
173 if (!found) {
174 ERROR_LOG_REPORT(LOADER, "R_MIPS_HI16: could not find R_MIPS_LO16");
175 }
176 op = (op & 0xFFFF0000) | hi;
177 }
178 break;
179
180 case R_MIPS_LO16: //addiu part of lui-addiu pairs
181 {
182 if (log)
183 DEBUG_LOG(LOADER, "LO reloc %08x", addr);
184 u32 cur = op & 0xFFFF;
185 cur += relocateTo;
186 cur &= 0xFFFF;
187 op = (op & 0xFFFF0000) | cur;
188 }
189 break;
190
191 case R_MIPS_GPREL16: //gp
192 // It seems safe to ignore this, almost a notification of a gp-relative operation?
193 break;
194
195 case R_MIPS_16:
196 op = (op & 0xFFFF0000) | (((int)(op & 0xFFFF) + (int)relocateTo) & 0xFFFF);
197 break;
198
199 case R_MIPS_NONE:
200 // This shouldn't matter, not sure the purpose of it.
201 break;
202
203 default:
204 {
205 char temp[256];
206 MIPSDisAsm(MIPSOpcode(op), 0, temp);
207 ERROR_LOG_REPORT(LOADER, "ARGH IT'S AN UNKNOWN RELOCATION!!!!!!!! %08x, type=%d : %s", addr, type, temp);
208 }
209 break;
210 }
211
212 Memory::WriteUnchecked_U32(op, addr);
213 NotifyMemInfo(MemBlockFlags::WRITE, addr, 4, "Relocation");
214 }
215 }, 0, numRelocs, 128);
216
217 if (numErrors) {
218 WARN_LOG(LOADER, "%i bad relocations found!!!", numErrors.load());
219 }
220 return numErrors == 0;
221 }
222
223
LoadRelocations2(int rel_seg)224 void ElfReader::LoadRelocations2(int rel_seg)
225 {
226 u8 *buf, *end, *flag_table, *type_table;
227 int flag_table_size, type_table_size;
228 int flag_bits, seg_bits, type_bits;
229 int cmd, flag, seg, type;
230 int off_seg = 0, addr_seg, rel_base, rel_offset;
231 int relocate_to, last_type, lo16 = 0;
232 u32 op, addr;
233 int rcount = 0;
234
235 const Elf32_Phdr *ph = segments + rel_seg;
236
237 buf = (u8*)GetSegmentPtr(rel_seg);
238 end = buf+ph->p_filesz;
239
240 flag_bits = buf[2];
241 type_bits = buf[3];
242
243 seg_bits = 1;
244 while((1<<seg_bits)<rel_seg)
245 seg_bits += 1;
246
247 buf += 4;
248
249 flag_table = buf;
250 flag_table_size = flag_table[0];
251 buf += flag_table_size;
252
253 type_table = buf;
254 type_table_size = type_table[0];
255 buf += type_table_size;
256
257 rel_base = 0;
258 last_type = -1;
259 while(buf<end){
260 cmd = *(u16*)(buf);
261 buf += 2;
262
263 flag = ( cmd<<(16-flag_bits))&0xffff;
264 flag = (flag>>(16-flag_bits))&0xffff;
265 flag = flag_table[flag];
266
267 seg = (cmd<<(16-seg_bits-flag_bits))&0xffff;
268 seg = (seg>>(16-seg_bits))&0xffff;
269
270 type = ( cmd<<(16-type_bits-seg_bits-flag_bits))&0xffff;
271 type = (type>>(16-type_bits))&0xffff;
272 type = type_table[type];
273
274 if((flag&0x01)==0){
275 off_seg = seg;
276 if((flag&0x06)==0){
277 rel_base = cmd>>(seg_bits+flag_bits);
278 }else if((flag&0x06)==4){
279 rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);
280 buf += 4;
281 }else{
282 ERROR_LOG_REPORT(LOADER, "Rel2: invalid size flag! %x", flag);
283 rel_base = 0;
284 }
285 }else{
286 addr_seg = seg;
287 relocate_to = segmentVAddr[addr_seg];
288 if (!Memory::IsValidAddress(relocate_to)) {
289 ERROR_LOG(LOADER, "ELF: Bad address to relocate to: %08x", relocate_to);
290 continue;
291 }
292
293 if((flag&0x06)==0x00){
294 rel_offset = cmd;
295 if(cmd&0x8000){
296 rel_offset |= 0xffff0000;
297 rel_offset >>= type_bits+seg_bits+flag_bits;
298 rel_offset |= 0xffff0000;
299 }else{
300 rel_offset >>= type_bits+seg_bits+flag_bits;
301 }
302 rel_base += rel_offset;
303 }else if((flag&0x06)==0x02){
304 rel_offset = cmd;
305 if(cmd&0x8000)
306 rel_offset |= 0xffff0000;
307 rel_offset >>= type_bits+seg_bits+flag_bits;
308 rel_offset = (rel_offset<<16) | (buf[0]) | (buf[1]<<8);
309 buf += 2;
310 rel_base += rel_offset;
311 }else if((flag&0x06)==0x04){
312 rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);
313 buf += 4;
314 }else{
315 ERROR_LOG_REPORT(LOADER, "Rel2: invalid relocat size flag! %x", flag);
316 }
317
318
319 rel_offset = rel_base+segmentVAddr[off_seg];
320 if (!Memory::IsValidAddress(rel_offset)) {
321 ERROR_LOG(LOADER, "ELF: Bad rel_offset: %08x", rel_offset);
322 continue;
323 }
324
325 if((flag&0x38)==0x00){
326 lo16 = 0;
327 }else if((flag&0x38)==0x08){
328 if(last_type!=0x04)
329 lo16 = 0;
330 }else if((flag&0x38)==0x10){
331 lo16 = (buf[0]) | (buf[1]<<8);
332 if(lo16&0x8000)
333 lo16 |= 0xffff0000;
334 buf += 2;
335 }else{
336 ERROR_LOG_REPORT(LOADER, "Rel2: invalid lo16 type! %x", flag);
337 }
338
339 op = Memory::Read_Instruction(rel_offset, true).encoding;
340 DEBUG_LOG(LOADER, "Rel2: %5d: CMD=0x%04X flag=%x type=%d off_seg=%d offset=%08x addr_seg=%d op=%08x\n", rcount, cmd, flag, type, off_seg, rel_base, addr_seg, op);
341
342 switch(type){
343 case 0:
344 continue;
345 case 2: // R_MIPS_32
346 op += relocate_to;
347 break;
348 case 3: // R_MIPS_26
349 case 6: // R_MIPS_J26
350 case 7: // R_MIPS_JAL26
351 op = (op&0xFC000000) | (((op&0x03FFFFFF)+(relocate_to>>2))&0x03FFFFFF);
352 // To be safe, let's force it to the specified jump.
353 if (type == 6)
354 op = (op & ~0xFC000000) | 0x08000000;
355 else if (type == 7)
356 op = (op & ~0xFC000000) | 0x0C000000;
357 break;
358 case 4: // R_MIPS_HI16
359 addr = ((op<<16)+lo16)+relocate_to;
360 if(addr&0x8000)
361 addr += 0x00010000;
362 op = (op&0xffff0000) | (addr>>16 );
363 break;
364 case 1:
365 case 5: // R_MIPS_LO16
366 op = (op&0xffff0000) | (((op&0xffff)+relocate_to)&0xffff);
367 break;
368 default:
369 ERROR_LOG_REPORT(LOADER, "Rel2: unexpected relocation type! %x", type);
370 break;
371 }
372
373 Memory::Write_U32(op, rel_offset);
374 NotifyMemInfo(MemBlockFlags::WRITE, addr, 4, "Relocation2");
375 rcount += 1;
376 }
377 }
378
379 }
380
381
LoadInto(u32 loadAddress,bool fromTop)382 int ElfReader::LoadInto(u32 loadAddress, bool fromTop)
383 {
384 DEBUG_LOG(LOADER,"String section: %i", header->e_shstrndx);
385
386 if (header->e_ident[0] != ELFMAG0 || header->e_ident[1] != ELFMAG1
387 || header->e_ident[2] != ELFMAG2 || header->e_ident[3] != ELFMAG3)
388 return SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE;
389
390 // technically ELFCLASSNONE would freeze the system, but that's not really desireable
391 if (header->e_ident[EI_CLASS] != ELFCLASS32) {
392 if (header->e_ident[EI_CLASS] != 0) {
393 return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
394 }
395
396 ERROR_LOG(LOADER, "Bad ELF, EI_CLASS (fifth byte) is 0x00, should be 0x01 - would lock up a PSP.");
397 }
398
399 if (header->e_ident[EI_DATA] != ELFDATA2LSB)
400 return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
401
402 // e_ident[EI_VERSION] is ignored
403
404 sectionOffsets = new u32[GetNumSections()];
405 sectionAddrs = new u32[GetNumSections()];
406
407 // Should we relocate?
408 bRelocate = (header->e_type != ET_EXEC);
409
410 // Look for the module info - we need to know whether this is kernel or user.
411 const PspModuleInfo *modInfo = 0;
412 for (int i = 0; i < GetNumSections(); i++) {
413 const Elf32_Shdr *s = §ions[i];
414 const char *name = GetSectionName(i);
415 if (name && !strcmp(name, ".rodata.sceModuleInfo")) {
416 modInfo = (const PspModuleInfo *)GetPtr(s->sh_offset);
417 }
418 }
419 if (!modInfo && GetNumSegments() >= 1) {
420 modInfo = (const PspModuleInfo *)GetPtr(segments[0].p_paddr & 0x7FFFFFFF);
421 }
422
423 bool kernelModule = modInfo ? (modInfo->moduleAttrs & 0x1000) != 0 : false;
424
425 std::string modName = "ELF";
426 if (modInfo) {
427 size_t n = strnlen(modInfo->name, 28);
428 modName = "ELF/" + std::string(modInfo->name, n);
429 }
430
431 entryPoint = header->e_entry;
432 u32 totalStart = 0xFFFFFFFF;
433 u32 totalEnd = 0;
434 for (int i = 0; i < header->e_phnum; i++) {
435 const Elf32_Phdr *p = &segments[i];
436 if (p->p_type == PT_LOAD) {
437 if (p->p_vaddr < totalStart) {
438 totalStart = p->p_vaddr;
439 firstSegAlign = p->p_align;
440 }
441 if (p->p_vaddr + p->p_memsz > totalEnd)
442 totalEnd = p->p_vaddr + p->p_memsz;
443 }
444 }
445 totalSize = totalEnd - totalStart;
446
447 // If a load address is specified that's in regular RAM, override kernel module status
448 bool inUser = totalStart >= PSP_GetUserMemoryBase();
449 BlockAllocator &memblock = (kernelModule && !inUser) ? kernelMemory : userMemory;
450
451 if (!bRelocate)
452 {
453 // Binary is prerelocated, load it where the first segment starts
454 vaddr = memblock.AllocAt(totalStart, totalSize, modName.c_str());
455 }
456 else if (loadAddress)
457 {
458 // Binary needs to be relocated: add loadAddress to the binary start address
459 vaddr = memblock.AllocAt(loadAddress + totalStart, totalSize, modName.c_str());
460 }
461 else
462 {
463 // Just put it where there is room
464 vaddr = memblock.Alloc(totalSize, fromTop, modName.c_str());
465 }
466
467 if (vaddr == (u32)-1) {
468 ERROR_LOG_REPORT(LOADER, "Failed to allocate memory for ELF!");
469 return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
470 }
471
472 if (bRelocate) {
473 DEBUG_LOG(LOADER,"Relocatable module");
474 if (entryPoint != (u32)-1)
475 entryPoint += vaddr;
476 } else {
477 DEBUG_LOG(LOADER,"Prerelocated executable");
478 }
479
480 DEBUG_LOG(LOADER,"%i segments:", header->e_phnum);
481
482 // First pass : Get the damn bits into RAM
483 u32 baseAddress = bRelocate ? vaddr : 0;
484
485 for (int i = 0; i < header->e_phnum; i++)
486 {
487 const Elf32_Phdr *p = segments + i;
488 DEBUG_LOG(LOADER, "Type: %08x Vaddr: %08x Filesz: %08x Memsz: %08x ", (int)p->p_type, (u32)p->p_vaddr, (int)p->p_filesz, (int)p->p_memsz);
489
490 if (p->p_type == PT_LOAD)
491 {
492 segmentVAddr[i] = baseAddress + p->p_vaddr;
493 u32 writeAddr = segmentVAddr[i];
494
495 const u8 *src = GetSegmentPtr(i);
496 u8 *dst = Memory::GetPointer(writeAddr);
497 u32 srcSize = p->p_filesz;
498 u32 dstSize = p->p_memsz;
499
500 if (srcSize < dstSize)
501 {
502 memset(dst + srcSize, 0, dstSize - srcSize); //zero out bss
503 NotifyMemInfo(MemBlockFlags::WRITE, writeAddr + srcSize, dstSize - srcSize, "ELFZero");
504 }
505
506 memcpy(dst, src, srcSize);
507 std::string tag = StringFromFormat("ELFLoad/%08x", writeAddr);
508 NotifyMemInfo(MemBlockFlags::WRITE, writeAddr, srcSize, tag.c_str(), tag.size());
509 DEBUG_LOG(LOADER,"Loadable Segment Copied to %08x, size %08x", writeAddr, (u32)p->p_memsz);
510 }
511 }
512 memblock.ListBlocks();
513
514 DEBUG_LOG(LOADER,"%i sections:", header->e_shnum);
515
516 for (int i = 0; i < GetNumSections(); i++)
517 {
518 const Elf32_Shdr *s = §ions[i];
519 const char *name = GetSectionName(i);
520
521 u32 writeAddr = s->sh_addr + baseAddress;
522 sectionOffsets[i] = writeAddr - vaddr;
523 sectionAddrs[i] = writeAddr;
524
525 if (s->sh_flags & SHF_ALLOC)
526 {
527 std::string tag = name && name[0] ? StringFromFormat("ELF/%s", name) : StringFromFormat("ELF/%08x", writeAddr);
528 NotifyMemInfo(MemBlockFlags::SUB_ALLOC, writeAddr, s->sh_size, tag.c_str(), tag.size());
529 DEBUG_LOG(LOADER,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, (u32)s->sh_size);
530 }
531 else
532 {
533 DEBUG_LOG(LOADER,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, (u32)s->sh_size, (u32)s->sh_flags);
534 }
535 }
536
537 DEBUG_LOG(LOADER,"Relocations:");
538
539 // Second pass: Do necessary relocations
540 for (int i = 0; i < GetNumSections(); i++)
541 {
542 const Elf32_Shdr *s = §ions[i];
543 const char *name = GetSectionName(i);
544
545 if (s->sh_type == SHT_PSPREL)
546 {
547 //We have a relocation table!
548 int sectionToModify = s->sh_info;
549 if (sectionToModify >= 0)
550 {
551 if (!(sections[sectionToModify].sh_flags & SHF_ALLOC))
552 {
553 ERROR_LOG_REPORT(LOADER, "Trying to relocate non-loaded section %s", GetSectionName(sectionToModify));
554 continue;
555 }
556
557 int numRelocs = s->sh_size / sizeof(Elf32_Rel);
558
559 Elf32_Rel *rels = (Elf32_Rel *)GetSectionDataPtr(i);
560
561 DEBUG_LOG(LOADER,"%s: Performing %i relocations on %s : offset = %08x", name, numRelocs, GetSectionName(sectionToModify), sections[i].sh_offset);
562 if (!LoadRelocations(rels, numRelocs)) {
563 WARN_LOG(LOADER, "LoadInto: Relocs failed, trying anyway");
564 }
565 }
566 else
567 {
568 WARN_LOG_REPORT(LOADER, "sectionToModify = %i - ignoring PSP relocation sector %i", sectionToModify, i);
569 }
570 }
571 else if (s->sh_type == SHT_REL)
572 {
573 DEBUG_LOG(LOADER, "Traditional relocation section found.");
574 if (!bRelocate)
575 {
576 DEBUG_LOG(LOADER, "Binary is prerelocated. Skipping relocations.");
577 }
578 else
579 {
580 //We have a relocation table!
581 int sectionToModify = s->sh_info;
582 if (sectionToModify >= 0)
583 {
584 if (!(sections[sectionToModify].sh_flags & SHF_ALLOC))
585 {
586 ERROR_LOG_REPORT(LOADER, "Trying to relocate non-loaded section %s, ignoring", GetSectionName(sectionToModify));
587 continue;
588 }
589 }
590 else
591 {
592 WARN_LOG_REPORT(LOADER, "sectionToModify = %i - ignoring relocation sector %i", sectionToModify, i);
593 }
594 ERROR_LOG_REPORT(LOADER, "Traditional relocations unsupported.");
595 }
596 }
597 }
598
599 // Segment relocations (a few games use them)
600 if (GetNumSections() == 0) {
601 for (int i = 0; i < header->e_phnum; i++)
602 {
603 const Elf32_Phdr *p = &segments[i];
604 if (p->p_type == PT_PSPREL1) {
605 INFO_LOG(LOADER,"Loading segment relocations");
606 int numRelocs = p->p_filesz / sizeof(Elf32_Rel);
607
608 Elf32_Rel *rels = (Elf32_Rel *)GetSegmentPtr(i);
609 if (!LoadRelocations(rels, numRelocs)) {
610 ERROR_LOG(LOADER, "LoadInto: Relocs failed, trying anyway (2)");
611 }
612 } else if (p->p_type == PT_PSPREL2) {
613 INFO_LOG(LOADER,"Loading segment relocations2");
614 LoadRelocations2(i);
615 }
616 }
617 }
618
619 return SCE_KERNEL_ERROR_OK;
620 }
621
622
GetSectionByName(const char * name,int firstSection) const623 SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const
624 {
625 if (!name)
626 return -1;
627 for (int i = firstSection; i < header->e_shnum; i++) {
628 const char *secname = GetSectionName(i);
629 if (secname && strcmp(name, secname) == 0) {
630 return i;
631 }
632 }
633 return -1;
634 }
635
GetTotalTextSize() const636 u32 ElfReader::GetTotalTextSize() const {
637 u32 total = 0;
638 for (int i = 0; i < GetNumSections(); ++i) {
639 if (!(sections[i].sh_flags & SHF_WRITE) && (sections[i].sh_flags & SHF_ALLOC) && !(sections[i].sh_flags & SHF_STRINGS)) {
640 total += sections[i].sh_size;
641 }
642 }
643 return total;
644 }
645
GetTotalTextSizeFromSeg() const646 u32 ElfReader::GetTotalTextSizeFromSeg() const {
647 u32 total = 0;
648 for (int i = 0; i < GetNumSegments(); ++i) {
649 if ((segments[i].p_flags & PF_X) != 0) {
650 total += segments[i].p_filesz;
651 }
652 }
653 return total;
654 }
655
GetTotalDataSize() const656 u32 ElfReader::GetTotalDataSize() const {
657 u32 total = 0;
658 for (int i = 0; i < GetNumSections(); ++i) {
659 if ((sections[i].sh_flags & SHF_WRITE) && (sections[i].sh_flags & SHF_ALLOC) && !(sections[i].sh_flags & SHF_MASKPROC)) {
660 total += sections[i].sh_size;
661 }
662 }
663 return total;
664 }
665
GetTotalSectionSizeByPrefix(const std::string & prefix) const666 u32 ElfReader::GetTotalSectionSizeByPrefix(const std::string &prefix) const {
667 u32 total = 0;
668 for (int i = 0; i < GetNumSections(); ++i) {
669 const char *secname = GetSectionName(i);
670 if (secname && !strncmp(secname, prefix.c_str(), prefix.length())) {
671 total += sections[i].sh_size;
672 }
673 }
674 return total;
675 }
676
GetCodeSections() const677 std::vector<SectionID> ElfReader::GetCodeSections() const {
678 std::vector<SectionID> ids;
679 for (int i = 0; i < GetNumSections(); ++i) {
680 u32 flags = sections[i].sh_flags;
681 if ((flags & (SHF_ALLOC | SHF_EXECINSTR)) == (SHF_ALLOC | SHF_EXECINSTR)) {
682 ids.push_back(i);
683 }
684 }
685 return ids;
686 }
687
LoadSymbols()688 bool ElfReader::LoadSymbols()
689 {
690 bool hasSymbols = false;
691 SectionID sec = GetSectionByName(".symtab");
692 if (sec != -1)
693 {
694 int stringSection = sections[sec].sh_link;
695
696 const char *stringBase = (const char*)GetSectionDataPtr(stringSection);
697
698 //We have a symbol table!
699 Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
700
701 int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
702
703 for (int sym = 0; sym<numSymbols; sym++)
704 {
705 int size = symtab[sym].st_size;
706 if (size == 0)
707 continue;
708
709 int bind = symtab[sym].st_info >> 4;
710 int type = symtab[sym].st_info & 0xF;
711 int sectionIndex = symtab[sym].st_shndx;
712 int value = symtab[sym].st_value;
713 const char *name = stringBase + symtab[sym].st_name;
714
715 if (bRelocate)
716 value += sectionAddrs[sectionIndex];
717
718 switch (type)
719 {
720 case STT_OBJECT:
721 g_symbolMap->AddData(value,size,DATATYPE_BYTE);
722 break;
723 case STT_FUNC:
724 g_symbolMap->AddFunction(name,value,size);
725 break;
726 default:
727 continue;
728 }
729 hasSymbols = true;
730 //...
731 }
732 }
733 return hasSymbols;
734 }
735