diff --git a/Elf2Mac/CMakeLists.txt b/Elf2Mac/CMakeLists.txt index c8d3db922d..a46de9dbca 100644 --- a/Elf2Mac/CMakeLists.txt +++ b/Elf2Mac/CMakeLists.txt @@ -19,7 +19,13 @@ cmake_minimum_required(VERSION 3.1) find_package(Boost COMPONENTS REQUIRED) -add_executable(Elf2Mac Elf2Mac.h Elf2Mac.cc SegmentMap.cc LdScript.cc) +add_executable(Elf2Mac + Elf2Mac.h Elf2Mac.cc SegmentMap.cc LdScript.cc + Reloc.h Reloc.cc + Symbol.h Symbol.cc + Symtab.h Symtab.cc + Section.h Section.cc + Object.h Object.cc) target_link_libraries(Elf2Mac ResourceFiles ELF) target_include_directories(Elf2Mac PRIVATE ${CMAKE_INSTALL_PREFIX}/include) diff --git a/Elf2Mac/Elf2Mac.cc b/Elf2Mac/Elf2Mac.cc index 8f16b66798..11d88ade61 100644 --- a/Elf2Mac/Elf2Mac.cc +++ b/Elf2Mac/Elf2Mac.cc @@ -20,756 +20,26 @@ #include "Elf2Mac.h" #include "SegmentMap.h" -#include "ResourceFork.h" -#include "BinaryIO.h" -#include "ResourceFile.h" - #include #include -#include -#include -#include #include -#include -#include #include #include #include -#include -#include + +#include +#include +#include #include -#include + +#include "Object.h" using std::string; -using std::unordered_map; -using std::map; using std::vector; using std::ofstream; -using std::shared_ptr; -using std::make_shared; -using std::unique_ptr; -using std::pair; -using std::make_pair; - -size_t sectionHeaderStringTableIdx; -size_t mainStringTableIdx = (size_t)-1; - -class Symtab; -class Section; - -SegmentMap segmentMap; - -Elf *elf; -std::vector relocs; -unique_ptr symtab; -unordered_map> sections; -unordered_map> sectionsByElfIndex; - -std::vector> codeSections; -shared_ptr
dataSection, bssSection; - -enum class SectionKind -{ - undefined = -1, - code = 0, - data, - bss -}; - -enum class RelocBase -{ - code = 0, - data, - bss, - jumptable, - code1 -}; - -class Symbol : public GElf_Sym -{ -public: - bool valid; - bool referencedExternally; - SectionKind sectionKind; - bool needsJT; - int jtIndex; - shared_ptr
section; - - Symbol(); - Symbol(const GElf_Sym& sym); - - string GetName(); -}; - -class Symtab -{ -public: - Elf_Scn *elfsec; - Elf_Data *data; - vector symbols; - map, int> symbolsByAddress; - unordered_map symbolsByName; - - Symtab(Elf_Scn *elfsec); - - Symbol& GetSym(int idx); - int FindSym(int secidx, uint32_t addr); - int FindSym(string name); -}; - -class Reloc : public GElf_Rela -{ -public: - RelocBase relocBase; - - Reloc(); - Reloc(const GElf_Rela& rela); -}; - -class Section -{ -public: - string name; - int idx; - SectionKind kind; - Elf_Scn *elfsec, *relasec; - Elf_Data *data; - GElf_Shdr shdr; - uint32_t outputBase; - uint32_t exceptionInfoStart; - - int codeID; - - std::vector relocs; - std::vector jtEntries; - int firstJTEntryIndex; - - Section(string name, int idx, SectionKind kind, Elf_Scn *elfsec); - void SetRela(Elf_Scn *scn); - - uint32_t GetSize(); - string GetData(); - string GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry = false); - - void ScanRelocs(); - void FixRelocs(); - -}; - -Symbol::Symbol() - : valid(false) -{ -} - -Symbol::Symbol(const GElf_Sym &sym) - : GElf_Sym(sym), valid(true), - referencedExternally(false), - sectionKind(SectionKind::undefined), - needsJT(false) -{ - if(st_shndx != SHN_UNDEF && st_shndx < SHN_LORESERVE) - { - section = sectionsByElfIndex[st_shndx]; - sectionKind = section->kind; - } -} - -string Symbol::GetName() -{ - return elf_strptr(elf, mainStringTableIdx, st_name); -} - -Symtab::Symtab(Elf_Scn *elfsec) - : elfsec(elfsec) -{ - data = elf_getdata(elfsec, NULL); - - GElf_Shdr shdr; - gelf_getshdr(elfsec, &shdr); - - int count = shdr.sh_size / shdr.sh_entsize; - symbols.reserve(count); - - for(int i = 0; i < count; i++) - { - GElf_Sym sym; - auto res = gelf_getsym(data, i, &sym); - assert(res != 0); - symbols.emplace_back(sym); - - if(sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE) - symbolsByAddress[make_pair((int)sym.st_shndx,sym.st_value)] = i; - } -} - -Symbol &Symtab::GetSym(int idx) -{ - return symbols[idx]; -} - -int Symtab::FindSym(int secidx, uint32_t addr) -{ - auto p = symbolsByAddress.find(make_pair(secidx, addr)); - if(p != symbolsByAddress.end()) - return p->second; - else - return -1; -} - -int Symtab::FindSym(string name) -{ - if(symbolsByName.empty()) - { - for(auto& sym : symbols) - if(sym.st_name) - { - symbolsByName[sym.GetName()] = &sym - symbols.data(); - } - } - auto p = symbolsByName.find(name); - if(p != symbolsByName.end()) - return p->second; - else - return -1; -} - - -Reloc::Reloc() -{ -} - -Reloc::Reloc(const GElf_Rela &rela) - : GElf_Rela(rela), relocBase(RelocBase::code) -{ -} - -Section::Section(string name, int idx, SectionKind kind, Elf_Scn *elfsec) - : name(name), idx(idx), kind(kind), elfsec(elfsec), relasec(NULL), - exceptionInfoStart(0), - codeID(-1), firstJTEntryIndex(0) -{ - data = elf_getdata(elfsec, NULL); - gelf_getshdr(elfsec, &shdr); - outputBase = shdr.sh_addr; -} - - -void Section::SetRela(Elf_Scn *scn) -{ - relasec = scn; - GElf_Shdr rshdr; - gelf_getshdr(relasec, &rshdr); - - int nRela = rshdr.sh_size / rshdr.sh_entsize; - Elf_Data *data = elf_getdata(relasec, NULL); - for(int i = 0; i < nRela; i++) - { - GElf_Rela rela; - gelf_getrela(data, i, &rela); - - if(rela.r_offset < shdr.sh_addr || rela.r_offset >= shdr.sh_addr + shdr.sh_size) - { - // For some reason, there sometimes are relocations beyond the end of the sections - // in LD output. That's bad. Let's ignore it. - continue; - } - relocs.push_back(rela); - } - - std::sort(relocs.begin(), relocs.end(), - [](GElf_Rela& a, GElf_Rela& b) { return a.r_offset < b.r_offset; }); -} - -uint32_t Section::GetSize() -{ - return data->d_size; -} - -string Section::GetData() -{ - return string((char*)data->d_buf, (char*)data->d_buf + data->d_size); -} - -string Section::GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry) -{ - std::ostringstream out; - - for(auto& rela : relocs) - { - //printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset); - - int symidx = GELF_R_SYM(rela.r_info); - if(symidx == 0) - continue; - - Symbol& sym = symtab->GetSym(symidx); - - if(sym.st_shndx == SHN_UNDEF || sym.st_shndx >= SHN_LORESERVE) - continue; - if(sym.sectionKind == SectionKind::undefined) - continue; - - if(GELF_R_TYPE(rela.r_info) == R_68K_32) - { - assert(sym.sectionKind != SectionKind::undefined); - - uint32_t offset = rela.r_offset; - if(useOffsets) - offset -= shdr.sh_addr; - - //std::cout << "RELA: " << std::hex << offset << " " << (int)rela.relocBase << std::dec << std::endl; - longword(out, offset | ((int)rela.relocBase << 24)); - } - } - if(!suppressTerminatingEntry) - longword(out, -1); - return out.str(); -} - -void Section::ScanRelocs() -{ - for(Reloc& rela : relocs) - { - int symidx = GELF_R_SYM(rela.r_info); - if(symidx == 0) - continue; - - Symbol *sym = &symtab->GetSym(symidx); - - if(sym->st_shndx == SHN_UNDEF) - continue; - - if(rela.r_addend != 0) - { - int symidx2 = symtab->FindSym(sym->st_shndx, sym->st_value + rela.r_addend); - if(symidx2 != -1) - { - sym = &symtab->GetSym(symidx2); - rela.r_addend = 0; - rela.r_info = GELF_R_INFO(symidx2, GELF_R_TYPE(rela.r_info)); - - } - } - - if(sym->st_shndx != idx) - sym->referencedExternally = true; - } -} - -void Section::FixRelocs() -{ - //bool first_reloc = true; - for(Reloc& rela : relocs) - { - if(GELF_R_TYPE(rela.r_info) != R_68K_32) - continue; - - int symidx = GELF_R_SYM(rela.r_info); - if(symidx == 0) - continue; - Symbol& sym = symtab->GetSym(symidx); - - if(sym.sectionKind == SectionKind::undefined) - continue; - - RelocBase relocBase; - switch(sym.sectionKind) - { - case SectionKind::code: - relocBase = RelocBase::code; - if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart || sym.GetName() == "__gxx_personality_v0")) - { - if(rela.r_addend == 0) - { - relocBase = RelocBase::jumptable; - } - else - { - if(sym.section.get() != this) - { - std::cerr << "Invalid ref from " - << name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec - << " to " << sym.section->name - << "(" << sym.GetName() << ")" - << "+" << rela.r_offset << std::endl; - } - assert(sym.section.get() == this); - } - } - else - { - if(sym.section.get() != this) - { - std::cerr << "Invalid ref from " - << name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec - << " to " << sym.section->name - << "(" << sym.GetName() << ")" - << "+" << rela.r_offset << std::endl; - std::cerr << "needsJT: " << (sym.needsJT ? "true" : "false") << std::endl; - std::cerr << "from addr: " << rela.r_offset << ", exceptionInfoStart: " << exceptionInfoStart << std::endl; - - } - assert(sym.section.get() == this); - } - break; - case SectionKind::data: - relocBase = RelocBase::data; - break; - case SectionKind::bss: - relocBase = RelocBase::bss; - break; - } - rela.relocBase = relocBase; - - uint8_t *relocand = ((uint8_t*) data->d_buf + rela.r_offset - shdr.sh_addr); - /*if(first_reloc) - { - std::cout << "sec kind: " << (int)sym.sectionKind << std::endl; - std::cout << "reloc addr:" << rela.r_offset << std::endl; - }*/ - - - if(relocBase == RelocBase::jumptable) - { - uint32_t dst = 0x20 + sym.jtIndex * 8 + 2; - relocand[0] = dst >> 24; - relocand[1] = dst >> 16; - relocand[2] = dst >> 8; - relocand[3] = dst; - } - else - { - uint32_t orig = (relocand[0] << 24) | (relocand[1] << 16) | (relocand[2] << 8) | relocand[3]; - uint32_t dst = orig + sym.section->outputBase - sym.section->shdr.sh_addr; - relocand[0] = dst >> 24; - relocand[1] = dst >> 16; - relocand[2] = dst >> 8; - relocand[3] = dst; - } - } -} - - -void GrokELF(string input) -{ - if(elf_version ( EV_CURRENT ) == EV_NONE) - errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1)); - - int fd = open(input.c_str(), O_RDONLY, 0); - elf = elf_begin(fd, ELF_C_READ, NULL); - - elf_getshdrstrndx(elf, §ionHeaderStringTableIdx); - - GElf_Ehdr ehdr; - gelf_getehdr(elf, &ehdr); - - int idx = 1; - for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++) - { - GElf_Shdr shdr; - gelf_getshdr(scn, &shdr); - std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name); - //std::cout << "section #" << idx << ": " << name << std::endl; - - if(shdr.sh_type == SHT_SYMTAB - && !symtab) - { - symtab.reset(new Symtab(scn)); - } - if(shdr.sh_type == SHT_STRTAB) - { - if(name == ".strtab") - mainStringTableIdx = idx; - } - if(shdr.sh_type == SHT_RELA - && !bssSection) // ignore everything after bss, that's just debug info - { - if(boost::algorithm::starts_with(name,".rela.")) - { - string progbitsName = name.substr(5); - assert(sections.find(progbitsName) != sections.end()); - sections[progbitsName]->SetRela(scn); - } - } - if(shdr.sh_type == SHT_PROGBITS - && !bssSection) // ignore everything after bss, that's just debug info - { - SectionKind kind = name == ".data" ? SectionKind::data : SectionKind::code; - auto section = make_shared
(name, idx, kind, scn); - - sections[name] = sectionsByElfIndex[idx] = section; - if(kind == SectionKind::data) - dataSection = section; - else if(kind == SectionKind::code) - codeSections.push_back(section); - } - if(shdr.sh_type == SHT_NOBITS) - { - // Currently, the bss section is used - // to know when to start skipping debug info sections. - // (What's the official way to distinguish a debug info section from a "real" section?) - - bssSection = sections[name] = sectionsByElfIndex[idx] = - make_shared
(name, idx, SectionKind::bss, scn); - } - } - - std::sort(codeSections.begin(), codeSections.end(), - [](shared_ptr
a, shared_ptr
b) { return a->name < b->name; }); -} - -void FlatCode(std::ostream& out) -{ - for(auto sec : codeSections) - out << sec->GetData(); - - out << dataSection->GetData(); - - for(auto sec : codeSections) - out << sec->GetAbsRelocations(false, true); - out << dataSection->GetAbsRelocations(false); - -} - -void FlatCode(string fn) -{ - ofstream out(fn); - FlatCode(out); -} - - -std::string fromhex(std::string hex) -{ - std::string bin; - int nibble; - bool haveNibble = false; - for(std::string::iterator p = hex.begin(); p != hex.end(); ++p) - { - if(std::isspace(*p)) - continue; - assert(isdigit(*p) || (tolower(*p) >= 'a' && tolower(*p) <= 'f')); - int digit; - if(isdigit(*p)) - digit = *p - '0'; - else - digit = tolower(*p) - 'a' + 0xA; - - if(haveNibble) - { - bin += (char) ((nibble << 4) | digit); - haveNibble = false; - } - else - { - nibble = digit; - haveNibble = true; - } - } - return bin; -} - - - -void SingleSegmentApp(string output) -{ - ResourceFile file(output); - Resources& rsrc = file.resources; - - rsrc.addResource(Resource(ResType("CODE"), 0, - fromhex( - "00000028 00000000 00000008 00000020" - "0000 3F3C 0001 A9F0" - ) - )); - - - { - std::ostringstream code1; - word(code1, 0); - word(code1, 1); - FlatCode(code1); - - rsrc.addResource(Resource(ResType("CODE"), 1, - code1.str())); - } - - file.creator = ResType("????"); - file.type = ResType("APPL"); - - file.write(); -} - - - -void MultiSegmentApp(string output) -{ - ResourceFile file(output); - Resources& rsrc = file.resources; - - for(auto namedSec : sections) - { - namedSec.second->ScanRelocs(); - } - - int jtEntryCount = 0; - unordered_map> jtEntries; - for(Symbol& sym : symtab->symbols) - { - if(sym.valid) - { - if(sym.referencedExternally && sym.sectionKind == SectionKind::code) - { - sym.needsJT = true; - sym.jtIndex = -1; - sym.section->jtEntries.push_back(&sym); - ++jtEntryCount; - } - } - } - - uint32_t data_and_bss_size = dataSection->shdr.sh_size + bssSection->shdr.sh_size; - - { - std::ostringstream code0; - longword(code0, 0x20 + 8 * (jtEntryCount+2)); - longword(code0, data_and_bss_size); - longword(code0, 8 * (jtEntryCount+2)); - longword(code0, 0x20); - - code0 << fromhex("0000 3F3C 0001 A9F0"); // jt entry for entrypoint - code0 << fromhex("0000 FFFF 0000 0000"); // 32-bit entries start from here - - int jtIndex = 2; - int id = 1; - for(auto sec : codeSections) - { - sec->codeID = id; - - sec->firstJTEntryIndex = jtIndex; - - GElf_Shdr &shdr = sec->shdr; - - for(Symbol* jtEntry : sec->jtEntries) - { - word(code0, id); - word(code0, 0xA9F0); - uint32_t offset = jtEntry->st_value - shdr.sh_addr; - if(id == 1) - offset += 4; - else - offset += 40; - longword(code0, offset); - - jtEntry->jtIndex = jtIndex++; - - //std::cout << "JT Entry " << jtEntry->jtIndex << ": " << jtEntry->GetName() << std::endl; - } - - id++; - } - - std::cout << "CODE 0: " << code0.str().size() << " bytes\n"; - std::cout << "above A5: " << 0x20 + 8 * (jtEntryCount+2) << " bytes\n"; - std::cout << "below A5: " << data_and_bss_size << " bytes\n"; - std::cout << ".data: " << dataSection->shdr.sh_size << " bytes at A5-" - << std::hex << data_and_bss_size << std::dec << "\n"; - std::cout << ".bss: " << bssSection->shdr.sh_size << " bytes at A5-" - << std::hex << bssSection->shdr.sh_size << std::dec << "\n"; - - rsrc.addResource(Resource(ResType("CODE"), 0, code0.str())); - } - - for(auto sec : codeSections) - { - int id = sec->codeID; - if(id == 1) - sec->outputBase = 4; // standard 'CODE' header - else - sec->outputBase = 40; // far-model 'CODE' header - - string exceptionInfoMarker = "__EH_FRAME_BEGIN__"; - if(id != 1) - exceptionInfoMarker += boost::lexical_cast(id); - int exceptionInfoSym = symtab->FindSym(exceptionInfoMarker); - if(exceptionInfoSym != -1) - { - Symbol& s = symtab->GetSym(exceptionInfoSym); - sec->exceptionInfoStart = s.st_value; - - int codeSize = sec->shdr.sh_size; - int exceptionSize = sec->shdr.sh_addr + codeSize - sec->exceptionInfoStart; - double percent = 100.0 * exceptionSize / codeSize; - - std::cout << "CODE " << id << " has " << exceptionSize << " bytes of exception info (" << percent << "%)\n"; - } - else - std::cout << "exception info marker not found: " << exceptionInfoMarker << std::endl; - } - dataSection->outputBase = -data_and_bss_size; - bssSection->outputBase = -bssSection->shdr.sh_size; - - - for(auto namedSec : sections) - { - namedSec.second->FixRelocs(); - } - - for(auto sec : codeSections) - { - int id = sec->codeID; - std::ostringstream code; - if(id == 1) - { - word(code, 0); - word(code, 1); - } - else - { - word(code, 0xFFFF); - word(code, 0); - longword(code, 0); - longword(code, 0); - longword(code, 8 * sec->firstJTEntryIndex ); - longword(code, sec->jtEntries.size()); - longword(code, 0); // reloc info for A5 - longword(code, 0); // assumed address for A5 - longword(code, 0); // reloc info for code - longword(code, 0); // assumed address for start of code resource - longword(code, 0); - } - code << sec->GetData(); - - std::cout << "CODE " << id << ": " << code.str().size() << " bytes\n"; - - if(code.str().size() == 80) - { - std::cout << "... empty. Skipping.\n"; - continue; - } - - string segmentName = segmentMap.GetSegmentName(id); - - rsrc.addResource(Resource(ResType("CODE"), id, - code.str(), - segmentName)); - - - rsrc.addResource(Resource(ResType("RELA"),id, sec->GetAbsRelocations(true))); - } - - rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData())); - rsrc.addResource(Resource(ResType("RELA"),0, dataSection->GetAbsRelocations(true))); - - std::cout << "DATA 0: " << dataSection->shdr.sh_size << " bytes\n"; - - file.creator = ResType("????"); - file.type = ResType("APPL"); - - file.write(); -} string argvZero; @@ -876,6 +146,7 @@ int main(int argc, char *argv[]) if(fd < 0) errx(EXIT_FAILURE, "can't create temp file"); + SegmentMap segmentMap; { ofstream out(tmpfile); if(segments) @@ -899,13 +170,13 @@ int main(int argc, char *argv[]) args2.push_back(tmpfile); RealLD(args2); unlink(tmpfile); - GrokELF(outputFile + ".gdb"); + Object theObject(outputFile + ".gdb"); if(flatoutput) - FlatCode(outputFile); + theObject.FlatCode(outputFile); else if(segments) - MultiSegmentApp(outputFile); + theObject.MultiSegmentApp(outputFile, segmentMap); else - SingleSegmentApp(outputFile); + theObject.SingleSegmentApp(outputFile); } else { @@ -917,11 +188,11 @@ int main(int argc, char *argv[]) { if(argc != 2) errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]); - GrokELF(argv[1]); - MultiSegmentApp("out.bin"); + Object theObject(argv[1]); + SegmentMap segmentMap; + theObject.MultiSegmentApp("out.bin", segmentMap); } return 0; } - diff --git a/Elf2Mac/Object.cc b/Elf2Mac/Object.cc new file mode 100644 index 0000000000..c731a76fde --- /dev/null +++ b/Elf2Mac/Object.cc @@ -0,0 +1,381 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#include "Object.h" +#include "Symbol.h" +#include "Symtab.h" +#include "Section.h" +#include "SegmentMap.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ResourceFork.h" +#include "BinaryIO.h" +#include "ResourceFile.h" + +using std::string; +using std::shared_ptr; +using std::make_shared; +using std::ofstream; +using std::unordered_map; +using std::vector; + +Object::~Object() +{ +} + + + +Object::Object(string input) +{ + if(elf_version ( EV_CURRENT ) == EV_NONE) + errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1)); + + int fd = open(input.c_str(), O_RDONLY, 0); + elf = elf_begin(fd, ELF_C_READ, NULL); + + elf_getshdrstrndx(elf, §ionHeaderStringTableIdx); + + GElf_Ehdr ehdr; + gelf_getehdr(elf, &ehdr); + + int idx; + + idx = 1; + for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++) + { + GElf_Shdr shdr; + gelf_getshdr(scn, &shdr); + std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name); + if(shdr.sh_type == SHT_STRTAB) + { + if(name == ".strtab") + mainStringTableIdx = idx; + } + } + + idx = 1; + for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++) + { + GElf_Shdr shdr; + gelf_getshdr(scn, &shdr); + std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name); + //std::cout << "section #" << idx << ": " << name << std::endl; + + if(shdr.sh_type == SHT_SYMTAB + && !symtab) + { + symtab.reset(new Symtab(*this, scn)); + } + + if(shdr.sh_type == SHT_RELA + && !bssSection) // ignore everything after bss, that's just debug info + { + if(boost::algorithm::starts_with(name,".rela.")) + { + string progbitsName = name.substr(5); + assert(sections.find(progbitsName) != sections.end()); + sections[progbitsName]->SetRela(scn); + } + } + if(shdr.sh_type == SHT_PROGBITS + && !bssSection) // ignore everything after bss, that's just debug info + { + SectionKind kind = name == ".data" ? SectionKind::data : SectionKind::code; + auto section = make_shared
(*this, name, idx, kind, scn); + + sections[name] = sectionsByElfIndex[idx] = section; + if(kind == SectionKind::data) + dataSection = section; + else if(kind == SectionKind::code) + codeSections.push_back(section); + } + if(shdr.sh_type == SHT_NOBITS) + { + // Currently, the bss section is used + // to know when to start skipping debug info sections. + // (What's the official way to distinguish a debug info section from a "real" section?) + + bssSection = sections[name] = sectionsByElfIndex[idx] = + make_shared
(*this, name, idx, SectionKind::bss, scn); + } + } + + std::sort(codeSections.begin(), codeSections.end(), + [](shared_ptr
a, shared_ptr
b) { return a->name < b->name; }); +} + +void Object::FlatCode(std::ostream& out) +{ + for(auto sec : codeSections) + out << sec->GetData(); + + out << dataSection->GetData(); + + for(auto sec : codeSections) + out << sec->GetAbsRelocations(false, true); + out << dataSection->GetAbsRelocations(false); + +} + +void Object::FlatCode(string fn) +{ + ofstream out(fn); + FlatCode(out); +} + + +std::string fromhex(std::string hex) +{ + std::string bin; + int nibble; + bool haveNibble = false; + for(std::string::iterator p = hex.begin(); p != hex.end(); ++p) + { + if(std::isspace(*p)) + continue; + assert(isdigit(*p) || (tolower(*p) >= 'a' && tolower(*p) <= 'f')); + int digit; + if(isdigit(*p)) + digit = *p - '0'; + else + digit = tolower(*p) - 'a' + 0xA; + + if(haveNibble) + { + bin += (char) ((nibble << 4) | digit); + haveNibble = false; + } + else + { + nibble = digit; + haveNibble = true; + } + } + return bin; +} + + + +void Object::SingleSegmentApp(string output) +{ + ResourceFile file(output); + Resources& rsrc = file.resources; + + rsrc.addResource(Resource(ResType("CODE"), 0, + fromhex( + "00000028 00000000 00000008 00000020" + "0000 3F3C 0001 A9F0" + ) + )); + + + { + std::ostringstream code1; + word(code1, 0); + word(code1, 1); + FlatCode(code1); + + rsrc.addResource(Resource(ResType("CODE"), 1, + code1.str())); + } + + file.creator = ResType("????"); + file.type = ResType("APPL"); + + file.write(); +} + + + +void Object::MultiSegmentApp(string output, SegmentMap& segmentMap) +{ + ResourceFile file(output); + Resources& rsrc = file.resources; + + for(auto namedSec : sections) + { + namedSec.second->ScanRelocs(); + } + + int jtEntryCount = 0; + unordered_map> jtEntries; + for(Symbol& sym : symtab->symbols) + { + if(sym.valid) + { + if(sym.referencedExternally && sym.sectionKind == SectionKind::code) + { + sym.needsJT = true; + sym.jtIndex = -1; + sym.section->jtEntries.push_back(&sym); + ++jtEntryCount; + } + } + } + + uint32_t data_and_bss_size = dataSection->shdr.sh_size + bssSection->shdr.sh_size; + + { + std::ostringstream code0; + longword(code0, 0x20 + 8 * (jtEntryCount+2)); + longword(code0, data_and_bss_size); + longword(code0, 8 * (jtEntryCount+2)); + longword(code0, 0x20); + + code0 << fromhex("0000 3F3C 0001 A9F0"); // jt entry for entrypoint + code0 << fromhex("0000 FFFF 0000 0000"); // 32-bit entries start from here + + int jtIndex = 2; + int id = 1; + for(auto sec : codeSections) + { + sec->codeID = id; + + sec->firstJTEntryIndex = jtIndex; + + GElf_Shdr &shdr = sec->shdr; + + for(Symbol* jtEntry : sec->jtEntries) + { + word(code0, id); + word(code0, 0xA9F0); + uint32_t offset = jtEntry->st_value - shdr.sh_addr; + if(id == 1) + offset += 4; + else + offset += 40; + longword(code0, offset); + + jtEntry->jtIndex = jtIndex++; + + //std::cout << "JT Entry " << jtEntry->jtIndex << ": " << jtEntry->name << std::endl; + } + + id++; + } + + std::cout << "CODE 0: " << code0.str().size() << " bytes\n"; + std::cout << "above A5: " << 0x20 + 8 * (jtEntryCount+2) << " bytes\n"; + std::cout << "below A5: " << data_and_bss_size << " bytes\n"; + std::cout << ".data: " << dataSection->shdr.sh_size << " bytes at A5-" + << std::hex << data_and_bss_size << std::dec << "\n"; + std::cout << ".bss: " << bssSection->shdr.sh_size << " bytes at A5-" + << std::hex << bssSection->shdr.sh_size << std::dec << "\n"; + + rsrc.addResource(Resource(ResType("CODE"), 0, code0.str())); + } + + for(auto sec : codeSections) + { + int id = sec->codeID; + if(id == 1) + sec->outputBase = 4; // standard 'CODE' header + else + sec->outputBase = 40; // far-model 'CODE' header + + string exceptionInfoMarker = "__EH_FRAME_BEGIN__"; + if(id != 1) + exceptionInfoMarker += boost::lexical_cast(id); + int exceptionInfoSym = symtab->FindSym(exceptionInfoMarker); + if(exceptionInfoSym != -1) + { + Symbol& s = symtab->GetSym(exceptionInfoSym); + sec->exceptionInfoStart = s.st_value; + + int codeSize = sec->shdr.sh_size; + int exceptionSize = sec->shdr.sh_addr + codeSize - sec->exceptionInfoStart; + double percent = 100.0 * exceptionSize / codeSize; + + std::cout << "CODE " << id << " has " << exceptionSize << " bytes of exception info (" << percent << "%)\n"; + } + else + std::cout << "exception info marker not found: " << exceptionInfoMarker << std::endl; + } + dataSection->outputBase = -data_and_bss_size; + bssSection->outputBase = -bssSection->shdr.sh_size; + + + for(auto namedSec : sections) + { + namedSec.second->FixRelocs(); + } + + for(auto sec : codeSections) + { + int id = sec->codeID; + std::ostringstream code; + if(id == 1) + { + word(code, 0); + word(code, 1); + } + else + { + word(code, 0xFFFF); + word(code, 0); + longword(code, 0); + longword(code, 0); + longword(code, 8 * sec->firstJTEntryIndex ); + longword(code, sec->jtEntries.size()); + longword(code, 0); // reloc info for A5 + longword(code, 0); // assumed address for A5 + longword(code, 0); // reloc info for code + longword(code, 0); // assumed address for start of code resource + longword(code, 0); + } + code << sec->GetData(); + + std::cout << "CODE " << id << ": " << code.str().size() << " bytes\n"; + + if(code.str().size() == 80) + { + std::cout << "... empty. Skipping.\n"; + continue; + } + + string segmentName = segmentMap.GetSegmentName(id); + + rsrc.addResource(Resource(ResType("CODE"), id, + code.str(), + segmentName)); + + + rsrc.addResource(Resource(ResType("RELA"),id, sec->GetAbsRelocations(true))); + } + + rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData())); + rsrc.addResource(Resource(ResType("RELA"),0, dataSection->GetAbsRelocations(true))); + + std::cout << "DATA 0: " << dataSection->shdr.sh_size << " bytes\n"; + + file.creator = ResType("????"); + file.type = ResType("APPL"); + + file.write(); +} diff --git a/Elf2Mac/Object.h b/Elf2Mac/Object.h new file mode 100644 index 0000000000..43d7df0096 --- /dev/null +++ b/Elf2Mac/Object.h @@ -0,0 +1,61 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#ifndef OBJECT_H +#define OBJECT_H + +#include + +#include +#include +#include +#include +#include +#include + +class Symtab; +class Section; +class SegmentMap; + +class Object +{ +public: + Elf *elf; + std::unique_ptr symtab; + std::unordered_map> sections; + std::unordered_map> sectionsByElfIndex; + + std::vector> codeSections; + std::shared_ptr
dataSection, bssSection; + size_t sectionHeaderStringTableIdx; + size_t mainStringTableIdx; + + + Object(std::string input); + ~Object(); + + void FlatCode(std::ostream& out); + void FlatCode(std::string fn); + + void SingleSegmentApp(std::string output); + void MultiSegmentApp(std::string output, SegmentMap &segmentMap); +}; + + +#endif // OBJECT_H diff --git a/Elf2Mac/Reloc.cc b/Elf2Mac/Reloc.cc new file mode 100644 index 0000000000..e9735c1b62 --- /dev/null +++ b/Elf2Mac/Reloc.cc @@ -0,0 +1,29 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#include "Reloc.h" + +Reloc::Reloc() +{ +} + +Reloc::Reloc(const GElf_Rela &rela) + : GElf_Rela(rela), relocBase(RelocBase::code) +{ +} diff --git a/Elf2Mac/Reloc.h b/Elf2Mac/Reloc.h new file mode 100644 index 0000000000..40ff45fa89 --- /dev/null +++ b/Elf2Mac/Reloc.h @@ -0,0 +1,43 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#ifndef RELOC_H +#define RELOC_H + +#include + +enum class RelocBase +{ + code = 0, + data, + bss, + jumptable, + code1 +}; + +class Reloc : public GElf_Rela +{ +public: + RelocBase relocBase; + + Reloc(); + Reloc(const GElf_Rela& rela); +}; + +#endif // RELOC_H diff --git a/Elf2Mac/Section.cc b/Elf2Mac/Section.cc new file mode 100644 index 0000000000..0298c73d4f --- /dev/null +++ b/Elf2Mac/Section.cc @@ -0,0 +1,237 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#include "Section.h" + +#include "Symbol.h" +#include "Reloc.h" +#include "Object.h" +#include "Symtab.h" + +#include +#include +#include +#include + +#include "BinaryIO.h" + +using std::string; + +Section::~Section() +{ +} + +Section::Section(Object& theObject, string name, int idx, SectionKind kind, Elf_Scn *elfsec) + : theObject(theObject), + name(name), idx(idx), kind(kind), elfsec(elfsec), relasec(NULL), + exceptionInfoStart(0), + codeID(-1), firstJTEntryIndex(0) +{ + data = elf_getdata(elfsec, NULL); + gelf_getshdr(elfsec, &shdr); + outputBase = shdr.sh_addr; +} + + +void Section::SetRela(Elf_Scn *scn) +{ + relasec = scn; + GElf_Shdr rshdr; + gelf_getshdr(relasec, &rshdr); + + int nRela = rshdr.sh_size / rshdr.sh_entsize; + Elf_Data *data = elf_getdata(relasec, NULL); + for(int i = 0; i < nRela; i++) + { + GElf_Rela rela; + gelf_getrela(data, i, &rela); + + if(rela.r_offset < shdr.sh_addr || rela.r_offset >= shdr.sh_addr + shdr.sh_size) + { + // For some reason, there sometimes are relocations beyond the end of the sections + // in LD output. That's bad. Let's ignore it. + continue; + } + relocs.push_back(rela); + } + + std::sort(relocs.begin(), relocs.end(), + [](GElf_Rela& a, GElf_Rela& b) { return a.r_offset < b.r_offset; }); +} + +uint32_t Section::GetSize() +{ + return data->d_size; +} + +string Section::GetData() +{ + return string((char*)data->d_buf, (char*)data->d_buf + data->d_size); +} + +string Section::GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry) +{ + std::ostringstream out; + + for(auto& rela : relocs) + { + //printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset); + + int symidx = GELF_R_SYM(rela.r_info); + if(symidx == 0) + continue; + + Symbol& sym = theObject.symtab->GetSym(symidx); + + if(sym.st_shndx == SHN_UNDEF || sym.st_shndx >= SHN_LORESERVE) + continue; + if(sym.sectionKind == SectionKind::undefined) + continue; + + if(GELF_R_TYPE(rela.r_info) == R_68K_32) + { + assert(sym.sectionKind != SectionKind::undefined); + + uint32_t offset = rela.r_offset; + if(useOffsets) + offset -= shdr.sh_addr; + + longword(out, offset | ((int)rela.relocBase << 24)); + } + } + if(!suppressTerminatingEntry) + longword(out, -1); + return out.str(); +} + +void Section::ScanRelocs() +{ + for(Reloc& rela : relocs) + { + int symidx = GELF_R_SYM(rela.r_info); + if(symidx == 0) + continue; + + Symbol *sym = &theObject.symtab->GetSym(symidx); + + if(sym->st_shndx == SHN_UNDEF) + continue; + + if(rela.r_addend != 0) + { + int symidx2 = theObject.symtab->FindSym(sym->st_shndx, sym->st_value + rela.r_addend); + if(symidx2 != -1) + { + sym = &theObject.symtab->GetSym(symidx2); + rela.r_addend = 0; + rela.r_info = GELF_R_INFO(symidx2, GELF_R_TYPE(rela.r_info)); + + } + } + + if(sym->st_shndx != idx) + sym->referencedExternally = true; + } +} + +void Section::FixRelocs() +{ + for(Reloc& rela : relocs) + { + if(GELF_R_TYPE(rela.r_info) != R_68K_32) + continue; + + int symidx = GELF_R_SYM(rela.r_info); + if(symidx == 0) + continue; + Symbol& sym = theObject.symtab->GetSym(symidx); + + if(sym.sectionKind == SectionKind::undefined) + continue; + + RelocBase relocBase; + switch(sym.sectionKind) + { + case SectionKind::code: + relocBase = RelocBase::code; + if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart || sym.name == "__gxx_personality_v0")) + { + if(rela.r_addend == 0) + { + relocBase = RelocBase::jumptable; + } + else + { + if(sym.section.get() != this) + { + std::cerr << "Invalid ref from " + << name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec + << " to " << sym.section->name + << "(" << sym.name << ")" + << "+" << rela.r_offset << std::endl; + } + assert(sym.section.get() == this); + } + } + else + { + if(sym.section.get() != this) + { + std::cerr << "Invalid ref from " + << name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec + << " to " << sym.section->name + << "(" << sym.name << ")" + << "+" << rela.r_offset << std::endl; + std::cerr << "needsJT: " << (sym.needsJT ? "true" : "false") << std::endl; + std::cerr << "from addr: " << rela.r_offset << ", exceptionInfoStart: " << exceptionInfoStart << std::endl; + + } + assert(sym.section.get() == this); + } + break; + case SectionKind::data: + relocBase = RelocBase::data; + break; + case SectionKind::bss: + relocBase = RelocBase::bss; + break; + } + rela.relocBase = relocBase; + + uint8_t *relocand = ((uint8_t*) data->d_buf + rela.r_offset - shdr.sh_addr); + + if(relocBase == RelocBase::jumptable) + { + uint32_t dst = 0x20 + sym.jtIndex * 8 + 2; + relocand[0] = dst >> 24; + relocand[1] = dst >> 16; + relocand[2] = dst >> 8; + relocand[3] = dst; + } + else + { + uint32_t orig = (relocand[0] << 24) | (relocand[1] << 16) | (relocand[2] << 8) | relocand[3]; + uint32_t dst = orig + sym.section->outputBase - sym.section->shdr.sh_addr; + relocand[0] = dst >> 24; + relocand[1] = dst >> 16; + relocand[2] = dst >> 8; + relocand[3] = dst; + } + } +} diff --git a/Elf2Mac/Section.h b/Elf2Mac/Section.h new file mode 100644 index 0000000000..096f5f5574 --- /dev/null +++ b/Elf2Mac/Section.h @@ -0,0 +1,74 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#ifndef SECTION_H +#define SECTION_H + +#include + +#include +#include +#include + +class Object; +class Reloc; +class Symbol; + +enum class SectionKind +{ + undefined = -1, + code = 0, + data, + bss +}; + +class Section +{ +public: + Object& theObject; + std::string name; + int idx; + SectionKind kind; + Elf_Scn *elfsec, *relasec; + Elf_Data *data; + GElf_Shdr shdr; + uint32_t outputBase; + uint32_t exceptionInfoStart; + + int codeID; + + std::vector relocs; + std::vector jtEntries; + int firstJTEntryIndex; + + Section(Object& object, std::string name, int idx, SectionKind kind, Elf_Scn *elfsec); + ~Section(); + void SetRela(Elf_Scn *scn); + + uint32_t GetSize(); + std::string GetData(); + std::string GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry = false); + + void ScanRelocs(); + void FixRelocs(); + +}; + + +#endif // SECTION_H diff --git a/Elf2Mac/SegmentMap.cc b/Elf2Mac/SegmentMap.cc index 8abc28b322..186ea54bbf 100644 --- a/Elf2Mac/SegmentMap.cc +++ b/Elf2Mac/SegmentMap.cc @@ -1,12 +1,28 @@ -#include "SegmentMap.h" +/* + Copyright 2017 Wolfgang Thaller. + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#include "SegmentMap.h" SegmentInfo::SegmentInfo() { - } - SegmentMap::SegmentMap() { segments.emplace_back(1, "Runtime", diff --git a/Elf2Mac/SegmentMap.h b/Elf2Mac/SegmentMap.h index 4146594ca6..4c24ec5da2 100644 --- a/Elf2Mac/SegmentMap.h +++ b/Elf2Mac/SegmentMap.h @@ -1,3 +1,22 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + #ifndef SEGMENTMAP_H #define SEGMENTMAP_H diff --git a/Elf2Mac/Symbol.cc b/Elf2Mac/Symbol.cc new file mode 100644 index 0000000000..b9a3e58455 --- /dev/null +++ b/Elf2Mac/Symbol.cc @@ -0,0 +1,45 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#include "Symbol.h" + +#include "Section.h" +#include "Object.h" + +Symbol::Symbol() + : valid(false) +{ +} + +Symbol::Symbol(Object& theObject, const GElf_Sym &sym) + : GElf_Sym(sym), valid(true), + referencedExternally(false), + sectionKind(SectionKind::undefined), + needsJT(false) +{ + if(st_shndx != SHN_UNDEF && st_shndx < SHN_LORESERVE) + { + section = theObject.sectionsByElfIndex[st_shndx]; + sectionKind = section->kind; + } + if(st_name) + { + name = elf_strptr(theObject.elf, theObject.mainStringTableIdx, st_name); + } +} diff --git a/Elf2Mac/Symbol.h b/Elf2Mac/Symbol.h new file mode 100644 index 0000000000..84f55dd1c7 --- /dev/null +++ b/Elf2Mac/Symbol.h @@ -0,0 +1,48 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#ifndef SYMBOL_H +#define SYMBOL_H + +#include + +#include +#include + +enum class SectionKind; +class Section; +class Object; + +class Symbol : public GElf_Sym +{ +public: + bool valid; + bool referencedExternally; + SectionKind sectionKind; + bool needsJT; + int jtIndex; + std::shared_ptr
section; + std::string name; + + Symbol(); + Symbol(Object &theObject, const GElf_Sym& sym); +}; + + +#endif // SYMBOL_H diff --git a/Elf2Mac/Symtab.cc b/Elf2Mac/Symtab.cc new file mode 100644 index 0000000000..dbc260ecdc --- /dev/null +++ b/Elf2Mac/Symtab.cc @@ -0,0 +1,81 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#include "Symtab.h" + +#include +#include + +#include "Symbol.h" + +using std::make_pair; +using std::string; + +Symtab::Symtab(Object& theObject, Elf_Scn *elfsec) + : elfsec(elfsec) +{ + data = elf_getdata(elfsec, NULL); + + GElf_Shdr shdr; + gelf_getshdr(elfsec, &shdr); + + int count = shdr.sh_size / shdr.sh_entsize; + symbols.reserve(count); + + for(int i = 0; i < count; i++) + { + GElf_Sym sym; + auto res = gelf_getsym(data, i, &sym); + assert(res != 0); + symbols.emplace_back(theObject, sym); + + if(sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE) + symbolsByAddress[make_pair((int)sym.st_shndx,sym.st_value)] = i; + if(sym.st_name) + symbolsByName[symbols.back().name] = i; + } +} + +Symtab::~Symtab() +{ + +} + +Symbol &Symtab::GetSym(int idx) +{ + return symbols[idx]; +} + +int Symtab::FindSym(int secidx, uint32_t addr) +{ + auto p = symbolsByAddress.find(make_pair(secidx, addr)); + if(p != symbolsByAddress.end()) + return p->second; + else + return -1; +} + +int Symtab::FindSym(string name) +{ + auto p = symbolsByName.find(name); + if(p != symbolsByName.end()) + return p->second; + else + return -1; +} diff --git a/Elf2Mac/Symtab.h b/Elf2Mac/Symtab.h new file mode 100644 index 0000000000..d5774c9d02 --- /dev/null +++ b/Elf2Mac/Symtab.h @@ -0,0 +1,50 @@ +/* + Copyright 2017 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#ifndef SYMTAB_H +#define SYMTAB_H + +#include + +#include +#include +#include + +class Object; +class Symbol; + +class Symtab +{ +public: + Elf_Scn *elfsec; + Elf_Data *data; + std::vector symbols; + std::map, int> symbolsByAddress; + std::unordered_map symbolsByName; + + Symtab(Object &theObject, Elf_Scn *elfsec); + ~Symtab(); + + Symbol& GetSym(int idx); + int FindSym(int secidx, uint32_t addr); + int FindSym(std::string name); +}; + + +#endif // SYMTAB_H