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