moving closer to multiseg

This commit is contained in:
Wolfgang Thaller 2017-09-26 02:38:05 +02:00
parent ce59176be5
commit a4716081c2
5 changed files with 390 additions and 108 deletions

View File

@ -54,21 +54,30 @@ size_t mainStringTableIdx = (size_t)-1;
class Symtab; class Symtab;
class Section; class Section;
Elf *elf;
std::vector<int> relocs; std::vector<int> relocs;
unique_ptr<Symtab> symtab; unique_ptr<Symtab> symtab;
unordered_map<string, shared_ptr<Section>> sections; unordered_map<string, shared_ptr<Section>> sections;
unordered_map<int, shared_ptr<Section>> sectionsByElfIndex; unordered_map<int, shared_ptr<Section>> sectionsByElfIndex;
std::vector<shared_ptr<Section>> codeSections; std::vector<shared_ptr<Section>> codeSections;
shared_ptr<Section> dataSection; shared_ptr<Section> dataSection, bssSection;
enum class SectionKind enum class SectionKind
{ {
undefined = -1, undefined = -1,
code = 0,
data,
bss
};
enum class RelocBase
{
code = 0, code = 0,
data, data,
bss, bss,
jumptable jumptable,
code1
}; };
class Symbol : public GElf_Sym class Symbol : public GElf_Sym
@ -77,9 +86,14 @@ public:
bool valid; bool valid;
bool referencedExternally; bool referencedExternally;
SectionKind sectionKind; SectionKind sectionKind;
bool needsJT;
int jtIndex;
shared_ptr<Section> section;
Symbol(); Symbol();
Symbol(GElf_Sym sym); Symbol(const GElf_Sym& sym);
string GetName();
}; };
class Symtab class Symtab
@ -94,6 +108,15 @@ public:
Symbol& GetSym(int idx); Symbol& GetSym(int idx);
}; };
class Reloc : public GElf_Rela
{
public:
RelocBase relocBase;
Reloc();
Reloc(const GElf_Rela& rela);
};
class Section class Section
{ {
public: public:
@ -102,17 +125,24 @@ public:
SectionKind kind; SectionKind kind;
Elf_Scn *elfsec, *relasec; Elf_Scn *elfsec, *relasec;
Elf_Data *data; Elf_Data *data;
GElf_Shdr shdr;
uint32_t outputBase;
std::vector<GElf_Rela> relocs; int codeID;
std::vector<Reloc> relocs;
std::vector<Symbol*> jtEntries;
int firstJTEntryIndex;
Section(string name, int idx, SectionKind kind, Elf_Scn *elfsec); Section(string name, int idx, SectionKind kind, Elf_Scn *elfsec);
void SetRela(Elf_Scn *scn); void SetRela(Elf_Scn *scn);
uint32_t GetSize(); uint32_t GetSize();
string GetData(); string GetData();
string GetAbsRelocations(bool suppressTerminatingEntry = false); string GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry = false);
void ScanRelocs(); void ScanRelocs();
void FixRelocs();
}; };
Symbol::Symbol() Symbol::Symbol()
@ -120,17 +150,24 @@ Symbol::Symbol()
{ {
} }
Symbol::Symbol(GElf_Sym sym) Symbol::Symbol(const GElf_Sym &sym)
: GElf_Sym(sym), valid(true), : GElf_Sym(sym), valid(true),
referencedExternally(false), referencedExternally(false),
sectionKind(SectionKind::undefined) sectionKind(SectionKind::undefined),
needsJT(false)
{ {
if(st_shndx != SHN_UNDEF) if(st_shndx != SHN_UNDEF && st_shndx < SHN_LORESERVE)
{ {
sectionKind = sectionsByElfIndex[st_shndx]->kind; section = sectionsByElfIndex[st_shndx];
sectionKind = section->kind;
} }
} }
string Symbol::GetName()
{
return elf_strptr(elf, mainStringTableIdx, st_name);
}
Symtab::Symtab(Elf_Scn *elfsec) Symtab::Symtab(Elf_Scn *elfsec)
: elfsec(elfsec) : elfsec(elfsec)
{ {
@ -157,10 +194,23 @@ Symbol &Symtab::GetSym(int idx)
} }
} }
Reloc::Reloc()
{
}
Reloc::Reloc(const GElf_Rela &rela)
: GElf_Rela(rela)
{
}
Section::Section(string name, int idx, SectionKind kind, Elf_Scn *elfsec) Section::Section(string name, int idx, SectionKind kind, Elf_Scn *elfsec)
: name(name), idx(idx), kind(kind), elfsec(elfsec), relasec(NULL) : name(name), idx(idx), kind(kind), elfsec(elfsec), relasec(NULL),
codeID(-1), firstJTEntryIndex(0)
{ {
data = elf_getdata(elfsec, NULL); data = elf_getdata(elfsec, NULL);
gelf_getshdr(elfsec, &shdr);
outputBase = shdr.sh_addr;
} }
void Section::SetRela(Elf_Scn *scn) void Section::SetRela(Elf_Scn *scn)
@ -192,10 +242,8 @@ string Section::GetData()
return string((char*)data->d_buf, (char*)data->d_buf + data->d_size); return string((char*)data->d_buf, (char*)data->d_buf + data->d_size);
} }
string Section::GetAbsRelocations(bool suppressTerminatingEntry) string Section::GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry)
{ {
if(!relasec)
return "";
std::ostringstream out; std::ostringstream out;
for(auto& rela : relocs) for(auto& rela : relocs)
@ -208,14 +256,21 @@ string Section::GetAbsRelocations(bool suppressTerminatingEntry)
Symbol& sym = symtab->GetSym(symidx); Symbol& sym = symtab->GetSym(symidx);
if(sym.st_shndx == SHN_UNDEF) if(sym.st_shndx == SHN_UNDEF || sym.st_shndx >= SHN_LORESERVE)
continue;
if(sym.sectionKind == SectionKind::undefined)
continue; continue;
if(GELF_R_TYPE(rela.r_info) == R_68K_32) if(GELF_R_TYPE(rela.r_info) == R_68K_32)
{ {
assert(sym.sectionKind != SectionKind::undefined); assert(sym.sectionKind != SectionKind::undefined);
longword(out, rela.r_offset | ((int)sym.sectionKind << 24)); uint32_t offset = rela.r_offset;
if(useOffsets)
offset -= shdr.sh_addr;
longword(out, offset | ((int)rela.relocBase << 24));
} }
} }
if(!suppressTerminatingEntry) if(!suppressTerminatingEntry)
@ -241,6 +296,84 @@ void Section::ScanRelocs()
} }
} }
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)
{
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);
}
}
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) void GrokELF(string input)
{ {
@ -248,15 +381,13 @@ void GrokELF(string input)
errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1)); errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1));
int fd = open(input.c_str(), O_RDONLY, 0); int fd = open(input.c_str(), O_RDONLY, 0);
Elf *elf = elf_begin(fd, ELF_C_READ, NULL); elf = elf_begin(fd, ELF_C_READ, NULL);
elf_getshdrstrndx(elf, &sectionHeaderStringTableIdx); elf_getshdrstrndx(elf, &sectionHeaderStringTableIdx);
GElf_Ehdr ehdr; GElf_Ehdr ehdr;
gelf_getehdr(elf, &ehdr); gelf_getehdr(elf, &ehdr);
Elf_Scn* bssSection = NULL;
int idx = 1; int idx = 1;
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++) for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
{ {
@ -299,12 +430,11 @@ void GrokELF(string input)
} }
if(shdr.sh_type == SHT_NOBITS) if(shdr.sh_type == SHT_NOBITS)
{ {
bssSection = scn;
// Currently, the bss section is used // Currently, the bss section is used
// to know when to start skipping debug info sections. // to know when to start skipping debug info sections.
// (What's the official way to distinguish a debug info section from a "real" section?) // (What's the official way to distinguish a debug info section from a "real" section?)
sections[name] = sectionsByElfIndex[idx] = bssSection = sections[name] = sectionsByElfIndex[idx] =
make_shared<Section>(name, idx, SectionKind::bss, scn); make_shared<Section>(name, idx, SectionKind::bss, scn);
} }
} }
@ -321,8 +451,8 @@ void FlatCode(std::ostream& out)
out << dataSection->GetData(); out << dataSection->GetData();
for(auto sec : codeSections) for(auto sec : codeSections)
out << sec->GetAbsRelocations(true); out << sec->GetAbsRelocations(false, true);
out << dataSection->GetAbsRelocations(); out << dataSection->GetAbsRelocations(false);
} }
@ -401,39 +531,134 @@ void MultiSegmentApp(string output)
ResourceFile file(output); ResourceFile file(output);
Resources& rsrc = file.resources; Resources& rsrc = file.resources;
for(auto sec : codeSections) for(auto namedSec : sections)
{ {
sec->ScanRelocs(); namedSec.second->ScanRelocs();
} }
rsrc.addResource(Resource(ResType("CODE"), 0, int jtEntryCount = 0;
fromhex( unordered_map<int, vector<Symbol*>> jtEntries;
"00000028 00000000 00000008 00000020" for(Symbol& sym : symtab->symbols)
"0000 3F3C 0001 A9F0" {
) 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; int id = 1;
for(auto sec : codeSections) 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
}
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; std::ostringstream code;
word(code, 0); //FIXME: header if(id == 1)
{
word(code, 0);
word(code, 1); word(code, 1);
}
else
{
word(code, 0xFFFF);
word(code, 0);
longword(code, 0);
longword(code, 0);
longword(code, 0x20 + 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(); code << sec->GetData();
std::cout << "CODE " << id << ": " << code.str().size() << " bytes\n";
rsrc.addResource(Resource(ResType("CODE"), id, rsrc.addResource(Resource(ResType("CODE"), id,
code.str())); code.str()));
rsrc.addResource(Resource(ResType("RELA"),id, sec->GetAbsRelocations())); rsrc.addResource(Resource(ResType("RELA"),id, sec->GetAbsRelocations(true)));
id++;
} }
rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData())); 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.creator = ResType("????");
file.type = ResType("APPL"); file.type = ResType("APPL");
@ -497,7 +722,7 @@ int main(int argc, char *argv[])
string outputFile = "a.out"; string outputFile = "a.out";
bool elf2mac = false; bool elf2mac = false;
bool flatoutput = false; bool flatoutput = false;
bool segments = false; bool segments = true;
vector<string> args2; vector<string> args2;
for(auto p = args.begin(), e = args.end(); p != e; ++p) for(auto p = args.begin(), e = args.end(); p != e; ++p)
@ -575,9 +800,10 @@ int main(int argc, char *argv[])
if(argc != 2) if(argc != 2)
errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]); errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]);
GrokELF(argv[1]); GrokELF(argv[1]);
FlatCode("out.flt"); MultiSegmentApp("out.bin");
} }
return 0; return 0;
} }

View File

@ -37,13 +37,16 @@ const char * textSection = R"ld(/* ld script for Elf2Mac */
PROVIDE(_rsrc_start = .); PROVIDE(_rsrc_start = .);
*(.rsrcheader) *(.rsrcheader)
. = ALIGN (2); . = ALIGN (2);
_entry_trampoline = .;
/* The entry point. */
_entry_trampoline = .;
SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71); SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71);
LONG(0x61000002); /* bsr *+2 */ LONG(0x61000002); /* bsr *+2 */
SHORT(0x0697); /* addi.l #_, (a7) */ SHORT(0x0697); /* addi.l #_, (a7) */
LONG(_start - _entry_trampoline - 6); LONG(_start - _entry_trampoline - 6);
PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */ PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */
Retro68InitMultisegApp = .; /* override this for the single-segment case */
SHORT(0x4e75); /* rts */ SHORT(0x4e75); /* rts */
*(.relocvars) *(.relocvars)
@ -83,9 +86,11 @@ const char * textSection = R"ld(/* ld script for Elf2Mac */
const char * code1Section = R"ld(/* ld script for Elf2Mac */ const char * code1Section = R"ld(/* ld script for Elf2Mac */
.code1 : { .code1 : {
_stext = . ; _stext = . ;
FILL(0x4E71);
PROVIDE(_rsrc_start = .); PROVIDE(_rsrc_start = .);
. = ALIGN (2); . = ALIGN (2);
_entry_trampoline = .; _entry_trampoline = .;
__break_on_entry = 1;
SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71); SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71);
LONG(0x61000002); /* bsr *+2 */ LONG(0x61000002); /* bsr *+2 */
SHORT(0x0697); /* addi.l #_, (a7) */ SHORT(0x0697); /* addi.l #_, (a7) */
@ -96,6 +101,9 @@ const char * code1Section = R"ld(/* ld script for Elf2Mac */
*(.relocvars) *(.relocvars)
*/libretrocrt.a:start.c.obj(.text*) */libretrocrt.a:start.c.obj(.text*)
*/libretrocrt.a:relocate.c.obj(.text*) */libretrocrt.a:relocate.c.obj(.text*)
*/libretrocrt.a:*(.text*)
*/libgcc.a:*(.text*)
*/libc.a:*(.text*)
. = ALIGN (4) ; . = ALIGN (4) ;
__init_section = . ; __init_section = . ;
@ -114,16 +122,17 @@ const char * code1Section = R"ld(/* ld script for Elf2Mac */
)ld"; )ld";
const char * codeSectionTemplate = R"ld(/* ld script for Elf2Mac */ const char * codeSectionTemplate = R"ld(/* ld script for Elf2Mac */
.code@N@ : { .code@N@ : {
FILL(0x4E71);
@FILTER@(.text*) @FILTER@(.text*)
@EXTRA@ @EXTRA@
. = ALIGN (4) ; . = ALIGN (4) ;
KEEP(@FILTER@(.eh_frame)) /* KEEP(@FILTER@(.eh_frame))
LONG(0); LONG(0);
KEEP(@FILTER@(.gcc_except_table)) KEEP(@FILTER@(.gcc_except_table))
KEEP(@FILTER@(.gcc_except_table.*)) KEEP(@FILTER@(.gcc_except_table.*)) */
. = ALIGN(0x4) ; . = ALIGN(0x4) ;
} }
@ -227,6 +236,8 @@ const char * scriptEnd = R"ld(
.debug_funcnames 0 : { *(.debug_funcnames) } .debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) } .debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) } .debug_varnames 0 : { *(.debug_varnames) }
/DISCARD/ : { *(*) }
} }
)ld"; )ld";
@ -236,6 +247,7 @@ void CreateLdScript(std::ostream& out, bool segments)
{ {
if(segments) if(segments)
{ {
out << "_MULTISEG_APP = 1;\n";
out << scriptStart << code1Section; out << scriptStart << code1Section;
string code = codeSectionTemplate; string code = codeSectionTemplate;
boost::replace_all(code, "@N@", "2"); boost::replace_all(code, "@N@", "2");
@ -245,5 +257,8 @@ void CreateLdScript(std::ostream& out, bool segments)
out << scriptEnd; out << scriptEnd;
} }
else else
{
out << "_MULTISEG_APP = 0;\n";
out << scriptStart << textSection << scriptEnd; out << scriptStart << textSection << scriptEnd;
}
} }

View File

@ -36,6 +36,8 @@ if(CMAKE_SYSTEM_NAME MATCHES Retro68)
start.c start.c
relocate.c relocate.c
PoorMansDebugging.h PoorMansDebugging.h
MultiSegApp.c
LoadSeg.s
# glue.c # glue.c
${CMAKE_CURRENT_BINARY_DIR}/Interface.s ${CMAKE_CURRENT_BINARY_DIR}/Interface.s
qdglobals.c qdglobals.c
@ -45,6 +47,7 @@ if(CMAKE_SYSTEM_NAME MATCHES Retro68)
install(FILES Retro68Runtime.h DESTINATION include) install(FILES Retro68Runtime.h DESTINATION include)
install(FILES Retro68.r Retro68APPL.r DESTINATION RIncludes) install(FILES Retro68.r Retro68APPL.r DESTINATION RIncludes)
elseif(CMAKE_SYSTEM_NAME MATCHES RetroPPC) elseif(CMAKE_SYSTEM_NAME MATCHES RetroPPC)
enable_language(ASM) enable_language(ASM)
set(ARCH_FILES set(ARCH_FILES

View File

@ -23,6 +23,8 @@
<http://www.gnu.org/licenses/>. <http://www.gnu.org/licenses/>.
*/ */
#include <stdint.h>
#define _RETRO68_GET_DISPLACEMENT(DISPLACEMENT, STRIP) \ #define _RETRO68_GET_DISPLACEMENT(DISPLACEMENT, STRIP) \
do { \ do { \
char *virtualstart, *realstart; \ char *virtualstart, *realstart; \
@ -63,5 +65,7 @@ void Retro68Relocate();
void Retro68CallConstructors(); void Retro68CallConstructors();
void Retro68CallDestructors(); void Retro68CallDestructors();
void Retro68FreeGlobals(); void Retro68FreeGlobals();
void Retro68InitMultisegApp();
void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, uint32_t displacements[]);
#define RETRO68_RELOCATE() RETRO68_CALL_UNRELOCATED(Retro68Relocate,()) #define RETRO68_RELOCATE() RETRO68_CALL_UNRELOCATED(Retro68Relocate,())

View File

@ -31,6 +31,7 @@
#include <Memory.h> #include <Memory.h>
#include <OSUtils.h> #include <OSUtils.h>
#include <Traps.h> #include <Traps.h>
#include <Resources.h>
#include "Retro68Runtime.h" #include "Retro68Runtime.h"
#include "PoorMansDebugging.h" #include "PoorMansDebugging.h"
@ -41,6 +42,10 @@ typedef void (*voidFunction)(void);
Linker-defined addresses in the binary; Linker-defined addresses in the binary;
*/ */
// absolute address 0x1 for multiseg applications,
// absolute address NULL (or undefined) for code resources
extern uint8_t _MULTISEG_APP __attribute__ ((weak));
// section boundaries // section boundaries
extern uint8_t _stext, _etext, _sdata, _edata, _sbss, _ebss; extern uint8_t _stext, _etext, _sdata, _edata, _sbss, _ebss;
// constructor list: // constructor list:
@ -101,6 +106,26 @@ static Retro68RelocState relocState __attribute__ ((section(".relocvars"))) = {
} while(0) } while(0)
void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, uint32_t displacements[])
{
uint32_t *reloc = (uint32_t*) relocations;
// Process relocation records
for(;*reloc != -1;++reloc)
{
uint32_t r = *reloc;
uint8_t *addrPtr = base + (r & 0xFFFFFF);
uint8_t *addr;
uint8_t kind = r >> 24;
assert(addrPtr >= base);
assert(addrPtr < base + size);
addr = (uint8_t*) READ_UNALIGNED_LONGWORD(addrPtr);
addr += displacements[kind];
WRITE_UNALIGNED_LONGWORD(addrPtr, (uint32_t) addr);
}
}
void Retro68Relocate() void Retro68Relocate()
{ {
// memory address to retrieve the ROM type (64K or a later ROM) // memory address to retrieve the ROM type (64K or a later ROM)
@ -173,6 +198,20 @@ void Retro68Relocate()
uint8_t *base = orig_stext + displacement; uint8_t *base = orig_stext + displacement;
long bss_displacement = 0;
long data_displacement = 0;
long jt_displacement = 0;
if(&_MULTISEG_APP)
{
uint8_t * a5 = (uint8_t*) SetCurrentA5();
bss_displacement = a5 - orig_ebss;
data_displacement = a5 - orig_ebss;
jt_displacement = a5 - (uint8_t*)NULL;
}
else
{
data_displacement = displacement;
{ {
uint8_t *orig_rsrc_start; uint8_t *orig_rsrc_start;
GET_VIRTUAL_ADDRESS(orig_rsrc_start, _rsrc_start); GET_VIRTUAL_ADDRESS(orig_rsrc_start, _rsrc_start);
@ -187,16 +226,10 @@ void Retro68Relocate()
} }
} }
uint32_t text_and_data_size = orig_edata - orig_stext;
long bss_size = orig_ebss - orig_sbss;
//uint32_t total_size = orig_ebss - orig_stext; // FIXME: not true for repeated reloc
//assert(total_size == header->bss_end - sizeof(*header));
long bss_displacement = 0;
// Allocate BSS section (uninitialized/zero-initialized global data) // Allocate BSS section (uninitialized/zero-initialized global data)
if(!rState->bssPtr) if(!rState->bssPtr)
{ {
uint32_t bss_size = orig_ebss - orig_sbss;
THz zone = ApplicationZone(); THz zone = ApplicationZone();
if(!zone || base < (uint8_t*)zone) if(!zone || base < (uint8_t*)zone)
rState->bssPtr = NewPtrSysClear(bss_size); rState->bssPtr = NewPtrSysClear(bss_size);
@ -204,6 +237,7 @@ void Retro68Relocate()
rState->bssPtr = NewPtrClear(bss_size); rState->bssPtr = NewPtrClear(bss_size);
bss_displacement = (uint8_t*)rState->bssPtr - orig_sbss; bss_displacement = (uint8_t*)rState->bssPtr - orig_sbss;
} }
}
/* /*
Relocation records consist of 4 bytes each. Relocation records consist of 4 bytes each.
@ -214,40 +248,33 @@ void Retro68Relocate()
*/ */
long displacements[4] = { long displacements[4] = {
displacement, // code displacement, // code
displacement, // data (contiguous with code) data_displacement,
bss_displacement, // bss (allocated separately) bss_displacement,
SetCurrentA5() // jump table (TODO) jt_displacement
}; };
// Process relocation records void *reloc;
for(long *reloc = (long*)( base + text_and_data_size ); Handle RELA = NULL;
*reloc != -1; uint32_t relocatableSize;
++reloc) if(&_MULTISEG_APP)
{ {
uint32_t r = *reloc; RELA = Get1Resource('RELA', 1);
uint8_t *addrPtr = base + (r & 0xFFFFFF); assert(RELA);
uint8_t *addr; reloc = *RELA;
uint8_t kind = r >> 24; uint32_t text_size = orig_etext - orig_stext;
relocatableSize = text_size;
assert(addrPtr >= base);
assert(addrPtr < base + text_and_data_size);
addr = (uint8_t*) READ_UNALIGNED_LONGWORD(addrPtr);
/* Check whether addresses are in range.
* This doesn't seem to work because exception handling tables
* seem to contain strange things.
*/
/*assert((uint8_t*)addr >= orig_stext); // TODO: not right for repeated reloc
assert((uint8_t*)addr <= orig_stext + total_size);*/
addr += displacements[kind];
/*assert((Ptr)addr >= (Ptr)base && (Ptr)addr <= (Ptr)base + text_and_data_size
|| (Ptr)addr >= rState->bssPtr && (Ptr)addr <= rState->bssPtr + bss_size);*/
WRITE_UNALIGNED_LONGWORD(addrPtr, (uint32_t) addr);
} }
else
{
uint32_t text_and_data_size = orig_edata - orig_stext;
reloc = base + text_and_data_size;
relocatableSize = text_and_data_size;
}
typedef typeof(&Retro68ApplyRelocations) ApplyRelocationsPtr;
ApplyRelocationsPtr RealApplyRelocations;
RealApplyRelocations = (ApplyRelocationsPtr) ((uint8_t*)&Retro68ApplyRelocations + displacement);
RealApplyRelocations(base, relocatableSize, reloc, displacements);
// We're basically done. // We're basically done.
// Now check whether we're on 68040 or later and need to flush the cache. // Now check whether we're on 68040 or later and need to flush the cache.
@ -267,13 +294,20 @@ void Retro68Relocate()
} }
// accessing globals and calling functions is OK below here. // accessing globals and calling functions is OK below here.
// ... as long as it is in the current segment.
Retro68InitMultisegApp();
// Now we're set.
// Someone still needs to invoke Retro68CallConstructors
// ... but that's the job of _start().
} }
void Retro68CallConstructors() void Retro68CallConstructors()
{ {
static struct object object; /*static struct object object;
if (__register_frame_info) if (__register_frame_info)
__register_frame_info(&__EH_FRAME_BEGIN__, &object); __register_frame_info(&__EH_FRAME_BEGIN__, &object);*/
{ {
uint8_t *p = &__init_section; uint8_t *p = &__init_section;
uint8_t *e = &__init_section_end; uint8_t *e = &__init_section_end;
@ -308,8 +342,8 @@ void Retro68CallDestructors()
p += 6; p += 6;
} }
} }
if (__deregister_frame_info) /* if (__deregister_frame_info)
__deregister_frame_info(&__EH_FRAME_BEGIN__); __deregister_frame_info(&__EH_FRAME_BEGIN__);*/
} }