1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[jitlink] R_X86_64_PC32 support for the elf x86 jitlinker

Summary:

Adding in our first relocation type, and all the required plumbing to support the rest in following patches

Differential Revision: https://reviews.llvm.org/D80613

Reviewer: lhames
This commit is contained in:
Jared Wyles 2020-05-30 09:11:42 +10:00
parent dde707298c
commit a93205f987
3 changed files with 164 additions and 64 deletions

View File

@ -19,36 +19,33 @@ namespace llvm {
namespace jitlink {
namespace ELF_x86_64_Edges {
enum ELFX86RelocationKind : Edge::Kind {
R_AMD64_NONE = Edge::FirstRelocation,
R_AMD64_64,
R_AMD64_PC32,
R_AMD64_GOT32,
R_AMD64_PLT32,
R_AMD64_COPY,
R_AMD64_GLOB_DAT,
R_AMD64_JUMP_SLOT,
R_AMD64_RELATIVE,
R_AMD64_GOTPCREL,
R_AMD64_32,
R_AMD64_32S,
R_AMD64_16,
R_AMD64_PC16,
R_AMD64_8,
R_AMD64_PC8,
R_AMD64_PC64,
R_AMD64_GOTOFF64,
R_AMD64_GOTPC32,
R_AMD64_SIZE32,
R_AMD64_SIZE64
Branch32 = Edge::FirstRelocation,
Branch32ToStub,
Pointer32,
Pointer64,
Pointer64Anon,
PCRel32,
PCRel32Minus1,
PCRel32Minus2,
PCRel32Minus4,
PCRel32Anon,
PCRel32Minus1Anon,
PCRel32Minus2Anon,
PCRel32Minus4Anon,
PCRel32GOTLoad,
PCRel32GOT,
PCRel32TLV,
Delta32,
Delta64,
NegDelta32,
NegDelta64,
};
} // end namespace ELF_x86_64_Edges
/// jit-link the given object buffer, which must be a ELF x86-64 object file.
void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx);
StringRef getELFX86RelocationKindName(Edge::Kind R);
} // end namespace jitlink
} // end namespace llvm

View File

@ -24,12 +24,19 @@ static const char *CommonSectionName = "__common";
namespace llvm {
namespace jitlink {
// This should become a template as the ELFFile is so a lot of this could become
// generic
class ELFLinkGraphBuilder_x86_64 {
private:
Section *CommonSection = nullptr;
// TODO hack to get this working
// Find a better way
using SymbolTable = object::ELFFile<object::ELF64LE>::Elf_Shdr;
// For now we just assume
std::map<int32_t, Symbol *> JITSymbolTable;
Section &getCommonSection() {
if (!CommonSection) {
auto Prot = static_cast<sys::Memory::ProtectionFlags>(
@ -39,10 +46,21 @@ private:
return *CommonSection;
}
static Expected<ELF_x86_64_Edges::ELFX86RelocationKind>
getRelocationKind(const uint32_t Type) {
switch (Type) {
case ELF::R_X86_64_PC32:
return ELF_x86_64_Edges::ELFX86RelocationKind::PCRel32;
}
return make_error<JITLinkError>("Unsupported x86-64 relocation:" +
formatv("{0:d}", Type));
}
std::unique_ptr<LinkGraph> G;
// This could be a template
const object::ELFFile<object::ELF64LE> &Obj;
object::ELFFile<object::ELF64LE>::Elf_Shdr_Range sections;
SymbolTable SymTab;
bool isRelocatable() { return Obj.getHeader()->e_type == llvm::ELF::ET_REL; }
@ -88,11 +106,11 @@ private:
// FIXME: Read size.
(void)Size;
if (auto NameOrErr = SymRef.getName(*StringTable)) {
if (auto NameOrErr = SymRef.getName(*StringTable))
Name = *NameOrErr;
} else {
else
return NameOrErr.takeError();
}
LLVM_DEBUG({
dbgs() << " ";
if (!Name)
@ -157,12 +175,93 @@ private:
// Do this here because we have it, but move it into graphify later
G->createContentBlock(section, StringRef(Data, Size), Address,
Alignment, 0);
if (SecRef.sh_type == ELF::SHT_SYMTAB)
// TODO: Dynamic?
SymTab = SecRef;
}
}
return Error::success();
}
Error addRelocations() {
LLVM_DEBUG(dbgs() << "Adding relocations\n");
// TODO a partern is forming of iterate some sections but only give me
// ones I am interested, i should abstract that concept some where
for (auto &SecRef : sections) {
if (SecRef.sh_type != ELF::SHT_RELA && SecRef.sh_type != ELF::SHT_REL)
continue;
// TODO can the elf obj file do this for me?
if (SecRef.sh_type == ELF::SHT_REL)
return make_error<llvm::StringError>("Shouldn't have REL in x64",
llvm::inconvertibleErrorCode());
auto RelSectName = Obj.getSectionName(&SecRef);
if (!RelSectName)
return RelSectName.takeError();
// Deal with .eh_frame later
if (*RelSectName == StringRef(".rela.eh_frame"))
continue;
auto UpdateSection = Obj.getSection(SecRef.sh_info);
if (!UpdateSection)
return UpdateSection.takeError();
auto UpdateSectionName = Obj.getSectionName(*UpdateSection);
if (!UpdateSectionName)
return UpdateSectionName.takeError();
auto JITSection = G->findSectionByName(*UpdateSectionName);
if (!JITSection)
return make_error<llvm::StringError>(
"Refencing a a section that wasn't added to graph" +
*UpdateSectionName,
llvm::inconvertibleErrorCode());
auto Relocations = Obj.relas(&SecRef);
if (!Relocations)
return Relocations.takeError();
for (const auto &Rela : *Relocations) {
auto Type = Rela.getType(false);
LLVM_DEBUG({
dbgs() << "Relocation Type: " << Type << "\n"
<< "Name: " << Obj.getRelocationTypeName(Type) << "\n";
});
auto Symbol = Obj.getRelocationSymbol(&Rela, &SymTab);
if (!Symbol)
return Symbol.takeError();
auto BlockToFix = *(JITSection->blocks().begin());
auto TargetSymbol = JITSymbolTable[(*Symbol)->st_shndx];
uint64_t Addend = Rela.r_addend;
JITTargetAddress FixupAddress =
(*UpdateSection)->sh_addr + Rela.r_offset;
LLVM_DEBUG({
dbgs() << "Processing relocation at "
<< format("0x%016" PRIx64, FixupAddress) << "\n";
});
auto Kind = getRelocationKind(Type);
if (!Kind)
return Kind.takeError();
LLVM_DEBUG({
Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
Addend);
// TODO a mapping of KIND => type then call getRelocationTypeName4
printEdge(dbgs(), *BlockToFix, GE, StringRef(""));
dbgs() << "\n";
});
BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
*TargetSymbol, Addend);
}
}
return Error::success();
}
Error graphifyRegularSymbols() {
// TODO: ELF supports beyond SHN_LORESERVE,
@ -219,11 +318,10 @@ private:
if (!Name)
return Name.takeError();
// TODO: weak and hidden
if (SymRef.isExternal()) {
if (SymRef.isExternal())
bindings = {Linkage::Strong, Scope::Default};
} else {
else
bindings = {Linkage::Strong, Scope::Local};
}
if (SymRef.isDefined() &&
(Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT)) {
@ -247,9 +345,10 @@ private:
auto B = *bs.begin();
LLVM_DEBUG({ dbgs() << " " << *Name << ": "; });
G->addDefinedSymbol(*B, SymRef.getValue(), *Name, SymRef.st_size,
bindings.first, bindings.second,
SymRef.getType() == ELF::STT_FUNC, false);
auto &S = G->addDefinedSymbol(
*B, SymRef.getValue(), *Name, SymRef.st_size, bindings.first,
bindings.second, SymRef.getType() == ELF::STT_FUNC, false);
JITSymbolTable[SymRef.st_shndx] = &S;
}
//TODO: The following has to be implmented.
// leaving commented out to save time for future patchs
@ -298,6 +397,9 @@ public:
if (auto Err = graphifyRegularSymbols())
return std::move(Err);
if (auto Err = addRelocations())
return std::move(Err);
return std::move(G);
}
};
@ -311,9 +413,7 @@ public:
: JITLinker(std::move(Ctx), std::move(PassConfig)) {}
private:
StringRef getEdgeKindName(Edge::Kind R) const override {
return getELFX86RelocationKindName(R);
}
StringRef getEdgeKindName(Edge::Kind R) const override { return StringRef(); }
Expected<std::unique_ptr<LinkGraph>>
buildGraph(MemoryBufferRef ObjBuffer) override {
@ -329,7 +429,17 @@ private:
}
Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
//TODO: add relocation handling
using namespace ELF_x86_64_Edges;
char *FixupPtr = BlockWorkingMem + E.getOffset();
JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
switch (E.getKind()) {
case ELFX86RelocationKind::PCRel32:
int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
// verify
*(support::little32_t *)FixupPtr = Value;
break;
}
return Error::success();
}
};
@ -349,30 +459,5 @@ void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
}
StringRef getELFX86RelocationKindName(Edge::Kind R) {
// case R_AMD64_NONE:
// return "None";
// case R_AMD64_PC32:
// case R_AMD64_GOT32:
// case R_AMD64_PLT32,
// R_AMD64_COPY,
// R_AMD64_GLOB_DAT,
// R_AMD64_JUMP_SLOT,
// R_AMD64_RELATIVE,
// R_AMD64_GOTPCREL,
// R_AMD64_32,
// R_AMD64_32S,
// R_AMD64_16,
// R_AMD64_PC16,
// R_AMD64_8,
// R_AMD64_PC8,
// R_AMD64_PC64,
// R_AMD64_GOTOFF64,
// R_AMD64_GOTPC32,
// R_AMD64_SIZE32,
// R_AMD64_SIZE64
return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
}
} // end namespace jitlink
} // end namespace llvm

View File

@ -1,20 +1,38 @@
# RUN: rm -rf %t && mkdir -p %t
# RUN: llvm-mc -triple=x86_64-unknown-linux -filetype=obj -o %t/elf_reloc.o %s
# RUN: llvm-jitlink -noexec %t/elf_reloc.o
# RUN: llvm-jitlink -noexec -check %s %t/elf_reloc.o
#
# Test standard ELF relocations.
.text
.file "testcase.c"
# Empty main entry point.
.globl main
.p2align 4, 0x90
.type main,@function
main:
movl $42, %eax
retq
.Lfunc_end0:
.size main, .Lfunc_end0-main
# Test PCRel32 / R_X86_64_PC32 handling.
# jitlink-check: decode_operand(test_pcrel32, 4) = named_data - next_pc(test_pcrel32)
.globl test_pcrel32
.p2align 4, 0x90
.type test_pcrel32,@function
test_pcrel32:
movl named_data(%rip), %eax
.Ltest_pcrel32_end:
.size test_pcrel32, .Ltest_pcrel32_end-test_pcrel32
.type named_data,@object
.data
.p2align 2
named_data:
.long 42
.size named_data, 4
.ident "clang version 10.0.0-4ubuntu1 "
.section ".note.GNU-stack","",@progbits
.addrsig
.addrsig