1db995d72SSunho Kim //===--- llvm-jitlink-coff.cpp -- COFF parsing support for llvm-jitlink ---===// 2db995d72SSunho Kim // 3db995d72SSunho Kim // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4db995d72SSunho Kim // See https://llvm.org/LICENSE.txt for license information. 5db995d72SSunho Kim // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6db995d72SSunho Kim // 7db995d72SSunho Kim //===----------------------------------------------------------------------===// 8db995d72SSunho Kim // 9db995d72SSunho Kim // COFF parsing support for llvm-jitlink. 10db995d72SSunho Kim // 11db995d72SSunho Kim //===----------------------------------------------------------------------===// 12db995d72SSunho Kim 13db995d72SSunho Kim #include "llvm-jitlink.h" 14db995d72SSunho Kim 15db995d72SSunho Kim #include "llvm/Support/Error.h" 16db995d72SSunho Kim #include "llvm/Support/Path.h" 17db995d72SSunho Kim 18db995d72SSunho Kim #define DEBUG_TYPE "llvm_jitlink" 19db995d72SSunho Kim 20db995d72SSunho Kim using namespace llvm; 21db995d72SSunho Kim using namespace llvm::jitlink; 22db995d72SSunho Kim 23db995d72SSunho Kim static bool isCOFFGOTSection(Section &S) { return S.getName() == "$__GOT"; } 24db995d72SSunho Kim 25db995d72SSunho Kim static bool isCOFFStubsSection(Section &S) { return S.getName() == "$__STUBS"; } 26db995d72SSunho Kim 27db995d72SSunho Kim static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) { 28ce9f007cSKazu Hirata auto EItr = 29ce9f007cSKazu Hirata llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); }); 30db995d72SSunho Kim if (EItr == B.edges().end()) 31db995d72SSunho Kim return make_error<StringError>("GOT entry in " + G.getName() + ", \"" + 32db995d72SSunho Kim B.getSection().getName() + 33db995d72SSunho Kim "\" has no relocations", 34db995d72SSunho Kim inconvertibleErrorCode()); 35db995d72SSunho Kim return *EItr; 36db995d72SSunho Kim } 37db995d72SSunho Kim 38db995d72SSunho Kim static Expected<Symbol &> getCOFFGOTTarget(LinkGraph &G, Block &B) { 39db995d72SSunho Kim auto E = getFirstRelocationEdge(G, B); 40db995d72SSunho Kim if (!E) 41db995d72SSunho Kim return E.takeError(); 42db995d72SSunho Kim auto &TargetSym = E->getTarget(); 43db995d72SSunho Kim if (!TargetSym.hasName()) 44db995d72SSunho Kim return make_error<StringError>( 45db995d72SSunho Kim "GOT entry in " + G.getName() + ", \"" + 46db995d72SSunho Kim TargetSym.getBlock().getSection().getName() + 47db995d72SSunho Kim "\" points to anonymous " 48db995d72SSunho Kim "symbol", 49db995d72SSunho Kim inconvertibleErrorCode()); 50db995d72SSunho Kim return TargetSym; 51db995d72SSunho Kim } 52db995d72SSunho Kim 53db995d72SSunho Kim static Expected<Symbol &> getCOFFStubTarget(LinkGraph &G, Block &B) { 54db995d72SSunho Kim auto E = getFirstRelocationEdge(G, B); 55db995d72SSunho Kim if (!E) 56db995d72SSunho Kim return E.takeError(); 57db995d72SSunho Kim auto &GOTSym = E->getTarget(); 58db995d72SSunho Kim if (!GOTSym.isDefined() || !isCOFFGOTSection(GOTSym.getBlock().getSection())) 59db995d72SSunho Kim return make_error<StringError>( 60db995d72SSunho Kim "Stubs entry in " + G.getName() + ", \"" + 61db995d72SSunho Kim GOTSym.getBlock().getSection().getName() + 62db995d72SSunho Kim "\" does not point to GOT entry", 63db995d72SSunho Kim inconvertibleErrorCode()); 64db995d72SSunho Kim return getCOFFGOTTarget(G, GOTSym.getBlock()); 65db995d72SSunho Kim } 66db995d72SSunho Kim 67db995d72SSunho Kim namespace llvm { 68db995d72SSunho Kim Error registerCOFFGraphInfo(Session &S, LinkGraph &G) { 69*09655153SLang Hames std::lock_guard<std::mutex> Lock(S.M); 70*09655153SLang Hames 71db995d72SSunho Kim auto FileName = sys::path::filename(G.getName()); 72db995d72SSunho Kim if (S.FileInfos.count(FileName)) { 73db995d72SSunho Kim return make_error<StringError>("When -check is passed, file names must be " 74db995d72SSunho Kim "distinct (duplicate: \"" + 75db995d72SSunho Kim FileName + "\")", 76db995d72SSunho Kim inconvertibleErrorCode()); 77db995d72SSunho Kim } 78db995d72SSunho Kim 79db995d72SSunho Kim auto &FileInfo = S.FileInfos[FileName]; 80db995d72SSunho Kim LLVM_DEBUG( 81db995d72SSunho Kim { dbgs() << "Registering COFF file info for \"" << FileName << "\"\n"; }); 82db995d72SSunho Kim for (auto &Sec : G.sections()) { 83db995d72SSunho Kim LLVM_DEBUG({ 84db995d72SSunho Kim dbgs() << " Section \"" << Sec.getName() << "\": " 8596066084SKazu Hirata << (Sec.symbols().empty() ? "empty. skipping." : "processing...") 86db995d72SSunho Kim << "\n"; 87db995d72SSunho Kim }); 88db995d72SSunho Kim 89db995d72SSunho Kim // Skip empty sections. 9096066084SKazu Hirata if (Sec.symbols().empty()) 91db995d72SSunho Kim continue; 92db995d72SSunho Kim 93db995d72SSunho Kim if (FileInfo.SectionInfos.count(Sec.getName())) 94db995d72SSunho Kim return make_error<StringError>("Encountered duplicate section name \"" + 95db995d72SSunho Kim Sec.getName() + "\" in \"" + FileName + 96db995d72SSunho Kim "\"", 97db995d72SSunho Kim inconvertibleErrorCode()); 98db995d72SSunho Kim 99db995d72SSunho Kim bool isGOTSection = isCOFFGOTSection(Sec); 100db995d72SSunho Kim bool isStubsSection = isCOFFStubsSection(Sec); 101db995d72SSunho Kim 102db995d72SSunho Kim bool SectionContainsContent = false; 103db995d72SSunho Kim bool SectionContainsZeroFill = false; 104db995d72SSunho Kim 105db995d72SSunho Kim auto *FirstSym = *Sec.symbols().begin(); 106db995d72SSunho Kim auto *LastSym = FirstSym; 107db995d72SSunho Kim for (auto *Sym : Sec.symbols()) { 108db995d72SSunho Kim if (Sym->getAddress() < FirstSym->getAddress()) 109db995d72SSunho Kim FirstSym = Sym; 110db995d72SSunho Kim if (Sym->getAddress() > LastSym->getAddress()) 111db995d72SSunho Kim LastSym = Sym; 112db995d72SSunho Kim 11301ba627fSStefan Gränitz if (isGOTSection || isStubsSection) { 114db995d72SSunho Kim if (isGOTSection) { 11501ba627fSStefan Gränitz // Skip the GOT start symbol 11601ba627fSStefan Gränitz if (Sym->getSize() != 0) 11701ba627fSStefan Gränitz if (Error E = FileInfo.registerGOTEntry(G, *Sym, getCOFFGOTTarget)) 11801ba627fSStefan Gränitz return E; 11901ba627fSStefan Gränitz } else { 12001ba627fSStefan Gränitz if (Error E = FileInfo.registerStubEntry(G, *Sym, getCOFFStubTarget)) 12101ba627fSStefan Gränitz return E; 122db995d72SSunho Kim } 123db995d72SSunho Kim SectionContainsContent = true; 124db995d72SSunho Kim } 125db995d72SSunho Kim 126db995d72SSunho Kim if (Sym->hasName()) { 127db995d72SSunho Kim if (Sym->isSymbolZeroFill()) { 128db995d72SSunho Kim S.SymbolInfos[Sym->getName()] = {Sym->getSize(), 129db995d72SSunho Kim Sym->getAddress().getValue()}; 130db995d72SSunho Kim SectionContainsZeroFill = true; 131db995d72SSunho Kim } else { 132db995d72SSunho Kim S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(), 1339c017a99SEymen Ünay Sym->getAddress().getValue(), 1349c017a99SEymen Ünay Sym->getTargetFlags()}; 135db995d72SSunho Kim SectionContainsContent = true; 136db995d72SSunho Kim } 137db995d72SSunho Kim } 138db995d72SSunho Kim } 139db995d72SSunho Kim 140db995d72SSunho Kim auto SecAddr = FirstSym->getAddress(); 141db995d72SSunho Kim auto SecSize = 142db995d72SSunho Kim (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) - 143db995d72SSunho Kim SecAddr; 144db995d72SSunho Kim 145db995d72SSunho Kim if (SectionContainsZeroFill && SectionContainsContent) 146db995d72SSunho Kim return make_error<StringError>("Mixed zero-fill and content sections not " 147db995d72SSunho Kim "supported yet", 148db995d72SSunho Kim inconvertibleErrorCode()); 149db995d72SSunho Kim 150db995d72SSunho Kim if (SectionContainsZeroFill) 151db995d72SSunho Kim FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()}; 152db995d72SSunho Kim else 153db995d72SSunho Kim FileInfo.SectionInfos[Sec.getName()] = { 154db995d72SSunho Kim ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize), 1559c017a99SEymen Ünay SecAddr.getValue(), FirstSym->getTargetFlags()}; 156db995d72SSunho Kim } 157db995d72SSunho Kim 158db995d72SSunho Kim return Error::success(); 159db995d72SSunho Kim } 160db995d72SSunho Kim 161db995d72SSunho Kim } // end namespace llvm 162