mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-26 00:32:02 +00:00
moving closer to multiseg
This commit is contained in:
parent
ce59176be5
commit
a4716081c2
@ -54,21 +54,30 @@ size_t mainStringTableIdx = (size_t)-1;
|
||||
class Symtab;
|
||||
class Section;
|
||||
|
||||
Elf *elf;
|
||||
std::vector<int> relocs;
|
||||
unique_ptr<Symtab> symtab;
|
||||
unordered_map<string, shared_ptr<Section>> sections;
|
||||
unordered_map<int, shared_ptr<Section>> sectionsByElfIndex;
|
||||
|
||||
std::vector<shared_ptr<Section>> codeSections;
|
||||
shared_ptr<Section> dataSection;
|
||||
shared_ptr<Section> dataSection, bssSection;
|
||||
|
||||
enum class SectionKind
|
||||
{
|
||||
undefined = -1,
|
||||
code = 0,
|
||||
data,
|
||||
bss
|
||||
};
|
||||
|
||||
enum class RelocBase
|
||||
{
|
||||
code = 0,
|
||||
data,
|
||||
bss,
|
||||
jumptable
|
||||
jumptable,
|
||||
code1
|
||||
};
|
||||
|
||||
class Symbol : public GElf_Sym
|
||||
@ -77,9 +86,14 @@ public:
|
||||
bool valid;
|
||||
bool referencedExternally;
|
||||
SectionKind sectionKind;
|
||||
bool needsJT;
|
||||
int jtIndex;
|
||||
shared_ptr<Section> section;
|
||||
|
||||
Symbol();
|
||||
Symbol(GElf_Sym sym);
|
||||
Symbol(const GElf_Sym& sym);
|
||||
|
||||
string GetName();
|
||||
};
|
||||
|
||||
class Symtab
|
||||
@ -94,6 +108,15 @@ public:
|
||||
Symbol& GetSym(int idx);
|
||||
};
|
||||
|
||||
class Reloc : public GElf_Rela
|
||||
{
|
||||
public:
|
||||
RelocBase relocBase;
|
||||
|
||||
Reloc();
|
||||
Reloc(const GElf_Rela& rela);
|
||||
};
|
||||
|
||||
class Section
|
||||
{
|
||||
public:
|
||||
@ -102,17 +125,24 @@ public:
|
||||
SectionKind kind;
|
||||
Elf_Scn *elfsec, *relasec;
|
||||
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);
|
||||
void SetRela(Elf_Scn *scn);
|
||||
|
||||
uint32_t GetSize();
|
||||
string GetData();
|
||||
string GetAbsRelocations(bool suppressTerminatingEntry = false);
|
||||
string GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry = false);
|
||||
|
||||
void ScanRelocs();
|
||||
void FixRelocs();
|
||||
};
|
||||
|
||||
Symbol::Symbol()
|
||||
@ -120,17 +150,24 @@ Symbol::Symbol()
|
||||
{
|
||||
}
|
||||
|
||||
Symbol::Symbol(GElf_Sym sym)
|
||||
Symbol::Symbol(const GElf_Sym &sym)
|
||||
: GElf_Sym(sym), valid(true),
|
||||
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)
|
||||
: 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)
|
||||
: 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);
|
||||
gelf_getshdr(elfsec, &shdr);
|
||||
outputBase = shdr.sh_addr;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
string Section::GetAbsRelocations(bool suppressTerminatingEntry)
|
||||
string Section::GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry)
|
||||
{
|
||||
if(!relasec)
|
||||
return "";
|
||||
std::ostringstream out;
|
||||
|
||||
for(auto& rela : relocs)
|
||||
@ -208,14 +256,21 @@ string Section::GetAbsRelocations(bool suppressTerminatingEntry)
|
||||
|
||||
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;
|
||||
|
||||
if(GELF_R_TYPE(rela.r_info) == R_68K_32)
|
||||
{
|
||||
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)
|
||||
@ -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)
|
||||
{
|
||||
@ -248,15 +381,13 @@ void GrokELF(string input)
|
||||
errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1));
|
||||
|
||||
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, §ionHeaderStringTableIdx);
|
||||
|
||||
GElf_Ehdr ehdr;
|
||||
gelf_getehdr(elf, &ehdr);
|
||||
|
||||
Elf_Scn* bssSection = NULL;
|
||||
|
||||
int idx = 1;
|
||||
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)
|
||||
{
|
||||
bssSection = scn;
|
||||
// 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?)
|
||||
|
||||
sections[name] = sectionsByElfIndex[idx] =
|
||||
bssSection = sections[name] = sectionsByElfIndex[idx] =
|
||||
make_shared<Section>(name, idx, SectionKind::bss, scn);
|
||||
}
|
||||
}
|
||||
@ -321,8 +451,8 @@ void FlatCode(std::ostream& out)
|
||||
out << dataSection->GetData();
|
||||
|
||||
for(auto sec : codeSections)
|
||||
out << sec->GetAbsRelocations(true);
|
||||
out << dataSection->GetAbsRelocations();
|
||||
out << sec->GetAbsRelocations(false, true);
|
||||
out << dataSection->GetAbsRelocations(false);
|
||||
|
||||
}
|
||||
|
||||
@ -401,39 +531,134 @@ void MultiSegmentApp(string output)
|
||||
ResourceFile file(output);
|
||||
Resources& rsrc = file.resources;
|
||||
|
||||
for(auto sec : codeSections)
|
||||
for(auto namedSec : sections)
|
||||
{
|
||||
sec->ScanRelocs();
|
||||
namedSec.second->ScanRelocs();
|
||||
}
|
||||
|
||||
rsrc.addResource(Resource(ResType("CODE"), 0,
|
||||
fromhex(
|
||||
"00000028 00000000 00000008 00000020"
|
||||
"0000 3F3C 0001 A9F0"
|
||||
)
|
||||
));
|
||||
int jtEntryCount = 0;
|
||||
unordered_map<int, vector<Symbol*>> 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()));
|
||||
}
|
||||
|
||||
int id = 1;
|
||||
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;
|
||||
word(code, 0); //FIXME: header
|
||||
word(code, 1);
|
||||
if(id == 1)
|
||||
{
|
||||
word(code, 0);
|
||||
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();
|
||||
|
||||
std::cout << "CODE " << id << ": " << code.str().size() << " bytes\n";
|
||||
|
||||
rsrc.addResource(Resource(ResType("CODE"), id,
|
||||
code.str()));
|
||||
|
||||
|
||||
rsrc.addResource(Resource(ResType("RELA"),id, sec->GetAbsRelocations()));
|
||||
id++;
|
||||
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");
|
||||
@ -497,7 +722,7 @@ int main(int argc, char *argv[])
|
||||
string outputFile = "a.out";
|
||||
bool elf2mac = false;
|
||||
bool flatoutput = false;
|
||||
bool segments = false;
|
||||
bool segments = true;
|
||||
|
||||
vector<string> args2;
|
||||
for(auto p = args.begin(), e = args.end(); p != e; ++p)
|
||||
@ -575,9 +800,10 @@ int main(int argc, char *argv[])
|
||||
if(argc != 2)
|
||||
errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]);
|
||||
GrokELF(argv[1]);
|
||||
FlatCode("out.flt");
|
||||
MultiSegmentApp("out.bin");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -37,13 +37,16 @@ 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 */
|
||||
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 */
|
||||
SHORT(0x4e75); /* rts */
|
||||
|
||||
*(.relocvars)
|
||||
@ -83,9 +86,11 @@ const char * textSection = R"ld(/* ld script for Elf2Mac */
|
||||
const char * code1Section = R"ld(/* ld script for Elf2Mac */
|
||||
.code1 : {
|
||||
_stext = . ;
|
||||
FILL(0x4E71);
|
||||
PROVIDE(_rsrc_start = .);
|
||||
. = ALIGN (2);
|
||||
_entry_trampoline = .;
|
||||
__break_on_entry = 1;
|
||||
SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71);
|
||||
LONG(0x61000002); /* bsr *+2 */
|
||||
SHORT(0x0697); /* addi.l #_, (a7) */
|
||||
@ -96,7 +101,10 @@ const char * code1Section = R"ld(/* ld script for Elf2Mac */
|
||||
*(.relocvars)
|
||||
*/libretrocrt.a:start.c.obj(.text*)
|
||||
*/libretrocrt.a:relocate.c.obj(.text*)
|
||||
|
||||
*/libretrocrt.a:*(.text*)
|
||||
*/libgcc.a:*(.text*)
|
||||
*/libc.a:*(.text*)
|
||||
|
||||
. = ALIGN (4) ;
|
||||
__init_section = . ;
|
||||
KEEP (*(.init))
|
||||
@ -114,16 +122,17 @@ const char * code1Section = R"ld(/* ld script for Elf2Mac */
|
||||
)ld";
|
||||
const char * codeSectionTemplate = R"ld(/* ld script for Elf2Mac */
|
||||
.code@N@ : {
|
||||
FILL(0x4E71);
|
||||
@FILTER@(.text*)
|
||||
|
||||
@EXTRA@
|
||||
|
||||
. = ALIGN (4) ;
|
||||
|
||||
KEEP(@FILTER@(.eh_frame))
|
||||
/* KEEP(@FILTER@(.eh_frame))
|
||||
LONG(0);
|
||||
KEEP(@FILTER@(.gcc_except_table))
|
||||
KEEP(@FILTER@(.gcc_except_table.*))
|
||||
KEEP(@FILTER@(.gcc_except_table.*)) */
|
||||
|
||||
. = ALIGN(0x4) ;
|
||||
}
|
||||
@ -227,6 +236,8 @@ const char * scriptEnd = R"ld(
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
|
||||
/DISCARD/ : { *(*) }
|
||||
}
|
||||
|
||||
)ld";
|
||||
@ -236,6 +247,7 @@ 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");
|
||||
@ -245,5 +257,8 @@ void CreateLdScript(std::ostream& out, bool segments)
|
||||
out << scriptEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "_MULTISEG_APP = 0;\n";
|
||||
out << scriptStart << textSection << scriptEnd;
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ if(CMAKE_SYSTEM_NAME MATCHES Retro68)
|
||||
start.c
|
||||
relocate.c
|
||||
PoorMansDebugging.h
|
||||
MultiSegApp.c
|
||||
LoadSeg.s
|
||||
# glue.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Interface.s
|
||||
qdglobals.c
|
||||
@ -45,6 +47,7 @@ if(CMAKE_SYSTEM_NAME MATCHES Retro68)
|
||||
|
||||
install(FILES Retro68Runtime.h DESTINATION include)
|
||||
install(FILES Retro68.r Retro68APPL.r DESTINATION RIncludes)
|
||||
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES RetroPPC)
|
||||
enable_language(ASM)
|
||||
set(ARCH_FILES
|
||||
|
@ -23,6 +23,8 @@
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define _RETRO68_GET_DISPLACEMENT(DISPLACEMENT, STRIP) \
|
||||
do { \
|
||||
char *virtualstart, *realstart; \
|
||||
@ -63,5 +65,7 @@ void Retro68Relocate();
|
||||
void Retro68CallConstructors();
|
||||
void Retro68CallDestructors();
|
||||
void Retro68FreeGlobals();
|
||||
void Retro68InitMultisegApp();
|
||||
void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, uint32_t displacements[]);
|
||||
|
||||
#define RETRO68_RELOCATE() RETRO68_CALL_UNRELOCATED(Retro68Relocate,())
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <Memory.h>
|
||||
#include <OSUtils.h>
|
||||
#include <Traps.h>
|
||||
#include <Resources.h>
|
||||
|
||||
#include "Retro68Runtime.h"
|
||||
#include "PoorMansDebugging.h"
|
||||
@ -41,6 +42,10 @@ typedef void (*voidFunction)(void);
|
||||
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
|
||||
extern uint8_t _stext, _etext, _sdata, _edata, _sbss, _ebss;
|
||||
// constructor list:
|
||||
@ -101,6 +106,26 @@ static Retro68RelocState relocState __attribute__ ((section(".relocvars"))) = {
|
||||
} 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()
|
||||
{
|
||||
// memory address to retrieve the ROM type (64K or a later ROM)
|
||||
@ -128,7 +153,7 @@ void Retro68Relocate()
|
||||
|
||||
if (hasStripAddr)
|
||||
{
|
||||
RETRO68_GET_DISPLACEMENT_STRIP(displacement);
|
||||
RETRO68_GET_DISPLACEMENT_STRIP(displacement);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -172,38 +197,47 @@ void Retro68Relocate()
|
||||
log(orig_ebss);
|
||||
|
||||
uint8_t *base = orig_stext + displacement;
|
||||
|
||||
{
|
||||
uint8_t *orig_rsrc_start;
|
||||
GET_VIRTUAL_ADDRESS(orig_rsrc_start, _rsrc_start);
|
||||
uint8_t *rsrc_start = orig_rsrc_start + displacement;
|
||||
|
||||
Handle h = RecoverHandle((Ptr) rsrc_start);
|
||||
if(MemError() == noErr && h)
|
||||
{
|
||||
// Make sure the code is locked. Only relevant for some code resources.
|
||||
HLock(h);
|
||||
rState->codeHandle = h;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if(!rState->bssPtr)
|
||||
long data_displacement = 0;
|
||||
long jt_displacement = 0;
|
||||
|
||||
if(&_MULTISEG_APP)
|
||||
{
|
||||
THz zone = ApplicationZone();
|
||||
if(!zone || base < (uint8_t*)zone)
|
||||
rState->bssPtr = NewPtrSysClear(bss_size);
|
||||
else
|
||||
rState->bssPtr = NewPtrClear(bss_size);
|
||||
bss_displacement = (uint8_t*)rState->bssPtr - orig_sbss;
|
||||
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;
|
||||
GET_VIRTUAL_ADDRESS(orig_rsrc_start, _rsrc_start);
|
||||
uint8_t *rsrc_start = orig_rsrc_start + displacement;
|
||||
|
||||
Handle h = RecoverHandle((Ptr) rsrc_start);
|
||||
if(MemError() == noErr && h)
|
||||
{
|
||||
// Make sure the code is locked. Only relevant for some code resources.
|
||||
HLock(h);
|
||||
rState->codeHandle = h;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate BSS section (uninitialized/zero-initialized global data)
|
||||
if(!rState->bssPtr)
|
||||
{
|
||||
uint32_t bss_size = orig_ebss - orig_sbss;
|
||||
THz zone = ApplicationZone();
|
||||
if(!zone || base < (uint8_t*)zone)
|
||||
rState->bssPtr = NewPtrSysClear(bss_size);
|
||||
else
|
||||
rState->bssPtr = NewPtrClear(bss_size);
|
||||
bss_displacement = (uint8_t*)rState->bssPtr - orig_sbss;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Relocation records consist of 4 bytes each.
|
||||
@ -214,40 +248,33 @@ void Retro68Relocate()
|
||||
*/
|
||||
long displacements[4] = {
|
||||
displacement, // code
|
||||
displacement, // data (contiguous with code)
|
||||
bss_displacement, // bss (allocated separately)
|
||||
SetCurrentA5() // jump table (TODO)
|
||||
data_displacement,
|
||||
bss_displacement,
|
||||
jt_displacement
|
||||
};
|
||||
|
||||
// Process relocation records
|
||||
for(long *reloc = (long*)( base + text_and_data_size );
|
||||
*reloc != -1;
|
||||
++reloc)
|
||||
void *reloc;
|
||||
Handle RELA = NULL;
|
||||
uint32_t relocatableSize;
|
||||
if(&_MULTISEG_APP)
|
||||
{
|
||||
uint32_t r = *reloc;
|
||||
uint8_t *addrPtr = base + (r & 0xFFFFFF);
|
||||
uint8_t *addr;
|
||||
uint8_t kind = r >> 24;
|
||||
|
||||
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);
|
||||
RELA = Get1Resource('RELA', 1);
|
||||
assert(RELA);
|
||||
reloc = *RELA;
|
||||
uint32_t text_size = orig_etext - orig_stext;
|
||||
relocatableSize = text_size;
|
||||
}
|
||||
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.
|
||||
// Now check whether we're on 68040 or later and need to flush the cache.
|
||||
@ -265,15 +292,22 @@ void Retro68Relocate()
|
||||
FlushCodeCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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()
|
||||
{
|
||||
static struct object object;
|
||||
/*static struct object object;
|
||||
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 *e = &__init_section_end;
|
||||
@ -308,8 +342,8 @@ void Retro68CallDestructors()
|
||||
p += 6;
|
||||
}
|
||||
}
|
||||
if (__deregister_frame_info)
|
||||
__deregister_frame_info(&__EH_FRAME_BEGIN__);
|
||||
/* if (__deregister_frame_info)
|
||||
__deregister_frame_info(&__EH_FRAME_BEGIN__);*/
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user