From 4c7b83bb75a011ae73bce66aa007fb6a4b9da54a Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Mon, 28 Dec 2020 00:25:36 +0100 Subject: [PATCH] add support for R_68K_PC32 relocations --- Elf2Mac/Reloc.cc | 37 ++++++++++++++++++++-------------- Elf2Mac/Reloc.h | 8 ++++---- Elf2Mac/Section.cc | 22 +++++++++++++-------- libretro/relocate.c | 48 ++++++++++++++++++++++++++------------------- 4 files changed, 68 insertions(+), 47 deletions(-) diff --git a/Elf2Mac/Reloc.cc b/Elf2Mac/Reloc.cc index 2e30606ac8..8ec241fd05 100644 --- a/Elf2Mac/Reloc.cc +++ b/Elf2Mac/Reloc.cc @@ -44,26 +44,33 @@ std::string SerializeRelocsUncompressed(std::vector relocs) std::string SerializeRelocs(std::vector relocs) { 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; - offset = r.offset; + uint32_t offset = -1; - uint32_t base = (uint32_t) r.base; - - uint32_t encoded = (delta << 2) | base; - - while(encoded >= 128) + for(const auto& r : relocs) { - byte(out, (encoded & 0x7F) | 0x80); - encoded >>= 7; - } - byte(out, encoded); - } + if(r.relative == (bool)relative) + { + uint32_t delta = r.offset - offset; + 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(); } diff --git a/Elf2Mac/Reloc.h b/Elf2Mac/Reloc.h index 9448661655..16cd264456 100644 --- a/Elf2Mac/Reloc.h +++ b/Elf2Mac/Reloc.h @@ -47,11 +47,11 @@ public: class RuntimeReloc { public: - RelocBase base; - uint32_t offset; + RelocBase base = RelocBase::code; + uint32_t offset = 0; + bool relative = false; - RuntimeReloc() : base(RelocBase::code), offset(0) {} - RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {} + RuntimeReloc(RelocBase b = RelocBase::code, uint32_t o = 0, bool r = false) : base(b), offset(o), relative(r) {} }; std::string SerializeRelocsUncompressed(std::vector relocs); diff --git a/Elf2Mac/Section.cc b/Elf2Mac/Section.cc index c05cf2a915..7cca25598e 100644 --- a/Elf2Mac/Section.cc +++ b/Elf2Mac/Section.cc @@ -104,17 +104,20 @@ std::vector Section::GetRelocations(bool useOffsets) if(sym.sectionKind == SectionKind::undefined) continue; + uint32_t offset = rela.r_offset; + if(useOffsets) + offset -= shdr.sh_addr; + 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); } + + if(GELF_R_TYPE(rela.r_info) == R_68K_PC32 + && sym.st_shndx != idx) + { + outRelocs.emplace_back(rela.relocBase, offset, true); + } } return outRelocs; @@ -154,7 +157,7 @@ void Section::FixRelocs(bool allowDirectCodeRefs) { 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; int symidx = GELF_R_SYM(rela.r_info); @@ -165,6 +168,9 @@ void Section::FixRelocs(bool allowDirectCodeRefs) if(sym.sectionKind == SectionKind::undefined) continue; + if(GELF_R_TYPE(rela.r_info) == R_68K_PC32 && sym.st_shndx == idx) + continue; + RelocBase relocBase; switch(sym.sectionKind) { diff --git a/libretro/relocate.c b/libretro/relocate.c index 6ec38c9e5e..5040fab205 100644 --- a/libretro/relocate.c +++ b/libretro/relocate.c @@ -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[]) { uint8_t *reloc = (uint8_t*) relocations; - uint8_t *addrPtr = base - 1; - while(*reloc) + for(int relative = 0; relative <= 1; relative++) { - // read an uleb128 value - uint32_t val = 0; - uint8_t b; - int i = 0; - do + uint8_t *addrPtr = base - 1; + while(*reloc) { - b = *reloc++; - val |= (b & 0x7F) << i; - i += 7; - } while(b & 0x80); + // 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; + // ... 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 - 4); + assert(addrPtr >= base); + assert(addrPtr <= base + size - 4); - uint8_t *addr = (uint8_t*) READ_UNALIGNED_LONGWORD(addrPtr); - addr += displacements[kind]; - WRITE_UNALIGNED_LONGWORD(addrPtr, (uint32_t) addr); + uint8_t *addr = (uint8_t*) READ_UNALIGNED_LONGWORD(addrPtr); + addr += displacements[kind]; + if(relative) + addr -= (uint32_t) addrPtr; + + WRITE_UNALIGNED_LONGWORD(addrPtr, (uint32_t) addr); + } + + reloc++; } } #endif