Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/ELF/ElfReader.cpp
5672 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
DEBUG_LOG(Log::Loader,"String section: %i", header->e_shstrndx);
409
410
if (size_ < sizeof(Elf32_Ehdr)) {
411
ERROR_LOG(Log::Loader, "Truncated ELF header, %d bytes", (int)size_);
412
// Probably not the right error code.
413
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
414
}
415
416
if (header->e_ident[0] != ELFMAG0 || header->e_ident[1] != ELFMAG1
417
|| header->e_ident[2] != ELFMAG2 || header->e_ident[3] != ELFMAG3)
418
return SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE;
419
420
// technically ELFCLASSNONE would freeze the system, but that's not really desireable
421
if (header->e_ident[EI_CLASS] != ELFCLASS32) {
422
if (header->e_ident[EI_CLASS] != 0) {
423
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
424
}
425
426
ERROR_LOG(Log::Loader, "Bad ELF, EI_CLASS (fifth byte) is 0x00, should be 0x01 - would lock up a PSP.");
427
}
428
429
if (header->e_ident[EI_DATA] != ELFDATA2LSB)
430
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
431
432
if (size_ < header->e_phoff + sizeof(Elf32_Phdr) * GetNumSegments() || size_ < header->e_shoff + sizeof(Elf32_Shdr) * GetNumSections()) {
433
ERROR_LOG(Log::Loader, "Truncated ELF, %d bytes with %d sections and %d segments", (int)size_, GetNumSections(), GetNumSegments());
434
// Probably not the right error code.
435
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
436
}
437
438
// e_ident[EI_VERSION] is ignored
439
440
// Should we relocate?
441
bRelocate = (header->e_type != ET_EXEC);
442
443
// Look for the module info - we need to know whether this is kernel or user.
444
const PspModuleInfo *modInfo = 0;
445
for (int i = 0; i < GetNumSections(); i++) {
446
const Elf32_Shdr *s = &sections[i];
447
const char *name = GetSectionName(i);
448
if (name && !strcmp(name, ".rodata.sceModuleInfo") && s->sh_offset + sizeof(PspModuleInfo) <= size_) {
449
modInfo = (const PspModuleInfo *)GetPtr(s->sh_offset);
450
}
451
}
452
if (!modInfo && GetNumSegments() >= 1 && (segments[0].p_paddr & 0x7FFFFFFF) + sizeof(PspModuleInfo) <= size_) {
453
modInfo = (const PspModuleInfo *)GetPtr(segments[0].p_paddr & 0x7FFFFFFF);
454
}
455
456
bool kernelModule = modInfo ? (modInfo->moduleAttrs & 0x1000) != 0 : false;
457
458
std::string modName = "ELF";
459
if (modInfo) {
460
size_t n = strnlen(modInfo->name, 28);
461
modName = "ELF/" + std::string(modInfo->name, n);
462
}
463
464
entryPoint = header->e_entry;
465
u32 totalStart = 0xFFFFFFFF;
466
u32 totalEnd = 0;
467
for (int i = 0; i < header->e_phnum; i++) {
468
const Elf32_Phdr *p = &segments[i];
469
if (p->p_type == PT_LOAD) {
470
if (p->p_vaddr < totalStart) {
471
totalStart = p->p_vaddr;
472
firstSegAlign = p->p_align;
473
}
474
if (p->p_vaddr + p->p_memsz > totalEnd)
475
totalEnd = p->p_vaddr + p->p_memsz;
476
}
477
}
478
totalSize = totalEnd - totalStart;
479
480
// If a load address is specified that's in regular RAM, override kernel module status
481
bool inUser = totalStart >= PSP_GetUserMemoryBase();
482
BlockAllocator &memblock = (kernelModule && !inUser) ? kernelMemory : userMemory;
483
484
if (!bRelocate)
485
{
486
// Binary is prerelocated, load it where the first segment starts
487
vaddr = memblock.AllocAt(totalStart, totalSize, modName.c_str());
488
}
489
else if (loadAddress)
490
{
491
// Binary needs to be relocated: add loadAddress to the binary start address
492
vaddr = memblock.AllocAt(loadAddress + totalStart, totalSize, modName.c_str());
493
}
494
else
495
{
496
// Just put it where there is room
497
vaddr = memblock.Alloc(totalSize, fromTop, modName.c_str());
498
}
499
500
if (vaddr == (u32)-1) {
501
ERROR_LOG(Log::Loader, "Failed to allocate memory for ELF!");
502
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
503
}
504
505
if (bRelocate) {
506
DEBUG_LOG(Log::Loader,"Relocatable module");
507
if (entryPoint != (u32)-1)
508
entryPoint += vaddr;
509
} else {
510
DEBUG_LOG(Log::Loader,"Prerelocated executable");
511
}
512
513
DEBUG_LOG(Log::Loader,"%i segments:", header->e_phnum);
514
515
// First pass: Get the bits into RAM
516
u32 baseAddress = bRelocate ? vaddr : 0;
517
518
for (int i = 0; i < header->e_phnum; i++)
519
{
520
const Elf32_Phdr *p = segments + i;
521
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);
522
523
if (p->p_type == PT_LOAD)
524
{
525
segmentVAddr[i] = baseAddress + p->p_vaddr;
526
const u32 writeAddr = segmentVAddr[i];
527
528
const u8 *src = GetSegmentPtr(i);
529
if (!src) {
530
ERROR_LOG(Log::Loader, "Segment %d pointer invalid?", i);
531
continue;
532
}
533
if (p->p_filesz > size_) {
534
ERROR_LOG(Log::Loader, "Segment %d size invalid", i);
535
continue;
536
}
537
if ((s64)p->p_filesz + (s64)p->p_offset > (s64)size_) {
538
ERROR_LOG(Log::Loader, "Segment %d size+offset invalid, reading outside the input", i);
539
continue;
540
}
541
if (p->p_filesz > p->p_memsz) {
542
ERROR_LOG(Log::Loader, "Segment %d filesz invalid - bigger than memsz", i);
543
continue;
544
}
545
const u32 srcSize = p->p_filesz;
546
const u32 dstSize = p->p_memsz; // can be bigger than size-in-file (p_filesz), we'll zero the rest below. But cannot be smaller!
547
u8 *dst = Memory::GetPointerWriteRange(writeAddr, dstSize);
548
if (dst) {
549
if (srcSize < dstSize) {
550
memset(dst + srcSize, 0, dstSize - srcSize); // zero out the rest of the segment, this also applies to bss (which is all-zero)
551
NotifyMemInfo(MemBlockFlags::WRITE, writeAddr + srcSize, dstSize - srcSize, "ELFZero");
552
}
553
554
memcpy(dst, src, srcSize);
555
std::string tag = StringFromFormat("ELFLoad/%08x", writeAddr);
556
NotifyMemInfo(MemBlockFlags::WRITE, writeAddr, srcSize, tag.c_str(), tag.size());
557
DEBUG_LOG(Log::Loader, "Loadable Segment Copied to %08x, size %08x", writeAddr, (u32)p->p_memsz);
558
} else {
559
ERROR_LOG(Log::Loader, "Bad ELF segment. Trying to write %d bytes to %08x", dstSize, writeAddr);
560
}
561
}
562
}
563
memblock.ListBlocks();
564
565
DEBUG_LOG(Log::Loader, "%d sections:", header->e_shnum);
566
567
sectionOffsets = new u32[GetNumSections()];
568
sectionAddrs = new u32[GetNumSections()];
569
570
for (int i = 0; i < GetNumSections(); i++)
571
{
572
const Elf32_Shdr *s = &sections[i];
573
const char *name = GetSectionName(i);
574
575
u32 writeAddr = s->sh_addr + baseAddress;
576
sectionOffsets[i] = writeAddr - vaddr;
577
sectionAddrs[i] = writeAddr;
578
579
if (s->sh_flags & SHF_ALLOC)
580
{
581
std::string tag = name && name[0] ? StringFromFormat("%s/%s", modName.c_str(), name) : StringFromFormat("%s/%08x", modName.c_str(), writeAddr);
582
NotifyMemInfo(MemBlockFlags::SUB_ALLOC, writeAddr, s->sh_size, tag.c_str(), tag.size());
583
DEBUG_LOG(Log::Loader,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, (u32)s->sh_size);
584
}
585
else
586
{
587
DEBUG_LOG(Log::Loader,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, (u32)s->sh_size, (u32)s->sh_flags);
588
}
589
}
590
591
DEBUG_LOG(Log::Loader, "Relocations:");
592
593
// Second pass: Do necessary relocations
594
595
for (int i = 0; i < GetNumSections(); i++)
596
{
597
const Elf32_Shdr *s = &sections[i];
598
const char *name = GetSectionName(i);
599
600
if (s->sh_type == SHT_PSPREL)
601
{
602
//We have a relocation table!
603
int sectionToModify = s->sh_info;
604
if (sectionToModify >= 0)
605
{
606
if (!(sections[sectionToModify].sh_flags & SHF_ALLOC))
607
{
608
ERROR_LOG_REPORT(Log::Loader, "Trying to relocate non-loaded section %s", GetSectionName(sectionToModify));
609
continue;
610
}
611
612
int numRelocs = s->sh_size / sizeof(Elf32_Rel);
613
614
Elf32_Rel *rels = (Elf32_Rel *)GetSectionDataPtr(i);
615
if (GetSectionDataOffset(i) + sizeof(Elf32_Rel) * numRelocs > size_)
616
rels = nullptr;
617
618
DEBUG_LOG(Log::Loader,"%s: Performing %i relocations on %s : offset = %08x", name, numRelocs, GetSectionName(sectionToModify), sections[i].sh_offset);
619
if (!rels || !LoadRelocations(rels, numRelocs)) {
620
WARN_LOG(Log::Loader, "LoadInto: Relocs failed, trying anyway");
621
}
622
}
623
else
624
{
625
WARN_LOG_REPORT(Log::Loader, "sectionToModify = %i - ignoring PSP relocation sector %i", sectionToModify, i);
626
}
627
}
628
else if (s->sh_type == SHT_REL)
629
{
630
DEBUG_LOG(Log::Loader, "Traditional relocation section found.");
631
if (!bRelocate)
632
{
633
DEBUG_LOG(Log::Loader, "Binary is prerelocated. Skipping relocations.");
634
}
635
else
636
{
637
//We have a relocation table!
638
int sectionToModify = s->sh_info;
639
if (sectionToModify >= 0)
640
{
641
if (!(sections[sectionToModify].sh_flags & SHF_ALLOC))
642
{
643
// Generally stuff like debug info. We don't need it.
644
INFO_LOG(Log::Loader, "Skipping relocation of non-loaded section %s", GetSectionName(sectionToModify));
645
continue;
646
}
647
}
648
else
649
{
650
WARN_LOG_REPORT(Log::Loader, "sectionToModify = %i - ignoring relocation sector %i", sectionToModify, i);
651
}
652
ERROR_LOG_REPORT(Log::Loader, "Traditional relocations unsupported.");
653
}
654
}
655
}
656
657
// Segment relocations (a few games use them)
658
if (GetNumSections() == 0) {
659
for (int i = 0; i < header->e_phnum; i++)
660
{
661
const Elf32_Phdr *p = &segments[i];
662
if (p->p_type == PT_PSPREL1) {
663
INFO_LOG(Log::Loader,"Loading segment relocations");
664
int numRelocs = p->p_filesz / sizeof(Elf32_Rel);
665
666
Elf32_Rel *rels = (Elf32_Rel *)GetSegmentPtr(i);
667
if (p->p_offset + p->p_filesz > size_)
668
rels = nullptr;
669
if (!rels || !LoadRelocations(rels, numRelocs)) {
670
ERROR_LOG(Log::Loader, "LoadInto: Relocs failed, trying anyway (2)");
671
}
672
} else if (p->p_type == PT_PSPREL2) {
673
INFO_LOG(Log::Loader,"Loading segment relocations2");
674
LoadRelocations2(i);
675
}
676
}
677
}
678
679
return SCE_KERNEL_ERROR_OK;
680
}
681
682
683
SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const
684
{
685
if (!name)
686
return -1;
687
for (int i = firstSection; i < header->e_shnum; i++) {
688
const char *secname = GetSectionName(i);
689
if (secname && strcmp(name, secname) == 0) {
690
return i;
691
}
692
}
693
return -1;
694
}
695
696
u32 ElfReader::GetTotalTextSize() const {
697
u32 total = 0;
698
for (int i = 0; i < GetNumSections(); ++i) {
699
if (!(sections[i].sh_flags & SHF_WRITE) && (sections[i].sh_flags & SHF_ALLOC) && !(sections[i].sh_flags & SHF_STRINGS)) {
700
total += sections[i].sh_size;
701
}
702
}
703
return total;
704
}
705
706
u32 ElfReader::GetTotalTextSizeFromSeg() const {
707
u32 total = 0;
708
for (int i = 0; i < GetNumSegments(); ++i) {
709
if ((segments[i].p_flags & PF_X) != 0) {
710
total += segments[i].p_filesz;
711
}
712
}
713
return total;
714
}
715
716
u32 ElfReader::GetTotalDataSize() const {
717
u32 total = 0;
718
for (int i = 0; i < GetNumSections(); ++i) {
719
if ((sections[i].sh_flags & SHF_WRITE) && (sections[i].sh_flags & SHF_ALLOC) && !(sections[i].sh_flags & SHF_MASKPROC)) {
720
total += sections[i].sh_size;
721
}
722
}
723
return total;
724
}
725
726
u32 ElfReader::GetTotalSectionSizeByPrefix(const std::string &prefix) const {
727
u32 total = 0;
728
for (int i = 0; i < GetNumSections(); ++i) {
729
const char *secname = GetSectionName(i);
730
if (secname && !strncmp(secname, prefix.c_str(), prefix.length())) {
731
total += sections[i].sh_size;
732
}
733
}
734
return total;
735
}
736
737
std::vector<SectionID> ElfReader::GetCodeSections() const {
738
std::vector<SectionID> ids;
739
for (int i = 0; i < GetNumSections(); ++i) {
740
u32 flags = sections[i].sh_flags;
741
if ((flags & (SHF_ALLOC | SHF_EXECINSTR)) == (SHF_ALLOC | SHF_EXECINSTR)) {
742
ids.push_back(i);
743
}
744
}
745
return ids;
746
}
747
748
bool ElfReader::LoadSymbols()
749
{
750
bool hasSymbols = false;
751
SectionID sec = GetSectionByName(".symtab");
752
if (sec != -1)
753
{
754
int stringSection = sections[sec].sh_link;
755
756
const char *stringBase = (const char*)GetSectionDataPtr(stringSection);
757
u32 stringOffset = GetSectionDataOffset(stringSection);
758
759
//We have a symbol table!
760
Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
761
u32 symtabOffset = GetSectionDataOffset(sec);
762
763
int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
764
if (!stringBase || !symtab || symtabOffset + sections[sec].sh_size > size_) {
765
ERROR_LOG(Log::Loader, "Symbols truncated - ignoring");
766
return false;
767
}
768
769
for (int sym = 0; sym<numSymbols; sym++)
770
{
771
int size = symtab[sym].st_size;
772
if (size == 0)
773
continue;
774
775
int bind = symtab[sym].st_info >> 4;
776
int type = symtab[sym].st_info & 0xF;
777
int sectionIndex = symtab[sym].st_shndx;
778
int value = symtab[sym].st_value;
779
const char *name = stringBase + symtab[sym].st_name;
780
if (stringOffset + symtab[sym].st_name >= size_)
781
continue;
782
783
if (bRelocate)
784
value += sectionAddrs[sectionIndex];
785
786
switch (type)
787
{
788
case STT_OBJECT:
789
g_symbolMap->AddData(value,size,DATATYPE_BYTE);
790
break;
791
case STT_FUNC:
792
g_symbolMap->AddFunction(name,value,size);
793
break;
794
default:
795
continue;
796
}
797
hasSymbols = true;
798
//...
799
}
800
}
801
return hasSymbols;
802
}
803
804