add support for R_68K_PC32 relocations

This commit is contained in:
Wolfgang Thaller 2020-12-28 00:25:36 +01:00
parent 522a96e6ff
commit 4c7b83bb75
4 changed files with 68 additions and 47 deletions

View File

@ -44,26 +44,33 @@ std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs)
std::string SerializeRelocs(std::vector<RuntimeReloc> relocs) std::string SerializeRelocs(std::vector<RuntimeReloc> relocs)
{ {
std::ostringstream out; std::ostringstream out;
uint32_t offset = -1;
for(const auto& r : relocs) for(int relative = 0; relative <= 1; relative++)
{ {
uint32_t delta = r.offset - offset; uint32_t offset = -1;
offset = r.offset;
uint32_t base = (uint32_t) r.base; for(const auto& r : relocs)
uint32_t encoded = (delta << 2) | base;
while(encoded >= 128)
{ {
byte(out, (encoded & 0x7F) | 0x80); if(r.relative == (bool)relative)
encoded >>= 7; {
} uint32_t delta = r.offset - offset;
byte(out, encoded); offset = r.offset;
}
byte(out, 0); uint32_t base = (uint32_t) r.base;
uint32_t encoded = (delta << 2) | base;
while(encoded >= 128)
{
byte(out, (encoded & 0x7F) | 0x80);
encoded >>= 7;
}
byte(out, encoded);
}
}
byte(out, 0);
}
return out.str(); return out.str();
} }

View File

@ -47,11 +47,11 @@ public:
class RuntimeReloc class RuntimeReloc
{ {
public: public:
RelocBase base; RelocBase base = RelocBase::code;
uint32_t offset; uint32_t offset = 0;
bool relative = false;
RuntimeReloc() : base(RelocBase::code), offset(0) {} RuntimeReloc(RelocBase b = RelocBase::code, uint32_t o = 0, bool r = false) : base(b), offset(o), relative(r) {}
RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {}
}; };
std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs); std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs);

View File

@ -104,17 +104,20 @@ std::vector<RuntimeReloc> Section::GetRelocations(bool useOffsets)
if(sym.sectionKind == SectionKind::undefined) if(sym.sectionKind == SectionKind::undefined)
continue; continue;
uint32_t offset = rela.r_offset;
if(useOffsets)
offset -= shdr.sh_addr;
if(GELF_R_TYPE(rela.r_info) == R_68K_32) if(GELF_R_TYPE(rela.r_info) == R_68K_32)
{ {
assert(sym.sectionKind != SectionKind::undefined);
uint32_t offset = rela.r_offset;
if(useOffsets)
offset -= shdr.sh_addr;
//longword(out, offset | ((int)rela.relocBase << 24));
outRelocs.emplace_back(rela.relocBase, offset); outRelocs.emplace_back(rela.relocBase, offset);
} }
if(GELF_R_TYPE(rela.r_info) == R_68K_PC32
&& sym.st_shndx != idx)
{
outRelocs.emplace_back(rela.relocBase, offset, true);
}
} }
return outRelocs; return outRelocs;
@ -154,7 +157,7 @@ void Section::FixRelocs(bool allowDirectCodeRefs)
{ {
for(Reloc& rela : relocs) for(Reloc& rela : relocs)
{ {
if(GELF_R_TYPE(rela.r_info) != R_68K_32) if(GELF_R_TYPE(rela.r_info) != R_68K_32 && GELF_R_TYPE(rela.r_info) != R_68K_PC32)
continue; continue;
int symidx = GELF_R_SYM(rela.r_info); int symidx = GELF_R_SYM(rela.r_info);
@ -165,6 +168,9 @@ void Section::FixRelocs(bool allowDirectCodeRefs)
if(sym.sectionKind == SectionKind::undefined) if(sym.sectionKind == SectionKind::undefined)
continue; continue;
if(GELF_R_TYPE(rela.r_info) == R_68K_PC32 && sym.st_shndx == idx)
continue;
RelocBase relocBase; RelocBase relocBase;
switch(sym.sectionKind) switch(sym.sectionKind)
{ {

View File

@ -111,31 +111,39 @@ void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, ui
void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, uint32_t displacements[]) void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, uint32_t displacements[])
{ {
uint8_t *reloc = (uint8_t*) relocations; uint8_t *reloc = (uint8_t*) relocations;
uint8_t *addrPtr = base - 1; for(int relative = 0; relative <= 1; relative++)
while(*reloc)
{ {
// read an uleb128 value uint8_t *addrPtr = base - 1;
uint32_t val = 0; while(*reloc)
uint8_t b;
int i = 0;
do
{ {
b = *reloc++; // read an uleb128 value
val |= (b & 0x7F) << i; uint32_t val = 0;
i += 7; uint8_t b;
} while(b & 0x80); int i = 0;
do
{
b = *reloc++;
val |= (b & 0x7F) << i;
i += 7;
} while(b & 0x80);
// ... which consists of an offset and the displacement base index // ... which consists of an offset and the displacement base index
// the offset is relative to the previous relocation, or to base-1 // the offset is relative to the previous relocation, or to base-1
addrPtr += val >> 2; addrPtr += val >> 2;
uint8_t kind = val & 0x3; uint8_t kind = val & 0x3;
assert(addrPtr >= base); assert(addrPtr >= base);
assert(addrPtr <= base + size - 4); assert(addrPtr <= base + size - 4);
uint8_t *addr = (uint8_t*) READ_UNALIGNED_LONGWORD(addrPtr); uint8_t *addr = (uint8_t*) READ_UNALIGNED_LONGWORD(addrPtr);
addr += displacements[kind]; addr += displacements[kind];
WRITE_UNALIGNED_LONGWORD(addrPtr, (uint32_t) addr); if(relative)
addr -= (uint32_t) addrPtr;
WRITE_UNALIGNED_LONGWORD(addrPtr, (uint32_t) addr);
}
reloc++;
} }
} }
#endif #endif