xref: /llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp (revision 096551537b2a747a3387726ca618ceeb3950e9bc)
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 bool isELFAArch32StubsSection(Section &S) {
28   return S.getName().starts_with("__llvm_jitlink_aarch32_STUBS_");
29 }
30 
31 static 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 
42 static 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 
57 static 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 
75 static 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 
82 enum SectionType { GOT, Stubs, AArch32Stubs, Other };
83 
84 static 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 symbol
90     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 
101 namespace llvm {
102 
103 Error registerELFGraphInfo(Session &S, LinkGraph &G) {
104   std::lock_guard<std::mutex> Lock(S.M);
105 
106   auto FileName = sys::path::filename(G.getName());
107   if (S.FileInfos.count(FileName)) {
108     return make_error<StringError>("When -check is passed, file names must be "
109                                    "distinct (duplicate: \"" +
110                                        FileName + "\")",
111                                    inconvertibleErrorCode());
112   }
113 
114   auto &FileInfo = S.FileInfos[FileName];
115   LLVM_DEBUG({
116     dbgs() << "Registering ELF file info for \"" << FileName << "\"\n";
117   });
118   for (auto &Sec : G.sections()) {
119     LLVM_DEBUG({
120       dbgs() << "  Section \"" << Sec.getName() << "\": "
121              << (Sec.symbols().empty() ? "empty. skipping." : "processing...")
122              << "\n";
123     });
124 
125     // Skip empty sections.
126     if (Sec.symbols().empty())
127       continue;
128 
129     if (FileInfo.SectionInfos.count(Sec.getName()))
130       return make_error<StringError>("Encountered duplicate section name \"" +
131                                          Sec.getName() + "\" in \"" + FileName +
132                                          "\"",
133                                      inconvertibleErrorCode());
134 
135     SectionType SecType;
136     if (isELFGOTSection(Sec)) {
137       SecType = GOT;
138     } else if (isELFStubsSection(Sec)) {
139       SecType = Stubs;
140     } else if (isELFAArch32StubsSection(Sec)) {
141       SecType = AArch32Stubs;
142     } else {
143       SecType = Other;
144     }
145 
146     bool SectionContainsContent = false;
147     bool SectionContainsZeroFill = false;
148 
149     auto *FirstSym = *Sec.symbols().begin();
150     auto *LastSym = FirstSym;
151     for (auto *Sym : Sec.symbols()) {
152       if (Sym->getAddress() < FirstSym->getAddress())
153         FirstSym = Sym;
154       if (Sym->getAddress() > LastSym->getAddress())
155         LastSym = Sym;
156 
157       if (SecType != Other) {
158         if (Error Err = registerSymbol(G, *Sym, FileInfo, SecType))
159           return Err;
160         SectionContainsContent = true;
161       }
162 
163       if (Sym->hasName()) {
164         if (Sym->isSymbolZeroFill()) {
165           S.SymbolInfos[Sym->getName()] = {Sym->getSize(),
166                                            Sym->getAddress().getValue()};
167           SectionContainsZeroFill = true;
168         } else {
169           S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(),
170                                            Sym->getAddress().getValue(),
171                                            Sym->getTargetFlags()};
172           SectionContainsContent = true;
173         }
174       }
175     }
176 
177     // Add symbol info for absolute symbols.
178     for (auto *Sym : G.absolute_symbols())
179       S.SymbolInfos[Sym->getName()] = {Sym->getSize(),
180                                        Sym->getAddress().getValue()};
181 
182     auto SecAddr = FirstSym->getAddress();
183     auto SecSize =
184         (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) -
185         SecAddr;
186 
187     if (SectionContainsZeroFill && SectionContainsContent)
188       return make_error<StringError>("Mixed zero-fill and content sections not "
189                                      "supported yet",
190                                      inconvertibleErrorCode());
191     if (SectionContainsZeroFill)
192       FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()};
193     else
194       FileInfo.SectionInfos[Sec.getName()] = {
195           ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
196           SecAddr.getValue(), FirstSym->getTargetFlags()};
197   }
198 
199   return Error::success();
200 }
201 
202 } // end namespace llvm
203