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
addInitSymbol(MaterializationUnit::Interface & I,ExecutionSession & ES,StringRef ObjFileName)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>
getMachOObjectFileSymbolInfo(ExecutionSession & ES,const object::MachOObjectFile & Obj)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->starts_with("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>
getELFObjectFileSymbolInfo(ExecutionSession & ES,const object::ELFObjectFileBase & Obj)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>
getCOFFObjectFileSymbolInfo(ExecutionSession & ES,const object::COFFObjectFile & Obj)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>
getGenericObjectFileSymbolInfo(ExecutionSession & ES,const object::ObjectFile & Obj)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>
getObjectFileInterface(ExecutionSession & ES,MemoryBufferRef ObjBuffer)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