From 68c43b7a39b7088157cf28a743dfa17ce53dd565 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Wed, 27 Sep 2017 00:30:06 +0200 Subject: [PATCH] SegmentMap, code flushing, cleanup --- Elf2Mac/CMakeLists.txt | 2 +- Elf2Mac/Elf2Mac.cc | 51 +++++++- Elf2Mac/Elf2Mac.h | 2 +- Elf2Mac/LdScript.cc | 241 ++++++++++++++++++++------------------ Elf2Mac/SegmentMap.cc | 28 +++++ Elf2Mac/SegmentMap.h | 35 ++++++ libretro/MultiSegApp.c | 22 +--- libretro/Retro68Runtime.h | 27 ++++- libretro/relocate.c | 30 ++--- 9 files changed, 279 insertions(+), 159 deletions(-) create mode 100644 Elf2Mac/SegmentMap.cc create mode 100644 Elf2Mac/SegmentMap.h diff --git a/Elf2Mac/CMakeLists.txt b/Elf2Mac/CMakeLists.txt index ba729ed618..f55647eb6a 100644 --- a/Elf2Mac/CMakeLists.txt +++ b/Elf2Mac/CMakeLists.txt @@ -19,7 +19,7 @@ cmake_minimum_required(VERSION 3.1) find_package(Boost COMPONENTS REQUIRED) -add_executable(Elf2Mac Elf2Mac.h Elf2Mac.cc LdScript.cc) +add_executable(Elf2Mac Elf2Mac.h Elf2Mac.cc SegmentMap.cc LdScript.cc) target_link_libraries(Elf2Mac ResourceFiles ${CMAKE_INSTALL_PREFIX}/lib/libelf.a -lz) target_include_directories(Elf2Mac PRIVATE ${CMAKE_INSTALL_PREFIX}/include) diff --git a/Elf2Mac/Elf2Mac.cc b/Elf2Mac/Elf2Mac.cc index f5e2ff92ff..3a2760f020 100644 --- a/Elf2Mac/Elf2Mac.cc +++ b/Elf2Mac/Elf2Mac.cc @@ -18,6 +18,7 @@ */ #include "Elf2Mac.h" +#include "SegmentMap.h" #include "ResourceFork.h" #include "BinaryIO.h" @@ -257,15 +258,22 @@ Section::Section(string name, int idx, SectionKind kind, Elf_Scn *elfsec) void Section::SetRela(Elf_Scn *scn) { relasec = scn; - GElf_Shdr shdr; - gelf_getshdr(relasec, &shdr); + GElf_Shdr rshdr; + gelf_getshdr(relasec, &rshdr); - int nRela = shdr.sh_size / shdr.sh_entsize; + 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); } @@ -370,7 +378,7 @@ void Section::FixRelocs() { case SectionKind::code: relocBase = RelocBase::code; - if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart)) + if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart || sym.GetName() == "__gxx_personality_v0")) { if(rela.r_addend == 0) { @@ -390,7 +398,20 @@ void Section::FixRelocs() } } 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; @@ -721,6 +742,11 @@ void MultiSegmentApp(string output) std::cout << "CODE " << id << ": " << code.str().size() << " bytes\n"; + if(code.str().size() == 80) + { + std::cout << "... empty. Skipping.\n"; + continue; + } rsrc.addResource(Resource(ResType("CODE"), id, code.str())); @@ -819,6 +845,7 @@ int main(int argc, char *argv[]) { elf2mac = true; flatoutput = true; + segments = false; } else if(*p == "--mac-segments") { @@ -845,8 +872,20 @@ int main(int argc, char *argv[]) { ofstream out(tmpfile); - CreateLdScript(out, segments); - CreateLdScript(std::cout, segments); + if(segments) + { + SegmentMap map; + map.CreateLdScript(out); + map.CreateLdScript(std::cout); + + ofstream f("/tmp/foo.ld"); + map.CreateLdScript(f); + } + else + { + CreateFlatLdScript(out); + CreateFlatLdScript(std::cout); + } } args2.push_back("-o"); diff --git a/Elf2Mac/Elf2Mac.h b/Elf2Mac/Elf2Mac.h index 4c658d66f2..683c2c395a 100644 --- a/Elf2Mac/Elf2Mac.h +++ b/Elf2Mac/Elf2Mac.h @@ -22,6 +22,6 @@ #include -void CreateLdScript(std::ostream& out, bool segments); +void CreateFlatLdScript(std::ostream& out); #endif // ELF2MAC_H diff --git a/Elf2Mac/LdScript.cc b/Elf2Mac/LdScript.cc index 564f48ac5e..8467172f26 100644 --- a/Elf2Mac/LdScript.cc +++ b/Elf2Mac/LdScript.cc @@ -18,9 +18,11 @@ */ #include "Elf2Mac.h" +#include "SegmentMap.h" #include #include +#include #include using std::string; @@ -37,21 +39,21 @@ const char * textSection = R"ld(/* ld script for Elf2Mac */ PROVIDE(_rsrc_start = .); *(.rsrcheader) . = ALIGN (2); - + /* The entry point. */ _entry_trampoline = .; SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71); - LONG(0x61000002); /* bsr *+2 */ + LONG(0x61000002); /* bsr *+2 */ SHORT(0x0697); /* addi.l #_, (a7) */ LONG(_start - _entry_trampoline - 6); - - PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */ - Retro68InitMultisegApp = .; /* override this for the single-segment case */ + + PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */ + Retro68InitMultisegApp = .; /* override this for the single-segment case */ SHORT(0x4e75); /* rts */ *(.relocvars) */libretrocrt.a:start.c.obj(.text*) - */libretrocrt.a:relocate.c.obj(.text*) + */libretrocrt.a:relocate.c.obj(.text*) */libretrocrt.a:*(.text*) *(.text*) @@ -71,7 +73,7 @@ const char * textSection = R"ld(/* ld script for Elf2Mac */ __EH_FRAME_BEGIN__ = .; KEEP(*(.eh_frame)) LONG(0); - + KEEP(*(.gcc_except_table)) KEEP(*(.gcc_except_table.*)) @@ -83,79 +85,6 @@ const char * textSection = R"ld(/* ld script for Elf2Mac */ } )ld"; -const char * code1Section = R"ld(/* ld script for Elf2Mac */ - .code1 : { - _stext = . ; - FILL(0x4E71); - PROVIDE(_rsrc_start = .); - . = ALIGN (2); - _entry_trampoline = .; - SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71); - LONG(0x61000002); /* bsr *+2 */ - SHORT(0x0697); /* addi.l #_, (a7) */ - LONG(_start - _entry_trampoline - 6); - PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */ - SHORT(0x4e75); /* rts */ - - *(.relocvars) - */libretrocrt.a:start.c.obj(.text*) - */libretrocrt.a:relocate.c.obj(.text*) - */libretrocrt.a:MultiSegApp.c.obj(.text*) - */libretrocrt.a:LoadSeg.s.obj(.text*) - */libretrocrt.a:*(.text*) - */libgcc.a:*(.text*) - */libc.a:*(.text*) - - . = ALIGN (4) ; - __init_section = . ; - KEEP (*(.init)) - __init_section_end = . ; - __fini_section = . ; - KEEP (*(.fini)) - __fini_section_end = . ; - - __EH_FRAME_BEGIN__ = .; - KEEP(*/libretrocrt.a:*(.eh_frame)) - KEEP(*/libgcc.a:*(.eh_frame)) - KEEP(*/libc.a:*(.eh_frame)) - LONG(0); - KEEP(*/libretrocrt.a:*(.gcc_except_table)) - KEEP(*/libretrocrt.a:*(.gcc_except_table.*)) - KEEP(*/libgcc.a:*(.gcc_except_table)) - KEEP(*/libgcc.a:*(.gcc_except_table.*)) - KEEP(*/libc.a:*(.gcc_except_table)) - KEEP(*/libc.a:*(.gcc_except_table.*)) - - . = ALIGN(0x4) ; - _etext = . ; - } -)ld"; -const char * codeSectionTemplate = R"ld(/* ld script for Elf2Mac */ - .code@N@ : { - FILL(0x4E71); - @FILTER@(.text*) - - @EXTRA@ - - . = ALIGN (4) ; - - __EH_FRAME_BEGIN__@N@ = .; - KEEP(@FILTER@(.eh_frame)) - LONG(0); - KEEP(@FILTER@(.gcc_except_table)) - KEEP(@FILTER@(.gcc_except_table.*)) - - . = ALIGN(0x4); - . += 32; - LONG(__EH_FRAME_BEGIN__@N@ - .); - } -)ld"; - -const char * lastCodeExtra = R"ld( - *(.gnu.linkonce.t*) -)ld"; - - const char * scriptEnd = R"ld( .data : { _sdata = . ; @@ -180,14 +109,14 @@ const char * scriptEnd = R"ld( KEEP (*(SORT(.ctors.*))) __CTOR_END__ = .; LONG(0); - + . = ALIGN(0x4); __DTOR_LIST__ = .; KEEP (*(.dtors)) KEEP (*(SORT(.dtors.*))) __DTOR_END__ = .; LONG(0); - + . = ALIGN(0x4); _edata = . ; } @@ -212,7 +141,7 @@ const char * scriptEnd = R"ld( * Keep them for now, they are discarded by Elf2Mac. */ /DISCARD/ : { *(.note.GNU-stack) } - /* Stabs debugging sections. */ + /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } @@ -224,50 +153,140 @@ const char * scriptEnd = R"ld( Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } + .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(*) } } )ld"; -void CreateLdScript(std::ostream& out, bool segments) +void CreateFlatLdScript(std::ostream& out) { - if(segments) + out << "_MULTISEG_APP = 0;\n"; + out << scriptStart << textSection << scriptEnd; +} + + +void SegmentInfo::WriteFilters(std::ostream &out, string section) +{ + for(string filter : filters) { - out << "_MULTISEG_APP = 1;\n"; - out << scriptStart << code1Section; - string code = codeSectionTemplate; - boost::replace_all(code, "@N@", "2"); - boost::replace_all(code, "@FILTER@", "*"); - boost::replace_all(code, "@EXTRA@", lastCodeExtra); - out << code; - out << scriptEnd; + out << " " << filter << "(" << section << ")\n"; + out << " " << filter << "(" << section << ".*)\n"; + } +} +void SegmentInfo::WriteFiltersKeep(std::ostream &out, string section) +{ + for(string filter : filters) + { + out << "\t\tKEEP(" << filter << "(" << section << "))\n"; + out << "\t\tKEEP(" << filter << "(" << section << ".*))\n"; + } +} + +void SegmentInfo::CreateLdScript(std::ostream &out) +{ + out << "\t.code" << id << " : {\n"; + out << "\t\tFILL(0x4E71);\n"; + if(id == 1) + { + out << R"ld( + _stext = .; + FILL(0x4E71); + PROVIDE(_rsrc_start = .); + . = ALIGN (2); + _entry_trampoline = .; + SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71); + LONG(0x61000002); /* bsr *+2 */ + SHORT(0x0697); /* addi.l #_, (a7) */ + LONG(_start - _entry_trampoline - 6); + PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */ + SHORT(0x4e75); /* rts */ + + FILL(0); + *(.relocvars) + FILL(0x4E71); +)ld"; + } + WriteFilters(out, ".text"); + + if(id == 2) + { + out << "\t\t*(.gnu.linkonce.t*)\n"; + } + if(id == 1) + { + out << R"ld( + . = ALIGN (4) ; + __init_section = .; + KEEP (*(.init)) + __init_section_end = .; + __fini_section = .; + KEEP (*(.fini)) + __fini_section_end = .; +)ld"; + } + + out << "\t\t. = ALIGN (4);\n"; // this is important, for some reason. + if(id == 1) + out << "\t\t__EH_FRAME_BEGIN__" << " = .;\n"; + else + out << "\t\t__EH_FRAME_BEGIN__" << id << " = .;\n"; + WriteFiltersKeep(out, ".eh_frame"); + out << "\t\tLONG(0);\n"; + WriteFiltersKeep(out, ".gcc_except_table"); + + if(id == 1) + { + out << R"ld( + . = ALIGN(0x4) ; + _etext = . ; +)ld"; } else - { - out << "_MULTISEG_APP = 0;\n"; - out << scriptStart << textSection << scriptEnd; - } + { + out << boost::replace_all_copy(R"ld( + . = ALIGN(0x4); + FILL(0); + . += 32; + LONG(__EH_FRAME_BEGIN__@N@ - .); +)ld", "@N@", boost::lexical_cast(id)); + } + + out << "\t}\n"; + +} + +void SegmentMap::CreateLdScript(std::ostream &out) +{ + out << "_MULTISEG_APP = 1;\n"; + out << scriptStart; + + for(SegmentInfo& seg: segments) + { + seg.CreateLdScript(out); + } + + out << scriptEnd; } diff --git a/Elf2Mac/SegmentMap.cc b/Elf2Mac/SegmentMap.cc new file mode 100644 index 0000000000..037a77ee2e --- /dev/null +++ b/Elf2Mac/SegmentMap.cc @@ -0,0 +1,28 @@ +#include "SegmentMap.h" + + +SegmentInfo::SegmentInfo() +{ + +} + + +SegmentMap::SegmentMap() +{ + segments.emplace_back(1, "Runtime", + "*/libretrocrt.a:start.c.obj", + "*/libretrocrt.a:relocate.c.obj", + "*/libretrocrt.a:MultiSegApp.c.obj", + "*/libretrocrt.a:LoadSeg.s.obj", + "*/libretrocrt.a:*", + "*/libgcc.a:*", + "*/libc.a:*" + ); + segments.emplace_back(3, "libstdc++", + "*/libstdc++.a:*"); + segments.emplace_back(4, "RetroConsole", + "*/libRetroConsole.a:*"); + + segments.emplace_back(2, "Main", + "*"); +} diff --git a/Elf2Mac/SegmentMap.h b/Elf2Mac/SegmentMap.h new file mode 100644 index 0000000000..3718175bb9 --- /dev/null +++ b/Elf2Mac/SegmentMap.h @@ -0,0 +1,35 @@ +#ifndef SEGMENTMAP_H +#define SEGMENTMAP_H + +#include +#include + +class SegmentInfo +{ +public: + int id; + //std::string name; + std::vector filters; + SegmentInfo(); + + template + SegmentInfo(int id, std::string name, Args... args) + : id(id), filters { args... } + { + } + + void WriteFilters(std::ostream& out, std::string section); + void WriteFiltersKeep(std::ostream& out, std::string section); + void CreateLdScript(std::ostream& out); +}; + +class SegmentMap +{ + std::vector segments; +public: + SegmentMap(); + + void CreateLdScript(std::ostream& out); +}; + +#endif // SEGMENTMAP_H diff --git a/libretro/MultiSegApp.c b/libretro/MultiSegApp.c index 8061f59ecc..629c5cefe5 100644 --- a/libretro/MultiSegApp.c +++ b/libretro/MultiSegApp.c @@ -49,18 +49,7 @@ typedef struct CODEHeader uint32_t reserved; } CODEHeader; -/* - struct object is an internal data structure in libgcc. - Comments in unwind-dw2-fde.h imply that it will not - increase in size. - */ -struct object { long space[8]; }; - -extern void __register_frame_info (const void *, struct object *) - __attribute__ ((weak)); -extern void *__deregister_frame_info (const void *) - __attribute__ ((weak)); - +#define StripAddressCompat(p) (relocState.hasStripAddr ? StripAddress(p) : StripAddress24(p)) pascal void* Retro68LoadSegment(uint8_t *p) { @@ -73,12 +62,12 @@ pascal void* Retro68LoadSegment(uint8_t *p) Handle CODE = GetResource('CODE', id); HLock(CODE); - uint8_t *base = StripAddress((uint8_t *)*CODE); + uint8_t *base = StripAddressCompat((uint8_t *)*CODE); CODEHeader *header = (CODEHeader*) base; uint32_t codeSize = GetHandleSize(CODE); // TODO: StripAddress24 - uint8_t * a5 = (uint8_t*) StripAddress((void*)SetCurrentA5()); + uint8_t * a5 = (uint8_t*) StripAddressCompat((void*)SetCurrentA5()); if(header->loadAddress != base || header->currentA5 != a5) { @@ -114,7 +103,8 @@ pascal void* Retro68LoadSegment(uint8_t *p) ++jtEntry; } - // TODO: Flush cache + if(relocState.needFlushCache) + FlushCodeCache(); /* Load Exception Information */ if (__register_frame_info) @@ -144,7 +134,7 @@ extern uint8_t _stext, _etext, _sdata, _edata, _sbss, _ebss; void Retro68InitMultisegApp() { - uint8_t * a5 = (uint8_t*) StripAddress((void*)SetCurrentA5()); + uint8_t * a5 = (uint8_t*) StripAddressCompat((void*)SetCurrentA5()); // CODE Segment 1 is already loaded - we are in it. // Update the jump table addresses. diff --git a/libretro/Retro68Runtime.h b/libretro/Retro68Runtime.h index c70b3ca008..7ad75bc07e 100644 --- a/libretro/Retro68Runtime.h +++ b/libretro/Retro68Runtime.h @@ -1,5 +1,5 @@ /* - Copyright 2015 Wolfgang Thaller. + Copyright 2017 Wolfgang Thaller. This file is part of Retro68. @@ -24,6 +24,7 @@ */ #include +#include #define _RETRO68_GET_DISPLACEMENT(DISPLACEMENT, STRIP) \ do { \ @@ -69,3 +70,27 @@ void Retro68InitMultisegApp(); void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, uint32_t displacements[]); #define RETRO68_RELOCATE() RETRO68_CALL_UNRELOCATED(Retro68Relocate,()) + + + +/* + struct object is an internal data structure in libgcc. + Comments in unwind-dw2-fde.h imply that it will not + increase in size. + */ +struct object { long space[8]; }; + +extern void __register_frame_info (const void *, struct object *) + __attribute__ ((weak)); +extern void *__deregister_frame_info (const void *) + __attribute__ ((weak)); + +typedef struct Retro68RelocState +{ + Ptr bssPtr; + Handle codeHandle; + char hasStripAddr; + char needFlushCache; +} Retro68RelocState; + +extern Retro68RelocState relocState; diff --git a/libretro/relocate.c b/libretro/relocate.c index d69600c7e0..f728e3ef7a 100644 --- a/libretro/relocate.c +++ b/libretro/relocate.c @@ -59,27 +59,9 @@ extern uint8_t _rsrc_start; extern voidFunction __CTOR_LIST__, __DTOR_LIST__; extern uint8_t __EH_FRAME_BEGIN__; -/* - struct object is an internal data structure in libgcc. - Comments in unwind-dw2-fde.h imply that it will not - increase in size. - */ -struct object { long space[8]; }; -extern void __register_frame_info (const void *, struct object *) - __attribute__ ((weak)); -extern void *__deregister_frame_info (const void *) - __attribute__ ((weak)); - - -typedef struct Retro68RelocState -{ - Ptr bssPtr; - Handle codeHandle; -} Retro68RelocState; - -static Retro68RelocState relocState __attribute__ ((section(".relocvars"))) = { - NULL, NULL +Retro68RelocState relocState __attribute__ ((section(".relocvars"))) = { + NULL, NULL, false, false }; @@ -162,8 +144,8 @@ void Retro68Relocate() struct Retro68RelocState *rState = (Retro68RelocState*) ((char*)&relocState + displacement); - // rState now points to the global relocState variable + // if(displacement == 0) { if(rState->bssPtr) @@ -178,6 +160,8 @@ void Retro68Relocate() return; } } + + rState->hasStripAddr = hasStripAddr; // Locate the start of the FLT file header inside the code resource uint8_t *orig_stext, *orig_etext, *orig_sdata, *orig_edata, *orig_sbss, *orig_ebss; @@ -256,7 +240,7 @@ void Retro68Relocate() void *reloc; Handle RELA = NULL; uint32_t relocatableSize; - if(&_MULTISEG_APP) + if(&_MULTISEG_APP == (uint8_t*)1) { RELA = Get1Resource('RELA', 1); assert(RELA); @@ -289,6 +273,7 @@ void Retro68Relocate() SysEnvirons(0, &env); if(env.processor >= env68040) { + rState->needFlushCache = true; FlushCodeCache(); } } @@ -355,4 +340,3 @@ void Retro68FreeGlobals() relocState.bssPtr = (Ptr) -1; } } -