CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/ELF/ElfReader.cpp
Views: 1401
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
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
ParallelRangeLoop(&g_threadManager, [&](int l, int h) {
72
for (int r = l; r < h; 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
relocOps[r] = Memory::ReadUnchecked_Instruction(addr, true).encoding;
102
}
103
}, 0, numRelocs, 128, TaskPriority::HIGH);
104
105
ParallelRangeLoop(&g_threadManager, [&](int l, int h) {
106
for (int r = l; r < h; 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
ERROR_LOG_REPORT(Log::Loader, "ELF relocation HI16/%d pair (instead of LO16) at %08x / %08x", t_type, addr, corrLoAddr);
169
continue;
170
} else {
171
WARN_LOG_REPORT(Log::Loader, "ELF relocation HI16/%d(16) pair (instead of LO16) at %08x / %08x", t_type, addr, corrLoAddr);
172
}
173
}
174
175
// Should have matching index and segment info, according to llvm, which makes sense.
176
if ((rels[t].r_info >> 8) != (rels[r].r_info >> 8)) {
177
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);
178
}
179
if (log) {
180
DEBUG_LOG(Log::Loader, "Corresponding lo found at %08x", corrLoAddr);
181
}
182
if (Memory::IsValidAddress(corrLoAddr)) {
183
s16 lo = (s16)relocOps[t];
184
cur += lo;
185
cur += relocateTo;
186
addrToHiLo(cur, hi, lo);
187
found = true;
188
break;
189
} else {
190
ERROR_LOG(Log::Loader, "Bad corrLoAddr %08x", corrLoAddr);
191
}
192
}
193
if (!found) {
194
ERROR_LOG_REPORT(Log::Loader, "R_MIPS_HI16: could not find R_MIPS_LO16 (r=%d of %d, addr=%08x)", r, numRelocs, addr);
195
}
196
op = (op & 0xFFFF0000) | hi;
197
}
198
break;
199
200
case R_MIPS_LO16: //addiu part of lui-addiu pairs
201
{
202
if (log)
203
DEBUG_LOG(Log::Loader, "LO reloc %08x", addr);
204
u32 cur = op & 0xFFFF;
205
cur += relocateTo;
206
cur &= 0xFFFF;
207
op = (op & 0xFFFF0000) | cur;
208
}
209
break;
210
211
case R_MIPS_GPREL16: //gp
212
// It seems safe to ignore this, almost a notification of a gp-relative operation?
213
break;
214
215
case R_MIPS_16:
216
op = (op & 0xFFFF0000) | (((int)(op & 0xFFFF) + (int)relocateTo) & 0xFFFF);
217
break;
218
219
case R_MIPS_NONE:
220
// This shouldn't matter, not sure the purpose of it.
221
break;
222
223
default:
224
{
225
char temp[256];
226
MIPSDisAsm(MIPSOpcode(op), 0, temp, sizeof(temp));
227
ERROR_LOG_REPORT(Log::Loader, "ARGH IT'S AN UNKNOWN RELOCATION!!!!!!!! %08x, type=%d : %s", addr, type, temp);
228
}
229
break;
230
}
231
232
Memory::WriteUnchecked_U32(op, addr);
233
NotifyMemInfo(MemBlockFlags::WRITE, addr, 4, "Relocation");
234
}
235
}, 0, numRelocs, 128, TaskPriority::HIGH);
236
237
if (numErrors) {
238
WARN_LOG(Log::Loader, "%i bad relocations found!!!", numErrors.load());
239
}
240
return numErrors == 0;
241
}
242
243
244
void ElfReader::LoadRelocations2(int rel_seg)
245
{
246
u8 *buf, *end, *flag_table, *type_table;
247
int flag_table_size, type_table_size;
248
int flag_bits, seg_bits, type_bits;
249
int cmd, flag, seg, type;
250
int off_seg = 0, addr_seg, rel_base, rel_offset;
251
int relocate_to, last_type, lo16 = 0;
252
u32 op, addr;
253
int rcount = 0;
254
255
const Elf32_Phdr *ph = segments + rel_seg;
256
257
buf = (u8*)GetSegmentPtr(rel_seg);
258
if (!buf) {
259
ERROR_LOG_REPORT(Log::Loader, "Rel2 segment invalid");
260
return;
261
}
262
end = buf+ph->p_filesz;
263
264
flag_bits = buf[2];
265
type_bits = buf[3];
266
267
seg_bits = 1;
268
while((1<<seg_bits)<rel_seg)
269
seg_bits += 1;
270
271
buf += 4;
272
273
flag_table = buf;
274
flag_table_size = flag_table[0];
275
buf += flag_table_size;
276
277
type_table = buf;
278
type_table_size = type_table[0];
279
buf += type_table_size;
280
281
rel_base = 0;
282
last_type = -1;
283
while(buf<end){
284
cmd = *(u16*)(buf);
285
buf += 2;
286
287
flag = ( cmd<<(16-flag_bits))&0xffff;
288
flag = (flag>>(16-flag_bits))&0xffff;
289
flag = flag_table[flag];
290
291
seg = (cmd<<(16-seg_bits-flag_bits))&0xffff;
292
seg = (seg>>(16-seg_bits))&0xffff;
293
294
type = ( cmd<<(16-type_bits-seg_bits-flag_bits))&0xffff;
295
type = (type>>(16-type_bits))&0xffff;
296
type = type_table[type];
297
298
if((flag&0x01)==0){
299
off_seg = seg;
300
if((flag&0x06)==0){
301
rel_base = cmd>>(seg_bits+flag_bits);
302
}else if((flag&0x06)==4){
303
rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);
304
buf += 4;
305
}else{
306
ERROR_LOG_REPORT(Log::Loader, "Rel2: invalid size flag! %x", flag);
307
rel_base = 0;
308
}
309
}else{
310
addr_seg = seg;
311
relocate_to = addr_seg >= (int)ARRAY_SIZE(segmentVAddr) ? 0 : segmentVAddr[addr_seg];
312
if (!Memory::IsValidAddress(relocate_to)) {
313
ERROR_LOG_REPORT(Log::Loader, "ELF: Bad address to relocate to: %08x (segment %d)", relocate_to, addr_seg);
314
continue;
315
}
316
317
if((flag&0x06)==0x00){
318
rel_offset = cmd;
319
if(cmd&0x8000){
320
rel_offset |= 0xffff0000;
321
rel_offset >>= type_bits+seg_bits+flag_bits;
322
rel_offset |= 0xffff0000;
323
}else{
324
rel_offset >>= type_bits+seg_bits+flag_bits;
325
}
326
rel_base += rel_offset;
327
}else if((flag&0x06)==0x02){
328
rel_offset = cmd;
329
if(cmd&0x8000)
330
rel_offset |= 0xffff0000;
331
rel_offset >>= type_bits+seg_bits+flag_bits;
332
rel_offset = (rel_offset<<16) | (buf[0]) | (buf[1]<<8);
333
buf += 2;
334
rel_base += rel_offset;
335
}else if((flag&0x06)==0x04){
336
rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);
337
buf += 4;
338
}else{
339
ERROR_LOG_REPORT(Log::Loader, "Rel2: invalid relocat size flag! %x", flag);
340
}
341
342
343
rel_offset = rel_base+segmentVAddr[off_seg];
344
if (!Memory::IsValidAddress(rel_offset)) {
345
ERROR_LOG_REPORT(Log::Loader, "ELF: Bad rel_offset: %08x", rel_offset);
346
continue;
347
}
348
349
if((flag&0x38)==0x00){
350
lo16 = 0;
351
}else if((flag&0x38)==0x08){
352
if(last_type!=0x04)
353
lo16 = 0;
354
}else if((flag&0x38)==0x10){
355
lo16 = (buf[0]) | (buf[1]<<8);
356
if(lo16&0x8000)
357
lo16 |= 0xffff0000;
358
buf += 2;
359
}else{
360
ERROR_LOG_REPORT(Log::Loader, "Rel2: invalid lo16 type! %x", flag);
361
}
362
363
op = Memory::Read_Instruction(rel_offset, true).encoding;
364
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);
365
366
switch(type){
367
case 0:
368
continue;
369
case 2: // R_MIPS_32
370
op += relocate_to;
371
break;
372
case 3: // R_MIPS_26
373
case 6: // R_MIPS_J26
374
case 7: // R_MIPS_JAL26
375
op = (op&0xFC000000) | (((op&0x03FFFFFF)+(relocate_to>>2))&0x03FFFFFF);
376
// To be safe, let's force it to the specified jump.
377
if (type == 6)
378
op = (op & ~0xFC000000) | 0x08000000;
379
else if (type == 7)
380
op = (op & ~0xFC000000) | 0x0C000000;
381
break;
382
case 4: // R_MIPS_HI16
383
addr = ((op<<16)+lo16)+relocate_to;
384
if(addr&0x8000)
385
addr += 0x00010000;
386
op = (op&0xffff0000) | (addr>>16 );
387
break;
388
case 1:
389
case 5: // R_MIPS_LO16
390
op = (op&0xffff0000) | (((op&0xffff)+relocate_to)&0xffff);
391
break;
392
default:
393
ERROR_LOG_REPORT(Log::Loader, "Rel2: unexpected relocation type! %x", type);
394
break;
395
}
396
397
Memory::Write_U32(op, rel_offset);
398
NotifyMemInfo(MemBlockFlags::WRITE, rel_offset, 4, "Relocation2");
399
rcount += 1;
400
}
401
}
402
403
}
404
405
406
int ElfReader::LoadInto(u32 loadAddress, bool fromTop)
407
{
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_REPORT(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 damn 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
u32 writeAddr = segmentVAddr[i];
527
528
const u8 *src = GetSegmentPtr(i);
529
if (!src || p->p_offset + p->p_filesz > size_) {
530
ERROR_LOG(Log::Loader, "Segment %d pointer invalid - truncated?", i);
531
continue;
532
}
533
u32 srcSize = p->p_filesz;
534
u32 dstSize = p->p_memsz;
535
u8 *dst = Memory::GetPointerWriteRange(writeAddr, dstSize);
536
if (dst) {
537
if (srcSize < dstSize) {
538
memset(dst + srcSize, 0, dstSize - srcSize); //zero out bss
539
NotifyMemInfo(MemBlockFlags::WRITE, writeAddr + srcSize, dstSize - srcSize, "ELFZero");
540
}
541
542
memcpy(dst, src, srcSize);
543
std::string tag = StringFromFormat("ELFLoad/%08x", writeAddr);
544
NotifyMemInfo(MemBlockFlags::WRITE, writeAddr, srcSize, tag.c_str(), tag.size());
545
DEBUG_LOG(Log::Loader, "Loadable Segment Copied to %08x, size %08x", writeAddr, (u32)p->p_memsz);
546
} else {
547
ERROR_LOG(Log::Loader, "Bad ELF segment. Trying to write %d bytes to %08x", dstSize, writeAddr);
548
}
549
}
550
}
551
memblock.ListBlocks();
552
553
DEBUG_LOG(Log::Loader,"%i sections:", header->e_shnum);
554
555
sectionOffsets = new u32[GetNumSections()];
556
sectionAddrs = new u32[GetNumSections()];
557
558
for (int i = 0; i < GetNumSections(); i++)
559
{
560
const Elf32_Shdr *s = &sections[i];
561
const char *name = GetSectionName(i);
562
563
u32 writeAddr = s->sh_addr + baseAddress;
564
sectionOffsets[i] = writeAddr - vaddr;
565
sectionAddrs[i] = writeAddr;
566
567
if (s->sh_flags & SHF_ALLOC)
568
{
569
std::string tag = name && name[0] ? StringFromFormat("%s/%s", modName.c_str(), name) : StringFromFormat("%s/%08x", modName.c_str(), writeAddr);
570
NotifyMemInfo(MemBlockFlags::SUB_ALLOC, writeAddr, s->sh_size, tag.c_str(), tag.size());
571
DEBUG_LOG(Log::Loader,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, (u32)s->sh_size);
572
}
573
else
574
{
575
DEBUG_LOG(Log::Loader,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, (u32)s->sh_size, (u32)s->sh_flags);
576
}
577
}
578
579
DEBUG_LOG(Log::Loader, "Relocations:");
580
581
// Second pass: Do necessary relocations
582
for (int i = 0; i < GetNumSections(); i++)
583
{
584
const Elf32_Shdr *s = &sections[i];
585
const char *name = GetSectionName(i);
586
587
if (s->sh_type == SHT_PSPREL)
588
{
589
//We have a relocation table!
590
int sectionToModify = s->sh_info;
591
if (sectionToModify >= 0)
592
{
593
if (!(sections[sectionToModify].sh_flags & SHF_ALLOC))
594
{
595
ERROR_LOG_REPORT(Log::Loader, "Trying to relocate non-loaded section %s", GetSectionName(sectionToModify));
596
continue;
597
}
598
599
int numRelocs = s->sh_size / sizeof(Elf32_Rel);
600
601
Elf32_Rel *rels = (Elf32_Rel *)GetSectionDataPtr(i);
602
if (GetSectionDataOffset(i) + sizeof(Elf32_Rel) * numRelocs > size_)
603
rels = nullptr;
604
605
DEBUG_LOG(Log::Loader,"%s: Performing %i relocations on %s : offset = %08x", name, numRelocs, GetSectionName(sectionToModify), sections[i].sh_offset);
606
if (!rels || !LoadRelocations(rels, numRelocs)) {
607
WARN_LOG(Log::Loader, "LoadInto: Relocs failed, trying anyway");
608
}
609
}
610
else
611
{
612
WARN_LOG_REPORT(Log::Loader, "sectionToModify = %i - ignoring PSP relocation sector %i", sectionToModify, i);
613
}
614
}
615
else if (s->sh_type == SHT_REL)
616
{
617
DEBUG_LOG(Log::Loader, "Traditional relocation section found.");
618
if (!bRelocate)
619
{
620
DEBUG_LOG(Log::Loader, "Binary is prerelocated. Skipping relocations.");
621
}
622
else
623
{
624
//We have a relocation table!
625
int sectionToModify = s->sh_info;
626
if (sectionToModify >= 0)
627
{
628
if (!(sections[sectionToModify].sh_flags & SHF_ALLOC))
629
{
630
// Generally stuff like debug info. We don't need it.
631
INFO_LOG(Log::Loader, "Skipping relocation of non-loaded section %s", GetSectionName(sectionToModify));
632
continue;
633
}
634
}
635
else
636
{
637
WARN_LOG_REPORT(Log::Loader, "sectionToModify = %i - ignoring relocation sector %i", sectionToModify, i);
638
}
639
ERROR_LOG_REPORT(Log::Loader, "Traditional relocations unsupported.");
640
}
641
}
642
}
643
644
// Segment relocations (a few games use them)
645
if (GetNumSections() == 0) {
646
for (int i = 0; i < header->e_phnum; i++)
647
{
648
const Elf32_Phdr *p = &segments[i];
649
if (p->p_type == PT_PSPREL1) {
650
INFO_LOG(Log::Loader,"Loading segment relocations");
651
int numRelocs = p->p_filesz / sizeof(Elf32_Rel);
652
653
Elf32_Rel *rels = (Elf32_Rel *)GetSegmentPtr(i);
654
if (p->p_offset + p->p_filesz > size_)
655
rels = nullptr;
656
if (!rels || !LoadRelocations(rels, numRelocs)) {
657
ERROR_LOG(Log::Loader, "LoadInto: Relocs failed, trying anyway (2)");
658
}
659
} else if (p->p_type == PT_PSPREL2) {
660
INFO_LOG(Log::Loader,"Loading segment relocations2");
661
LoadRelocations2(i);
662
}
663
}
664
}
665
666
return SCE_KERNEL_ERROR_OK;
667
}
668
669
670
SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const
671
{
672
if (!name)
673
return -1;
674
for (int i = firstSection; i < header->e_shnum; i++) {
675
const char *secname = GetSectionName(i);
676
if (secname && strcmp(name, secname) == 0) {
677
return i;
678
}
679
}
680
return -1;
681
}
682
683
u32 ElfReader::GetTotalTextSize() const {
684
u32 total = 0;
685
for (int i = 0; i < GetNumSections(); ++i) {
686
if (!(sections[i].sh_flags & SHF_WRITE) && (sections[i].sh_flags & SHF_ALLOC) && !(sections[i].sh_flags & SHF_STRINGS)) {
687
total += sections[i].sh_size;
688
}
689
}
690
return total;
691
}
692
693
u32 ElfReader::GetTotalTextSizeFromSeg() const {
694
u32 total = 0;
695
for (int i = 0; i < GetNumSegments(); ++i) {
696
if ((segments[i].p_flags & PF_X) != 0) {
697
total += segments[i].p_filesz;
698
}
699
}
700
return total;
701
}
702
703
u32 ElfReader::GetTotalDataSize() const {
704
u32 total = 0;
705
for (int i = 0; i < GetNumSections(); ++i) {
706
if ((sections[i].sh_flags & SHF_WRITE) && (sections[i].sh_flags & SHF_ALLOC) && !(sections[i].sh_flags & SHF_MASKPROC)) {
707
total += sections[i].sh_size;
708
}
709
}
710
return total;
711
}
712
713
u32 ElfReader::GetTotalSectionSizeByPrefix(const std::string &prefix) const {
714
u32 total = 0;
715
for (int i = 0; i < GetNumSections(); ++i) {
716
const char *secname = GetSectionName(i);
717
if (secname && !strncmp(secname, prefix.c_str(), prefix.length())) {
718
total += sections[i].sh_size;
719
}
720
}
721
return total;
722
}
723
724
std::vector<SectionID> ElfReader::GetCodeSections() const {
725
std::vector<SectionID> ids;
726
for (int i = 0; i < GetNumSections(); ++i) {
727
u32 flags = sections[i].sh_flags;
728
if ((flags & (SHF_ALLOC | SHF_EXECINSTR)) == (SHF_ALLOC | SHF_EXECINSTR)) {
729
ids.push_back(i);
730
}
731
}
732
return ids;
733
}
734
735
bool ElfReader::LoadSymbols()
736
{
737
bool hasSymbols = false;
738
SectionID sec = GetSectionByName(".symtab");
739
if (sec != -1)
740
{
741
int stringSection = sections[sec].sh_link;
742
743
const char *stringBase = (const char*)GetSectionDataPtr(stringSection);
744
u32 stringOffset = GetSectionDataOffset(stringSection);
745
746
//We have a symbol table!
747
Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
748
u32 symtabOffset = GetSectionDataOffset(sec);
749
750
int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
751
if (!stringBase || !symtab || symtabOffset + sections[sec].sh_size > size_) {
752
ERROR_LOG(Log::Loader, "Symbols truncated - ignoring");
753
return false;
754
}
755
756
for (int sym = 0; sym<numSymbols; sym++)
757
{
758
int size = symtab[sym].st_size;
759
if (size == 0)
760
continue;
761
762
int bind = symtab[sym].st_info >> 4;
763
int type = symtab[sym].st_info & 0xF;
764
int sectionIndex = symtab[sym].st_shndx;
765
int value = symtab[sym].st_value;
766
const char *name = stringBase + symtab[sym].st_name;
767
if (stringOffset + symtab[sym].st_name >= size_)
768
continue;
769
770
if (bRelocate)
771
value += sectionAddrs[sectionIndex];
772
773
switch (type)
774
{
775
case STT_OBJECT:
776
g_symbolMap->AddData(value,size,DATATYPE_BYTE);
777
break;
778
case STT_FUNC:
779
g_symbolMap->AddFunction(name,value,size);
780
break;
781
default:
782
continue;
783
}
784
hasSymbols = true;
785
//...
786
}
787
}
788
return hasSymbols;
789
}
790
791