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