mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-22 08:34:35 +00:00
MultiSeg Apps: First working version (exceptions don't work)
This commit is contained in:
parent
a4716081c2
commit
d08331584e
@ -32,6 +32,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@ -42,11 +43,14 @@
|
||||
|
||||
using std::string;
|
||||
using std::unordered_map;
|
||||
using std::map;
|
||||
using std::vector;
|
||||
using std::ofstream;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
using std::unique_ptr;
|
||||
using std::pair;
|
||||
using std::make_pair;
|
||||
|
||||
size_t sectionHeaderStringTableIdx;
|
||||
size_t mainStringTableIdx = (size_t)-1;
|
||||
@ -102,10 +106,12 @@ public:
|
||||
Elf_Scn *elfsec;
|
||||
Elf_Data *data;
|
||||
vector<Symbol> symbols;
|
||||
map<pair<int,uint32_t>, int> symbolsByAddress;
|
||||
|
||||
Symtab(Elf_Scn *elfsec);
|
||||
|
||||
Symbol& GetSym(int idx);
|
||||
int FindSym(int secidx, uint32_t addr);
|
||||
};
|
||||
|
||||
class Reloc : public GElf_Rela
|
||||
@ -143,6 +149,7 @@ public:
|
||||
|
||||
void ScanRelocs();
|
||||
void FixRelocs();
|
||||
|
||||
};
|
||||
|
||||
Symbol::Symbol()
|
||||
@ -177,21 +184,32 @@ Symtab::Symtab(Elf_Scn *elfsec)
|
||||
gelf_getshdr(elfsec, &shdr);
|
||||
|
||||
int count = shdr.sh_size / shdr.sh_entsize;
|
||||
symbols.resize(count);
|
||||
symbols.reserve(count);
|
||||
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
GElf_Sym sym;
|
||||
auto res = gelf_getsym(data, i, &sym);
|
||||
assert(res != 0);
|
||||
symbols.emplace_back(sym);
|
||||
|
||||
if(sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
|
||||
symbolsByAddress[make_pair((int)sym.st_shndx,sym.st_value)] = i;
|
||||
}
|
||||
}
|
||||
|
||||
Symbol &Symtab::GetSym(int idx)
|
||||
{
|
||||
if(symbols[idx].valid)
|
||||
return symbols[idx];
|
||||
else
|
||||
{
|
||||
GElf_Sym sym;
|
||||
auto res = gelf_getsym(data, idx, &sym);
|
||||
assert(res != 0);
|
||||
return symbols[idx];
|
||||
}
|
||||
|
||||
return (symbols[idx] = Symbol(sym));
|
||||
}
|
||||
int Symtab::FindSym(int secidx, uint32_t addr)
|
||||
{
|
||||
auto p = symbolsByAddress.find(make_pair(secidx, addr));
|
||||
if(p != symbolsByAddress.end())
|
||||
return p->second;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@ -213,6 +231,7 @@ Section::Section(string name, int idx, SectionKind kind, Elf_Scn *elfsec)
|
||||
outputBase = shdr.sh_addr;
|
||||
}
|
||||
|
||||
|
||||
void Section::SetRela(Elf_Scn *scn)
|
||||
{
|
||||
relasec = scn;
|
||||
@ -269,7 +288,7 @@ string Section::GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry
|
||||
if(useOffsets)
|
||||
offset -= shdr.sh_addr;
|
||||
|
||||
|
||||
std::cout << "RELA: " << std::hex << offset << " " << (int)rela.relocBase << std::dec << std::endl;
|
||||
longword(out, offset | ((int)rela.relocBase << 24));
|
||||
}
|
||||
}
|
||||
@ -280,19 +299,31 @@ string Section::GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry
|
||||
|
||||
void Section::ScanRelocs()
|
||||
{
|
||||
for(auto& rela : relocs)
|
||||
for(Reloc& rela : relocs)
|
||||
{
|
||||
int symidx = GELF_R_SYM(rela.r_info);
|
||||
if(symidx == 0)
|
||||
continue;
|
||||
|
||||
Symbol& sym = symtab->GetSym(symidx);
|
||||
Symbol *sym = &symtab->GetSym(symidx);
|
||||
|
||||
if(sym.st_shndx == SHN_UNDEF)
|
||||
if(sym->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
|
||||
if(sym.st_shndx != idx)
|
||||
sym.referencedExternally = true;
|
||||
if(rela.r_addend != 0)
|
||||
{
|
||||
int symidx2 = symtab->FindSym(sym->st_shndx, sym->st_value + rela.r_addend);
|
||||
if(symidx2 != -1)
|
||||
{
|
||||
sym = &symtab->GetSym(symidx2);
|
||||
rela.r_addend = 0;
|
||||
rela.r_info = GELF_R_INFO(symidx2, GELF_R_TYPE(rela.r_info));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(sym->st_shndx != idx)
|
||||
sym->referencedExternally = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,6 +367,8 @@ void Section::FixRelocs()
|
||||
assert(sym.section.get() == this);
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(sym.section.get() == this);
|
||||
break;
|
||||
case SectionKind::data:
|
||||
relocBase = RelocBase::data;
|
||||
@ -636,7 +669,7 @@ void MultiSegmentApp(string output)
|
||||
word(code, 0);
|
||||
longword(code, 0);
|
||||
longword(code, 0);
|
||||
longword(code, 0x20 + 8 * sec->firstJTEntryIndex );
|
||||
longword(code, 8 * sec->firstJTEntryIndex );
|
||||
longword(code, sec->jtEntries.size());
|
||||
longword(code, 0); // reloc info for A5
|
||||
longword(code, 0); // assumed address for A5
|
||||
@ -773,6 +806,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
ofstream out(tmpfile);
|
||||
CreateLdScript(out, segments);
|
||||
CreateLdScript(std::cout, segments);
|
||||
}
|
||||
|
||||
args2.push_back("-o");
|
||||
|
@ -90,7 +90,6 @@ const char * code1Section = R"ld(/* ld script for Elf2Mac */
|
||||
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) */
|
||||
@ -101,9 +100,11 @@ const char * code1Section = R"ld(/* ld script for Elf2Mac */
|
||||
*(.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*)
|
||||
*/libc.a:*(.text*)
|
||||
|
||||
. = ALIGN (4) ;
|
||||
__init_section = . ;
|
||||
@ -114,7 +115,16 @@ const char * code1Section = R"ld(/* ld script for Elf2Mac */
|
||||
__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 = . ;
|
||||
@ -129,21 +139,21 @@ const char * codeSectionTemplate = R"ld(/* ld script for Elf2Mac */
|
||||
|
||||
. = ALIGN (4) ;
|
||||
|
||||
/* KEEP(@FILTER@(.eh_frame))
|
||||
__EH_FRAME_BEGIN__@N@ = .;
|
||||
KEEP(@FILTER@(.eh_frame))
|
||||
LONG(0);
|
||||
KEEP(@FILTER@(.gcc_except_table))
|
||||
KEEP(@FILTER@(.gcc_except_table.*)) */
|
||||
KEEP(@FILTER@(.gcc_except_table.*))
|
||||
|
||||
. = ALIGN(0x4) ;
|
||||
. = ALIGN(0x4);
|
||||
LONG(0xDEADBEEF);
|
||||
. += 32;
|
||||
LONG(__EH_FRAME_BEGIN__@N@ - .);
|
||||
}
|
||||
)ld";
|
||||
|
||||
const char * lastCodeExtra = R"ld(
|
||||
*(.stub)
|
||||
*(.gnu.linkonce.t*)
|
||||
*(.glue_7t)
|
||||
*(.glue_7)
|
||||
*(.jcr)
|
||||
)ld";
|
||||
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <exception>
|
||||
|
||||
#include <Events.h>
|
||||
|
||||
@ -30,8 +32,26 @@ void foobar()
|
||||
throw Foo();
|
||||
}
|
||||
|
||||
void UnexpectedExceptionOccurred()
|
||||
{
|
||||
printf("std::unexpected called.\n");
|
||||
printf("Press Enter...\n");
|
||||
getchar();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void UncaughtExceptionOccurred()
|
||||
{
|
||||
printf("std::terminate called.\n");
|
||||
printf("Press Enter...\n");
|
||||
getchar();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::set_unexpected(&UnexpectedExceptionOccurred);
|
||||
std::set_terminate(&UncaughtExceptionOccurred);
|
||||
bool throwFail = false;
|
||||
bool catchFail = true;
|
||||
for(int i = 0; i < 5; i++)
|
||||
@ -53,16 +73,7 @@ int main(int argc, char** argv)
|
||||
if(catchFail)
|
||||
printf("******** FAILURE: catch block never entered\n");
|
||||
|
||||
const int n = 3;
|
||||
printf("Click mouse %d times...\n", n);
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
while(!Button())
|
||||
;
|
||||
while(Button())
|
||||
;
|
||||
printf("Click #%d\n", i+1);
|
||||
}
|
||||
FlushEvents(everyEvent, 0);
|
||||
printf("Press Enter...\n");
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
|
25
libretro/LoadSeg.s
Normal file
25
libretro/LoadSeg.s
Normal file
@ -0,0 +1,25 @@
|
||||
.text
|
||||
.globl PATCHEDLOADSEG
|
||||
|
||||
PATCHEDLOADSEG:
|
||||
|
||||
# Stack on Entry:
|
||||
# (arguments for function)
|
||||
# (return address)
|
||||
# (return address from trap (== address in jt entry))
|
||||
movel %sp@, %sp@-
|
||||
|
||||
# Stack now:
|
||||
# (arguments for function)
|
||||
# (return address)
|
||||
# (don't care)
|
||||
# (return address from trap (== address in jt entry))
|
||||
|
||||
jsr RETRO68LOADSEGMENT
|
||||
|
||||
# Stack now:
|
||||
# (arguments for function)
|
||||
# (return address)
|
||||
# (address of loaded function)
|
||||
|
||||
rts
|
193
libretro/MultiSegApp.c
Normal file
193
libretro/MultiSegApp.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include <OSUtils.h>
|
||||
#include <Traps.h>
|
||||
#include <Resources.h>
|
||||
#include <Memory.h>
|
||||
#include <stdint.h>
|
||||
#include "PoorMansDebugging.h"
|
||||
|
||||
#include "Retro68Runtime.h"
|
||||
|
||||
static pascal void (*OriginalLoadSeg)(short id);
|
||||
static pascal void (*OriginalUnloadSeg)(void *ptr);
|
||||
static pascal void (*OriginalExitToShell)();
|
||||
|
||||
extern pascal void PatchedLoadSeg();
|
||||
|
||||
typedef union JTEntry
|
||||
{
|
||||
struct {
|
||||
uint16_t offset;
|
||||
uint16_t push;
|
||||
int16_t id;
|
||||
uint16_t loadseg;
|
||||
} near;
|
||||
struct {
|
||||
int16_t id;
|
||||
uint16_t loadseg;
|
||||
uint32_t offset;
|
||||
} far;
|
||||
struct {
|
||||
int16_t id;
|
||||
uint16_t jmp;
|
||||
void* addr;
|
||||
} jmp;
|
||||
|
||||
} JTEntry;
|
||||
|
||||
typedef struct CODEHeader
|
||||
{
|
||||
int16_t magic0;
|
||||
int16_t magic1;
|
||||
uint32_t nearEntryOffset;
|
||||
uint32_t nNearEntries;
|
||||
uint32_t farEntryOffset;
|
||||
uint32_t nFarEntries;
|
||||
uint32_t a5relocOffset;
|
||||
uint8_t *currentA5;
|
||||
uint32_t relocOffset;
|
||||
uint8_t *loadAddress;
|
||||
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));
|
||||
|
||||
|
||||
pascal void* Retro68LoadSegment(uint8_t *p)
|
||||
{
|
||||
union JTEntry *jtEntry = (JTEntry*) (p - 4);
|
||||
|
||||
short id = jtEntry->far.id;
|
||||
uint32_t offset = jtEntry->far.offset;
|
||||
|
||||
// TODO: UseResFile?
|
||||
Handle CODE = GetResource('CODE', id);
|
||||
HLock(CODE);
|
||||
|
||||
uint8_t *base = StripAddress((uint8_t *)*CODE);
|
||||
CODEHeader *header = (CODEHeader*) base;
|
||||
uint32_t codeSize = GetHandleSize(CODE);
|
||||
|
||||
// TODO: StripAddress24
|
||||
uint8_t * a5 = (uint8_t*) StripAddress((void*)SetCurrentA5());
|
||||
|
||||
if(header->loadAddress != base || header->currentA5 != a5)
|
||||
{
|
||||
long displacements[4] = {
|
||||
base - header->loadAddress, // code
|
||||
a5 - header->currentA5,
|
||||
a5 - header->currentA5,
|
||||
a5 - header->currentA5
|
||||
};
|
||||
|
||||
header->loadAddress = base;
|
||||
header->currentA5 = a5;
|
||||
|
||||
Handle RELA = NULL;
|
||||
RELA = GetResource('RELA', id);
|
||||
assert(RELA);
|
||||
Retro68ApplyRelocations(base + 40, codeSize, *RELA, displacements);
|
||||
}
|
||||
else
|
||||
DebugStr("\prelocation unnecessary???");
|
||||
|
||||
|
||||
/* Update JT Entries */
|
||||
// FIXME: hardcoded JT offset, there is a LM global for this somewhere:
|
||||
jtEntry = (JTEntry*) (a5 + 32 + header->farEntryOffset);
|
||||
int n = header->nFarEntries;
|
||||
while(n--)
|
||||
{
|
||||
void * addr = base + jtEntry->far.offset;
|
||||
//jtEntry->jmp.id = jtEntry->far.id;
|
||||
jtEntry->jmp.jmp = 0x4EF9;
|
||||
jtEntry->jmp.addr = addr;
|
||||
++jtEntry;
|
||||
}
|
||||
|
||||
// TODO: Flush cache
|
||||
|
||||
/* Load Exception Information */
|
||||
if (__register_frame_info)
|
||||
{
|
||||
int32_t offset = ((int32_t*) (base + codeSize))[-1];
|
||||
void *eh_frame_info = *(void**) (base + codeSize + offset);
|
||||
struct object *object = (struct object*) (base + codeSize - 36);
|
||||
__register_frame_info(eh_frame_info, object);
|
||||
}
|
||||
return base + offset;
|
||||
}
|
||||
|
||||
static pascal void PatchedUnloadSeg(void *ptr)
|
||||
{
|
||||
|
||||
}
|
||||
static pascal void PatchedExitToShell()
|
||||
{
|
||||
SetToolTrapAddress((UniversalProcPtr)OriginalLoadSeg, _LoadSeg);
|
||||
SetToolTrapAddress((UniversalProcPtr)OriginalUnloadSeg, _UnLoadSeg);
|
||||
SetToolTrapAddress((UniversalProcPtr)OriginalExitToShell, _ExitToShell);
|
||||
OriginalExitToShell();
|
||||
}
|
||||
|
||||
// section boundaries
|
||||
extern uint8_t _stext, _etext, _sdata, _edata, _sbss, _ebss;
|
||||
|
||||
void Retro68InitMultisegApp()
|
||||
{
|
||||
uint8_t * a5 = (uint8_t*) StripAddress((void*)SetCurrentA5());
|
||||
|
||||
// CODE Segment 1 is already loaded - we are in it.
|
||||
// Update the jump table addresses.
|
||||
JTEntry *jtEntry = (JTEntry*) (a5 + 32 + 16); // TODO: hardcoded offsets
|
||||
while(jtEntry->far.id == 1)
|
||||
{
|
||||
void * addr = &_stext - 4 + jtEntry->far.offset;
|
||||
//jtEntry->jmp.id = jtEntry->far.id;
|
||||
jtEntry->jmp.jmp = 0x4EF9;
|
||||
jtEntry->jmp.addr = addr;
|
||||
++jtEntry;
|
||||
}
|
||||
|
||||
// Zero-initialize bss
|
||||
for(uint32_t *p = (uint32_t*) &_sbss;
|
||||
p < (uint32_t*) &_ebss; ++p)
|
||||
*p = 0;
|
||||
|
||||
// Set up patched LoadSeg
|
||||
|
||||
// NOTE: OriginalLoadSeg is the first global variable we can use
|
||||
OriginalLoadSeg = (void(*)(short)) GetToolTrapAddress(_LoadSeg);
|
||||
OriginalUnloadSeg = (void(*)(void*)) GetToolTrapAddress(_UnLoadSeg);
|
||||
OriginalExitToShell = (void(*)()) GetToolTrapAddress(_ExitToShell);
|
||||
SetToolTrapAddress((UniversalProcPtr)&PatchedLoadSeg, _LoadSeg);
|
||||
SetToolTrapAddress((UniversalProcPtr)&PatchedUnloadSeg, _UnLoadSeg);
|
||||
SetToolTrapAddress((UniversalProcPtr)&PatchedExitToShell, _ExitToShell);
|
||||
|
||||
// Load and relocate statically initialized DATA
|
||||
Handle DATA = Get1Resource('DATA', 0);
|
||||
BlockMoveData(*DATA, &_sdata, &_edata - &_sdata);
|
||||
ReleaseResource(DATA);
|
||||
|
||||
long displacements[4] = {
|
||||
0,
|
||||
a5 - (uint8_t*)NULL,
|
||||
a5 - (uint8_t*)NULL,
|
||||
a5 - (uint8_t*)NULL
|
||||
};
|
||||
|
||||
Handle RELA = NULL;
|
||||
RELA = GetResource('RELA', 0);
|
||||
assert(RELA);
|
||||
Retro68ApplyRelocations(&_sdata, &_edata - &_sdata, *RELA, displacements);
|
||||
|
||||
}
|
@ -305,9 +305,9 @@ void Retro68Relocate()
|
||||
|
||||
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;
|
||||
@ -342,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__);
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,9 +23,7 @@
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Retro68Runtime.h"
|
||||
|
||||
int main(int argc, char* argv[]);
|
||||
|
Loading…
Reference in New Issue
Block a user