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
20using namespace llvm;
21using namespace llvm::jitlink;
22
23static bool isELFGOTSection(Section &S) { return S.getName() == "$__GOT"; }
24
25static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
26
27static bool isELFAArch32StubsSection(Section &S) {
28 return S.getName().starts_with(Prefix: "__llvm_jitlink_aarch32_STUBS_");
29}
30
31static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
32 auto EItr =
33 llvm::find_if(Range: B.edges(), P: [](Edge &E) { return E.isRelocation(); });
34 if (EItr == B.edges().end())
35 return make_error<StringError>(Args: "GOT entry in " + G.getName() + ", \"" +
36 B.getSection().getName() +
37 "\" has no relocations",
38 Args: inconvertibleErrorCode());
39 return *EItr;
40}
41
42static 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 Args: "GOT entry in " + G.getName() + ", \"" +
50 TargetSym.getBlock().getSection().getName() +
51 "\" points to anonymous "
52 "symbol",
53 Args: inconvertibleErrorCode());
54 return TargetSym;
55}
56
57static 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>(Args: "Stubs entry in " + G.getName() +
64 " does not point to GOT entry",
65 Args: inconvertibleErrorCode());
66 if (!isELFGOTSection(S&: GOTSym.getBlock().getSection()))
67 return make_error<StringError>(
68 Args: "Stubs entry in " + G.getName() + ", \"" +
69 GOTSym.getBlock().getSection().getName() +
70 "\" does not point to GOT entry",
71 Args: inconvertibleErrorCode());
72 return getELFGOTTarget(G, B&: GOTSym.getBlock());
73}
74
75static 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
82enum SectionType { GOT, Stubs, AArch32Stubs, Other };
83
84static 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, GetSymbolTarget: getELFGOTTarget);
91 case Stubs:
92 return FI.registerStubEntry(G, Sym, GetSymbolTarget: getELFStubTarget);
93 case AArch32Stubs:
94 return FI.registerMultiStubEntry(G, Sym, GetSymbolTarget: getELFAArch32StubTarget);
95 case Other:
96 return Error::success();
97 }
98 llvm_unreachable("Unhandled SectionType enum");
99}
100
101namespace llvm {
102
103Error registerELFGraphInfo(Session &S, LinkGraph &G) {
104 auto FileName = sys::path::filename(path: G.getName());
105 if (S.FileInfos.count(Key: FileName)) {
106 return make_error<StringError>(Args: "When -check is passed, file names must be "
107 "distinct (duplicate: \"" +
108 FileName + "\")",
109 Args: 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(Key: Sec.getName()))
128 return make_error<StringError>(Args: "Encountered duplicate section name \"" +
129 Sec.getName() + "\" in \"" + FileName +
130 "\"",
131 Args: inconvertibleErrorCode());
132
133 SectionType SecType;
134 if (isELFGOTSection(S&: Sec)) {
135 SecType = GOT;
136 } else if (isELFStubsSection(S&: Sec)) {
137 SecType = Stubs;
138 } else if (isELFAArch32StubsSection(S&: 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&: *Sym, FI&: 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>(Args: "Mixed zero-fill and content sections not "
187 "supported yet",
188 Args: 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