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