New, more compact format for relocations

This commit is contained in:
Wolfgang Thaller 2017-09-30 23:03:17 +02:00
parent a68112b08d
commit 32a2da9547
6 changed files with 111 additions and 13 deletions

View File

@ -22,6 +22,7 @@
#include "Symtab.h"
#include "Section.h"
#include "SegmentMap.h"
#include "Reloc.h"
#include <err.h>
#include <fcntl.h>
@ -135,10 +136,17 @@ void Object::FlatCode(std::ostream& out)
out << dataSection->GetData();
std::vector<RuntimeReloc> 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";

View File

@ -18,6 +18,8 @@
*/
#include "Reloc.h"
#include <sstream>
#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<RuntimeReloc> 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<RuntimeReloc> 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();
}

View File

@ -21,6 +21,10 @@
#define RELOC_H
#include <gelf.h>
#include <stdint.h>
#include <string>
#include <vector>
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<RuntimeReloc> relocs);
std::string SerializeRelocs(std::vector<RuntimeReloc> relocs);
#endif // RELOC_H

View File

@ -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<RuntimeReloc> Section::GetRelocations(bool useOffsets)
{
std::ostringstream out;
std::vector<RuntimeReloc> 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()

View File

@ -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<RuntimeReloc> GetRelocations(bool useOffsets);
void ScanRelocs();
void FixRelocs();

View File

@ -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()
{