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 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, &sectionHeaderStringTableIdx);
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;
}

View File

@ -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;
}
}

View File

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

View File

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

View File

@ -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__);*/
}