diff --git a/wiiu/wut/elf2rpl/main.cpp b/wiiu/wut/elf2rpl/main.cpp index 6e0a56abbf..f06577dec8 100644 --- a/wiiu/wut/elf2rpl/main.cpp +++ b/wiiu/wut/elf2rpl/main.cpp @@ -2,8 +2,10 @@ #include #include #include +#include #include #include +#include #include #include #include "elf.h" @@ -26,14 +28,67 @@ static const uint32_t WiiuLoadAddress = 0xC0000000u; int verbose = 0; constexpr int verbose_loaded_sections = 1; -constexpr int verbose_loaded_symbols = 2; +constexpr int verbose_loaded_symbols = 3; constexpr int verbose_loaded_imports = 2; -constexpr int verbose_loaded_relocations = 3; +constexpr int verbose_loaded_relocations = 4; +constexpr int verbose_loaded_dyn_reloc = 4; constexpr int verbose_pruned_symbols = 2; -constexpr int verbose_convert_relocations = 3; +constexpr int verbose_convert_relocations = 4; +constexpr int verbose_dup_symbols = 3; +constexpr int verbose_output_sections = 1; +constexpr int verbose_output_symbols = 2; + +struct OutputSection; +using OutputSectionPtr = std::shared_ptr; struct ElfFile { + struct DataSection + { + std::string name; + uint32_t address = 0; + elf::SectionType type = elf::SHT_NULL; + elf::SectionFlags flags = elf::SectionFlags(0); + OutputSectionPtr outSection; + int inIndex = -1; + + /* Data used if type == SHT_PROGBITS */ + std::vector data; + + /* Size used if type == SHT_NOBITS */ + uint32_t size = 0; + + DataSection(uint32_t _address, std::string _name, + elf::SectionType _type, elf::SectionFlags _flags) + : name(_name), address(_address), type(_type), flags(_flags) + {} + + static std::shared_ptr + New(uint32_t _address, std::string _name, + elf::SectionType _type, elf::SectionFlags _flags) + { + return std::make_shared(_address, _name, _type, _flags); + } + + bool contains(uint32_t _address, uint32_t _size = 0) + { + + if (!(flags & elf::SHF_ALLOC) || size == 0 || size == uint32_t(-1)) + return false; + + auto start = address; + auto end = start + size; + + if (_address >= start && _address + _size <= end) + return true; + + return false; + } + }; + + using DataSectionPtr = std::shared_ptr; + using DataSectionList = std::vector; + struct Symbol { std::string name; @@ -43,50 +98,310 @@ struct ElfFile elf::SymbolBinding binding = elf::STB_LOCAL; uint32_t outNamePos = 0; uint32_t refCount = 0; + int inIndex = -1; + int outIndex = -1; + DataSectionPtr inSection; + OutputSectionPtr outSection; + + Symbol(uint32_t _address, const std::string& _name, + uint32_t _size, elf::SymbolType _type, elf::SymbolBinding _binding) + : name(_name), address(_address), size(_size), type(_type), binding(_binding) + {} + + static std::shared_ptr + New(uint32_t _address, const std::string& _name, + uint32_t _size, elf::SymbolType _type, elf::SymbolBinding _binding) + { + return std::make_shared(_address, _name, _size, _type, _binding); + } }; + using SymbolPtr = std::shared_ptr; + using SymbolList = std::vector; + using SymbolByAddrMap = std::map; + struct Relocation { uint32_t target = 0; elf::RelocationType type = elf::R_PPC_NONE; - Symbol *symbol = nullptr; + SymbolPtr symbol; + DataSectionPtr symbolSection; uint32_t addend = 0; + OutputSectionPtr targetSection; }; - struct DataSection - { - std::string name; - uint32_t address = 0; - elf::SectionType type = elf::SHT_NULL; - elf::SectionFlags flags = elf::SectionFlags(0); - - /* Data used if type == SHT_PROGBITS */ - std::vector data; - - /* Size used if type == SHT_NOBITS */ - uint32_t size = 0; - }; + using RelocationPtr = std::shared_ptr; + using RelocationList = std::vector; struct RplImport { - Symbol *trampSymbol = nullptr; - Symbol *stubSymbol = nullptr; + SymbolPtr trampSymbol; + SymbolPtr stubSymbol; uint32_t stubAddr = 0; uint32_t trampAddr = 0; + + RplImport(uint32_t _stubAddr, uint32_t _trampAddr, + SymbolPtr _stubSymbol, SymbolPtr _trampSymbol) + : trampSymbol(_trampSymbol), stubSymbol(_stubSymbol), + stubAddr(_stubAddr), trampAddr(_trampAddr) + {} + + static std::shared_ptr + New(uint32_t _stubAddr, uint32_t _trampAddr, + SymbolPtr _stubSymbol, SymbolPtr _trampSymbol) + { + return std::make_shared(_stubAddr, _trampAddr, _stubSymbol, _trampSymbol); + } }; + using RplImportPtr = std::shared_ptr; + using RplImportList = std::vector; + using RplImportByAddrMap = std::map; + struct RplImportLibrary { std::string name; - std::vector> imports; + RplImportList imports; + + RplImportLibrary(const std::string& _name) + : name(_name) + {} + + static std::shared_ptr + New(const std::string& _name) + { + return std::make_shared(_name); + } + + void + addImport(const RplImportPtr& import) + { + imports.emplace_back(import); + } }; + using RplImportLibraryPtr = std::shared_ptr; + using RplImportLibraryList = std::vector; + uint32_t entryPoint = 0; - std::vector> dataSections; - std::vector> symbols; - std::vector> relocations; - std::vector> rplImports; + +private: + DataSectionList dataSections; + SymbolList symbols; + RelocationList relocations; + RplImportLibraryList rplImports; + + SymbolByAddrMap symbolsByAddr; + RplImportByAddrMap importsByAddr; + +public: + void + addDataSection(const DataSectionPtr& section) + { + dataSections.emplace_back(section); + } + + void + addSymbolToIndex(const SymbolPtr& symbol) + { + auto iter = symbolsByAddr.find(symbol->address); + if (iter != symbolsByAddr.end()) + { + if ((iter->second->type == elf::STT_NOTYPE + && symbol->type != elf::STT_NOTYPE) + || (iter->second->type != elf::STT_SECTION + && symbol->type == elf::STT_SECTION + && symbol->address != 0)) + { + if (verbose >= verbose_dup_symbols) + { + std::cout << "Duplicate symbol - changed type " + << std::hex << "0x" << symbol->address << " " + << iter->second->name << " / " << symbol->name + << std::endl; + } + iter->second = symbol; + } + else if ((iter->second->type != elf::STT_SECTION || symbol->type == elf::STT_SECTION) + && symbol->type != elf::STT_NOTYPE && iter->second->size == 0 + && symbol->size != 0 && symbol->size != uint32_t(-1) && symbol->address != 0) + { + if (verbose >= verbose_dup_symbols) + { + std::cout << "Duplicate symbol - changed size " + << std::hex << "0x" << symbol->address << " " + << iter->second->size << " / " << symbol->size << " " + << iter->second->type << " / " << symbol->type << " " + << iter->second->name << " / " << symbol->name + << std::endl; + } + iter->second = symbol; + } + else + { + if (symbol->name != iter->second->name && symbol->address != 0) + { + if (verbose >= verbose_dup_symbols) + { + std::cout << "Duplicate symbol " + << std::hex << "0x" << symbol->address << " " + << iter->second->size << " / " << symbol->size << " " + << iter->second->type << " / " << symbol->type << " " + << iter->second->name << " / " << symbol->name + << std::endl; + } + } + } + } + else + { + symbolsByAddr.emplace(symbol->address, symbol); + } + } + + void + addSymbol(const SymbolPtr& symbol) + { + symbols.emplace_back(symbol); + addSymbolToIndex(symbol); + } + + SymbolList::iterator + insertSymbol(SymbolList::iterator iter, const SymbolPtr& symbol) + { + addSymbolToIndex(symbol); + return symbols.insert(iter, symbol); + } + + void + addImport(const RplImportLibraryPtr& lib, + const RplImportPtr& import) + { + lib->addImport(import); + auto result = importsByAddr.emplace(import->stubAddr, import); + if (!result.second) + { + std::cout << "Duplicate import stub address " + << import->stubSymbol->name << std::endl; + } + result = importsByAddr.emplace(import->trampAddr, import); + if (!result.second) + { + std::cout << "Duplicate import tramp address " + << import->trampSymbol->name << std::endl; + } + } + + void + addImportLibrary(const RplImportLibraryPtr& lib) + { + rplImports.emplace_back(lib); + } + + void + addRelocation(const RelocationPtr& relocation) + { + relocations.emplace_back(relocation); + } + + SymbolPtr + findSymbol(uint32_t address) + { + auto iter = symbolsByAddr.find(address); + if (iter != symbolsByAddr.end()) + return iter->second; + return nullptr; + } + + RplImportPtr + findImport(uint32_t address) + { + auto iter = importsByAddr.find(address); + if (iter != importsByAddr.end()) + return iter->second; + return nullptr; + } + + DataSectionPtr + findSection(uint32_t address, + const DataSectionPtr& hint = nullptr) + { + if (address == 0) + return dataSections[0]; + + if (hint && hint->contains(address)) + return hint; + + for (auto §ion : dataSections) { + if (section->contains(address)) + return section; + } + + return nullptr; + } + + DataSectionList& + getDataSections() + { + return dataSections; + } + + SymbolList& + getSymbols() + { + return symbols; + } + + RelocationList& + getRelocations() + { + return relocations; + } + + RplImportLibraryList& + getImportLibs() + { + return rplImports; + } + + void + pruneSymbols() + { + SymbolList new_symbols; + new_symbols.resize(symbols.size()); + unsigned d = 0; + + /* Prune out unneeded symbols - but keep those used for relocations! */ + for (unsigned s = 0u; s < symbols.size(); ++s) + { + if (!symbols[s]->name.empty() && symbols[s]->type == elf::STT_NOTYPE + && symbols[s]->size == 0 && symbols[s]->refCount == 0) + { + if (verbose >= verbose_pruned_symbols) + { + std::cout << "Pruning symbol " << symbols[s]->name << std::endl; + } + } + else + { + std::swap(new_symbols[d], symbols[s]); + ++d; + } + } + + new_symbols.resize(d); + std::swap(new_symbols, symbols); + } + + void + indexSymbols() + { + for (unsigned i = 0; i < symbols.size(); ++i) + { + symbols[i]->outIndex = i; + } + } }; struct InputSection @@ -95,39 +410,6 @@ struct InputSection std::vector data; }; -static ElfFile::Symbol * -findSymbol(ElfFile &file, uint32_t address) -{ - for (auto &symbol : file.symbols) - { - if (symbol->address == address && symbol->type != elf::STT_NOTYPE) - return symbol.get(); - } - - for (auto &symbol : file.symbols) - { - if (symbol->address == address) - return symbol.get(); - } - - return nullptr; -} - -static ElfFile::RplImport * -findImport(ElfFile &file, uint32_t address) -{ - for (auto &lib : file.rplImports) - { - for (auto &import : lib->imports) - { - if (import->stubAddr == address || import->trampAddr == address) - return import.get(); - } - } - - return nullptr; -} - template static Type * getLoaderDataPtr(std::vector &inSections, uint32_t address) @@ -159,6 +441,7 @@ read(ElfFile &file, const std::string &filename) { std::ifstream in { filename, std::ifstream::binary }; std::vector inSections; + ElfFile::DataSectionList dataSectionIndex; if (!in.is_open()) { std::cout << "Could not open " << filename << " for reading" << std::endl; @@ -199,6 +482,7 @@ read(ElfFile &file, const std::string &filename) /* Read section headers and data */ in.seekg(static_cast(header.shoff)); inSections.resize(header.shnum); + dataSectionIndex.resize(header.shnum); for (auto §ion : inSections) { in.read(reinterpret_cast(§ion.header), sizeof(elf::SectionHeader)); @@ -249,6 +533,10 @@ read(ElfFile &file, const std::string &filename) switch (type) { case elf::R_PPC_RELATIVE: + if (verbose >= verbose_loaded_dyn_reloc) + { + std::cout << "Dyn relocation 0x" << std::hex << rela.offset << " 0x" << byte_swap(*ptr) << " -> 0x" << addr << std::endl; + } *ptr = byte_swap(addr); break; case elf::R_PPC_NONE: @@ -261,86 +549,69 @@ read(ElfFile &file, const std::string &filename) } } + int index = -1; /* Read text/data sections */ for (auto §ion : inSections) { + + ++index; + if (section.header.addr >= LoadAddress && section.header.addr < CodeAddress) { /* Skip any load sections */ continue; } auto name = std::string { shStrTab + section.header.name }; + auto address = section.header.addr.value(); + auto type = elf::SectionType(section.header.type.value()); + auto flags = elf::SectionFlags(section.header.flags.value()); + auto size = section.header.size.value(); - if (section.header.type == elf::SHT_PROGBITS) { - auto data = new ElfFile::DataSection(); - data->type = elf::SHT_PROGBITS; - data->flags = static_cast(section.header.flags.value()); - data->name = shStrTab + section.header.name; - data->address = section.header.addr; + if (type == elf::SHT_PROGBITS) { + auto data = ElfFile::DataSection::New(address, name, type, flags); data->data = section.data; - data->size = section.header.size; - file.dataSections.emplace_back(data); + data->size = size; + data->inIndex = index; + dataSectionIndex[index] = data; + file.addDataSection(data); + if (verbose >= verbose_loaded_sections) { - std::cout << "Data section " << data->name - << std::hex << ": 0x" << data->address - << " - 0x" << data->address + data->size << std::endl; + std::cout << "Data section #" << index << ' ' << name + << std::hex << ": 0x" << address << " - 0x" << address + size << std::endl; } - } else if (section.header.type == elf::SHT_NOBITS) { - auto bss = new ElfFile::DataSection(); - bss->type = elf::SHT_NOBITS; - bss->flags = static_cast(section.header.flags.value()); - bss->name = shStrTab + section.header.name; - bss->address = section.header.addr; - bss->size = section.header.size; - file.dataSections.emplace_back(bss); + } else if (type == elf::SHT_NOBITS) { + auto bss = ElfFile::DataSection::New(address, name, type, flags); + bss->size = size; + bss->inIndex = index; + dataSectionIndex[index] = bss; + file.addDataSection(bss); + if (verbose >= verbose_loaded_sections) { - std::cout << "BSS section " << bss->name - << std::hex << ": 0x" << bss->address << " - 0x" - << bss->address + bss->size << std::endl; + std::cout << "BSS section #" << index << ' ' << name + << std::hex << ": 0x" << address << " - 0x" << address + size << std::endl; } } else { if (verbose >= verbose_loaded_sections) { - std::string name = shStrTab + section.header.name; - std::cout << "Section type 0x" << section.header.type << ' ' << name - << std::hex << ": 0x" << section.header.addr << " - 0x" - << section.header.addr + section.header.size << std::endl; + std::cout << "Section #" << index << " type 0x" << type << ' ' << name + << std::hex << ": 0x" << address << " - 0x" << address + size << std::endl; } } } /* Default symbols */ - auto symNull = new ElfFile::Symbol(); - symNull->address = 0; - symNull->size = 0; - symNull->type = elf::STT_NOTYPE; - symNull->binding = elf::STB_LOCAL; - file.symbols.emplace_back(symNull); + auto symNull = ElfFile::Symbol::New(0, "", 0, elf::STT_NOTYPE, elf::STB_LOCAL); + file.addSymbol(symNull); - auto symText = new ElfFile::Symbol(); - symText->name = "$TEXT"; - symText->address = CodeAddress; - symText->size = 0; - symText->type = elf::STT_SECTION; - symText->binding = elf::STB_LOCAL; - file.symbols.emplace_back(symText); + auto symText = ElfFile::Symbol::New(CodeAddress, "$TEXT", 0, elf::STT_SECTION, elf::STB_LOCAL); + file.addSymbol(symText); - auto symData = new ElfFile::Symbol(); - symData->name = "$DATA"; - symData->address = DataAddress; - symData->size = 0; - symData->type = elf::STT_SECTION; - symData->binding = elf::STB_LOCAL; - file.symbols.emplace_back(symData); + auto symData = ElfFile::Symbol::New(DataAddress, "$DATA", 0, elf::STT_SECTION, elf::STB_LOCAL); + file.addSymbol(symData); - auto symUndef = new ElfFile::Symbol(); - symUndef->name = "$UNDEF"; - symUndef->address = 0; - symUndef->size = 0; - symUndef->type = elf::STT_OBJECT; - symUndef->binding = elf::STB_GLOBAL; - file.symbols.emplace_back(symUndef); + auto symUndef = ElfFile::Symbol::New(0, "$UNDEF", 0, elf::STT_OBJECT, elf::STB_GLOBAL); + file.addSymbol(symUndef); /* Read symbols */ for (auto §ion : inSections) @@ -368,8 +639,8 @@ read(ElfFile &file, const std::string &filename) if (sym.value >= LoadAddress && sym.value < CodeAddress) continue; - auto type = static_cast(sym.info & 0xF); - auto binding = static_cast((sym.info >> 4) & 0xF); + auto type = elf::SymbolType(sym.info & 0xF); + auto binding = elf::SymbolBinding((sym.info >> 4) & 0xF); if (type == elf::STT_NOTYPE && sym.value == 0) { /* Skip null symbol */ @@ -381,19 +652,24 @@ read(ElfFile &file, const std::string &filename) continue; } - auto symbol = new ElfFile::Symbol(); - symbol->name = strTab + sym.name; - symbol->address = sym.value; - symbol->size = sym.size; - symbol->type = type; - symbol->binding = binding; - file.symbols.emplace_back(symbol); + auto name = strTab + sym.name; + auto symbol = ElfFile::Symbol::New(sym.value, name, sym.size, type, binding); + auto inSection = dataSectionIndex[sym.shndx]; + if (inSection && inSection->size != 0) + symbol->inSection = dataSectionIndex[sym.shndx]; if (verbose >= verbose_loaded_symbols) { std::cout << "Symbol " << symbol->name << " 0x" << std::hex << symbol->address - << " 0x" << symbol->size << '\n'; + << " 0x" << symbol->size; + if (symbol->inSection) + { + std::cout << " (" << symbol->inSection->name << ')'; + } + std::cout << '\n'; } + + file.addSymbol(symbol); } } @@ -410,49 +686,50 @@ read(ElfFile &file, const std::string &filename) for (unsigned i = 0u; i < count; ++i) { auto &rpl = rplTab[i]; - auto lib = new ElfFile::RplImportLibrary(); - lib->name = getLoaderDataPtr(inSections, rpl.name); + auto libName = getLoaderDataPtr(inSections, rpl.name); + auto lib = ElfFile::RplImportLibrary::New(libName); - if (verbose >= verbose_loaded_imports) + if (verbose >= verbose_loaded_sections) { - std::cout << "Import library " << lib->name << std::endl; + std::cout << "Import library " << libName << std::endl; } for (auto stubAddr = rpl.stubStart; stubAddr < rpl.stubEnd; stubAddr += 4) { - auto import = new ElfFile::RplImport(); - import->trampAddr = byte_swap(*getLoaderDataPtr(inSections, stubAddr)); - import->stubAddr = stubAddr; + auto trampAddr = byte_swap(*getLoaderDataPtr(inSections, stubAddr)); /* Get the tramp symbol */ - import->trampSymbol = findSymbol(file, import->trampAddr); - import->trampSymbol->refCount++; + auto trampSymbol = file.findSymbol(trampAddr); - /* Create a new symbol to use for the import */ - auto stubSymbol = new ElfFile::Symbol(); - import->stubSymbol = stubSymbol; - stubSymbol->name = import->trampSymbol->name; - stubSymbol->address = 0; - stubSymbol->size = 0; - stubSymbol->binding = elf::STB_GLOBAL; - stubSymbol->type = elf::STT_FUNC; - stubSymbol->refCount++; - file.symbols.emplace_back(stubSymbol); - - /* Rename tramp symbol */ - import->trampSymbol->name += "_tramp"; - - if (verbose >= verbose_loaded_symbols) + if (!trampSymbol) { - std::cout << "Import trampoline " << import->trampSymbol->name << std::endl; + std::cout << "No symbol found for import @ 0x" << std::hex << trampAddr << " in " << libName << std::endl; } - lib->imports.emplace_back(import); + if (verbose >= verbose_loaded_imports) + { + std::cout << "Import symbol " << trampSymbol->name << " 0x" << std::hex << stubAddr << " -> 0x" << trampAddr << std::endl; + } + + /* Create a new symbol to use for the import */ + auto stubSymbol = ElfFile::Symbol::New(0, trampSymbol->name, 0, elf::STT_FUNC, elf::STB_GLOBAL); + auto import = ElfFile::RplImport::New(stubAddr, trampAddr, stubSymbol, trampSymbol); + + /* Rename tramp symbol */ + /* These are not needed anymore, right */ + /* trampSymbol->refCount++; */ + trampSymbol->name += "_tramp"; + + stubSymbol->refCount++; + file.addSymbol(stubSymbol); + file.addImport(lib, import); } - file.rplImports.emplace_back(lib); + file.addImportLibrary(lib); } } + ElfFile::DataSectionPtr prevSection; + /* Read relocations */ for (auto §ion : inSections) { if (section.header.type != elf::SHT_RELA) @@ -471,7 +748,7 @@ read(ElfFile &file, const std::string &filename) for (unsigned i = 0u; i < count; ++i) { - auto relocation = new ElfFile::Relocation(); + auto relocation = std::make_shared(); auto &rela = relTab[i]; auto type = rela.info & 0xff; @@ -490,43 +767,54 @@ read(ElfFile &file, const std::string &filename) if (verbose >= verbose_loaded_relocations) { - std::cout << "Relocation #" << std::dec << file.relocations.size() + std::cout << "Relocation #" << std::dec << file.getRelocations().size() + << " sym index " << index << ' ' << " offset 0x" << std::hex << rela.offset << " addend 0x" << addend; } - if (auto import = findImport(file, addend)) { + if (auto import = file.findImport(addend)) { relocation->symbol = import->stubSymbol; relocation->addend = 0; if (verbose >= verbose_loaded_relocations) { std::cout << " -> import "; } - } else if (auto symbol = findSymbol(file, addend)) { + } else if (auto symbol = file.findSymbol(addend)) { relocation->symbol = symbol; relocation->addend = 0; if (verbose >= verbose_loaded_relocations) { std::cout << " -> symbol "; } +#if 0 } else if (addend >= DataAddress && addend < WiiuLoadAddress) { - relocation->symbol = findSymbol(file, DataAddress); + relocation->symbol = symData; relocation->addend = addend - DataAddress; if (verbose >= verbose_loaded_relocations) { std::cout << " -> data symbol "; } } else if (addend >= CodeAddress && addend < DataAddress) { - relocation->symbol = findSymbol(file, CodeAddress); + relocation->symbol = symText; relocation->addend = addend - CodeAddress; if (verbose >= verbose_loaded_relocations) { - std::cout << "-> code symbol "; + std::cout << " -> code symbol "; } +#else + } else if ((prevSection = file.findSection(addend)) != nullptr) { + relocation->symbolSection = prevSection; + relocation->addend = addend - prevSection->address; + if (verbose >= verbose_loaded_relocations) + { + std::cout << " -> section "; + } +#endif } else { if (verbose >= verbose_loaded_relocations) { - std::cout << "-> not found" << std::endl; + std::cout << " -> not found" << std::endl; } /* If we can't find a proper symbol, write the addend in and hope for the best */ @@ -539,13 +827,21 @@ read(ElfFile &file, const std::string &filename) if (verbose >= verbose_loaded_relocations) { - std::cout << relocation->symbol->name << std::endl; + if (relocation->symbol) + std::cout << relocation->symbol->name; + else if (relocation->symbolSection) + std::cout << relocation->symbolSection->name; + if (relocation->addend != 0) + std::cout << " + " << relocation->addend; + std::cout << std::endl; } - - relocation->symbol->refCount++; + + if (relocation->symbol) + relocation->symbol->refCount++; relocation->target = rela.offset; relocation->type = static_cast(type); - file.relocations.emplace_back(relocation); + + file.addRelocation(relocation); } } @@ -565,7 +861,7 @@ read(ElfFile &file, const std::string &filename) auto count = section.data.size() / sizeof(elf::Rela); for (unsigned i = 0u; i < count; ++i) { - auto relocation = new ElfFile::Relocation(); + auto relocation = std::make_shared(); auto &rela = relas[i]; auto type = rela.info & 0xff; @@ -573,57 +869,67 @@ read(ElfFile &file, const std::string &filename) auto symbol = getSectionSymbol(symSection, index); auto addr = symbol->value + rela.addend; - if(type == elf::R_PPC_NONE) + if (type == elf::R_PPC_NONE) { /* ignore padding */ continue; } - if (verbose >= verbose_loaded_relocations) + if (verbose >= verbose_loaded_dyn_reloc) { - std::cout << "Dyn relocation #" << std::dec << file.relocations.size() + std::cout << "Dyn relocation #" << std::dec << file.getRelocations().size() << " offset 0x" << std::hex << rela.offset << " addend 0x" << rela.addend << " addr 0x" << addr; } - // Why index must be == 0? + // Why index must be == 0? Cause it's required for R_PPC_RELATIVE if (index == 0) { auto addend = static_cast(rela.addend); - if (auto import = findImport(file, addend)) { + if (auto import = file.findImport(addend)) { relocation->symbol = import->stubSymbol; relocation->addend = 0; - if (verbose >= verbose_loaded_relocations) + if (verbose >= verbose_loaded_dyn_reloc) { - std::cout << "-> import "; + std::cout << " -> import "; } - } else if (auto symbol = findSymbol(file, addend)) { + } else if (auto symbol = file.findSymbol(addend)) { relocation->symbol = symbol; - relocation->addend = 0; - if (verbose >= verbose_loaded_relocations) + relocation->addend = addend - symbol->address; + if (verbose >= verbose_loaded_dyn_reloc) { - std::cout << "-> symbol "; + std::cout << " -> symbol "; } +#if 0 } else if (addr >= CodeAddress && addr < DataAddress) { index = 1; - relocation->symbol = findSymbol(file, CodeAddress); + relocation->symbol = symText; relocation->addend = rela.addend - CodeAddress; - if (verbose >= verbose_loaded_relocations) + if (verbose >= verbose_loaded_dyn_reloc) { - std::cout << "-> code symbol "; + std::cout << " -> code symbol "; } } else if (addr >= DataAddress && addr < WiiuLoadAddress) { index = 2; - relocation->symbol = findSymbol(file, DataAddress); + relocation->symbol = symData; relocation->addend = rela.addend - DataAddress; + if (verbose >= verbose_loaded_dyn_reloc) + { + std::cout << " -> data symbol "; + } +#else + } else if ((prevSection = file.findSection(addend)) != nullptr) { + relocation->symbolSection = prevSection; + relocation->addend = addend - prevSection->address; if (verbose >= verbose_loaded_relocations) { - std::cout << "-> data symbol"; + std::cout << " -> section "; } +#endif } else { - if (verbose >= verbose_loaded_relocations) + if (verbose >= verbose_loaded_dyn_reloc) { std::cout << " -> bad" << std::endl; } @@ -634,11 +940,9 @@ read(ElfFile &file, const std::string &filename) } else { - // Again, I don't know why we fall here, but relocation is now uninitialized, - // so I can't continue and add it to list - if (verbose >= verbose_loaded_relocations) + if (verbose >= verbose_loaded_dyn_reloc) { - std::cout << " -> index" << index << std::endl; + std::cout << " -> index " << std::dec << index << std::endl; } std::cout << "Unexpected relocation symbol index " << std::dec << index @@ -646,6 +950,17 @@ read(ElfFile &file, const std::string &filename) return false; } + if (verbose >= verbose_loaded_dyn_reloc) + { + if (relocation->symbol) + std::cout << relocation->symbol->name; + else if (relocation->symbolSection) + std::cout << relocation->symbolSection->name; + if (relocation->addend != 0) + std::cout << " + " << relocation->addend; + std::cout << std::endl; + } + switch (type) { case elf::R_PPC_RELATIVE: type = elf::R_PPC_ADDR32; @@ -661,8 +976,9 @@ read(ElfFile &file, const std::string &filename) /* Scrap any compiler/linker garbage */ if(relocation->target >= CodeAddress && relocation->target < WiiuLoadAddress) { - relocation->symbol->refCount++; - file.relocations.emplace_back(relocation); + if (relocation->symbol) + relocation->symbol->refCount++; + file.addRelocation(relocation); } } @@ -676,69 +992,177 @@ struct OutputSection std::string name; elf::SectionHeader header; std::vector data; - OutputSection *relocationSection = nullptr; - ElfFile::Symbol *sectionSymbol = nullptr; + std::shared_ptr relocationSection; + std::shared_ptr sectionSymbol; + uint32_t index = uint32_t(-1); + + bool contains(uint32_t address, uint32_t size = 0) + { + + if (!(header.flags & elf::SHF_ALLOC) || header.size == 0 || header.size == uint32_t(-1)) + return false; + + auto start = header.addr; + auto end = start + header.size; + + if (address >= start && address + size <= end) + return true; + return false; + } }; -template -SymbolIterator addSection(ElfFile &file, std::vector &outSections, SymbolIterator symbolIterator, OutputSection *section) +struct OutputSections { - auto sectionSymbol = new ElfFile::Symbol(); - sectionSymbol->name = section->name; - sectionSymbol->address = section->header.addr; - sectionSymbol->size = -1; - sectionSymbol->type = elf::STT_SECTION; - sectionSymbol->binding = elf::STB_LOCAL; - section->sectionSymbol = sectionSymbol; - outSections.push_back(section); - return file.symbols.insert(symbolIterator, std::unique_ptr { sectionSymbol }) + 1; + std::vector> sections; + std::map> sections_by_name; + + void addSection(std::shared_ptr section) + { + section->index = sections.size(); + sections.push_back(section); + if (verbose >= verbose_output_sections) + { + auto& header = section->header; + std::cout << "Output section #" << std::dec << section->index + << std::hex << ' ' << section->header.type << ' ' << section->header.flags + << ' ' << section->name + << " (0x" << header.addr << " - 0x" << header.addr + header.size << ')' + << std::endl; + } + if (!section->name.empty()) + { + if (sections_by_name.count(section->name)) + { + std::cout << "Duplicate output section name " << section->name + << std::endl; + } + else + { + sections_by_name[section->name] = section; + } + } + }; + + + template + SymbolIterator addSection(ElfFile &file, SymbolIterator symbolIterator, std::shared_ptr section) + { + ElfFile::SymbolPtr sectionSymbol; + if (section->header.size != 0) + { + sectionSymbol = ElfFile::Symbol::New(section->header.addr, section->name, -1, elf::STT_SECTION, elf::STB_LOCAL); + sectionSymbol->outSection = section; + section->sectionSymbol = sectionSymbol; + } + section->index = sections.size(); + sections.push_back(section); + + if (verbose >= verbose_output_sections) + { + auto& header = section->header; + std::cout << "Output section #" << std::dec << section->index + << std::hex << ' ' << section->header.type << ' ' << section->header.flags + << ' ' << section->name + << " (0x" << header.addr << " - 0x" << header.addr + header.size << ')' + << std::endl; + } + + if (sections_by_name.count(section->name)) + { + std::cout << "Duplicate output section name " << section->name + << std::endl; + } + else + { + sections_by_name[section->name] = section; + } + + if (!sectionSymbol) + return symbolIterator; + + if (verbose >= verbose_loaded_symbols) + { + std::cout << "Section symbol " << sectionSymbol->name << " 0x" << std::hex << sectionSymbol->address + << " 0x" << sectionSymbol->size << '\n'; + } + + return file.insertSymbol(symbolIterator, sectionSymbol) + 1; + }; + + uint32_t + getSectionIndex(uint32_t address) + { + if (address == 0) + return 0; + + for (unsigned i = 0u; i < sections.size(); ++i) + { + if (sections[i]->contains(address)) + return i; + } + + return -1; + } + + uint32_t + getSectionIndex(const std::string &name) + { + auto iter = sections_by_name.find(name); + if (iter == sections_by_name.end()) + return -1; + return iter->second->index; + } + + std::shared_ptr + getSection(uint32_t address, + const std::shared_ptr& hint = nullptr) + { + if (address == 0) + return sections[0]; + + if (hint && hint->contains(address)) + return hint; + + for (auto §ion : sections) { + if (section->contains(address)) + return section; + } + + return nullptr; + } + + std::shared_ptr + getSection(const std::string &name) + { + auto iter = sections_by_name.find(name); + if (iter == sections_by_name.end()) + return nullptr; + return iter->second; + } + + const std::vector>& + getSections() + { + return sections; + } + }; -static uint32_t -getSectionIndex(std::vector &outSections, uint32_t address) -{ - for (unsigned i = 0u; i < outSections.size(); ++i) - { - auto §ion = outSections[i]; - auto start = section->header.addr; - auto end = start + section->header.size; - - if (address >= start && address < end) - return i; - } - - return -1; -} - -static uint32_t -getSectionIndex(std::vector &outSections, const std::string &name) -{ - for (unsigned i = 0u; i < outSections.size(); ++i) - { - auto §ion = outSections[i]; - - if (section->name.compare(name) == 0) - return i; - } - - return -1; -} - static bool write(ElfFile &file, const std::string &filename) { - std::vector outSections; - auto sectionSymbolItr = file.symbols.begin() + 4; + OutputSections outSections; + auto sectionSymbolItr = file.getSymbols().begin() + 4; /* Create NULL section */ - auto nullSection = new OutputSection(); + auto nullSection = std::make_shared(); memset(&nullSection->header, 0, sizeof(elf::SectionHeader)); - outSections.push_back(nullSection); + outSections.addSection(nullSection); /* Create text/data sections */ - for (auto §ion : file.dataSections) + for (auto §ion : file.getDataSections()) { - auto out = new OutputSection(); + auto out = std::make_shared(); out->header.name = -1; out->header.type = section->type; out->header.flags = section->flags; @@ -766,22 +1190,15 @@ write(ElfFile &file, const std::string &filename) /* Add section */ out->name = section->name; out->data = section->data; - sectionSymbolItr = addSection(file, outSections, sectionSymbolItr, out); + section->outSection = out; + sectionSymbolItr = outSections.addSection(file, sectionSymbolItr, out); } + std::shared_ptr targetSection; + /* Create relocation sections */ - for (auto &relocation : file.relocations) { - OutputSection *targetSection = nullptr; - - for (auto §ion : outSections) { - auto start = section->header.addr; - auto end = start + section->header.size; - - if (relocation->target >= start && relocation->target < end) { - targetSection = section; - break; - } - } + for (auto &relocation : file.getRelocations()) { + targetSection = outSections.getSection(relocation->target, targetSection); if (!targetSection) { @@ -789,10 +1206,12 @@ write(ElfFile &file, const std::string &filename) return false; } + relocation->targetSection = targetSection; + if (!targetSection->relocationSection) { /* Create new relocation section */ - auto out = new OutputSection(); + auto out = std::make_shared(); out->header.name = -1; out->header.type = elf::SHT_RELA; out->header.flags = 0; @@ -800,13 +1219,13 @@ write(ElfFile &file, const std::string &filename) out->header.offset = -1; out->header.size = -1; out->header.link = -1; - out->header.info = getSectionIndex(outSections, targetSection->header.addr); + out->header.info = targetSection->index; out->header.addralign = 4; out->header.entsize = sizeof(elf::Rela); /* Add section */ out->name = ".rela" + targetSection->name; - sectionSymbolItr = addSection(file, outSections, sectionSymbolItr, out); + sectionSymbolItr = outSections.addSection(file, sectionSymbolItr, out); targetSection->relocationSection = out; } } @@ -817,13 +1236,13 @@ write(ElfFile &file, const std::string &filename) auto predictSymTabSize = 1; auto predictShstrTabSize = 1; - for (auto &symbol : file.symbols) + for (auto &symbol : file.getSymbols()) { predictStrTabSize += symbol->name.size() + 1; predictSymTabSize += sizeof(elf::Symbol); } - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) predictShstrTabSize += section->name.size() + 1; predictStrTabSize = align_up(predictStrTabSize, 0x10); @@ -832,9 +1251,9 @@ write(ElfFile &file, const std::string &filename) loadAddress += predictStrTabSize + predictSymTabSize + predictShstrTabSize; /* Create RPL import sections, .fimport_*, .dimport_* */ - for (auto &lib : file.rplImports) + for (auto &lib : file.getImportLibs()) { - auto out = new OutputSection(); + auto out = std::make_shared(); out->header.name = -1; out->header.type = elf::SHT_RPL_IMPORTS; out->header.flags = elf::SHF_ALLOC | elf::SHF_EXECINSTR; @@ -866,42 +1285,23 @@ write(ElfFile &file, const std::string &filename) loadAddress = align_up(loadAddress + out->header.size, 4); /* Add section */ - sectionSymbolItr = addSection(file, outSections, sectionSymbolItr, out); + sectionSymbolItr = outSections.addSection(file, sectionSymbolItr, out); } /* Prune out unneeded symbols - but keep those used for relocations! */ - for (unsigned i = 0u; i < file.symbols.size(); ++i) - { - if (!file.symbols[i]->name.empty() && file.symbols[i]->type == elf::STT_NOTYPE - && file.symbols[i]->size == 0 && file.symbols[i]->refCount == 0) - { - if (verbose >= verbose_pruned_symbols) - { - std::cout << "Pruning symbol " << file.symbols[i]->name << std::endl; - } - - file.symbols.erase(file.symbols.begin() + i); - i--; - } - } + file.pruneSymbols(); + file.indexSymbols(); /* NOTICE: FROM NOW ON DO NOT MODIFY mSymbols */ + auto symText = file.findSymbol(CodeAddress); + auto symData = file.findSymbol(DataAddress); + int number = -1; /* Convert relocations */ - for (auto &relocation : file.relocations) { + for (auto &relocation : file.getRelocations()) { ++number; - OutputSection *targetSection = nullptr; - - for (auto §ion : outSections) { - auto start = section->header.addr; - auto end = start + section->header.size; - - if (relocation->target >= start && relocation->target < end) { - targetSection = section; - break; - } - } + auto targetSection = relocation->targetSection; if (!targetSection || !targetSection->relocationSection) { std::cout << "Error could not find section for relocation" << std::endl; @@ -912,12 +1312,13 @@ write(ElfFile &file, const std::string &filename) auto relocationSection = targetSection->relocationSection; /* Find symbol this relocation points to */ - auto itr = std::find_if(file.symbols.begin(), file.symbols.end(), [&relocation](auto &val) { - return val.get() == relocation->symbol; - }); + if (!relocation->symbol && relocation->symbolSection && relocation->symbolSection->outSection) + relocation->symbol = relocation->symbolSection->outSection->sectionSymbol; - auto idx = itr - file.symbols.begin(); - bool symbol_found = (itr != file.symbols.end()); + auto symbol = relocation->symbol; + + auto idx = symbol->outIndex; + bool symbol_found = idx != -1; if ((verbose >= verbose_convert_relocations) || !symbol_found) { @@ -926,20 +1327,21 @@ write(ElfFile &file, const std::string &filename) } if ((verbose >= verbose_convert_relocations) && symbol_found) { - std::cout << "-> symbol index: " << idx << std::endl; + std::cout << "-> symbol " << std::dec << idx + << ' ' << symbol->name << std::endl; } /* If the symbol doesn't exist but it is within DATA or TEXT, use those symbols + an addend */ - if (itr == file.symbols.end()) { + if (!symbol_found) { if (relocation->symbol->address >= CodeAddress && relocation->symbol->address < DataAddress) { idx = 1; relocation->addend = relocation->symbol->address - CodeAddress; - relocation->symbol = findSymbol(file, CodeAddress); + relocation->symbol = symText; std::cout << "-> no symbol, using TEXT" << std::endl; } else if (relocation->symbol->address >= DataAddress && relocation->symbol->address < WiiuLoadAddress) { idx = 2; relocation->addend = relocation->symbol->address - DataAddress; - relocation->symbol = findSymbol(file, DataAddress); + relocation->symbol = symData; std::cout << "-> no symbol, using DATA" << std::endl; } else { std::cout << "-> invalid" << std::endl; @@ -964,25 +1366,25 @@ write(ElfFile &file, const std::string &filename) } /* String + Symbol sections */ - auto symTabSection = new OutputSection(); - auto strTabSection = new OutputSection(); - auto shStrTabSection = new OutputSection(); + auto symTabSection = std::make_shared(); + auto strTabSection = std::make_shared(); + auto shStrTabSection = std::make_shared(); symTabSection->name = ".symtab"; strTabSection->name = ".strtab"; shStrTabSection->name = ".shstrtab"; - auto symTabIndex = outSections.size(); - outSections.push_back(symTabSection); + outSections.addSection(symTabSection); + auto symTabIndex = symTabSection->index; - auto strTabIndex = outSections.size(); - outSections.push_back(strTabSection); + outSections.addSection(strTabSection); + auto strTabIndex = strTabSection->index; - auto shStrTabIndex = outSections.size(); - outSections.push_back(shStrTabSection); + outSections.addSection(shStrTabSection); + auto shStrTabIndex = shStrTabSection->index; /* Update relocation sections to link to symtab */ - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) { if (section->header.type == elf::SHT_RELA) section->header.link = symTabIndex; @@ -1012,7 +1414,7 @@ write(ElfFile &file, const std::string &filename) /* Add all symbol names to data, update symbol->outNamePos */ strTabSection->data.push_back(0); - for (auto &symbol : file.symbols) + for (auto &symbol : file.getSymbols()) { if (symbol->name.empty()) symbol->outNamePos = 0; @@ -1036,17 +1438,24 @@ write(ElfFile &file, const std::string &filename) symTabSection->header.addralign = 4; symTabSection->header.entsize = sizeof(elf::Symbol); - for (auto &symbol : file.symbols) + std::shared_ptr symSection; + + for (auto &symbol : file.getSymbols()) { elf::Symbol sym; - auto shndx = getSectionIndex(outSections, symbol->address); + if (symbol->outSection) + symSection = symbol->outSection; + else if (symbol->inSection && symbol->inSection->outSection) + symSection = symbol->inSection->outSection; + else if (symbol->type == elf::STT_SECTION && symbol->address == 0) + symSection = outSections.getSection(symbol->name); + else + symSection = outSections.getSection(symbol->address, symSection); - if (symbol->type == elf::STT_SECTION && symbol->address == 0) - shndx = getSectionIndex(outSections, symbol->name); - - if (shndx == (uint32_t)-1) + if (symSection == nullptr) { - std::cout << "Could not find section for symbol" << std::endl; + std::cout << "Could not find section for symbol " << symbol->name + << " 0x" << std::hex << symbol->address << std::endl; return false; } @@ -1055,13 +1464,22 @@ write(ElfFile &file, const std::string &filename) sym.size = symbol->size; sym.info = symbol->type | (symbol->binding << 4); sym.other = 0; - sym.shndx = shndx; + sym.shndx = symSection->index; + + if (verbose >= verbose_output_symbols) + { + std::cout << std::right + << std::hex << std::setfill('0') << std::setw(8) << symbol->address + << ' ' << std::setw(8) << symbol->size << std::dec + << ' ' << std::setfill(' ') << std::setw(3) << sym.shndx + << ' ' << std::setw(12) << std::left << symSection->name + << ' ' << symbol->name << std::endl; + } /* Compound symbol crc into section crc */ - auto crcSection = outSections[shndx]; - if(crcSection->header.type == elf::SHT_RPL_IMPORTS && symbol->type != elf::STT_SECTION) + if (symSection->header.type == elf::SHT_RPL_IMPORTS && symbol->type != elf::STT_SECTION) { - auto rplImport = reinterpret_cast(crcSection->data.data()); + auto rplImport = reinterpret_cast(symSection->data.data()); rplImport->signature = crc32(rplImport->signature, reinterpret_cast(strTabSection->data.data() + sym.name),strlen(strTabSection->data.data() + sym.name)+1); } @@ -1072,7 +1490,7 @@ write(ElfFile &file, const std::string &filename) /* Finish SHT_RPL_IMPORTS signatures */ Bytef *zero_buffer = reinterpret_cast(calloc(0x10, 1)); - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) { if(section->header.type == elf::SHT_RPL_IMPORTS) { @@ -1097,7 +1515,7 @@ write(ElfFile &file, const std::string &filename) /* Add all section header names to data, update section->header.name */ shStrTabSection->data.push_back(0); - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) { if (section->name.empty()) section->header.name = 0; @@ -1124,7 +1542,7 @@ write(ElfFile &file, const std::string &filename) shStrTabSection->header.size = shStrTabSection->data.size(); /* Create SHT_RPL_FILEINFO section */ - auto fileInfoSection = new OutputSection(); + auto fileInfoSection = std::make_shared(); fileInfoSection->header.name = 0; fileInfoSection->header.type = elf::SHT_RPL_FILEINFO; fileInfoSection->header.flags = 0; @@ -1164,7 +1582,7 @@ write(ElfFile &file, const std::string &filename) fileInfo.tagOffset = 0; /* Count file info textSize, dataSize, loadSize */ - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) { auto size = section->data.size(); @@ -1201,7 +1619,7 @@ write(ElfFile &file, const std::string &filename) fileInfoSection->data.insert(fileInfoSection->data.end(), fileInfoData, fileInfoData + sizeof(elf::RplFileInfo)); /* Create SHT_RPL_CRCS section */ - auto crcSection = new OutputSection(); + auto crcSection = std::make_shared(); crcSection->header.name = 0; crcSection->header.type = elf::SHT_RPL_CRCS; crcSection->header.flags = 0; @@ -1213,12 +1631,12 @@ write(ElfFile &file, const std::string &filename) crcSection->header.addralign = 4; crcSection->header.entsize = 4; - outSections.push_back(crcSection); - outSections.push_back(fileInfoSection); + outSections.addSection(crcSection); + outSections.addSection(fileInfoSection); std::vector sectionCRCs; - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) { auto crc = 0u; @@ -1236,10 +1654,10 @@ write(ElfFile &file, const std::string &filename) /* Update section sizes and offsets */ auto shoff = align_up(sizeof(elf::Header), 64); - auto dataOffset = align_up(shoff + outSections.size() * sizeof(elf::SectionHeader), 64); + auto dataOffset = align_up(shoff + outSections.getSections().size() * sizeof(elf::SectionHeader), 64); /* Add CRC and FileInfo sections first */ - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) { if (section->header.type != elf::SHT_RPL_CRCS && section->header.type != elf::SHT_RPL_FILEINFO) continue; @@ -1257,7 +1675,7 @@ write(ElfFile &file, const std::string &filename) } /* Add data sections next */ - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) { if(section->header.offset != -1) continue; @@ -1268,17 +1686,12 @@ write(ElfFile &file, const std::string &filename) if (section->header.type != elf::SHT_NOBITS) section->header.size = section->data.size(); - if (!section->data.empty()) - { - section->header.offset = dataOffset; - dataOffset = align_up(section->header.offset + section->data.size(), 64); - } - else - section->header.offset = 0; + section->header.offset = dataOffset; + dataOffset = align_up(section->header.offset + section->data.size(), 64); } /* Add load sections next */ - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) { if(section->header.offset != -1) continue; @@ -1298,7 +1711,7 @@ write(ElfFile &file, const std::string &filename) } /* Everything else */ - for (auto §ion : outSections) { + for (auto §ion : outSections.getSections()) { if(section->header.offset != -1) continue; @@ -1339,7 +1752,7 @@ write(ElfFile &file, const std::string &filename) header.phentsize = 0; header.phnum = 0; header.shoff = shoff; - header.shnum = outSections.size(); + header.shnum = outSections.getSections().size(); header.shentsize = sizeof(elf::SectionHeader); header.flags = 0; header.ehsize = sizeof(elf::Header); @@ -1349,11 +1762,11 @@ write(ElfFile &file, const std::string &filename) /* Write section headers */ out.seekp(header.shoff.value()); - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) out.write(reinterpret_cast(§ion->header), sizeof(elf::SectionHeader)); /* Write section data */ - for (auto §ion : outSections) + for (auto §ion : outSections.getSections()) { if (!section->data.empty()) {