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