diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h index ee43c356aebe3..7860088f35692 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h @@ -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 Ctx); -StringRef getELFX86RelocationKindName(Edge::Kind R); } // end namespace jitlink } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp index a7118eb9b563f..505f03590b6b0 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp @@ -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::Elf_Shdr; + // For now we just assume + std::map JITSymbolTable; + Section &getCommonSection() { if (!CommonSection) { auto Prot = static_cast( @@ -39,10 +46,21 @@ class ELFLinkGraphBuilder_x86_64 { return *CommonSection; } + static Expected + getRelocationKind(const uint32_t Type) { + switch (Type) { + case ELF::R_X86_64_PC32: + return ELF_x86_64_Edges::ELFX86RelocationKind::PCRel32; + } + return make_error("Unsupported x86-64 relocation:" + + formatv("{0:d}", Type)); + } + std::unique_ptr G; // This could be a template const object::ELFFile &Obj; object::ELFFile::Elf_Shdr_Range sections; + SymbolTable SymTab; bool isRelocatable() { return Obj.getHeader()->e_type == llvm::ELF::ET_REL; } @@ -88,11 +106,11 @@ class ELFLinkGraphBuilder_x86_64 { // 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 @@ class ELFLinkGraphBuilder_x86_64 { // 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("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( + "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 @@ class ELFLinkGraphBuilder_x86_64 { 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 @@ class ELFLinkGraphBuilder_x86_64 { 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 @@ class ELFLinkGraphBuilder_x86_64 { if (auto Err = graphifyRegularSymbols()) return std::move(Err); + if (auto Err = addRelocations()) + return std::move(Err); + return std::move(G); } }; @@ -311,9 +413,7 @@ class ELFJITLinker_x86_64 : public JITLinker { : 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> buildGraph(MemoryBufferRef ObjBuffer) override { @@ -329,7 +429,17 @@ class ELFJITLinker_x86_64 : public JITLinker { } 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 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(R)); -} } // end namespace jitlink } // end namespace llvm diff --git a/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s b/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s index 12186e4f5433c..20b26b1826ba9 100644 --- a/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s +++ b/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s @@ -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 \ No newline at end of file + .addrsig