mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-26 06:49:33 +00:00
SegmentMap, code flushing, cleanup
This commit is contained in:
parent
8a2038601a
commit
68c43b7a39
@ -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)
|
||||
|
@ -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");
|
||||
|
@ -22,6 +22,6 @@
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
void CreateLdScript(std::ostream& out, bool segments);
|
||||
void CreateFlatLdScript(std::ostream& out);
|
||||
|
||||
#endif // ELF2MAC_H
|
||||
|
@ -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;
|
||||
@ -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 = . ;
|
||||
@ -252,22 +181,112 @@ const char * scriptEnd = R"ld(
|
||||
)ld";
|
||||
|
||||
|
||||
void CreateLdScript(std::ostream& out, bool segments)
|
||||
{
|
||||
if(segments)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
void CreateFlatLdScript(std::ostream& out)
|
||||
{
|
||||
out << "_MULTISEG_APP = 0;\n";
|
||||
out << scriptStart << textSection << scriptEnd;
|
||||
}
|
||||
|
||||
|
||||
void SegmentInfo::WriteFilters(std::ostream &out, string section)
|
||||
{
|
||||
for(string filter : filters)
|
||||
{
|
||||
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 << 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
28
Elf2Mac/SegmentMap.cc
Normal 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
35
Elf2Mac/SegmentMap.h
Normal 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
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user