#include "stdafx.h" #include "ELF32.h" ELF32Loader::ELF32Loader(vfsStream& f) : elf32_f(f) , LoaderBase() { } bool ELF32Loader::LoadInfo() { if(!elf32_f.IsOpened()) return false; if(!LoadEhdrInfo()) return false; if(!LoadPhdrInfo()) return false; if(!LoadShdrInfo()) return false; return true; } bool ELF32Loader::LoadData(u64 offset) { if(!elf32_f.IsOpened()) return false; if(!LoadEhdrData(offset)) return false; if(!LoadPhdrData(offset)) return false; if(!LoadShdrData(offset)) return false; return true; } bool ELF32Loader::Close() { return elf32_f.Close(); } bool ELF32Loader::LoadEhdrInfo() { elf32_f.Seek(0); ehdr.Load(elf32_f); if(!ehdr.CheckMagic()) return false; if(ehdr.IsLittleEndian()) ConLog.Warning("ELF32 LE"); switch(ehdr.e_machine) { case MACHINE_MIPS: case MACHINE_PPC64: case MACHINE_SPU: case MACHINE_ARM: machine = (Elf_Machine)ehdr.e_machine; break; default: machine = MACHINE_Unknown; ConLog.Error("Unknown elf32 machine: 0x%x", ehdr.e_machine); return false; } entry = ehdr.GetEntry(); if(entry == 0) { ConLog.Error("elf32 error: entry is null!"); return false; } return true; } bool ELF32Loader::LoadPhdrInfo() { if(ehdr.e_phoff == 0 && ehdr.e_phnum) { ConLog.Error("LoadPhdr32 error: Program header offset is null!"); return false; } elf32_f.Seek(ehdr.e_phoff); for(uint i=0; iLoadLE(elf32_f); else phdr->Load(elf32_f); phdr_arr.Move(phdr); } if(!Memory.IsGoodAddr(entry)) { //entry is physical, convert to virtual for(size_t i=0; i= entry && entry < phdr_arr[i].p_paddr + phdr_arr[i].p_memsz) { entry += phdr_arr[i].p_vaddr; ConLog.Warning("virtual entry = 0x%x", entry); break; } } } return true; } bool ELF32Loader::LoadShdrInfo() { elf32_f.Seek(ehdr.e_shoff); for(u32 i=0; iLoadLE(elf32_f); else shdr->Load(elf32_f); shdr_arr.Move(shdr); } if(ehdr.e_shstrndx >= shdr_arr.GetCount()) { ConLog.Error("LoadShdr32 error: shstrndx too big!"); return false; } for(u32 i=0; i max_addr) { max_addr = phdr_arr[i].p_vaddr + phdr_arr[i].p_memsz; } if(phdr_arr[i].p_vaddr != phdr_arr[i].p_paddr) { ConLog.Warning ( "LoadPhdr32 different load addrs: paddr=0x%8.8x, vaddr=0x%8.8x", phdr_arr[i].p_paddr, phdr_arr[i].p_vaddr ); } switch(machine) { case MACHINE_SPU: Memory.MainMem.Alloc(phdr_arr[i].p_vaddr + offset, phdr_arr[i].p_memsz); break; case MACHINE_MIPS: Memory.PSPMemory.RAM.Alloc(phdr_arr[i].p_vaddr + offset, phdr_arr[i].p_memsz); break; case MACHINE_ARM: Memory.PSVMemory.RAM.Alloc(phdr_arr[i].p_vaddr + offset, phdr_arr[i].p_memsz); break; default: continue; } elf32_f.Seek(phdr_arr[i].p_offset); elf32_f.Read(&Memory[phdr_arr[i].p_vaddr + offset], phdr_arr[i].p_filesz); } else if(phdr_arr[i].p_type == 0x00000004) { elf32_f.Seek(phdr_arr[i].p_offset); Elf32_Note note; if(ehdr.IsLittleEndian()) note.LoadLE(elf32_f); else note.Load(elf32_f); if(note.type != 1) { ConLog.Error("ELF32: Bad NOTE type (%d)", note.type); break; } if(note.namesz != sizeof(note.name)) { ConLog.Error("ELF32: Bad NOTE namesz (%d)", note.namesz); break; } if(note.descsz != sizeof(note.desc) && note.descsz != 32) { ConLog.Error("ELF32: Bad NOTE descsz (%d)", note.descsz); break; } //if(note.desc.flags) //{ // ConLog.Error("ELF32: Bad NOTE flags (0x%x)", note.desc.flags); // break; //} if(note.descsz == sizeof(note.desc)) { ConLog.Warning("name = %s", note.name); ConLog.Warning("ls_size = %d", note.desc.ls_size); ConLog.Warning("stack_size = %d", note.desc.stack_size); } else { ConLog.Warning("desc = '%s'", note.desc_text); } } #ifdef LOADER_DEBUG ConLog.SkipLn(); #endif } return true; } bool ELF32Loader::LoadShdrData(u64 offset) { for(u32 i=0; i max_addr) { max_addr = shdr.sh_addr + shdr.sh_size; } } //TODO return true; }