diff --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h --- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h +++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h @@ -110,6 +110,31 @@ Error graphifySections(); Error graphifySymbols(); + /// Traverse all matching relocation records in the given section. The handler + /// function Func should be callable with this signature: + /// Error(const typename ELFT::Rela &, + /// const typename ELFT::Shdr &, Section &) + /// + template + Error forEachRelocation(const typename ELFT::Shdr &RelSect, + RelocHandlerFunction &&Func, + bool ProcessDebugSections = false); + + /// Traverse all matching relocation records in the given section. Convenience + /// wrapper to allow passing a member function for the handler. + /// + template + Error forEachRelocation(const typename ELFT::Shdr &RelSect, ClassT *Instance, + RelocHandlerMethod &&Method, + bool ProcessDebugSections = false) { + return forEachRelocation( + RelSect, + [Instance, Method](const auto &Rel, const auto &Target, auto &GS) { + return (Instance->*Method)(Rel, Target, GS); + }, + ProcessDebugSections); + } + const ELFFile &Obj; typename ELFFile::Elf_Shdr_Range Sections; @@ -426,6 +451,54 @@ return Error::success(); } +template +template +Error ELFLinkGraphBuilder::forEachRelocation( + const typename ELFT::Shdr &RelSect, RelocHandlerFunction &&Func, + bool ProcessDebugSections) { + + // Only look into sections that store relocation entries. + if (RelSect.sh_type != ELF::SHT_RELA && RelSect.sh_type != ELF::SHT_REL) + return Error::success(); + + // sh_info contains the section header index of the target (FixupSection), + // which is the section to which all relocations in RelSect apply. + auto FixupSection = Obj.getSection(RelSect.sh_info); + if (!FixupSection) + return FixupSection.takeError(); + + // Target sections have names in valid ELF object files. + Expected Name = Obj.getSectionName(**FixupSection); + if (!Name) + return Name.takeError(); + LLVM_DEBUG(dbgs() << " " << *Name << ":\n"); + + // Consider skipping these relocations. + if (!ProcessDebugSections && isDwarfSection(*Name)) { + LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n"); + return Error::success(); + } + + // Lookup the link-graph node corresponding to the target section name. + Section *GraphSect = G->findSectionByName(*Name); + if (!GraphSect) + return make_error( + "Refencing a section that wasn't added to the graph: " + *Name, + inconvertibleErrorCode()); + + auto RelEntries = Obj.relas(RelSect); + if (!RelEntries) + return RelEntries.takeError(); + + // Let the callee process relocation entries one by one. + for (const typename ELFT::Rela &R : *RelEntries) + if (Error Err = Func(R, **FixupSection, *GraphSect)) + return Err; + + LLVM_DEBUG(dbgs() << "\n"); + return Error::success(); +} + } // end namespace jitlink } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp @@ -86,89 +86,54 @@ } Error addRelocations() override { + LLVM_DEBUG(dbgs() << "Processing relocations:\n"); + using Base = ELFLinkGraphBuilder; - LLVM_DEBUG(dbgs() << "Adding relocations\n"); - - // Iterate sections and only process the interesting ones. - for (auto &SecRef : Base::Sections) { - if (SecRef.sh_type != ELF::SHT_RELA && SecRef.sh_type != ELF::SHT_REL) - continue; - auto RelSectName = Base::Obj.getSectionName(SecRef); - if (!RelSectName) - return RelSectName.takeError(); - - LLVM_DEBUG({ - dbgs() << "Adding relocations from section " << *RelSectName << "\n"; - }); - - auto UpdateSect = Base::Obj.getSection(SecRef.sh_info); - if (!UpdateSect) - return UpdateSect.takeError(); - - auto UpdateSectName = Base::Obj.getSectionName(**UpdateSect); - if (!UpdateSectName) - return UpdateSectName.takeError(); - - // Don't process relocations for debug sections. - if (Base::isDwarfSection(*UpdateSectName)) { - LLVM_DEBUG({ - dbgs() << " Target is dwarf section " << *UpdateSectName - << ". Skipping.\n"; - }); - continue; - } - LLVM_DEBUG(dbgs() << " For target section " << *UpdateSectName << "\n"); - - auto *JITSection = Base::G->findSectionByName(*UpdateSectName); - if (!JITSection) - return make_error( - "Refencing a section that wasn't added to graph" + *UpdateSectName, - llvm::inconvertibleErrorCode()); - - auto Relocations = Base::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: " << Base::Obj.getRelocationTypeName(Type) << "\n"; - }); - - auto SymbolIndex = Rela.getSymbol(false); - auto Symbol = Base::Obj.getRelocationSymbol(Rela, Base::SymTabSec); - if (!Symbol) - return Symbol.takeError(); - - auto BlockToFix = *(JITSection->blocks().begin()); - auto *TargetSymbol = Base::getGraphSymbol(SymbolIndex); - - if (!TargetSymbol) { - return make_error( - "Could not find symbol at given index, did you add it to " - "JITSymbolTable? index: " + - std::to_string(SymbolIndex) + ", shndx: " + - std::to_string((*Symbol)->st_shndx) + " Size of table: " + - std::to_string(Base::GraphSymbols.size()), - llvm::inconvertibleErrorCode()); - } - int64_t Addend = Rela.r_addend; - JITTargetAddress FixupAddress = (*UpdateSect)->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(); - - BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(), - *TargetSymbol, Addend); - } - } + using Self = ELFLinkGraphBuilder_aarch64; + for (const auto &RelSect : Base::Sections) + if (Error Err = Base::forEachRelocation(RelSect, this, + &Self::addSingleRelocation)) + return Err; + + return Error::success(); + } + + Error addSingleRelocation(const typename ELFT::Rela &Rel, + const typename ELFT::Shdr &FixupSect, + Section &GraphSection) { + using Base = ELFLinkGraphBuilder; + + uint32_t SymbolIndex = Rel.getSymbol(false); + auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); + if (!ObjSymbol) + return ObjSymbol.takeError(); + + Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); + if (!GraphSymbol) + return make_error( + formatv("Could not find symbol at given index, did you add it to " + "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}", + SymbolIndex, (*ObjSymbol)->st_shndx, + Base::GraphSymbols.size()), + inconvertibleErrorCode()); + + uint32_t Type = Rel.getType(false); + Expected Kind = getRelocationKind(Type); + if (!Kind) + return Kind.takeError(); + + int64_t Addend = Rel.r_addend; + Block *BlockToFix = *(GraphSection.blocks().begin()); + JITTargetAddress FixupAddress = FixupSect.sh_addr + Rel.r_offset; + Edge::OffsetT Offset = FixupAddress - BlockToFix->getAddress(); + Edge GE(*Kind, Offset, *GraphSymbol, Addend); + LLVM_DEBUG({ + dbgs() << " "; + printEdge(dbgs(), *BlockToFix, GE, aarch64::getEdgeKindName(*Kind)); + dbgs() << "\n"; + }); + + BlockToFix->addEdge(std::move(GE)); return Error::success(); }