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
23namespace llvm {
24namespace orc {
25
26void 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
41static Expected<MaterializationUnit::Interface>
42getMachOObjectFileSymbolInfo(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
98static Expected<MaterializationUnit::Interface>
99getELFObjectFileSymbolInfo(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
152static Expected<MaterializationUnit::Interface>
153getCOFFObjectFileSymbolInfo(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
234Expected<MaterializationUnit::Interface>
235getGenericObjectFileSymbolInfo(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
274Expected<MaterializationUnit::Interface>
275getObjectFileInterface(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