xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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 
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>
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>
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>
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>
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>
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>
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