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(SymName: InitSymString); |
36 | } while (I.SymbolFlags.count(Val: 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(Symbol: Sym); |
71 | if (!SymFlags) |
72 | return SymFlags.takeError(); |
73 | |
74 | // Strip the 'exported' flag from MachO linker-private symbols. |
75 | if (Name->starts_with(Prefix: "l" )) |
76 | *SymFlags &= ~JITSymbolFlags::Exported; |
77 | |
78 | I.SymbolFlags[ES.intern(SymName: *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, ObjFileName: Obj.getFileName()); |
85 | break; |
86 | } |
87 | auto SegName = Obj.getSectionFinalSegmentName(Sec: Sec.getRawDataRefImpl()); |
88 | auto SecName = cantFail(ValOrErr: Obj.getSectionName(Sec: Sec.getRawDataRefImpl())); |
89 | if (isMachOInitializerSection(SegName, SecName)) { |
90 | addInitSymbol(I, ES, ObjFileName: 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(Symbol: 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(SymName: *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: *SecName)) { |
143 | addInitSymbol(I, ES, ObjFileName: 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(Symbol: Sym); |
166 | bool IsWeak = false; |
167 | if (auto *Def = COFFSym.getSectionDefinition()) { |
168 | auto Sec = Obj.getSection(index: 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(SectionNumber: 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(Symbol: 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(SymName: *Name)] = std::move(*SymFlags); |
218 | } |
219 | |
220 | SymbolStringPtr InitSymbol; |
221 | for (auto &Sec : Obj.sections()) { |
222 | if (auto SecName = Sec.getName()) { |
223 | if (isCOFFInitializerSection(Name: *SecName)) { |
224 | addInitSymbol(I, ES, ObjFileName: 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(Symbol: Sym); |
265 | if (!SymFlags) |
266 | return SymFlags.takeError(); |
267 | |
268 | I.SymbolFlags[ES.intern(SymName: *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(Object: ObjBuffer); |
277 | |
278 | if (!Obj) |
279 | return Obj.takeError(); |
280 | |
281 | if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(Val: Obj->get())) |
282 | return getMachOObjectFileSymbolInfo(ES, Obj: *MachOObj); |
283 | else if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(Val: Obj->get())) |
284 | return getELFObjectFileSymbolInfo(ES, Obj: *ELFObj); |
285 | else if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Val: Obj->get())) |
286 | return getCOFFObjectFileSymbolInfo(ES, Obj: *COFFObj); |
287 | |
288 | return getGenericObjectFileSymbolInfo(ES, Obj: **Obj); |
289 | } |
290 | |
291 | } // End namespace orc. |
292 | } // End namespace llvm. |
293 | |