diff --git a/src/core/src/elf/elf_reader.cpp b/src/core/src/elf/elf_reader.cpp new file mode 100644 index 000000000..21d8aea67 --- /dev/null +++ b/src/core/src/elf/elf_reader.cpp @@ -0,0 +1,238 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "common.h" +#include "mem_map.h" + +#include "elf/elf_reader.h" +//#include "Core/Debugger/Debugger_SymbolMap.h" +//#include "Core/HW/Memmap.h" +//#include "Core/PowerPC/PPCSymbolDB.h" + +//void bswap(Elf32_Word &w) {w = Common::swap32(w);} +//void bswap(Elf32_Half &w) {w = Common::swap16(w);} + +#define bswap(w) w // Dirty bswap disable for now... 3DS is little endian, anyway + +static void byteswapHeader(Elf32_Ehdr &ELF_H) +{ + bswap(ELF_H.e_type); + bswap(ELF_H.e_machine); + bswap(ELF_H.e_ehsize); + bswap(ELF_H.e_phentsize); + bswap(ELF_H.e_phnum); + bswap(ELF_H.e_shentsize); + bswap(ELF_H.e_shnum); + bswap(ELF_H.e_shstrndx); + bswap(ELF_H.e_version); + bswap(ELF_H.e_entry); + bswap(ELF_H.e_phoff); + bswap(ELF_H.e_shoff); + bswap(ELF_H.e_flags); +} + +static void byteswapSegment(Elf32_Phdr &sec) +{ + bswap(sec.p_align); + bswap(sec.p_filesz); + bswap(sec.p_flags); + bswap(sec.p_memsz); + bswap(sec.p_offset); + bswap(sec.p_paddr); + bswap(sec.p_vaddr); + bswap(sec.p_type); +} + +static void byteswapSection(Elf32_Shdr &sec) +{ + bswap(sec.sh_addr); + bswap(sec.sh_addralign); + bswap(sec.sh_entsize); + bswap(sec.sh_flags); + bswap(sec.sh_info); + bswap(sec.sh_link); + bswap(sec.sh_name); + bswap(sec.sh_offset); + bswap(sec.sh_size); + bswap(sec.sh_type); +} + +ElfReader::ElfReader(void *ptr) +{ + base = (char*)ptr; + base32 = (u32 *)ptr; + header = (Elf32_Ehdr*)ptr; + byteswapHeader(*header); + + segments = (Elf32_Phdr *)(base + header->e_phoff); + sections = (Elf32_Shdr *)(base + header->e_shoff); + + for (int i = 0; i < GetNumSegments(); i++) + { + byteswapSegment(segments[i]); + } + + for (int i = 0; i < GetNumSections(); i++) + { + byteswapSection(sections[i]); + } + entryPoint = header->e_entry; +} + +const char *ElfReader::GetSectionName(int section) const +{ + if (sections[section].sh_type == SHT_NULL) + return nullptr; + + int nameOffset = sections[section].sh_name; + char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx); + + if (ptr) + return ptr + nameOffset; + else + return nullptr; +} + +bool ElfReader::LoadInto(u32 vaddr) +{ + DEBUG_LOG(MASTER_LOG,"String section: %i", header->e_shstrndx); + +// sectionOffsets = new u32[GetNumSections()]; +// sectionAddrs = new u32[GetNumSections()]; + + // Should we relocate? + bRelocate = (header->e_type != ET_EXEC); + + if (bRelocate) + { + DEBUG_LOG(MASTER_LOG,"Relocatable module"); + entryPoint += vaddr; + } + else + { + DEBUG_LOG(MASTER_LOG,"Prerelocated executable"); + } + + INFO_LOG(MASTER_LOG,"%i segments:", header->e_phnum); + + // First pass : Get the bits into RAM + u32 segmentVAddr[32]; + + u32 baseAddress = bRelocate?vaddr:0; + for (int i = 0; i < header->e_phnum; i++) + { + Elf32_Phdr *p = segments + i; + + INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); + + if (p->p_type == PT_LOAD) + { + segmentVAddr[i] = baseAddress + p->p_vaddr; + u32 writeAddr = segmentVAddr[i]; + + const u8 *src = GetSegmentPtr(i); + u8 *dst = Memory::GetPointer(writeAddr); + u32 srcSize = p->p_filesz; + u32 dstSize = p->p_memsz; + u32 *s = (u32*)src; + u32 *d = (u32*)dst; + for (int j = 0; j < (int)(srcSize + 3) / 4; j++) + { + *d++ = /*_byteswap_ulong*/(*s++); + } + if (srcSize < dstSize) + { + //memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss + } + INFO_LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz); + } + } + + /* + LOG(MASTER_LOG,"%i sections:", header->e_shnum); + + for (int i=0; ish_addr + baseAddress; + sectionOffsets[i] = writeAddr - vaddr; + sectionAddrs[i] = writeAddr; + + if (s->sh_flags & SHF_ALLOC) + { + LOG(MASTER_LOG,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, s->sh_size); + + } + else + { + LOG(MASTER_LOG,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, s->sh_size, s->sh_flags); + } + } +*/ + INFO_LOG(MASTER_LOG,"Done loading."); + return true; +} + +SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const +{ + for (int i = firstSection; i < header->e_shnum; i++) + { + const char *secname = GetSectionName(i); + + if (secname != nullptr && strcmp(name, secname) == 0) + return i; + } + return -1; +} + +/* TODO(bunnei): The following is verbatim from Dolphin - needs to be updated for this project: + +bool ElfReader::LoadSymbols() +{ + bool hasSymbols = false; + SectionID sec = GetSectionByName(".symtab"); + if (sec != -1) + { + int stringSection = sections[sec].sh_link; + const char *stringBase = (const char *)GetSectionDataPtr(stringSection); + + //We have a symbol table! + Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); + int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); + for (int sym = 0; sym < numSymbols; sym++) + { + int size = Common::swap32(symtab[sym].st_size); + if (size == 0) + continue; + + // int bind = symtab[sym].st_info >> 4; + int type = symtab[sym].st_info & 0xF; + int sectionIndex = Common::swap16(symtab[sym].st_shndx); + int value = Common::swap32(symtab[sym].st_value); + const char *name = stringBase + Common::swap32(symtab[sym].st_name); + if (bRelocate) + value += sectionAddrs[sectionIndex]; + + int symtype = Symbol::SYMBOL_DATA; + switch (type) + { + case STT_OBJECT: + symtype = Symbol::SYMBOL_DATA; break; + case STT_FUNC: + symtype = Symbol::SYMBOL_FUNCTION; break; + default: + continue; + } + g_symbolDB.AddKnownSymbol(value, size, name, symtype); + hasSymbols = true; + } + } + g_symbolDB.Index(); + return hasSymbols; +} +*/ diff --git a/src/core/src/elf/elf_reader.h b/src/core/src/elf/elf_reader.h new file mode 100644 index 000000000..9393a589d --- /dev/null +++ b/src/core/src/elf/elf_reader.h @@ -0,0 +1,75 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "elf/elf_types.h" + +enum KnownElfTypes +{ + KNOWNELF_PSP = 0, + KNOWNELF_DS = 1, + KNOWNELF_GBA = 2, + KNOWNELF_GC = 3, +}; + +typedef int SectionID; + +class ElfReader +{ +private: + char *base; + u32 *base32; + + Elf32_Ehdr *header; + Elf32_Phdr *segments; + Elf32_Shdr *sections; + + u32 *sectionAddrs; + bool bRelocate; + u32 entryPoint; + +public: + ElfReader(void *ptr); + ~ElfReader() { } + + u32 Read32(int off) const { return base32[off>>2]; } + + // Quick accessors + ElfType GetType() const { return (ElfType)(header->e_type); } + ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } + u32 GetEntryPoint() const { return entryPoint; } + u32 GetFlags() const { return (u32)(header->e_flags); } + bool LoadInto(u32 vaddr); + bool LoadSymbols(); + + int GetNumSegments() const { return (int)(header->e_phnum); } + int GetNumSections() const { return (int)(header->e_shnum); } + const u8 *GetPtr(int offset) const { return (u8*)base + offset; } + const char *GetSectionName(int section) const; + const u8 *GetSectionDataPtr(int section) const + { + if (section < 0 || section >= header->e_shnum) + return nullptr; + if (sections[section].sh_type != SHT_NOBITS) + return GetPtr(sections[section].sh_offset); + else + return nullptr; + } + bool IsCodeSection(int section) const + { + return sections[section].sh_type == SHT_PROGBITS; + } + const u8 *GetSegmentPtr(int segment) + { + return GetPtr(segments[segment].p_offset); + } + u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } + int GetSectionSize(SectionID section) const { return sections[section].sh_size; } + SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found + + bool DidRelocate() { + return bRelocate; + } +}; diff --git a/src/core/src/elf/elf_types.h b/src/core/src/elf/elf_types.h new file mode 100644 index 000000000..f1bf3db72 --- /dev/null +++ b/src/core/src/elf/elf_types.h @@ -0,0 +1,281 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +// ELF Header Constants + +// File type +enum ElfType +{ + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, + ET_LOPROC = 0xFF00, + ET_HIPROC = 0xFFFF, +}; + +// Machine/Architecture +enum ElfMachine +{ + EM_NONE = 0, + EM_M32 = 1, + EM_SPARC = 2, + EM_386 = 3, + EM_68K = 4, + EM_88K = 5, + EM_860 = 7, + EM_MIPS = 8 +}; + +// File version +#define EV_NONE 0 +#define EV_CURRENT 1 + +// Identification index +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 +#define EI_NIDENT 16 + +// Magic number +#define ELFMAG0 0x7F +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +// File class +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// Encoding +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + + + +// Sections constants + +// Section indexes +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xFF00 +#define SHN_LOPROC 0xFF00 +#define SHN_HIPROC 0xFF1F +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 +#define SHN_HIRESERVE 0xFFFF + +// Section types +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7FFFFFFF +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xFFFFFFFF + +// Custom section types +#define SHT_PSPREL 0x700000a0 + + +// Section flags +enum ElfSectionFlags +{ + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_MASKPROC = 0xF0000000, +}; + +// Symbol binding +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +// Symbol types +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +// Undefined name +#define STN_UNDEF 0 + +// Relocation types +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 + +// Segment types +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + +// Segment flags +#define PF_X 1 +#define PF_W 2 +#define PF_R 4 + +// Dynamic Array Tags +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7FFFFFFF + +typedef unsigned int Elf32_Addr; +typedef unsigned short Elf32_Half; +typedef unsigned int Elf32_Off; +typedef signed int Elf32_Sword; +typedef unsigned int Elf32_Word; + + +// ELF file header +struct Elf32_Ehdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +}; + +// Section header +struct Elf32_Shdr +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +}; + +// Segment header +struct Elf32_Phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +}; + +// Symbol table entry +struct Elf32_Sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +}; + +#define ELF32_ST_BIND(i) ((i)>>4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +// Relocation entries +struct Elf32_Rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +}; + +struct Elf32_Rela +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +}; + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t)) + + +struct Elf32_Dyn +{ + Elf32_Sword d_tag; + union + { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +};