SegmentMap, code flushing, cleanup

This commit is contained in:
Wolfgang Thaller 2017-09-27 00:30:06 +02:00
parent 8a2038601a
commit 68c43b7a39
9 changed files with 279 additions and 159 deletions

View File

@ -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)

View File

@ -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");

View File

@ -22,6 +22,6 @@
#include <iosfwd>
void CreateLdScript(std::ostream& out, bool segments);
void CreateFlatLdScript(std::ostream& out);
#endif // ELF2MAC_H

View File

@ -18,9 +18,11 @@
*/
#include "Elf2Mac.h"
#include "SegmentMap.h"
#include <iostream>
#include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
using std::string;
@ -41,12 +43,12 @@ const char * textSection = R"ld(/* ld script for Elf2Mac */
/* 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)
@ -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 = . ;
@ -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,27 +153,27 @@ 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/ : { *(*) }
}
@ -252,22 +181,112 @@ const char * scriptEnd = R"ld(
)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<string>(R"ld(
. = ALIGN(0x4);
FILL(0);
. += 32;
LONG(__EH_FRAME_BEGIN__@N@ - .);
)ld", "@N@", boost::lexical_cast<string>(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;
}

28
Elf2Mac/SegmentMap.cc Normal file
View File

@ -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",
"*");
}

35
Elf2Mac/SegmentMap.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef SEGMENTMAP_H
#define SEGMENTMAP_H
#include <vector>
#include <string>
class SegmentInfo
{
public:
int id;
//std::string name;
std::vector<std::string> filters;
SegmentInfo();
template<typename... Args>
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<SegmentInfo> segments;
public:
SegmentMap();
void CreateLdScript(std::ostream& out);
};
#endif // SEGMENTMAP_H

View File

@ -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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2015 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
@ -24,6 +24,7 @@
*/
#include <stdint.h>
#include <Types.h>
#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;

View File

@ -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)
@ -179,6 +161,8 @@ void Retro68Relocate()
}
}
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;
}
}