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