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