From 32a2da9547fe55655e7eaec47d94f0e3079139c1 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Sat, 30 Sep 2017 23:03:17 +0200 Subject: [PATCH] New, more compact format for relocations --- Elf2Mac/Object.cc | 18 +++++++++++++----- Elf2Mac/Reloc.cc | 40 ++++++++++++++++++++++++++++++++++++++++ Elf2Mac/Reloc.h | 17 +++++++++++++++++ Elf2Mac/Section.cc | 12 ++++++------ Elf2Mac/Section.h | 3 ++- libretro/relocate.c | 34 +++++++++++++++++++++++++++++++++- 6 files changed, 111 insertions(+), 13 deletions(-) diff --git a/Elf2Mac/Object.cc b/Elf2Mac/Object.cc index b812441fb5..ca96127b4d 100644 --- a/Elf2Mac/Object.cc +++ b/Elf2Mac/Object.cc @@ -22,6 +22,7 @@ #include "Symtab.h" #include "Section.h" #include "SegmentMap.h" +#include "Reloc.h" #include #include @@ -135,10 +136,17 @@ void Object::FlatCode(std::ostream& out) out << dataSection->GetData(); + std::vector relocs; for(auto sec : codeSections) - out << sec->GetAbsRelocations(false, true); - out << dataSection->GetAbsRelocations(false); - + { + auto tmp = sec->GetRelocations(false); + relocs.insert(relocs.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = dataSection->GetRelocations(false); + relocs.insert(relocs.end(), tmp.begin(), tmp.end()); + } + out << SerializeRelocs(relocs); } void Object::FlatCode(string fn) @@ -364,11 +372,11 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap) segmentName)); - rsrc.addResource(Resource(ResType("RELA"),id, sec->GetAbsRelocations(true))); + rsrc.addResource(Resource(ResType("RELA"),id, SerializeRelocs(sec->GetRelocations(true)))); } rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData())); - rsrc.addResource(Resource(ResType("RELA"),0, dataSection->GetAbsRelocations(true))); + rsrc.addResource(Resource(ResType("RELA"),0, SerializeRelocs(dataSection->GetRelocations(true)))); std::cout << "DATA 0: " << dataSection->shdr.sh_size << " bytes\n"; diff --git a/Elf2Mac/Reloc.cc b/Elf2Mac/Reloc.cc index e9735c1b62..4848b01ac7 100644 --- a/Elf2Mac/Reloc.cc +++ b/Elf2Mac/Reloc.cc @@ -18,6 +18,8 @@ */ #include "Reloc.h" +#include +#include "BinaryIO.h" Reloc::Reloc() { @@ -27,3 +29,41 @@ Reloc::Reloc(const GElf_Rela &rela) : GElf_Rela(rela), relocBase(RelocBase::code) { } + +std::string SerializeRelocsUncompressed(std::vector relocs) +{ + std::ostringstream out; + for(const auto& r : relocs) + { + longword(out, r.offset | ((int)r.base << 24)); + } + longword(out, -1); + return out.str(); +} + +std::string SerializeRelocs(std::vector relocs) +{ + std::ostringstream out; + uint32_t offset = -1; + + for(const auto& r : relocs) + { + uint32_t delta = r.offset - offset; + offset = r.offset; + + 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(); +} diff --git a/Elf2Mac/Reloc.h b/Elf2Mac/Reloc.h index 40ff45fa89..d3fd4ad9cc 100644 --- a/Elf2Mac/Reloc.h +++ b/Elf2Mac/Reloc.h @@ -21,6 +21,10 @@ #define RELOC_H #include +#include + +#include +#include enum class RelocBase { @@ -40,4 +44,17 @@ public: Reloc(const GElf_Rela& rela); }; +class RuntimeReloc +{ +public: + RelocBase base; + uint32_t offset; + + RuntimeReloc() : base(RelocBase::code), offset(0) {} + RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {} +}; + +std::string SerializeRelocsUncompressed(std::vector relocs); +std::string SerializeRelocs(std::vector relocs); + #endif // RELOC_H diff --git a/Elf2Mac/Section.cc b/Elf2Mac/Section.cc index 0298c73d4f..fd14ccaf5d 100644 --- a/Elf2Mac/Section.cc +++ b/Elf2Mac/Section.cc @@ -85,9 +85,9 @@ string Section::GetData() return string((char*)data->d_buf, (char*)data->d_buf + data->d_size); } -string Section::GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry) +std::vector Section::GetRelocations(bool useOffsets) { - std::ostringstream out; + std::vector outRelocs; for(auto& rela : relocs) { @@ -112,12 +112,12 @@ string Section::GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry if(useOffsets) offset -= shdr.sh_addr; - longword(out, offset | ((int)rela.relocBase << 24)); + //longword(out, offset | ((int)rela.relocBase << 24)); + outRelocs.emplace_back(rela.relocBase, offset); } } - if(!suppressTerminatingEntry) - longword(out, -1); - return out.str(); + + return outRelocs; } void Section::ScanRelocs() diff --git a/Elf2Mac/Section.h b/Elf2Mac/Section.h index 096f5f5574..e85930a861 100644 --- a/Elf2Mac/Section.h +++ b/Elf2Mac/Section.h @@ -29,6 +29,7 @@ class Object; class Reloc; class Symbol; +class RuntimeReloc; enum class SectionKind { @@ -63,7 +64,7 @@ public: uint32_t GetSize(); std::string GetData(); - std::string GetAbsRelocations(bool useOffsets, bool suppressTerminatingEntry = false); + std::vector GetRelocations(bool useOffsets); void ScanRelocs(); void FixRelocs(); diff --git a/libretro/relocate.c b/libretro/relocate.c index e147c9b666..ba644d4d9e 100644 --- a/libretro/relocate.c +++ b/libretro/relocate.c @@ -87,7 +87,7 @@ Retro68RelocState relocState __attribute__ ((section(".relocvars"))) = { _ptr[0] = (_a >>= 8); \ } while(0) - +#if 0 void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, uint32_t displacements[]) { uint32_t *reloc = (uint32_t*) relocations; @@ -107,6 +107,38 @@ void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, ui WRITE_UNALIGNED_LONGWORD(addrPtr, (uint32_t) addr); } } +#else +void Retro68ApplyRelocations(uint8_t *base, uint32_t size, void *relocations, uint32_t displacements[]) +{ + uint8_t *reloc = (uint8_t*) relocations; + uint8_t *addrPtr = base - 1; + while(*reloc) + { + // read an uleb128 value + uint32_t val = 0; + uint8_t b; + 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 + // the offset is relative to the previous relocation, or to base-1 + addrPtr += val >> 2; + uint8_t kind = val & 0x3; + + assert(addrPtr >= base); + assert(addrPtr < base + size); + + uint8_t *addr = (uint8_t*) READ_UNALIGNED_LONGWORD(addrPtr); + addr += displacements[kind]; + WRITE_UNALIGNED_LONGWORD(addrPtr, (uint32_t) addr); + } +} +#endif void Retro68Relocate() {