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-exception 6 // 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 20 using namespace llvm; 21 using namespace llvm::jitlink; 22 23 static bool isELFGOTSection(Section &S) { return S.getName() == "$__GOT"; } 24 25 static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; } 26 27 static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) { 28 auto EItr = 29 llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); }); 30 if (EItr == B.edges().end()) 31 return make_error<StringError>("GOT entry in " + G.getName() + ", \"" + 32 B.getSection().getName() + 33 "\" has no relocations", 34 inconvertibleErrorCode()); 35 return *EItr; 36 } 37 38 static Expected<Symbol &> getELFGOTTarget(LinkGraph &G, Block &B) { 39 auto E = getFirstRelocationEdge(G, B); 40 if (!E) 41 return E.takeError(); 42 auto &TargetSym = E->getTarget(); 43 if (!TargetSym.hasName()) 44 return make_error<StringError>( 45 "GOT entry in " + G.getName() + ", \"" + 46 TargetSym.getBlock().getSection().getName() + 47 "\" points to anonymous " 48 "symbol", 49 inconvertibleErrorCode()); 50 return TargetSym; 51 } 52 53 static Expected<Symbol &> getELFStubTarget(LinkGraph &G, Block &B) { 54 auto E = getFirstRelocationEdge(G, B); 55 if (!E) 56 return E.takeError(); 57 auto &GOTSym = E->getTarget(); 58 if (!GOTSym.isDefined()) 59 return make_error<StringError>("Stubs entry in " + G.getName() + 60 " does not point to GOT entry", 61 inconvertibleErrorCode()); 62 if (!isELFGOTSection(GOTSym.getBlock().getSection())) 63 return make_error<StringError>( 64 "Stubs entry in " + G.getName() + ", \"" + 65 GOTSym.getBlock().getSection().getName() + 66 "\" does not point to GOT entry", 67 inconvertibleErrorCode()); 68 return getELFGOTTarget(G, GOTSym.getBlock()); 69 } 70 71 namespace llvm { 72 73 Error registerELFGraphInfo(Session &S, LinkGraph &G) { 74 auto FileName = sys::path::filename(G.getName()); 75 if (S.FileInfos.count(FileName)) { 76 return make_error<StringError>("When -check is passed, file names must be " 77 "distinct (duplicate: \"" + 78 FileName + "\")", 79 inconvertibleErrorCode()); 80 } 81 82 auto &FileInfo = S.FileInfos[FileName]; 83 LLVM_DEBUG({ 84 dbgs() << "Registering ELF file info for \"" << FileName << "\"\n"; 85 }); 86 for (auto &Sec : G.sections()) { 87 LLVM_DEBUG({ 88 dbgs() << " Section \"" << Sec.getName() << "\": " 89 << (Sec.symbols().empty() ? "empty. skipping." : "processing...") 90 << "\n"; 91 }); 92 93 // Skip empty sections. 94 if (Sec.symbols().empty()) 95 continue; 96 97 if (FileInfo.SectionInfos.count(Sec.getName())) 98 return make_error<StringError>("Encountered duplicate section name \"" + 99 Sec.getName() + "\" in \"" + FileName + 100 "\"", 101 inconvertibleErrorCode()); 102 103 bool isGOTSection = isELFGOTSection(Sec); 104 bool isStubsSection = isELFStubsSection(Sec); 105 106 bool SectionContainsContent = false; 107 bool SectionContainsZeroFill = false; 108 109 auto *FirstSym = *Sec.symbols().begin(); 110 auto *LastSym = FirstSym; 111 for (auto *Sym : Sec.symbols()) { 112 if (Sym->getAddress() < FirstSym->getAddress()) 113 FirstSym = Sym; 114 if (Sym->getAddress() > LastSym->getAddress()) 115 LastSym = Sym; 116 117 if (isGOTSection) { 118 if (Sym->isSymbolZeroFill()) 119 return make_error<StringError>("zero-fill atom in GOT section", 120 inconvertibleErrorCode()); 121 122 // If this is a GOT symbol with size (i.e. not the GOT start symbol) 123 // then add it to the GOT entry info table. 124 if (Sym->getSize() != 0) { 125 if (auto TS = getELFGOTTarget(G, Sym->getBlock())) 126 FileInfo.GOTEntryInfos[TS->getName()] = { 127 Sym->getSymbolContent(), Sym->getAddress().getValue(), 128 Sym->getTargetFlags()}; 129 else 130 return TS.takeError(); 131 } 132 SectionContainsContent = true; 133 } else if (isStubsSection) { 134 if (Sym->isSymbolZeroFill()) 135 return make_error<StringError>("zero-fill atom in Stub section", 136 inconvertibleErrorCode()); 137 138 if (auto TS = getELFStubTarget(G, Sym->getBlock())) 139 FileInfo.StubInfos[TS->getName()] = {Sym->getSymbolContent(), 140 Sym->getAddress().getValue(), 141 Sym->getTargetFlags()}; 142 else 143 return TS.takeError(); 144 SectionContainsContent = true; 145 } 146 147 if (Sym->hasName()) { 148 if (Sym->isSymbolZeroFill()) { 149 S.SymbolInfos[Sym->getName()] = {Sym->getSize(), 150 Sym->getAddress().getValue()}; 151 SectionContainsZeroFill = true; 152 } else { 153 S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(), 154 Sym->getAddress().getValue(), 155 Sym->getTargetFlags()}; 156 SectionContainsContent = true; 157 } 158 } 159 } 160 161 // Add symbol info for absolute symbols. 162 for (auto *Sym : G.absolute_symbols()) 163 S.SymbolInfos[Sym->getName()] = {Sym->getSize(), 164 Sym->getAddress().getValue()}; 165 166 auto SecAddr = FirstSym->getAddress(); 167 auto SecSize = 168 (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) - 169 SecAddr; 170 171 if (SectionContainsZeroFill && SectionContainsContent) 172 return make_error<StringError>("Mixed zero-fill and content sections not " 173 "supported yet", 174 inconvertibleErrorCode()); 175 if (SectionContainsZeroFill) 176 FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()}; 177 else 178 FileInfo.SectionInfos[Sec.getName()] = { 179 ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize), 180 SecAddr.getValue(), FirstSym->getTargetFlags()}; 181 } 182 183 return Error::success(); 184 } 185 186 } // end namespace llvm 187