1//===------ ObjectFileInterface.cpp - MU interface utils for objects ------===//
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#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
10#include "llvm/ExecutionEngine/JITSymbol.h"
11#include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
12#include "llvm/Object/COFF.h"
13#include "llvm/Object/ELFObjectFile.h"
14#include "llvm/Object/MachO.h"
15#include "llvm/Object/ObjectFile.h"
16#include "llvm/Object/XCOFFObjectFile.h"
17#include <optional>
18
19#define DEBUG_TYPE "orc"
20
21namespace llvm {
22namespace orc {
23
24void addInitSymbol(MaterializationUnit::Interface &I, ExecutionSession &ES,
25 StringRef ObjFileName) {
26 assert(!I.InitSymbol && "I already has an init symbol");
27 size_t Counter = 0;
28
29 do {
30 std::string InitSymString;
31 raw_string_ostream(InitSymString)
32 << "$." << ObjFileName << ".__inits." << Counter++;
33 I.InitSymbol = ES.intern(SymName: InitSymString);
34 } while (I.SymbolFlags.count(Val: I.InitSymbol));
35
36 I.SymbolFlags[I.InitSymbol] = JITSymbolFlags::MaterializationSideEffectsOnly;
37}
38
39static Expected<MaterializationUnit::Interface>
40getMachOObjectFileSymbolInfo(ExecutionSession &ES,
41 const object::MachOObjectFile &Obj) {
42 MaterializationUnit::Interface I;
43
44 for (auto &Sym : Obj.symbols()) {
45 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
46 if (!SymFlagsOrErr)
47 // TODO: Test this error.
48 return SymFlagsOrErr.takeError();
49
50 // Skip symbols not defined in this object file.
51 if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
52 continue;
53
54 // Skip symbols that are not global.
55 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
56 continue;
57
58 // Skip symbols that have type SF_File.
59 if (auto SymType = Sym.getType()) {
60 if (*SymType == object::SymbolRef::ST_File)
61 continue;
62 } else
63 return SymType.takeError();
64
65 auto Name = Sym.getName();
66 if (!Name)
67 return Name.takeError();
68 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Symbol: Sym);
69 if (!SymFlags)
70 return SymFlags.takeError();
71
72 // Strip the 'exported' flag from MachO linker-private symbols.
73 if (Name->starts_with(Prefix: "l"))
74 *SymFlags &= ~JITSymbolFlags::Exported;
75
76 I.SymbolFlags[ES.intern(SymName: *Name)] = std::move(*SymFlags);
77 }
78
79 for (auto &Sec : Obj.sections()) {
80 auto SecType = Obj.getSectionType(Sec);
81 if ((SecType & MachO::SECTION_TYPE) == MachO::S_MOD_INIT_FUNC_POINTERS) {
82 addInitSymbol(I, ES, ObjFileName: Obj.getFileName());
83 break;
84 }
85 auto SegName = Obj.getSectionFinalSegmentName(Sec: Sec.getRawDataRefImpl());
86 auto SecName = cantFail(ValOrErr: Obj.getSectionName(Sec: Sec.getRawDataRefImpl()));
87 if (isMachOInitializerSection(SegName, SecName)) {
88 addInitSymbol(I, ES, ObjFileName: Obj.getFileName());
89 break;
90 }
91 }
92
93 return I;
94}
95
96static Expected<MaterializationUnit::Interface>
97getELFObjectFileSymbolInfo(ExecutionSession &ES,
98 const object::ELFObjectFileBase &Obj) {
99 MaterializationUnit::Interface I;
100
101 for (auto &Sym : Obj.symbols()) {
102 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
103 if (!SymFlagsOrErr)
104 // TODO: Test this error.
105 return SymFlagsOrErr.takeError();
106
107 // Skip symbols not defined in this object file.
108 if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
109 continue;
110
111 // Skip symbols that are not global.
112 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
113 continue;
114
115 // Skip symbols that have type SF_File.
116 if (auto SymType = Sym.getType()) {
117 if (*SymType == object::SymbolRef::ST_File)
118 continue;
119 } else
120 return SymType.takeError();
121
122 auto Name = Sym.getName();
123 if (!Name)
124 return Name.takeError();
125
126 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Symbol: Sym);
127 if (!SymFlags)
128 return SymFlags.takeError();
129
130 // ELF STB_GNU_UNIQUE should map to Weak for ORC.
131 if (Sym.getBinding() == ELF::STB_GNU_UNIQUE)
132 *SymFlags |= JITSymbolFlags::Weak;
133
134 I.SymbolFlags[ES.intern(SymName: std::move(*Name))] = std::move(*SymFlags);
135 }
136
137 SymbolStringPtr InitSymbol;
138 for (auto &Sec : Obj.sections()) {
139 if (auto SecName = Sec.getName()) {
140 if (isELFInitializerSection(SecName: *SecName)) {
141 addInitSymbol(I, ES, ObjFileName: Obj.getFileName());
142 break;
143 }
144 }
145 }
146
147 return I;
148}
149
150static Expected<MaterializationUnit::Interface>
151getCOFFObjectFileSymbolInfo(ExecutionSession &ES,
152 const object::COFFObjectFile &Obj) {
153 MaterializationUnit::Interface I;
154 std::vector<std::optional<object::coff_aux_section_definition>> ComdatDefs(
155 Obj.getNumberOfSections() + 1);
156 for (auto &Sym : Obj.symbols()) {
157 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
158 if (!SymFlagsOrErr)
159 // TODO: Test this error.
160 return SymFlagsOrErr.takeError();
161
162 // Handle comdat symbols
163 auto COFFSym = Obj.getCOFFSymbol(Symbol: Sym);
164 bool IsWeak = false;
165 if (auto *Def = COFFSym.getSectionDefinition()) {
166 auto Sec = Obj.getSection(index: COFFSym.getSectionNumber());
167 if (!Sec)
168 return Sec.takeError();
169 if (((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT) &&
170 Def->Selection != COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
171 ComdatDefs[COFFSym.getSectionNumber()] = *Def;
172 continue;
173 }
174 }
175 if (!COFF::isReservedSectionNumber(SectionNumber: COFFSym.getSectionNumber()) &&
176 ComdatDefs[COFFSym.getSectionNumber()]) {
177 auto Def = ComdatDefs[COFFSym.getSectionNumber()];
178 if (Def->Selection != COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) {
179 IsWeak = true;
180 }
181 ComdatDefs[COFFSym.getSectionNumber()] = std::nullopt;
182 } else {
183 // Skip symbols not defined in this object file.
184 if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
185 continue;
186 }
187
188 // Skip symbols that are not global.
189 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
190 continue;
191
192 // Skip symbols that have type SF_File.
193 if (auto SymType = Sym.getType()) {
194 if (*SymType == object::SymbolRef::ST_File)
195 continue;
196 } else
197 return SymType.takeError();
198
199 auto Name = Sym.getName();
200 if (!Name)
201 return Name.takeError();
202
203 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Symbol: Sym);
204 if (!SymFlags)
205 return SymFlags.takeError();
206 *SymFlags |= JITSymbolFlags::Exported;
207
208 // Weak external is always a function
209 if (COFFSym.isWeakExternal())
210 *SymFlags |= JITSymbolFlags::Callable;
211
212 if (IsWeak)
213 *SymFlags |= JITSymbolFlags::Weak;
214
215 I.SymbolFlags[ES.intern(SymName: *Name)] = std::move(*SymFlags);
216 }
217
218 SymbolStringPtr InitSymbol;
219 for (auto &Sec : Obj.sections()) {
220 if (auto SecName = Sec.getName()) {
221 if (isCOFFInitializerSection(Name: *SecName)) {
222 addInitSymbol(I, ES, ObjFileName: Obj.getFileName());
223 break;
224 }
225 } else
226 return SecName.takeError();
227 }
228
229 return I;
230}
231
232Expected<MaterializationUnit::Interface>
233getXCOFFObjectFileSymbolInfo(ExecutionSession &ES,
234 const object::ObjectFile &Obj) {
235
236 MaterializationUnit::Interface I;
237
238 for (auto &Sym : Obj.symbols()) {
239 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
240 if (!SymFlagsOrErr)
241 return SymFlagsOrErr.takeError();
242 uint32_t Flags = *SymFlagsOrErr;
243
244 // Skip undefined, non global and ST_File
245 if (Flags & object::SymbolRef::SF_Undefined)
246 continue;
247 if (!(Flags & object::SymbolRef::SF_Global))
248 continue;
249
250 auto SymbolType = Sym.getType();
251 if (!SymbolType)
252 return SymbolType.takeError();
253
254 if (*SymbolType == object::SymbolRef::ST_File)
255 continue;
256
257 auto Name = Sym.getName();
258 if (!Name)
259 return Name.takeError();
260 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Symbol: Sym);
261 if (!SymFlags)
262 return SymFlags.takeError();
263
264 // TODO: Revisit symbol visibility
265 // On AIX, symbols with C_EXT and C_WEAKEXT symbols have no specified
266 // visibility are considered to have Default scope for LinkGraph. When the
267 // object is not a DSO, symbol visibility is not specified. In the absence
268 // of an Export List, its reasonable to minimic roughly the behaviour of
269 // -bexpall or CreateExportList.
270 *SymFlags |= JITSymbolFlags::Exported;
271
272 I.SymbolFlags[ES.intern(SymName: std::move(*Name))] = std::move(*SymFlags);
273 }
274 // TODO: Find all initialization symbols for c++ static initializers
275 return I;
276}
277
278Expected<MaterializationUnit::Interface>
279getGenericObjectFileSymbolInfo(ExecutionSession &ES,
280 const object::ObjectFile &Obj) {
281 MaterializationUnit::Interface I;
282
283 for (auto &Sym : Obj.symbols()) {
284 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
285 if (!SymFlagsOrErr)
286 // TODO: Test this error.
287 return SymFlagsOrErr.takeError();
288
289 // Skip symbols not defined in this object file.
290 if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
291 continue;
292
293 // Skip symbols that are not global.
294 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
295 continue;
296
297 // Skip symbols that have type SF_File.
298 if (auto SymType = Sym.getType()) {
299 if (*SymType == object::SymbolRef::ST_File)
300 continue;
301 } else
302 return SymType.takeError();
303
304 auto Name = Sym.getName();
305 if (!Name)
306 return Name.takeError();
307
308 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Symbol: Sym);
309 if (!SymFlags)
310 return SymFlags.takeError();
311
312 I.SymbolFlags[ES.intern(SymName: *Name)] = std::move(*SymFlags);
313 }
314
315 return I;
316}
317
318Expected<MaterializationUnit::Interface>
319getObjectFileInterface(ExecutionSession &ES, MemoryBufferRef ObjBuffer) {
320 auto Obj = object::ObjectFile::createObjectFile(Object: ObjBuffer);
321
322 if (!Obj)
323 return Obj.takeError();
324
325 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(Val: Obj->get()))
326 return getMachOObjectFileSymbolInfo(ES, Obj: *MachOObj);
327 else if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(Val: Obj->get()))
328 return getELFObjectFileSymbolInfo(ES, Obj: *ELFObj);
329 else if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Val: Obj->get()))
330 return getCOFFObjectFileSymbolInfo(ES, Obj: *COFFObj);
331 else if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Val: Obj->get()))
332 return getXCOFFObjectFileSymbolInfo(ES, Obj: *XCOFFObj);
333
334 return getGenericObjectFileSymbolInfo(ES, Obj: **Obj);
335}
336
337} // End namespace orc.
338} // End namespace llvm.
339