explicitly store target section in relocations

This commit is contained in:
Wolfgang Thaller 2017-09-24 21:25:58 +02:00
parent 33a2744643
commit ce59176be5
4 changed files with 183 additions and 77 deletions

View File

@ -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()); }
for(int reloc : relocs) if(!suppressTerminatingEntry)
longword(out, reloc); longword(out, -1);
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);
} }

View File

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

View File

@ -232,11 +232,10 @@ 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");
@ -244,5 +243,7 @@ void CreateLdScript(std::ostream& out)
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;
} }

View File

@ -205,13 +205,29 @@ void Retro68Relocate()
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);*/