204 lines · cpp
1//===---- llvm-jitlink-elf.cpp -- ELF parsing support for llvm-jitlink ----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// ELF parsing support for llvm-jitlink.10//11//===----------------------------------------------------------------------===//12 13#include "llvm-jitlink.h"14 15#include "llvm/Support/Error.h"16#include "llvm/Support/Path.h"17 18#define DEBUG_TYPE "llvm_jitlink"19 20using namespace llvm;21using namespace llvm::jitlink;22 23static bool isELFGOTSection(Section &S) { return S.getName() == "$__GOT"; }24 25static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }26 27static bool isELFAArch32StubsSection(Section &S) {28 return S.getName().starts_with("__llvm_jitlink_aarch32_STUBS_");29}30 31static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {32 auto EItr =33 llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });34 if (EItr == B.edges().end())35 return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +36 B.getSection().getName() +37 "\" has no relocations",38 inconvertibleErrorCode());39 return *EItr;40}41 42static Expected<Symbol &> getELFGOTTarget(LinkGraph &G, Block &B) {43 auto E = getFirstRelocationEdge(G, B);44 if (!E)45 return E.takeError();46 auto &TargetSym = E->getTarget();47 if (!TargetSym.hasName())48 return make_error<StringError>(49 "GOT entry in " + G.getName() + ", \"" +50 TargetSym.getBlock().getSection().getName() +51 "\" points to anonymous "52 "symbol",53 inconvertibleErrorCode());54 return TargetSym;55}56 57static Expected<Symbol &> getELFStubTarget(LinkGraph &G, Block &B) {58 auto E = getFirstRelocationEdge(G, B);59 if (!E)60 return E.takeError();61 auto &GOTSym = E->getTarget();62 if (!GOTSym.isDefined())63 return make_error<StringError>("Stubs entry in " + G.getName() +64 " does not point to GOT entry",65 inconvertibleErrorCode());66 if (!isELFGOTSection(GOTSym.getBlock().getSection()))67 return make_error<StringError>(68 "Stubs entry in " + G.getName() + ", \"" +69 GOTSym.getBlock().getSection().getName() +70 "\" does not point to GOT entry",71 inconvertibleErrorCode());72 return getELFGOTTarget(G, GOTSym.getBlock());73}74 75static Expected<Symbol &> getELFAArch32StubTarget(LinkGraph &G, Block &B) {76 auto E = getFirstRelocationEdge(G, B);77 if (!E)78 return E.takeError();79 return E->getTarget();80}81 82enum SectionType { GOT, Stubs, AArch32Stubs, Other };83 84static Error registerSymbol(LinkGraph &G, Symbol &Sym, Session::FileInfo &FI,85 SectionType SecType) {86 switch (SecType) {87 case GOT:88 if (Sym.getSize() == 0)89 return Error::success(); // Skip the GOT start symbol90 return FI.registerGOTEntry(G, Sym, getELFGOTTarget);91 case Stubs:92 return FI.registerStubEntry(G, Sym, getELFStubTarget);93 case AArch32Stubs:94 return FI.registerMultiStubEntry(G, Sym, getELFAArch32StubTarget);95 case Other:96 return Error::success();97 }98 llvm_unreachable("Unhandled SectionType enum");99}100 101namespace llvm {102 103Error registerELFGraphInfo(Session &S, LinkGraph &G) {104 std::lock_guard<std::mutex> Lock(S.M);105 106 auto FileName = sys::path::filename(G.getName());107 auto [It, Inserted] = S.FileInfos.try_emplace(FileName);108 if (!Inserted) {109 return make_error<StringError>("When -check is passed, file names must be "110 "distinct (duplicate: \"" +111 FileName + "\")",112 inconvertibleErrorCode());113 }114 115 auto &FileInfo = It->second;116 LLVM_DEBUG({117 dbgs() << "Registering ELF file info for \"" << FileName << "\"\n";118 });119 for (auto &Sec : G.sections()) {120 LLVM_DEBUG({121 dbgs() << " Section \"" << Sec.getName() << "\": "122 << (Sec.symbols().empty() ? "empty. skipping." : "processing...")123 << "\n";124 });125 126 // Skip empty sections.127 if (Sec.symbols().empty())128 continue;129 130 if (FileInfo.SectionInfos.count(Sec.getName()))131 return make_error<StringError>("Encountered duplicate section name \"" +132 Sec.getName() + "\" in \"" + FileName +133 "\"",134 inconvertibleErrorCode());135 136 SectionType SecType;137 if (isELFGOTSection(Sec)) {138 SecType = GOT;139 } else if (isELFStubsSection(Sec)) {140 SecType = Stubs;141 } else if (isELFAArch32StubsSection(Sec)) {142 SecType = AArch32Stubs;143 } else {144 SecType = Other;145 }146 147 bool SectionContainsContent = false;148 bool SectionContainsZeroFill = false;149 150 auto *FirstSym = *Sec.symbols().begin();151 auto *LastSym = FirstSym;152 for (auto *Sym : Sec.symbols()) {153 if (Sym->getAddress() < FirstSym->getAddress())154 FirstSym = Sym;155 if (Sym->getAddress() > LastSym->getAddress())156 LastSym = Sym;157 158 if (SecType != Other) {159 if (Error Err = registerSymbol(G, *Sym, FileInfo, SecType))160 return Err;161 SectionContainsContent = true;162 }163 164 if (Sym->hasName()) {165 if (Sym->isSymbolZeroFill()) {166 S.SymbolInfos[Sym->getName()] = {Sym->getSize(),167 Sym->getAddress().getValue()};168 SectionContainsZeroFill = true;169 } else {170 S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(),171 Sym->getAddress().getValue(),172 Sym->getTargetFlags()};173 SectionContainsContent = true;174 }175 }176 }177 178 // Add symbol info for absolute symbols.179 for (auto *Sym : G.absolute_symbols())180 S.SymbolInfos[Sym->getName()] = {Sym->getSize(),181 Sym->getAddress().getValue()};182 183 auto SecAddr = FirstSym->getAddress();184 auto SecSize =185 (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) -186 SecAddr;187 188 if (SectionContainsZeroFill && SectionContainsContent)189 return make_error<StringError>("Mixed zero-fill and content sections not "190 "supported yet",191 inconvertibleErrorCode());192 if (SectionContainsZeroFill)193 FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()};194 else195 FileInfo.SectionInfos[Sec.getName()] = {196 ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),197 SecAddr.getValue(), FirstSym->getTargetFlags()};198 }199 200 return Error::success();201}202 203} // end namespace llvm204