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
21 namespace llvm {
22 namespace orc {
23
addInitSymbol(MaterializationUnit::Interface & I,ExecutionSession & ES,StringRef ObjFileName)24 void 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(InitSymString);
34 } while (I.SymbolFlags.count(I.InitSymbol));
35
36 I.SymbolFlags[I.InitSymbol] = JITSymbolFlags::MaterializationSideEffectsOnly;
37 }
38
39 static Expected<MaterializationUnit::Interface>
getMachOObjectFileSymbolInfo(ExecutionSession & ES,const object::MachOObjectFile & Obj)40 getMachOObjectFileSymbolInfo(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(Sym);
69 if (!SymFlags)
70 return SymFlags.takeError();
71
72 // Strip the 'exported' flag from MachO linker-private symbols.
73 if (Name->starts_with("l"))
74 *SymFlags &= ~JITSymbolFlags::Exported;
75
76 I.SymbolFlags[ES.intern(*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, Obj.getFileName());
83 break;
84 }
85 auto SegName = Obj.getSectionFinalSegmentName(Sec.getRawDataRefImpl());
86 auto SecName = cantFail(Obj.getSectionName(Sec.getRawDataRefImpl()));
87 if (isMachOInitializerSection(SegName, SecName)) {
88 addInitSymbol(I, ES, Obj.getFileName());
89 break;
90 }
91 }
92
93 return I;
94 }
95
96 static Expected<MaterializationUnit::Interface>
getELFObjectFileSymbolInfo(ExecutionSession & ES,const object::ELFObjectFileBase & Obj)97 getELFObjectFileSymbolInfo(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(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(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)) {
141 addInitSymbol(I, ES, Obj.getFileName());
142 break;
143 }
144 }
145 }
146
147 return I;
148 }
149
150 static Expected<MaterializationUnit::Interface>
getCOFFObjectFileSymbolInfo(ExecutionSession & ES,const object::COFFObjectFile & Obj)151 getCOFFObjectFileSymbolInfo(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(Sym);
164 bool IsWeak = false;
165 if (auto *Def = COFFSym.getSectionDefinition()) {
166 auto Sec = Obj.getSection(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(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(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(*Name)] = std::move(*SymFlags);
216 }
217
218 SymbolStringPtr InitSymbol;
219 for (auto &Sec : Obj.sections()) {
220 if (auto SecName = Sec.getName()) {
221 if (isCOFFInitializerSection(*SecName)) {
222 addInitSymbol(I, ES, Obj.getFileName());
223 break;
224 }
225 } else
226 return SecName.takeError();
227 }
228
229 return I;
230 }
231
232 Expected<MaterializationUnit::Interface>
getXCOFFObjectFileSymbolInfo(ExecutionSession & ES,const object::ObjectFile & Obj)233 getXCOFFObjectFileSymbolInfo(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(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(std::move(*Name))] = std::move(*SymFlags);
273 }
274 // TODO: Find all initialization symbols for c++ static initializers
275 return I;
276 }
277
278 Expected<MaterializationUnit::Interface>
getGenericObjectFileSymbolInfo(ExecutionSession & ES,const object::ObjectFile & Obj)279 getGenericObjectFileSymbolInfo(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(Sym);
309 if (!SymFlags)
310 return SymFlags.takeError();
311
312 I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags);
313 }
314
315 return I;
316 }
317
318 Expected<MaterializationUnit::Interface>
getObjectFileInterface(ExecutionSession & ES,MemoryBufferRef ObjBuffer)319 getObjectFileInterface(ExecutionSession &ES, MemoryBufferRef ObjBuffer) {
320 auto Obj = object::ObjectFile::createObjectFile(ObjBuffer);
321
322 if (!Obj)
323 return Obj.takeError();
324
325 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(Obj->get()))
326 return getMachOObjectFileSymbolInfo(ES, *MachOObj);
327 else if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(Obj->get()))
328 return getELFObjectFileSymbolInfo(ES, *ELFObj);
329 else if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj->get()))
330 return getCOFFObjectFileSymbolInfo(ES, *COFFObj);
331 else if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Obj->get()))
332 return getXCOFFObjectFileSymbolInfo(ES, *XCOFFObj);
333
334 return getGenericObjectFileSymbolInfo(ES, **Obj);
335 }
336
337 } // End namespace orc.
338 } // End namespace llvm.
339