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 = &sections[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 = &sections[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 = &sections[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