xref: /llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp (revision 096551537b2a747a3387726ca618ceeb3950e9bc)
1a6deaeecSLang Hames //===---- llvm-jitlink-elf.cpp -- ELF parsing support for llvm-jitlink ----===//
2a6deaeecSLang Hames //
3a6deaeecSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a6deaeecSLang Hames // See https://llvm.org/LICENSE.txt for license information.
5a6deaeecSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a6deaeecSLang Hames //
7a6deaeecSLang Hames //===----------------------------------------------------------------------===//
8a6deaeecSLang Hames //
9a6deaeecSLang Hames // ELF parsing support for llvm-jitlink.
10a6deaeecSLang Hames //
11a6deaeecSLang Hames //===----------------------------------------------------------------------===//
12a6deaeecSLang Hames 
13a6deaeecSLang Hames #include "llvm-jitlink.h"
14a6deaeecSLang Hames 
15a6deaeecSLang Hames #include "llvm/Support/Error.h"
16a6deaeecSLang Hames #include "llvm/Support/Path.h"
17a6deaeecSLang Hames 
18a6deaeecSLang Hames #define DEBUG_TYPE "llvm_jitlink"
19a6deaeecSLang Hames 
20a6deaeecSLang Hames using namespace llvm;
21a6deaeecSLang Hames using namespace llvm::jitlink;
22a6deaeecSLang Hames 
233b55bfadSLang Hames static bool isELFGOTSection(Section &S) { return S.getName() == "$__GOT"; }
243b55bfadSLang Hames 
253b55bfadSLang Hames static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
263b55bfadSLang Hames 
2795dcb8b4SStefan Gränitz static bool isELFAArch32StubsSection(Section &S) {
2895dcb8b4SStefan Gränitz   return S.getName().starts_with("__llvm_jitlink_aarch32_STUBS_");
2995dcb8b4SStefan Gränitz }
3095dcb8b4SStefan Gränitz 
313b55bfadSLang Hames static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
32ce9f007cSKazu Hirata   auto EItr =
33ce9f007cSKazu Hirata       llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
343b55bfadSLang Hames   if (EItr == B.edges().end())
353b55bfadSLang Hames     return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
363b55bfadSLang Hames                                        B.getSection().getName() +
373b55bfadSLang Hames                                        "\" has no relocations",
383b55bfadSLang Hames                                    inconvertibleErrorCode());
393b55bfadSLang Hames   return *EItr;
403b55bfadSLang Hames }
413b55bfadSLang Hames 
423b55bfadSLang Hames static Expected<Symbol &> getELFGOTTarget(LinkGraph &G, Block &B) {
433b55bfadSLang Hames   auto E = getFirstRelocationEdge(G, B);
443b55bfadSLang Hames   if (!E)
453b55bfadSLang Hames     return E.takeError();
463b55bfadSLang Hames   auto &TargetSym = E->getTarget();
473b55bfadSLang Hames   if (!TargetSym.hasName())
483b55bfadSLang Hames     return make_error<StringError>(
493b55bfadSLang Hames         "GOT entry in " + G.getName() + ", \"" +
503b55bfadSLang Hames             TargetSym.getBlock().getSection().getName() +
513b55bfadSLang Hames             "\" points to anonymous "
523b55bfadSLang Hames             "symbol",
533b55bfadSLang Hames         inconvertibleErrorCode());
543b55bfadSLang Hames   return TargetSym;
553b55bfadSLang Hames }
563b55bfadSLang Hames 
573b55bfadSLang Hames static Expected<Symbol &> getELFStubTarget(LinkGraph &G, Block &B) {
583b55bfadSLang Hames   auto E = getFirstRelocationEdge(G, B);
593b55bfadSLang Hames   if (!E)
603b55bfadSLang Hames     return E.takeError();
613b55bfadSLang Hames   auto &GOTSym = E->getTarget();
62c8562e81SStefan Gränitz   if (!GOTSym.isDefined())
63c8562e81SStefan Gränitz     return make_error<StringError>("Stubs entry in " + G.getName() +
64c8562e81SStefan Gränitz                                        " does not point to GOT entry",
65c8562e81SStefan Gränitz                                    inconvertibleErrorCode());
66c8562e81SStefan Gränitz   if (!isELFGOTSection(GOTSym.getBlock().getSection()))
673b55bfadSLang Hames     return make_error<StringError>(
683b55bfadSLang Hames         "Stubs entry in " + G.getName() + ", \"" +
693b55bfadSLang Hames             GOTSym.getBlock().getSection().getName() +
703b55bfadSLang Hames             "\" does not point to GOT entry",
713b55bfadSLang Hames         inconvertibleErrorCode());
723b55bfadSLang Hames   return getELFGOTTarget(G, GOTSym.getBlock());
733b55bfadSLang Hames }
743b55bfadSLang Hames 
7501ba627fSStefan Gränitz static Expected<Symbol &> getELFAArch32StubTarget(LinkGraph &G, Block &B) {
7695dcb8b4SStefan Gränitz   auto E = getFirstRelocationEdge(G, B);
7795dcb8b4SStefan Gränitz   if (!E)
7895dcb8b4SStefan Gränitz     return E.takeError();
7901ba627fSStefan Gränitz   return E->getTarget();
8001ba627fSStefan Gränitz }
8101ba627fSStefan Gränitz 
8201ba627fSStefan Gränitz enum SectionType { GOT, Stubs, AArch32Stubs, Other };
8301ba627fSStefan Gränitz 
8401ba627fSStefan Gränitz static Error registerSymbol(LinkGraph &G, Symbol &Sym, Session::FileInfo &FI,
8501ba627fSStefan Gränitz                             SectionType SecType) {
8601ba627fSStefan Gränitz   switch (SecType) {
8701ba627fSStefan Gränitz   case GOT:
8801ba627fSStefan Gränitz     if (Sym.getSize() == 0)
8901ba627fSStefan Gränitz       return Error::success(); // Skip the GOT start symbol
9001ba627fSStefan Gränitz     return FI.registerGOTEntry(G, Sym, getELFGOTTarget);
9101ba627fSStefan Gränitz   case Stubs:
9201ba627fSStefan Gränitz     return FI.registerStubEntry(G, Sym, getELFStubTarget);
9301ba627fSStefan Gränitz   case AArch32Stubs:
946a433d77SStefan Gränitz     return FI.registerMultiStubEntry(G, Sym, getELFAArch32StubTarget);
9501ba627fSStefan Gränitz   case Other:
9601ba627fSStefan Gränitz     return Error::success();
9701ba627fSStefan Gränitz   }
98836dcdb8SSimon Pilgrim   llvm_unreachable("Unhandled SectionType enum");
9995dcb8b4SStefan Gränitz }
10095dcb8b4SStefan Gränitz 
101a6deaeecSLang Hames namespace llvm {
102a6deaeecSLang Hames 
103a6deaeecSLang Hames Error registerELFGraphInfo(Session &S, LinkGraph &G) {
104*09655153SLang Hames   std::lock_guard<std::mutex> Lock(S.M);
105*09655153SLang Hames 
106a6deaeecSLang Hames   auto FileName = sys::path::filename(G.getName());
107a6deaeecSLang Hames   if (S.FileInfos.count(FileName)) {
108a6deaeecSLang Hames     return make_error<StringError>("When -check is passed, file names must be "
109a6deaeecSLang Hames                                    "distinct (duplicate: \"" +
110a6deaeecSLang Hames                                        FileName + "\")",
111a6deaeecSLang Hames                                    inconvertibleErrorCode());
112a6deaeecSLang Hames   }
113a6deaeecSLang Hames 
114a6deaeecSLang Hames   auto &FileInfo = S.FileInfos[FileName];
115a6deaeecSLang Hames   LLVM_DEBUG({
116a6deaeecSLang Hames     dbgs() << "Registering ELF file info for \"" << FileName << "\"\n";
117a6deaeecSLang Hames   });
118a6deaeecSLang Hames   for (auto &Sec : G.sections()) {
119a6deaeecSLang Hames     LLVM_DEBUG({
120a6deaeecSLang Hames       dbgs() << "  Section \"" << Sec.getName() << "\": "
12196066084SKazu Hirata              << (Sec.symbols().empty() ? "empty. skipping." : "processing...")
122a6deaeecSLang Hames              << "\n";
123a6deaeecSLang Hames     });
124a6deaeecSLang Hames 
125a6deaeecSLang Hames     // Skip empty sections.
12696066084SKazu Hirata     if (Sec.symbols().empty())
127a6deaeecSLang Hames       continue;
128a6deaeecSLang Hames 
129a6deaeecSLang Hames     if (FileInfo.SectionInfos.count(Sec.getName()))
130a6deaeecSLang Hames       return make_error<StringError>("Encountered duplicate section name \"" +
131a6deaeecSLang Hames                                          Sec.getName() + "\" in \"" + FileName +
132a6deaeecSLang Hames                                          "\"",
133a6deaeecSLang Hames                                      inconvertibleErrorCode());
134a6deaeecSLang Hames 
13501ba627fSStefan Gränitz     SectionType SecType;
13601ba627fSStefan Gränitz     if (isELFGOTSection(Sec)) {
13701ba627fSStefan Gränitz       SecType = GOT;
13801ba627fSStefan Gränitz     } else if (isELFStubsSection(Sec)) {
13901ba627fSStefan Gränitz       SecType = Stubs;
14001ba627fSStefan Gränitz     } else if (isELFAArch32StubsSection(Sec)) {
14101ba627fSStefan Gränitz       SecType = AArch32Stubs;
14201ba627fSStefan Gränitz     } else {
14301ba627fSStefan Gränitz       SecType = Other;
14401ba627fSStefan Gränitz     }
1453b55bfadSLang Hames 
146a6deaeecSLang Hames     bool SectionContainsContent = false;
147a6deaeecSLang Hames     bool SectionContainsZeroFill = false;
148a6deaeecSLang Hames 
149a6deaeecSLang Hames     auto *FirstSym = *Sec.symbols().begin();
150a6deaeecSLang Hames     auto *LastSym = FirstSym;
151a6deaeecSLang Hames     for (auto *Sym : Sec.symbols()) {
152a6deaeecSLang Hames       if (Sym->getAddress() < FirstSym->getAddress())
153a6deaeecSLang Hames         FirstSym = Sym;
154a6deaeecSLang Hames       if (Sym->getAddress() > LastSym->getAddress())
155a6deaeecSLang Hames         LastSym = Sym;
156a6deaeecSLang Hames 
15701ba627fSStefan Gränitz       if (SecType != Other) {
15801ba627fSStefan Gränitz         if (Error Err = registerSymbol(G, *Sym, FileInfo, SecType))
15901ba627fSStefan Gränitz           return Err;
16095dcb8b4SStefan Gränitz         SectionContainsContent = true;
161fc36a511SLang Hames       }
162fc36a511SLang Hames 
163fc36a511SLang Hames       if (Sym->hasName()) {
164a6deaeecSLang Hames         if (Sym->isSymbolZeroFill()) {
165118e953bSLang Hames           S.SymbolInfos[Sym->getName()] = {Sym->getSize(),
166118e953bSLang Hames                                            Sym->getAddress().getValue()};
167a6deaeecSLang Hames           SectionContainsZeroFill = true;
168a6deaeecSLang Hames         } else {
169a6deaeecSLang Hames           S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(),
1709c017a99SEymen Ünay                                            Sym->getAddress().getValue(),
1719c017a99SEymen Ünay                                            Sym->getTargetFlags()};
172a6deaeecSLang Hames           SectionContainsContent = true;
173a6deaeecSLang Hames         }
174a6deaeecSLang Hames       }
175a6deaeecSLang Hames     }
176a6deaeecSLang Hames 
177e4b6e686SLang Hames     // Add symbol info for absolute symbols.
178e4b6e686SLang Hames     for (auto *Sym : G.absolute_symbols())
179e4b6e686SLang Hames       S.SymbolInfos[Sym->getName()] = {Sym->getSize(),
180e4b6e686SLang Hames                                        Sym->getAddress().getValue()};
181e4b6e686SLang Hames 
182118e953bSLang Hames     auto SecAddr = FirstSym->getAddress();
183118e953bSLang Hames     auto SecSize =
184a6deaeecSLang Hames         (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) -
185a6deaeecSLang Hames         SecAddr;
186a6deaeecSLang Hames 
187a6deaeecSLang Hames     if (SectionContainsZeroFill && SectionContainsContent)
188a6deaeecSLang Hames       return make_error<StringError>("Mixed zero-fill and content sections not "
189a6deaeecSLang Hames                                      "supported yet",
190a6deaeecSLang Hames                                      inconvertibleErrorCode());
191a6deaeecSLang Hames     if (SectionContainsZeroFill)
192118e953bSLang Hames       FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()};
193a6deaeecSLang Hames     else
194a6deaeecSLang Hames       FileInfo.SectionInfos[Sec.getName()] = {
1950269a407SLang Hames           ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
1969c017a99SEymen Ünay           SecAddr.getValue(), FirstSym->getTargetFlags()};
197a6deaeecSLang Hames   }
198a6deaeecSLang Hames 
199a6deaeecSLang Hames   return Error::success();
200a6deaeecSLang Hames }
201a6deaeecSLang Hames 
202a6deaeecSLang Hames } // end namespace llvm
203