mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-26 06:49:33 +00:00
explicitly store target section in relocations
This commit is contained in:
parent
33a2744643
commit
ce59176be5
@ -64,42 +64,73 @@ shared_ptr<Section> dataSection;
|
|||||||
|
|
||||||
enum class SectionKind
|
enum class SectionKind
|
||||||
{
|
{
|
||||||
code,
|
undefined = -1,
|
||||||
|
code = 0,
|
||||||
data,
|
data,
|
||||||
bss
|
bss,
|
||||||
|
jumptable
|
||||||
};
|
};
|
||||||
|
|
||||||
class Symbol : public GElf_Sym
|
class Symbol : public GElf_Sym
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool valid;
|
bool valid;
|
||||||
|
bool referencedExternally;
|
||||||
|
SectionKind sectionKind;
|
||||||
|
|
||||||
Symbol();
|
Symbol();
|
||||||
Symbol(GElf_Sym sym);
|
Symbol(GElf_Sym sym);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Symtab
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Elf_Scn *elfsec;
|
||||||
|
Elf_Data *data;
|
||||||
|
vector<Symbol> symbols;
|
||||||
|
|
||||||
|
Symtab(Elf_Scn *elfsec);
|
||||||
|
|
||||||
|
Symbol& GetSym(int idx);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Section
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
string name;
|
||||||
|
int idx;
|
||||||
|
SectionKind kind;
|
||||||
|
Elf_Scn *elfsec, *relasec;
|
||||||
|
Elf_Data *data;
|
||||||
|
|
||||||
|
std::vector<GElf_Rela> relocs;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
void ScanRelocs();
|
||||||
|
};
|
||||||
|
|
||||||
Symbol::Symbol()
|
Symbol::Symbol()
|
||||||
: valid(false)
|
: valid(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol::Symbol(GElf_Sym sym)
|
Symbol::Symbol(GElf_Sym sym)
|
||||||
: GElf_Sym(sym), valid(true)
|
: GElf_Sym(sym), valid(true),
|
||||||
|
referencedExternally(false),
|
||||||
|
sectionKind(SectionKind::undefined)
|
||||||
{
|
{
|
||||||
|
if(st_shndx != SHN_UNDEF)
|
||||||
|
{
|
||||||
|
sectionKind = sectionsByElfIndex[st_shndx]->kind;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Symtab
|
|
||||||
{
|
|
||||||
vector<Symbol> symbols;
|
|
||||||
public:
|
|
||||||
Elf_Scn *elfsec;
|
|
||||||
Elf_Data *data;
|
|
||||||
|
|
||||||
Symtab(Elf_Scn *elfsec);
|
|
||||||
|
|
||||||
Symbol& GetSym(int idx);
|
|
||||||
};
|
|
||||||
|
|
||||||
Symtab::Symtab(Elf_Scn *elfsec)
|
Symtab::Symtab(Elf_Scn *elfsec)
|
||||||
: elfsec(elfsec)
|
: elfsec(elfsec)
|
||||||
{
|
{
|
||||||
@ -126,25 +157,8 @@ Symbol &Symtab::GetSym(int idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Section::Section(string name, int idx, SectionKind kind, Elf_Scn *elfsec)
|
||||||
class Section
|
: name(name), idx(idx), kind(kind), elfsec(elfsec), relasec(NULL)
|
||||||
{
|
|
||||||
public:
|
|
||||||
string name;
|
|
||||||
SectionKind kind;
|
|
||||||
Elf_Scn *elfsec, *relasec;
|
|
||||||
Elf_Data *data;
|
|
||||||
|
|
||||||
Section(string name, SectionKind kind, Elf_Scn *elfsec);
|
|
||||||
void SetRela(Elf_Scn *scn);
|
|
||||||
|
|
||||||
uint32_t GetSize();
|
|
||||||
string GetData();
|
|
||||||
string GetAbsRelocations();
|
|
||||||
};
|
|
||||||
|
|
||||||
Section::Section(string name, SectionKind kind, Elf_Scn *elfsec)
|
|
||||||
: name(name), kind(kind), elfsec(elfsec), relasec(NULL)
|
|
||||||
{
|
{
|
||||||
data = elf_getdata(elfsec, NULL);
|
data = elf_getdata(elfsec, NULL);
|
||||||
}
|
}
|
||||||
@ -152,6 +166,20 @@ Section::Section(string name, SectionKind kind, Elf_Scn *elfsec)
|
|||||||
void Section::SetRela(Elf_Scn *scn)
|
void Section::SetRela(Elf_Scn *scn)
|
||||||
{
|
{
|
||||||
relasec = scn;
|
relasec = scn;
|
||||||
|
GElf_Shdr shdr;
|
||||||
|
gelf_getshdr(relasec, &shdr);
|
||||||
|
|
||||||
|
int nRela = shdr.sh_size / shdr.sh_entsize;
|
||||||
|
Elf_Data *data = elf_getdata(relasec, NULL);
|
||||||
|
for(int i = 0; i < nRela; i++)
|
||||||
|
{
|
||||||
|
GElf_Rela rela;
|
||||||
|
gelf_getrela(data, i, &rela);
|
||||||
|
relocs.push_back(rela);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(relocs.begin(), relocs.end(),
|
||||||
|
[](GElf_Rela& a, GElf_Rela& b) { return a.r_offset < b.r_offset; });
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Section::GetSize()
|
uint32_t Section::GetSize()
|
||||||
@ -164,45 +192,55 @@ 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()
|
string Section::GetAbsRelocations(bool suppressTerminatingEntry)
|
||||||
{
|
{
|
||||||
if(!relasec)
|
if(!relasec)
|
||||||
return "";
|
return "";
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
|
|
||||||
|
for(auto& rela : relocs)
|
||||||
std::vector<int> relocs;
|
|
||||||
|
|
||||||
GElf_Shdr shdr;
|
|
||||||
gelf_getshdr(relasec, &shdr);
|
|
||||||
|
|
||||||
int nRela = shdr.sh_size / shdr.sh_entsize;
|
|
||||||
Elf_Data *data = elf_getdata(relasec, NULL);
|
|
||||||
for(int i = 0; i < nRela; i++)
|
|
||||||
{
|
{
|
||||||
GElf_Rela rela;
|
|
||||||
gelf_getrela(data, i, &rela);
|
|
||||||
|
|
||||||
//printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset);
|
//printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset);
|
||||||
|
|
||||||
int symidx = GELF_R_SYM(rela.r_info);
|
int symidx = GELF_R_SYM(rela.r_info);
|
||||||
if(symidx == 0)
|
if(symidx == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
GElf_Sym sym = symtab->GetSym(symidx);
|
Symbol& sym = symtab->GetSym(symidx);
|
||||||
|
|
||||||
if(sym.st_shndx == SHN_UNDEF)
|
if(sym.st_shndx == SHN_UNDEF)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(GELF_R_TYPE(rela.r_info) == R_68K_32)
|
if(GELF_R_TYPE(rela.r_info) == R_68K_32)
|
||||||
relocs.push_back(rela.r_offset);
|
{
|
||||||
|
assert(sym.sectionKind != SectionKind::undefined);
|
||||||
|
|
||||||
|
longword(out, rela.r_offset | ((int)sym.sectionKind << 24));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::sort(relocs.begin(), relocs.end());
|
if(!suppressTerminatingEntry)
|
||||||
for(int reloc : relocs)
|
longword(out, -1);
|
||||||
longword(out, reloc);
|
|
||||||
return out.str();
|
return out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Section::ScanRelocs()
|
||||||
|
{
|
||||||
|
for(auto& rela : relocs)
|
||||||
|
{
|
||||||
|
int symidx = GELF_R_SYM(rela.r_info);
|
||||||
|
if(symidx == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Symbol& sym = symtab->GetSym(symidx);
|
||||||
|
|
||||||
|
if(sym.st_shndx == SHN_UNDEF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(sym.st_shndx != idx)
|
||||||
|
sym.referencedExternally = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GrokELF(string input)
|
void GrokELF(string input)
|
||||||
{
|
{
|
||||||
@ -219,13 +257,13 @@ void GrokELF(string input)
|
|||||||
|
|
||||||
Elf_Scn* bssSection = NULL;
|
Elf_Scn* bssSection = NULL;
|
||||||
|
|
||||||
int idx = 0;
|
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++)
|
||||||
{
|
{
|
||||||
GElf_Shdr shdr;
|
GElf_Shdr shdr;
|
||||||
gelf_getshdr(scn, &shdr);
|
gelf_getshdr(scn, &shdr);
|
||||||
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
|
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
|
||||||
//printf("section: %s\n", name.c_str());
|
//std::cout << "section #" << idx << ": " << name << std::endl;
|
||||||
|
|
||||||
if(shdr.sh_type == SHT_SYMTAB
|
if(shdr.sh_type == SHT_SYMTAB
|
||||||
&& !symtab)
|
&& !symtab)
|
||||||
@ -251,7 +289,7 @@ void GrokELF(string input)
|
|||||||
&& !bssSection) // ignore everything after bss, that's just debug info
|
&& !bssSection) // ignore everything after bss, that's just debug info
|
||||||
{
|
{
|
||||||
SectionKind kind = name == ".data" ? SectionKind::data : SectionKind::code;
|
SectionKind kind = name == ".data" ? SectionKind::data : SectionKind::code;
|
||||||
auto section = make_shared<Section>(name,kind, scn);
|
auto section = make_shared<Section>(name, idx, kind, scn);
|
||||||
|
|
||||||
sections[name] = sectionsByElfIndex[idx] = section;
|
sections[name] = sectionsByElfIndex[idx] = section;
|
||||||
if(kind == SectionKind::data)
|
if(kind == SectionKind::data)
|
||||||
@ -267,7 +305,7 @@ void GrokELF(string input)
|
|||||||
// (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] =
|
sections[name] = sectionsByElfIndex[idx] =
|
||||||
make_shared<Section>(name,SectionKind::bss, scn);
|
make_shared<Section>(name, idx, SectionKind::bss, scn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,9 +321,9 @@ void FlatCode(std::ostream& out)
|
|||||||
out << dataSection->GetData();
|
out << dataSection->GetData();
|
||||||
|
|
||||||
for(auto sec : codeSections)
|
for(auto sec : codeSections)
|
||||||
out << sec->GetAbsRelocations();
|
out << sec->GetAbsRelocations(true);
|
||||||
out << dataSection->GetAbsRelocations();
|
out << dataSection->GetAbsRelocations();
|
||||||
longword(out, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlatCode(string fn)
|
void FlatCode(string fn)
|
||||||
@ -356,6 +394,53 @@ void SingleSegmentApp(string output)
|
|||||||
file.write();
|
file.write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MultiSegmentApp(string output)
|
||||||
|
{
|
||||||
|
ResourceFile file(output);
|
||||||
|
Resources& rsrc = file.resources;
|
||||||
|
|
||||||
|
for(auto sec : codeSections)
|
||||||
|
{
|
||||||
|
sec->ScanRelocs();
|
||||||
|
}
|
||||||
|
|
||||||
|
rsrc.addResource(Resource(ResType("CODE"), 0,
|
||||||
|
fromhex(
|
||||||
|
"00000028 00000000 00000008 00000020"
|
||||||
|
"0000 3F3C 0001 A9F0"
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
int id = 1;
|
||||||
|
for(auto sec : codeSections)
|
||||||
|
{
|
||||||
|
std::ostringstream code;
|
||||||
|
word(code, 0); //FIXME: header
|
||||||
|
word(code, 1);
|
||||||
|
code << sec->GetData();
|
||||||
|
|
||||||
|
rsrc.addResource(Resource(ResType("CODE"), id,
|
||||||
|
code.str()));
|
||||||
|
|
||||||
|
|
||||||
|
rsrc.addResource(Resource(ResType("RELA"),id, sec->GetAbsRelocations()));
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData()));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
file.creator = ResType("????");
|
||||||
|
file.type = ResType("APPL");
|
||||||
|
|
||||||
|
file.write();
|
||||||
|
}
|
||||||
|
|
||||||
string argvZero;
|
string argvZero;
|
||||||
|
|
||||||
void RealLD(vector<string> args)
|
void RealLD(vector<string> args)
|
||||||
@ -412,6 +497,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;
|
||||||
|
|
||||||
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)
|
||||||
@ -458,10 +544,12 @@ int main(int argc, char *argv[])
|
|||||||
int fd = mkstemp(tmpfile);
|
int fd = mkstemp(tmpfile);
|
||||||
if(fd < 0)
|
if(fd < 0)
|
||||||
errx(EXIT_FAILURE, "can't create temp file");
|
errx(EXIT_FAILURE, "can't create temp file");
|
||||||
|
|
||||||
{
|
{
|
||||||
ofstream out(tmpfile);
|
ofstream out(tmpfile);
|
||||||
CreateLdScript(out);
|
CreateLdScript(out, segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
args2.push_back("-o");
|
args2.push_back("-o");
|
||||||
args2.push_back(outputFile + ".gdb");
|
args2.push_back(outputFile + ".gdb");
|
||||||
args2.push_back("-T");
|
args2.push_back("-T");
|
||||||
@ -471,6 +559,8 @@ int main(int argc, char *argv[])
|
|||||||
GrokELF(outputFile + ".gdb");
|
GrokELF(outputFile + ".gdb");
|
||||||
if(flatoutput)
|
if(flatoutput)
|
||||||
FlatCode(outputFile);
|
FlatCode(outputFile);
|
||||||
|
else if(segments)
|
||||||
|
MultiSegmentApp(outputFile);
|
||||||
else
|
else
|
||||||
SingleSegmentApp(outputFile);
|
SingleSegmentApp(outputFile);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,6 @@
|
|||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
|
||||||
void CreateLdScript(std::ostream& out);
|
void CreateLdScript(std::ostream& out, bool segments);
|
||||||
|
|
||||||
#endif // ELF2MAC_H
|
#endif // ELF2MAC_H
|
||||||
|
@ -232,17 +232,18 @@ const char * scriptEnd = R"ld(
|
|||||||
)ld";
|
)ld";
|
||||||
|
|
||||||
|
|
||||||
void CreateLdScript(std::ostream& out)
|
void CreateLdScript(std::ostream& out, bool segments)
|
||||||
{
|
{
|
||||||
#if 1
|
if(segments)
|
||||||
out << scriptStart << textSection << scriptEnd;
|
{
|
||||||
#else
|
out << scriptStart << code1Section;
|
||||||
out << scriptStart << code1Section;
|
string code = codeSectionTemplate;
|
||||||
string code = codeSectionTemplate;
|
boost::replace_all(code, "@N@", "2");
|
||||||
boost::replace_all(code, "@N@", "2");
|
boost::replace_all(code, "@FILTER@", "*");
|
||||||
boost::replace_all(code, "@FILTER@", "*");
|
boost::replace_all(code, "@EXTRA@", lastCodeExtra);
|
||||||
boost::replace_all(code, "@EXTRA@", lastCodeExtra);
|
out << code;
|
||||||
out << code;
|
out << scriptEnd;
|
||||||
out << scriptEnd;
|
}
|
||||||
#endif
|
else
|
||||||
|
out << scriptStart << textSection << scriptEnd;
|
||||||
}
|
}
|
||||||
|
@ -204,14 +204,30 @@ 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.
|
||||||
|
The lower three bytes are the offset of the longword being relocated.
|
||||||
|
the first byte of each longword specifies which segment
|
||||||
|
the relocation leads to; the corresponding displacements are taken
|
||||||
|
from the following table:
|
||||||
|
*/
|
||||||
|
long displacements[4] = {
|
||||||
|
displacement, // code
|
||||||
|
displacement, // data (contiguous with code)
|
||||||
|
bss_displacement, // bss (allocated separately)
|
||||||
|
SetCurrentA5() // jump table (TODO)
|
||||||
|
};
|
||||||
|
|
||||||
// Process relocation records
|
// Process relocation records
|
||||||
for(long *reloc = (long*)( base + text_and_data_size );
|
for(long *reloc = (long*)( base + text_and_data_size );
|
||||||
*reloc != -1;
|
*reloc != -1;
|
||||||
++reloc)
|
++reloc)
|
||||||
{
|
{
|
||||||
uint8_t *addrPtr = base + *reloc;
|
uint32_t r = *reloc;
|
||||||
|
uint8_t *addrPtr = base + (r & 0xFFFFFF);
|
||||||
uint8_t *addr;
|
uint8_t *addr;
|
||||||
|
uint8_t kind = r >> 24;
|
||||||
|
|
||||||
assert(addrPtr >= base);
|
assert(addrPtr >= base);
|
||||||
assert(addrPtr < base + text_and_data_size);
|
assert(addrPtr < base + text_and_data_size);
|
||||||
@ -225,8 +241,7 @@ void Retro68Relocate()
|
|||||||
/*assert((uint8_t*)addr >= orig_stext); // TODO: not right for repeated reloc
|
/*assert((uint8_t*)addr >= orig_stext); // TODO: not right for repeated reloc
|
||||||
assert((uint8_t*)addr <= orig_stext + total_size);*/
|
assert((uint8_t*)addr <= orig_stext + total_size);*/
|
||||||
|
|
||||||
addr += (addr - orig_stext) >= text_and_data_size ?
|
addr += displacements[kind];
|
||||||
bss_displacement : displacement;
|
|
||||||
|
|
||||||
/*assert((Ptr)addr >= (Ptr)base && (Ptr)addr <= (Ptr)base + text_and_data_size
|
/*assert((Ptr)addr >= (Ptr)base && (Ptr)addr <= (Ptr)base + text_and_data_size
|
||||||
|| (Ptr)addr >= rState->bssPtr && (Ptr)addr <= rState->bssPtr + bss_size);*/
|
|| (Ptr)addr >= rState->bssPtr && (Ptr)addr <= rState->bssPtr + bss_size);*/
|
||||||
|
Loading…
Reference in New Issue
Block a user