CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/ELF/ElfReader.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <atomic>1819#include "Common/StringUtils.h"20#include "Common/Thread/ParallelLoop.h"2122#include "Core/MemMap.h"23#include "Core/Reporting.h"24#include "Core/ThreadPools.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/sceKernelMemory.h"30#include "Core/HLE/sceKernelModule.h"3132const char *ElfReader::GetSectionName(int section) const {33if (sections[section].sh_type == SHT_NULL)34return nullptr;3536int stringsOffset = GetSectionDataOffset(header->e_shstrndx);37int nameOffset = sections[section].sh_name;38if (nameOffset < 0 || (size_t)nameOffset + stringsOffset >= size_) {39ERROR_LOG(Log::Loader, "ELF: Bad name offset %d + %d in section %d (max = %d)", nameOffset, stringsOffset, section, (int)size_);40return nullptr;41}42const char *ptr = (const char *)GetSectionDataPtr(header->e_shstrndx);4344if (ptr)45return ptr + nameOffset;46else47return nullptr;48}4950void addrToHiLo(u32 addr, u16 &hi, s16 &lo)51{52lo = (addr & 0xFFFF);53u32 naddr = addr - lo;54hi = naddr>>16;55u32 test = (hi<<16) + lo;56if (test != addr)57{58WARN_LOG_REPORT(Log::Loader, "HI16/LO16 relocation failure?");59}60}6162bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) {63std::vector<u32> relocOps;64relocOps.resize(numRelocs);6566DEBUG_LOG(Log::Loader, "Loading %i relocations...", numRelocs);67std::atomic<int> numErrors;68numErrors.store(0);6970ParallelRangeLoop(&g_threadManager, [&](int l, int h) {71for (int r = l; r < h; r++) {72u32 info = rels[r].r_info;73u32 addr = rels[r].r_offset;7475int type = info & 0xf;7677// Often: 0 = code, 1 = data.78int readwrite = (info >> 8) & 0xff;79if (readwrite >= (int)ARRAY_SIZE(segmentVAddr)) {80if (numErrors < 10) {81ERROR_LOG_REPORT(Log::Loader, "Bad segment number %i", readwrite);82}83numErrors++;84continue;85}8687addr += segmentVAddr[readwrite];8889// It appears that misaligned relocations are allowed.90if (((addr & 3) && type != R_MIPS_32) || !Memory::IsValidAddress(addr)) {91if (numErrors < 10) {92WARN_LOG_REPORT(Log::Loader, "Suspicious address %08x, skipping reloc, type = %d", addr, type);93} else if (numErrors == 10) {94WARN_LOG(Log::Loader, "Too many bad relocations, skipping logging");95}96numErrors++;97continue;98}99100relocOps[r] = Memory::ReadUnchecked_Instruction(addr, true).encoding;101}102}, 0, numRelocs, 128, TaskPriority::HIGH);103104ParallelRangeLoop(&g_threadManager, [&](int l, int h) {105for (int r = l; r < h; r++) {106VERBOSE_LOG(Log::Loader, "Loading reloc %i (%p)...", r, rels + r);107u32 info = rels[r].r_info;108u32 addr = rels[r].r_offset;109110int type = info & 0xf;111int readwrite = (info >> 8) & 0xff;112int relative = (info >> 16) & 0xff;113114if (readwrite >= (int)ARRAY_SIZE(segmentVAddr)) {115continue;116}117118addr += segmentVAddr[readwrite];119if (((addr & 3) && type != R_MIPS_32) || !Memory::IsValidAddress(addr)) {120continue;121}122123u32 op = relocOps[r];124125const bool log = false;126//log=true;127if (log) {128DEBUG_LOG(Log::Loader, "rel at: %08x info: %08x type: %i", addr, info, type);129}130u32 relocateTo = relative >= (int)ARRAY_SIZE(segmentVAddr) ? 0 : segmentVAddr[relative];131132switch (type) {133case R_MIPS_32:134if (log)135DEBUG_LOG(Log::Loader, "Full address reloc %08x", addr);136//full address, no problemo137op += relocateTo;138break;139140case R_MIPS_26: //j, jal141//add on to put in correct address space142if (log)143DEBUG_LOG(Log::Loader, "j/jal reloc %08x", addr);144op = (op & 0xFC000000) | (((op & 0x03FFFFFF) + (relocateTo >> 2)) & 0x03FFFFFF);145break;146147case R_MIPS_HI16: //lui part of lui-addiu pairs148{149if (log)150DEBUG_LOG(Log::Loader, "HI reloc %08x", addr);151152u32 cur = (op & 0xFFFF) << 16;153u16 hi = 0;154bool found = false;155for (int t = r + 1; t < numRelocs; t++) {156int t_type = rels[t].r_info & 0xF;157if (t_type == R_MIPS_HI16)158continue;159160u32 corrLoAddr = rels[t].r_offset + segmentVAddr[readwrite];161162// In MotorStorm: Arctic Edge (US), these are sometimes R_MIPS_16 (instead of LO16.)163// It appears the PSP takes any relocation that is not a HI16.164if (t_type != R_MIPS_LO16) {165if (t_type != R_MIPS_16) {166// Let's play it safe for now and skip. We've only seen this type.167ERROR_LOG_REPORT(Log::Loader, "ELF relocation HI16/%d pair (instead of LO16) at %08x / %08x", t_type, addr, corrLoAddr);168continue;169} else {170WARN_LOG_REPORT(Log::Loader, "ELF relocation HI16/%d(16) pair (instead of LO16) at %08x / %08x", t_type, addr, corrLoAddr);171}172}173174// Should have matching index and segment info, according to llvm, which makes sense.175if ((rels[t].r_info >> 8) != (rels[r].r_info >> 8)) {176WARN_LOG_REPORT(Log::Loader, "ELF relocation HI16/LO16 with mismatching r_info lo=%08x, hi=%08x", rels[t].r_info, rels[r].r_info);177}178if (log) {179DEBUG_LOG(Log::Loader, "Corresponding lo found at %08x", corrLoAddr);180}181if (Memory::IsValidAddress(corrLoAddr)) {182s16 lo = (s16)relocOps[t];183cur += lo;184cur += relocateTo;185addrToHiLo(cur, hi, lo);186found = true;187break;188} else {189ERROR_LOG(Log::Loader, "Bad corrLoAddr %08x", corrLoAddr);190}191}192if (!found) {193ERROR_LOG_REPORT(Log::Loader, "R_MIPS_HI16: could not find R_MIPS_LO16 (r=%d of %d, addr=%08x)", r, numRelocs, addr);194}195op = (op & 0xFFFF0000) | hi;196}197break;198199case R_MIPS_LO16: //addiu part of lui-addiu pairs200{201if (log)202DEBUG_LOG(Log::Loader, "LO reloc %08x", addr);203u32 cur = op & 0xFFFF;204cur += relocateTo;205cur &= 0xFFFF;206op = (op & 0xFFFF0000) | cur;207}208break;209210case R_MIPS_GPREL16: //gp211// It seems safe to ignore this, almost a notification of a gp-relative operation?212break;213214case R_MIPS_16:215op = (op & 0xFFFF0000) | (((int)(op & 0xFFFF) + (int)relocateTo) & 0xFFFF);216break;217218case R_MIPS_NONE:219// This shouldn't matter, not sure the purpose of it.220break;221222default:223{224char temp[256];225MIPSDisAsm(MIPSOpcode(op), 0, temp, sizeof(temp));226ERROR_LOG_REPORT(Log::Loader, "ARGH IT'S AN UNKNOWN RELOCATION!!!!!!!! %08x, type=%d : %s", addr, type, temp);227}228break;229}230231Memory::WriteUnchecked_U32(op, addr);232NotifyMemInfo(MemBlockFlags::WRITE, addr, 4, "Relocation");233}234}, 0, numRelocs, 128, TaskPriority::HIGH);235236if (numErrors) {237WARN_LOG(Log::Loader, "%i bad relocations found!!!", numErrors.load());238}239return numErrors == 0;240}241242243void ElfReader::LoadRelocations2(int rel_seg)244{245u8 *buf, *end, *flag_table, *type_table;246int flag_table_size, type_table_size;247int flag_bits, seg_bits, type_bits;248int cmd, flag, seg, type;249int off_seg = 0, addr_seg, rel_base, rel_offset;250int relocate_to, last_type, lo16 = 0;251u32 op, addr;252int rcount = 0;253254const Elf32_Phdr *ph = segments + rel_seg;255256buf = (u8*)GetSegmentPtr(rel_seg);257if (!buf) {258ERROR_LOG_REPORT(Log::Loader, "Rel2 segment invalid");259return;260}261end = buf+ph->p_filesz;262263flag_bits = buf[2];264type_bits = buf[3];265266seg_bits = 1;267while((1<<seg_bits)<rel_seg)268seg_bits += 1;269270buf += 4;271272flag_table = buf;273flag_table_size = flag_table[0];274buf += flag_table_size;275276type_table = buf;277type_table_size = type_table[0];278buf += type_table_size;279280rel_base = 0;281last_type = -1;282while(buf<end){283cmd = *(u16*)(buf);284buf += 2;285286flag = ( cmd<<(16-flag_bits))&0xffff;287flag = (flag>>(16-flag_bits))&0xffff;288flag = flag_table[flag];289290seg = (cmd<<(16-seg_bits-flag_bits))&0xffff;291seg = (seg>>(16-seg_bits))&0xffff;292293type = ( cmd<<(16-type_bits-seg_bits-flag_bits))&0xffff;294type = (type>>(16-type_bits))&0xffff;295type = type_table[type];296297if((flag&0x01)==0){298off_seg = seg;299if((flag&0x06)==0){300rel_base = cmd>>(seg_bits+flag_bits);301}else if((flag&0x06)==4){302rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);303buf += 4;304}else{305ERROR_LOG_REPORT(Log::Loader, "Rel2: invalid size flag! %x", flag);306rel_base = 0;307}308}else{309addr_seg = seg;310relocate_to = addr_seg >= (int)ARRAY_SIZE(segmentVAddr) ? 0 : segmentVAddr[addr_seg];311if (!Memory::IsValidAddress(relocate_to)) {312ERROR_LOG_REPORT(Log::Loader, "ELF: Bad address to relocate to: %08x (segment %d)", relocate_to, addr_seg);313continue;314}315316if((flag&0x06)==0x00){317rel_offset = cmd;318if(cmd&0x8000){319rel_offset |= 0xffff0000;320rel_offset >>= type_bits+seg_bits+flag_bits;321rel_offset |= 0xffff0000;322}else{323rel_offset >>= type_bits+seg_bits+flag_bits;324}325rel_base += rel_offset;326}else if((flag&0x06)==0x02){327rel_offset = cmd;328if(cmd&0x8000)329rel_offset |= 0xffff0000;330rel_offset >>= type_bits+seg_bits+flag_bits;331rel_offset = (rel_offset<<16) | (buf[0]) | (buf[1]<<8);332buf += 2;333rel_base += rel_offset;334}else if((flag&0x06)==0x04){335rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);336buf += 4;337}else{338ERROR_LOG_REPORT(Log::Loader, "Rel2: invalid relocat size flag! %x", flag);339}340341342rel_offset = rel_base+segmentVAddr[off_seg];343if (!Memory::IsValidAddress(rel_offset)) {344ERROR_LOG_REPORT(Log::Loader, "ELF: Bad rel_offset: %08x", rel_offset);345continue;346}347348if((flag&0x38)==0x00){349lo16 = 0;350}else if((flag&0x38)==0x08){351if(last_type!=0x04)352lo16 = 0;353}else if((flag&0x38)==0x10){354lo16 = (buf[0]) | (buf[1]<<8);355if(lo16&0x8000)356lo16 |= 0xffff0000;357buf += 2;358}else{359ERROR_LOG_REPORT(Log::Loader, "Rel2: invalid lo16 type! %x", flag);360}361362op = Memory::Read_Instruction(rel_offset, true).encoding;363DEBUG_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);364365switch(type){366case 0:367continue;368case 2: // R_MIPS_32369op += relocate_to;370break;371case 3: // R_MIPS_26372case 6: // R_MIPS_J26373case 7: // R_MIPS_JAL26374op = (op&0xFC000000) | (((op&0x03FFFFFF)+(relocate_to>>2))&0x03FFFFFF);375// To be safe, let's force it to the specified jump.376if (type == 6)377op = (op & ~0xFC000000) | 0x08000000;378else if (type == 7)379op = (op & ~0xFC000000) | 0x0C000000;380break;381case 4: // R_MIPS_HI16382addr = ((op<<16)+lo16)+relocate_to;383if(addr&0x8000)384addr += 0x00010000;385op = (op&0xffff0000) | (addr>>16 );386break;387case 1:388case 5: // R_MIPS_LO16389op = (op&0xffff0000) | (((op&0xffff)+relocate_to)&0xffff);390break;391default:392ERROR_LOG_REPORT(Log::Loader, "Rel2: unexpected relocation type! %x", type);393break;394}395396Memory::Write_U32(op, rel_offset);397NotifyMemInfo(MemBlockFlags::WRITE, rel_offset, 4, "Relocation2");398rcount += 1;399}400}401402}403404405int ElfReader::LoadInto(u32 loadAddress, bool fromTop)406{407DEBUG_LOG(Log::Loader,"String section: %i", header->e_shstrndx);408409if (size_ < sizeof(Elf32_Ehdr)) {410ERROR_LOG(Log::Loader, "Truncated ELF header, %d bytes", (int)size_);411// Probably not the right error code.412return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;413}414415if (header->e_ident[0] != ELFMAG0 || header->e_ident[1] != ELFMAG1416|| header->e_ident[2] != ELFMAG2 || header->e_ident[3] != ELFMAG3)417return SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE;418419// technically ELFCLASSNONE would freeze the system, but that's not really desireable420if (header->e_ident[EI_CLASS] != ELFCLASS32) {421if (header->e_ident[EI_CLASS] != 0) {422return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;423}424425ERROR_LOG(Log::Loader, "Bad ELF, EI_CLASS (fifth byte) is 0x00, should be 0x01 - would lock up a PSP.");426}427428if (header->e_ident[EI_DATA] != ELFDATA2LSB)429return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;430431if (size_ < header->e_phoff + sizeof(Elf32_Phdr) * GetNumSegments() || size_ < header->e_shoff + sizeof(Elf32_Shdr) * GetNumSections()) {432ERROR_LOG(Log::Loader, "Truncated ELF, %d bytes with %d sections and %d segments", (int)size_, GetNumSections(), GetNumSegments());433// Probably not the right error code.434return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;435}436437// e_ident[EI_VERSION] is ignored438439// Should we relocate?440bRelocate = (header->e_type != ET_EXEC);441442// Look for the module info - we need to know whether this is kernel or user.443const PspModuleInfo *modInfo = 0;444for (int i = 0; i < GetNumSections(); i++) {445const Elf32_Shdr *s = §ions[i];446const char *name = GetSectionName(i);447if (name && !strcmp(name, ".rodata.sceModuleInfo") && s->sh_offset + sizeof(PspModuleInfo) <= size_) {448modInfo = (const PspModuleInfo *)GetPtr(s->sh_offset);449}450}451if (!modInfo && GetNumSegments() >= 1 && (segments[0].p_paddr & 0x7FFFFFFF) + sizeof(PspModuleInfo) <= size_) {452modInfo = (const PspModuleInfo *)GetPtr(segments[0].p_paddr & 0x7FFFFFFF);453}454455bool kernelModule = modInfo ? (modInfo->moduleAttrs & 0x1000) != 0 : false;456457std::string modName = "ELF";458if (modInfo) {459size_t n = strnlen(modInfo->name, 28);460modName = "ELF/" + std::string(modInfo->name, n);461}462463entryPoint = header->e_entry;464u32 totalStart = 0xFFFFFFFF;465u32 totalEnd = 0;466for (int i = 0; i < header->e_phnum; i++) {467const Elf32_Phdr *p = &segments[i];468if (p->p_type == PT_LOAD) {469if (p->p_vaddr < totalStart) {470totalStart = p->p_vaddr;471firstSegAlign = p->p_align;472}473if (p->p_vaddr + p->p_memsz > totalEnd)474totalEnd = p->p_vaddr + p->p_memsz;475}476}477totalSize = totalEnd - totalStart;478479// If a load address is specified that's in regular RAM, override kernel module status480bool inUser = totalStart >= PSP_GetUserMemoryBase();481BlockAllocator &memblock = (kernelModule && !inUser) ? kernelMemory : userMemory;482483if (!bRelocate)484{485// Binary is prerelocated, load it where the first segment starts486vaddr = memblock.AllocAt(totalStart, totalSize, modName.c_str());487}488else if (loadAddress)489{490// Binary needs to be relocated: add loadAddress to the binary start address491vaddr = memblock.AllocAt(loadAddress + totalStart, totalSize, modName.c_str());492}493else494{495// Just put it where there is room496vaddr = memblock.Alloc(totalSize, fromTop, modName.c_str());497}498499if (vaddr == (u32)-1) {500ERROR_LOG_REPORT(Log::Loader, "Failed to allocate memory for ELF!");501return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;502}503504if (bRelocate) {505DEBUG_LOG(Log::Loader,"Relocatable module");506if (entryPoint != (u32)-1)507entryPoint += vaddr;508} else {509DEBUG_LOG(Log::Loader,"Prerelocated executable");510}511512DEBUG_LOG(Log::Loader,"%i segments:", header->e_phnum);513514// First pass : Get the damn bits into RAM515u32 baseAddress = bRelocate ? vaddr : 0;516517for (int i = 0; i < header->e_phnum; i++)518{519const Elf32_Phdr *p = segments + i;520DEBUG_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);521522if (p->p_type == PT_LOAD)523{524segmentVAddr[i] = baseAddress + p->p_vaddr;525u32 writeAddr = segmentVAddr[i];526527const u8 *src = GetSegmentPtr(i);528if (!src || p->p_offset + p->p_filesz > size_) {529ERROR_LOG(Log::Loader, "Segment %d pointer invalid - truncated?", i);530continue;531}532u32 srcSize = p->p_filesz;533u32 dstSize = p->p_memsz;534u8 *dst = Memory::GetPointerWriteRange(writeAddr, dstSize);535if (dst) {536if (srcSize < dstSize) {537memset(dst + srcSize, 0, dstSize - srcSize); //zero out bss538NotifyMemInfo(MemBlockFlags::WRITE, writeAddr + srcSize, dstSize - srcSize, "ELFZero");539}540541memcpy(dst, src, srcSize);542std::string tag = StringFromFormat("ELFLoad/%08x", writeAddr);543NotifyMemInfo(MemBlockFlags::WRITE, writeAddr, srcSize, tag.c_str(), tag.size());544DEBUG_LOG(Log::Loader, "Loadable Segment Copied to %08x, size %08x", writeAddr, (u32)p->p_memsz);545} else {546ERROR_LOG(Log::Loader, "Bad ELF segment. Trying to write %d bytes to %08x", dstSize, writeAddr);547}548}549}550memblock.ListBlocks();551552DEBUG_LOG(Log::Loader,"%i sections:", header->e_shnum);553554sectionOffsets = new u32[GetNumSections()];555sectionAddrs = new u32[GetNumSections()];556557for (int i = 0; i < GetNumSections(); i++)558{559const Elf32_Shdr *s = §ions[i];560const char *name = GetSectionName(i);561562u32 writeAddr = s->sh_addr + baseAddress;563sectionOffsets[i] = writeAddr - vaddr;564sectionAddrs[i] = writeAddr;565566if (s->sh_flags & SHF_ALLOC)567{568std::string tag = name && name[0] ? StringFromFormat("%s/%s", modName.c_str(), name) : StringFromFormat("%s/%08x", modName.c_str(), writeAddr);569NotifyMemInfo(MemBlockFlags::SUB_ALLOC, writeAddr, s->sh_size, tag.c_str(), tag.size());570DEBUG_LOG(Log::Loader,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, (u32)s->sh_size);571}572else573{574DEBUG_LOG(Log::Loader,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, (u32)s->sh_size, (u32)s->sh_flags);575}576}577578DEBUG_LOG(Log::Loader, "Relocations:");579580// Second pass: Do necessary relocations581for (int i = 0; i < GetNumSections(); i++)582{583const Elf32_Shdr *s = §ions[i];584const char *name = GetSectionName(i);585586if (s->sh_type == SHT_PSPREL)587{588//We have a relocation table!589int sectionToModify = s->sh_info;590if (sectionToModify >= 0)591{592if (!(sections[sectionToModify].sh_flags & SHF_ALLOC))593{594ERROR_LOG_REPORT(Log::Loader, "Trying to relocate non-loaded section %s", GetSectionName(sectionToModify));595continue;596}597598int numRelocs = s->sh_size / sizeof(Elf32_Rel);599600Elf32_Rel *rels = (Elf32_Rel *)GetSectionDataPtr(i);601if (GetSectionDataOffset(i) + sizeof(Elf32_Rel) * numRelocs > size_)602rels = nullptr;603604DEBUG_LOG(Log::Loader,"%s: Performing %i relocations on %s : offset = %08x", name, numRelocs, GetSectionName(sectionToModify), sections[i].sh_offset);605if (!rels || !LoadRelocations(rels, numRelocs)) {606WARN_LOG(Log::Loader, "LoadInto: Relocs failed, trying anyway");607}608}609else610{611WARN_LOG_REPORT(Log::Loader, "sectionToModify = %i - ignoring PSP relocation sector %i", sectionToModify, i);612}613}614else if (s->sh_type == SHT_REL)615{616DEBUG_LOG(Log::Loader, "Traditional relocation section found.");617if (!bRelocate)618{619DEBUG_LOG(Log::Loader, "Binary is prerelocated. Skipping relocations.");620}621else622{623//We have a relocation table!624int sectionToModify = s->sh_info;625if (sectionToModify >= 0)626{627if (!(sections[sectionToModify].sh_flags & SHF_ALLOC))628{629// Generally stuff like debug info. We don't need it.630INFO_LOG(Log::Loader, "Skipping relocation of non-loaded section %s", GetSectionName(sectionToModify));631continue;632}633}634else635{636WARN_LOG_REPORT(Log::Loader, "sectionToModify = %i - ignoring relocation sector %i", sectionToModify, i);637}638ERROR_LOG_REPORT(Log::Loader, "Traditional relocations unsupported.");639}640}641}642643// Segment relocations (a few games use them)644if (GetNumSections() == 0) {645for (int i = 0; i < header->e_phnum; i++)646{647const Elf32_Phdr *p = &segments[i];648if (p->p_type == PT_PSPREL1) {649INFO_LOG(Log::Loader,"Loading segment relocations");650int numRelocs = p->p_filesz / sizeof(Elf32_Rel);651652Elf32_Rel *rels = (Elf32_Rel *)GetSegmentPtr(i);653if (p->p_offset + p->p_filesz > size_)654rels = nullptr;655if (!rels || !LoadRelocations(rels, numRelocs)) {656ERROR_LOG(Log::Loader, "LoadInto: Relocs failed, trying anyway (2)");657}658} else if (p->p_type == PT_PSPREL2) {659INFO_LOG(Log::Loader,"Loading segment relocations2");660LoadRelocations2(i);661}662}663}664665return SCE_KERNEL_ERROR_OK;666}667668669SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const670{671if (!name)672return -1;673for (int i = firstSection; i < header->e_shnum; i++) {674const char *secname = GetSectionName(i);675if (secname && strcmp(name, secname) == 0) {676return i;677}678}679return -1;680}681682u32 ElfReader::GetTotalTextSize() const {683u32 total = 0;684for (int i = 0; i < GetNumSections(); ++i) {685if (!(sections[i].sh_flags & SHF_WRITE) && (sections[i].sh_flags & SHF_ALLOC) && !(sections[i].sh_flags & SHF_STRINGS)) {686total += sections[i].sh_size;687}688}689return total;690}691692u32 ElfReader::GetTotalTextSizeFromSeg() const {693u32 total = 0;694for (int i = 0; i < GetNumSegments(); ++i) {695if ((segments[i].p_flags & PF_X) != 0) {696total += segments[i].p_filesz;697}698}699return total;700}701702u32 ElfReader::GetTotalDataSize() const {703u32 total = 0;704for (int i = 0; i < GetNumSections(); ++i) {705if ((sections[i].sh_flags & SHF_WRITE) && (sections[i].sh_flags & SHF_ALLOC) && !(sections[i].sh_flags & SHF_MASKPROC)) {706total += sections[i].sh_size;707}708}709return total;710}711712u32 ElfReader::GetTotalSectionSizeByPrefix(const std::string &prefix) const {713u32 total = 0;714for (int i = 0; i < GetNumSections(); ++i) {715const char *secname = GetSectionName(i);716if (secname && !strncmp(secname, prefix.c_str(), prefix.length())) {717total += sections[i].sh_size;718}719}720return total;721}722723std::vector<SectionID> ElfReader::GetCodeSections() const {724std::vector<SectionID> ids;725for (int i = 0; i < GetNumSections(); ++i) {726u32 flags = sections[i].sh_flags;727if ((flags & (SHF_ALLOC | SHF_EXECINSTR)) == (SHF_ALLOC | SHF_EXECINSTR)) {728ids.push_back(i);729}730}731return ids;732}733734bool ElfReader::LoadSymbols()735{736bool hasSymbols = false;737SectionID sec = GetSectionByName(".symtab");738if (sec != -1)739{740int stringSection = sections[sec].sh_link;741742const char *stringBase = (const char*)GetSectionDataPtr(stringSection);743u32 stringOffset = GetSectionDataOffset(stringSection);744745//We have a symbol table!746Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));747u32 symtabOffset = GetSectionDataOffset(sec);748749int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);750if (!stringBase || !symtab || symtabOffset + sections[sec].sh_size > size_) {751ERROR_LOG(Log::Loader, "Symbols truncated - ignoring");752return false;753}754755for (int sym = 0; sym<numSymbols; sym++)756{757int size = symtab[sym].st_size;758if (size == 0)759continue;760761int bind = symtab[sym].st_info >> 4;762int type = symtab[sym].st_info & 0xF;763int sectionIndex = symtab[sym].st_shndx;764int value = symtab[sym].st_value;765const char *name = stringBase + symtab[sym].st_name;766if (stringOffset + symtab[sym].st_name >= size_)767continue;768769if (bRelocate)770value += sectionAddrs[sectionIndex];771772switch (type)773{774case STT_OBJECT:775g_symbolMap->AddData(value,size,DATATYPE_BYTE);776break;777case STT_FUNC:778g_symbolMap->AddFunction(name,value,size);779break;780default:781continue;782}783hasSymbols = true;784//...785}786}787return hasSymbols;788}789790791