1 | //===-- LTOModule.cpp - LLVM Link Time Optimizer --------------------------===// |
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 | // This file implements the Link Time Optimization library. This library is |
10 | // intended to be used by linker to optimize code at link time. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "llvm/LTO/legacy/LTOModule.h" |
15 | #include "llvm/Bitcode/BitcodeReader.h" |
16 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
17 | #include "llvm/IR/Constants.h" |
18 | #include "llvm/IR/LLVMContext.h" |
19 | #include "llvm/IR/Mangler.h" |
20 | #include "llvm/IR/Metadata.h" |
21 | #include "llvm/IR/Module.h" |
22 | #include "llvm/MC/MCExpr.h" |
23 | #include "llvm/MC/MCInst.h" |
24 | #include "llvm/MC/MCSection.h" |
25 | #include "llvm/MC/MCSymbol.h" |
26 | #include "llvm/MC/TargetRegistry.h" |
27 | #include "llvm/Object/IRObjectFile.h" |
28 | #include "llvm/Object/MachO.h" |
29 | #include "llvm/Object/ObjectFile.h" |
30 | #include "llvm/Support/FileSystem.h" |
31 | #include "llvm/Support/MemoryBuffer.h" |
32 | #include "llvm/Support/SourceMgr.h" |
33 | #include "llvm/Target/TargetLoweringObjectFile.h" |
34 | #include "llvm/TargetParser/Host.h" |
35 | #include "llvm/TargetParser/SubtargetFeature.h" |
36 | #include "llvm/TargetParser/Triple.h" |
37 | #include "llvm/Transforms/Utils/GlobalStatus.h" |
38 | #include <system_error> |
39 | using namespace llvm; |
40 | using namespace llvm::object; |
41 | |
42 | LTOModule::LTOModule(std::unique_ptr<Module> M, MemoryBufferRef MBRef, |
43 | llvm::TargetMachine *TM) |
44 | : Mod(std::move(M)), MBRef(MBRef), _target(TM) { |
45 | assert(_target && "target machine is null" ); |
46 | SymTab.addModule(M: Mod.get()); |
47 | } |
48 | |
49 | LTOModule::~LTOModule() = default; |
50 | |
51 | /// isBitcodeFile - Returns 'true' if the file (or memory contents) is LLVM |
52 | /// bitcode. |
53 | bool LTOModule::isBitcodeFile(const void *Mem, size_t Length) { |
54 | Expected<MemoryBufferRef> BCData = IRObjectFile::findBitcodeInMemBuffer( |
55 | Object: MemoryBufferRef(StringRef((const char *)Mem, Length), "<mem>" )); |
56 | return !errorToBool(Err: BCData.takeError()); |
57 | } |
58 | |
59 | bool LTOModule::isBitcodeFile(StringRef Path) { |
60 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = |
61 | MemoryBuffer::getFile(Filename: Path); |
62 | if (!BufferOrErr) |
63 | return false; |
64 | |
65 | Expected<MemoryBufferRef> BCData = IRObjectFile::findBitcodeInMemBuffer( |
66 | Object: BufferOrErr.get()->getMemBufferRef()); |
67 | return !errorToBool(Err: BCData.takeError()); |
68 | } |
69 | |
70 | bool LTOModule::isThinLTO() { |
71 | Expected<BitcodeLTOInfo> Result = getBitcodeLTOInfo(Buffer: MBRef); |
72 | if (!Result) { |
73 | logAllUnhandledErrors(E: Result.takeError(), OS&: errs()); |
74 | return false; |
75 | } |
76 | return Result->IsThinLTO; |
77 | } |
78 | |
79 | bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer, |
80 | StringRef TriplePrefix) { |
81 | Expected<MemoryBufferRef> BCOrErr = |
82 | IRObjectFile::findBitcodeInMemBuffer(Object: Buffer->getMemBufferRef()); |
83 | if (errorToBool(Err: BCOrErr.takeError())) |
84 | return false; |
85 | LLVMContext Context; |
86 | ErrorOr<std::string> TripleOrErr = |
87 | expectedToErrorOrAndEmitErrors(Ctx&: Context, Val: getBitcodeTargetTriple(Buffer: *BCOrErr)); |
88 | if (!TripleOrErr) |
89 | return false; |
90 | return StringRef(*TripleOrErr).starts_with(Prefix: TriplePrefix); |
91 | } |
92 | |
93 | std::string LTOModule::getProducerString(MemoryBuffer *Buffer) { |
94 | Expected<MemoryBufferRef> BCOrErr = |
95 | IRObjectFile::findBitcodeInMemBuffer(Object: Buffer->getMemBufferRef()); |
96 | if (errorToBool(Err: BCOrErr.takeError())) |
97 | return "" ; |
98 | LLVMContext Context; |
99 | ErrorOr<std::string> ProducerOrErr = expectedToErrorOrAndEmitErrors( |
100 | Ctx&: Context, Val: getBitcodeProducerString(Buffer: *BCOrErr)); |
101 | if (!ProducerOrErr) |
102 | return "" ; |
103 | return *ProducerOrErr; |
104 | } |
105 | |
106 | ErrorOr<std::unique_ptr<LTOModule>> |
107 | LTOModule::createFromFile(LLVMContext &Context, StringRef path, |
108 | const TargetOptions &options) { |
109 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = |
110 | MemoryBuffer::getFile(Filename: path); |
111 | if (std::error_code EC = BufferOrErr.getError()) { |
112 | Context.emitError(ErrorStr: EC.message()); |
113 | return EC; |
114 | } |
115 | std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOrErr.get()); |
116 | return makeLTOModule(Buffer: Buffer->getMemBufferRef(), options, Context, |
117 | /* ShouldBeLazy*/ false); |
118 | } |
119 | |
120 | ErrorOr<std::unique_ptr<LTOModule>> |
121 | LTOModule::createFromOpenFile(LLVMContext &Context, int fd, StringRef path, |
122 | size_t size, const TargetOptions &options) { |
123 | return createFromOpenFileSlice(Context, fd, path, map_size: size, offset: 0, options); |
124 | } |
125 | |
126 | ErrorOr<std::unique_ptr<LTOModule>> |
127 | LTOModule::createFromOpenFileSlice(LLVMContext &Context, int fd, StringRef path, |
128 | size_t map_size, off_t offset, |
129 | const TargetOptions &options) { |
130 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = |
131 | MemoryBuffer::getOpenFileSlice(FD: sys::fs::convertFDToNativeFile(FD: fd), Filename: path, |
132 | MapSize: map_size, Offset: offset); |
133 | if (std::error_code EC = BufferOrErr.getError()) { |
134 | Context.emitError(ErrorStr: EC.message()); |
135 | return EC; |
136 | } |
137 | std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOrErr.get()); |
138 | return makeLTOModule(Buffer: Buffer->getMemBufferRef(), options, Context, |
139 | /* ShouldBeLazy */ false); |
140 | } |
141 | |
142 | ErrorOr<std::unique_ptr<LTOModule>> |
143 | LTOModule::createFromBuffer(LLVMContext &Context, const void *mem, |
144 | size_t length, const TargetOptions &options, |
145 | StringRef path) { |
146 | StringRef Data((const char *)mem, length); |
147 | MemoryBufferRef Buffer(Data, path); |
148 | return makeLTOModule(Buffer, options, Context, /* ShouldBeLazy */ false); |
149 | } |
150 | |
151 | ErrorOr<std::unique_ptr<LTOModule>> |
152 | LTOModule::createInLocalContext(std::unique_ptr<LLVMContext> Context, |
153 | const void *mem, size_t length, |
154 | const TargetOptions &options, StringRef path) { |
155 | StringRef Data((const char *)mem, length); |
156 | MemoryBufferRef Buffer(Data, path); |
157 | // If we own a context, we know this is being used only for symbol extraction, |
158 | // not linking. Be lazy in that case. |
159 | ErrorOr<std::unique_ptr<LTOModule>> Ret = |
160 | makeLTOModule(Buffer, options, Context&: *Context, /* ShouldBeLazy */ true); |
161 | if (Ret) |
162 | (*Ret)->OwnedContext = std::move(Context); |
163 | return Ret; |
164 | } |
165 | |
166 | static ErrorOr<std::unique_ptr<Module>> |
167 | parseBitcodeFileImpl(MemoryBufferRef Buffer, LLVMContext &Context, |
168 | bool ShouldBeLazy) { |
169 | // Find the buffer. |
170 | Expected<MemoryBufferRef> MBOrErr = |
171 | IRObjectFile::findBitcodeInMemBuffer(Object: Buffer); |
172 | if (Error E = MBOrErr.takeError()) { |
173 | std::error_code EC = errorToErrorCode(Err: std::move(E)); |
174 | Context.emitError(ErrorStr: EC.message()); |
175 | return EC; |
176 | } |
177 | |
178 | if (!ShouldBeLazy) { |
179 | // Parse the full file. |
180 | return expectedToErrorOrAndEmitErrors(Ctx&: Context, |
181 | Val: parseBitcodeFile(Buffer: *MBOrErr, Context)); |
182 | } |
183 | |
184 | // Parse lazily. |
185 | return expectedToErrorOrAndEmitErrors( |
186 | Ctx&: Context, |
187 | Val: getLazyBitcodeModule(Buffer: *MBOrErr, Context, ShouldLazyLoadMetadata: true /*ShouldLazyLoadMetadata*/)); |
188 | } |
189 | |
190 | ErrorOr<std::unique_ptr<LTOModule>> |
191 | LTOModule::makeLTOModule(MemoryBufferRef Buffer, const TargetOptions &options, |
192 | LLVMContext &Context, bool ShouldBeLazy) { |
193 | ErrorOr<std::unique_ptr<Module>> MOrErr = |
194 | parseBitcodeFileImpl(Buffer, Context, ShouldBeLazy); |
195 | if (std::error_code EC = MOrErr.getError()) |
196 | return EC; |
197 | std::unique_ptr<Module> &M = *MOrErr; |
198 | |
199 | llvm::Triple Triple = M->getTargetTriple(); |
200 | if (Triple.empty()) |
201 | Triple = llvm::Triple(sys::getDefaultTargetTriple()); |
202 | |
203 | // find machine architecture for this module |
204 | std::string errMsg; |
205 | const Target *march = TargetRegistry::lookupTarget(TheTriple: Triple, Error&: errMsg); |
206 | if (!march) |
207 | return make_error_code(e: object::object_error::arch_not_found); |
208 | |
209 | // construct LTOModule, hand over ownership of module and target |
210 | SubtargetFeatures Features; |
211 | Features.getDefaultSubtargetFeatures(Triple); |
212 | std::string FeatureStr = Features.getString(); |
213 | // Set a default CPU for Darwin triples. |
214 | std::string CPU; |
215 | if (Triple.isOSDarwin()) { |
216 | if (Triple.getArch() == llvm::Triple::x86_64) |
217 | CPU = "core2" ; |
218 | else if (Triple.getArch() == llvm::Triple::x86) |
219 | CPU = "yonah" ; |
220 | else if (Triple.isArm64e()) |
221 | CPU = "apple-a12" ; |
222 | else if (Triple.getArch() == llvm::Triple::aarch64 || |
223 | Triple.getArch() == llvm::Triple::aarch64_32) |
224 | CPU = "cyclone" ; |
225 | } |
226 | |
227 | TargetMachine *target = march->createTargetMachine(TT: Triple, CPU, Features: FeatureStr, |
228 | Options: options, RM: std::nullopt); |
229 | |
230 | std::unique_ptr<LTOModule> Ret(new LTOModule(std::move(M), Buffer, target)); |
231 | Ret->parseSymbols(); |
232 | Ret->parseMetadata(); |
233 | |
234 | return std::move(Ret); |
235 | } |
236 | |
237 | /// Create a MemoryBuffer from a memory range with an optional name. |
238 | std::unique_ptr<MemoryBuffer> |
239 | LTOModule::makeBuffer(const void *mem, size_t length, StringRef name) { |
240 | const char *startPtr = (const char*)mem; |
241 | return MemoryBuffer::getMemBuffer(InputData: StringRef(startPtr, length), BufferName: name, RequiresNullTerminator: false); |
242 | } |
243 | |
244 | /// objcClassNameFromExpression - Get string that the data pointer points to. |
245 | bool |
246 | LTOModule::objcClassNameFromExpression(const Constant *c, std::string &name) { |
247 | if (const ConstantExpr *ce = dyn_cast<ConstantExpr>(Val: c)) { |
248 | Constant *op = ce->getOperand(i_nocapture: 0); |
249 | if (GlobalVariable *gvn = dyn_cast<GlobalVariable>(Val: op)) { |
250 | Constant *cn = gvn->getInitializer(); |
251 | if (ConstantDataArray *ca = dyn_cast<ConstantDataArray>(Val: cn)) { |
252 | if (ca->isCString()) { |
253 | name = (".objc_class_name_" + ca->getAsCString()).str(); |
254 | return true; |
255 | } |
256 | } |
257 | } |
258 | } |
259 | return false; |
260 | } |
261 | |
262 | /// addObjCClass - Parse i386/ppc ObjC class data structure. |
263 | void LTOModule::addObjCClass(const GlobalVariable *clgv) { |
264 | const ConstantStruct *c = dyn_cast<ConstantStruct>(Val: clgv->getInitializer()); |
265 | if (!c) return; |
266 | |
267 | // second slot in __OBJC,__class is pointer to superclass name |
268 | std::string superclassName; |
269 | if (objcClassNameFromExpression(c: c->getOperand(i_nocapture: 1), name&: superclassName)) { |
270 | auto IterBool = _undefines.try_emplace(Key: superclassName); |
271 | if (IterBool.second) { |
272 | NameAndAttributes &info = IterBool.first->second; |
273 | info.name = IterBool.first->first(); |
274 | info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; |
275 | info.isFunction = false; |
276 | info.symbol = clgv; |
277 | } |
278 | } |
279 | |
280 | // third slot in __OBJC,__class is pointer to class name |
281 | std::string className; |
282 | if (objcClassNameFromExpression(c: c->getOperand(i_nocapture: 2), name&: className)) { |
283 | auto Iter = _defines.insert(key: className).first; |
284 | |
285 | NameAndAttributes info; |
286 | info.name = Iter->first(); |
287 | info.attributes = LTO_SYMBOL_PERMISSIONS_DATA | |
288 | LTO_SYMBOL_DEFINITION_REGULAR | LTO_SYMBOL_SCOPE_DEFAULT; |
289 | info.isFunction = false; |
290 | info.symbol = clgv; |
291 | _symbols.push_back(x: info); |
292 | } |
293 | } |
294 | |
295 | /// addObjCCategory - Parse i386/ppc ObjC category data structure. |
296 | void LTOModule::addObjCCategory(const GlobalVariable *clgv) { |
297 | const ConstantStruct *c = dyn_cast<ConstantStruct>(Val: clgv->getInitializer()); |
298 | if (!c) return; |
299 | |
300 | // second slot in __OBJC,__category is pointer to target class name |
301 | std::string targetclassName; |
302 | if (!objcClassNameFromExpression(c: c->getOperand(i_nocapture: 1), name&: targetclassName)) |
303 | return; |
304 | |
305 | auto IterBool = _undefines.try_emplace(Key: targetclassName); |
306 | |
307 | if (!IterBool.second) |
308 | return; |
309 | |
310 | NameAndAttributes &info = IterBool.first->second; |
311 | info.name = IterBool.first->first(); |
312 | info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; |
313 | info.isFunction = false; |
314 | info.symbol = clgv; |
315 | } |
316 | |
317 | /// addObjCClassRef - Parse i386/ppc ObjC class list data structure. |
318 | void LTOModule::addObjCClassRef(const GlobalVariable *clgv) { |
319 | std::string targetclassName; |
320 | if (!objcClassNameFromExpression(c: clgv->getInitializer(), name&: targetclassName)) |
321 | return; |
322 | |
323 | auto IterBool = _undefines.try_emplace(Key: targetclassName); |
324 | |
325 | if (!IterBool.second) |
326 | return; |
327 | |
328 | NameAndAttributes &info = IterBool.first->second; |
329 | info.name = IterBool.first->first(); |
330 | info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; |
331 | info.isFunction = false; |
332 | info.symbol = clgv; |
333 | } |
334 | |
335 | void LTOModule::addDefinedDataSymbol(ModuleSymbolTable::Symbol Sym) { |
336 | SmallString<64> Buffer; |
337 | { |
338 | raw_svector_ostream OS(Buffer); |
339 | SymTab.printSymbolName(OS, S: Sym); |
340 | Buffer.c_str(); |
341 | } |
342 | |
343 | const GlobalValue *V = cast<GlobalValue *>(Val&: Sym); |
344 | addDefinedDataSymbol(Name: Buffer, v: V); |
345 | } |
346 | |
347 | void LTOModule::addDefinedDataSymbol(StringRef Name, const GlobalValue *v) { |
348 | // Add to list of defined symbols. |
349 | addDefinedSymbol(Name, def: v, isFunction: false); |
350 | |
351 | if (!v->hasSection() /* || !isTargetDarwin */) |
352 | return; |
353 | |
354 | // Special case i386/ppc ObjC data structures in magic sections: |
355 | // The issue is that the old ObjC object format did some strange |
356 | // contortions to avoid real linker symbols. For instance, the |
357 | // ObjC class data structure is allocated statically in the executable |
358 | // that defines that class. That data structures contains a pointer to |
359 | // its superclass. But instead of just initializing that part of the |
360 | // struct to the address of its superclass, and letting the static and |
361 | // dynamic linkers do the rest, the runtime works by having that field |
362 | // instead point to a C-string that is the name of the superclass. |
363 | // At runtime the objc initialization updates that pointer and sets |
364 | // it to point to the actual super class. As far as the linker |
365 | // knows it is just a pointer to a string. But then someone wanted the |
366 | // linker to issue errors at build time if the superclass was not found. |
367 | // So they figured out a way in mach-o object format to use an absolute |
368 | // symbols (.objc_class_name_Foo = 0) and a floating reference |
369 | // (.reference .objc_class_name_Bar) to cause the linker into erroring when |
370 | // a class was missing. |
371 | // The following synthesizes the implicit .objc_* symbols for the linker |
372 | // from the ObjC data structures generated by the front end. |
373 | |
374 | // special case if this data blob is an ObjC class definition |
375 | if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Val: v)) { |
376 | StringRef Section = GV->getSection(); |
377 | if (Section.starts_with(Prefix: "__OBJC,__class," )) { |
378 | addObjCClass(clgv: GV); |
379 | } |
380 | |
381 | // special case if this data blob is an ObjC category definition |
382 | else if (Section.starts_with(Prefix: "__OBJC,__category," )) { |
383 | addObjCCategory(clgv: GV); |
384 | } |
385 | |
386 | // special case if this data blob is the list of referenced classes |
387 | else if (Section.starts_with(Prefix: "__OBJC,__cls_refs," )) { |
388 | addObjCClassRef(clgv: GV); |
389 | } |
390 | } |
391 | } |
392 | |
393 | void LTOModule::addDefinedFunctionSymbol(ModuleSymbolTable::Symbol Sym) { |
394 | SmallString<64> Buffer; |
395 | { |
396 | raw_svector_ostream OS(Buffer); |
397 | SymTab.printSymbolName(OS, S: Sym); |
398 | Buffer.c_str(); |
399 | } |
400 | |
401 | auto *GV = cast<GlobalValue *>(Val&: Sym); |
402 | assert((isa<Function>(GV) || |
403 | (isa<GlobalAlias>(GV) && |
404 | isa<Function>(cast<GlobalAlias>(GV)->getAliasee()))) && |
405 | "Not function or function alias" ); |
406 | |
407 | addDefinedFunctionSymbol(Name: Buffer, F: GV); |
408 | } |
409 | |
410 | void LTOModule::addDefinedFunctionSymbol(StringRef Name, const GlobalValue *F) { |
411 | // add to list of defined symbols |
412 | addDefinedSymbol(Name, def: F, isFunction: true); |
413 | } |
414 | |
415 | void LTOModule::addDefinedSymbol(StringRef Name, const GlobalValue *def, |
416 | bool isFunction) { |
417 | uint32_t attr = 0; |
418 | if (auto *gv = dyn_cast<GlobalVariable>(Val: def)) |
419 | attr = Log2(A: gv->getAlign().valueOrOne()); |
420 | else if (auto *f = dyn_cast<Function>(Val: def)) |
421 | attr = Log2(A: f->getAlign().valueOrOne()); |
422 | |
423 | // set permissions part |
424 | if (isFunction) { |
425 | attr |= LTO_SYMBOL_PERMISSIONS_CODE; |
426 | } else { |
427 | const GlobalVariable *gv = dyn_cast<GlobalVariable>(Val: def); |
428 | if (gv && gv->isConstant()) |
429 | attr |= LTO_SYMBOL_PERMISSIONS_RODATA; |
430 | else |
431 | attr |= LTO_SYMBOL_PERMISSIONS_DATA; |
432 | } |
433 | |
434 | // set definition part |
435 | if (def->hasWeakLinkage() || def->hasLinkOnceLinkage()) |
436 | attr |= LTO_SYMBOL_DEFINITION_WEAK; |
437 | else if (def->hasCommonLinkage()) |
438 | attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; |
439 | else |
440 | attr |= LTO_SYMBOL_DEFINITION_REGULAR; |
441 | |
442 | // set scope part |
443 | if (def->hasLocalLinkage()) |
444 | // Ignore visibility if linkage is local. |
445 | attr |= LTO_SYMBOL_SCOPE_INTERNAL; |
446 | else if (def->hasHiddenVisibility()) |
447 | attr |= LTO_SYMBOL_SCOPE_HIDDEN; |
448 | else if (def->hasProtectedVisibility()) |
449 | attr |= LTO_SYMBOL_SCOPE_PROTECTED; |
450 | else if (def->canBeOmittedFromSymbolTable()) |
451 | attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; |
452 | else |
453 | attr |= LTO_SYMBOL_SCOPE_DEFAULT; |
454 | |
455 | if (def->hasComdat()) |
456 | attr |= LTO_SYMBOL_COMDAT; |
457 | |
458 | if (isa<GlobalAlias>(Val: def)) |
459 | attr |= LTO_SYMBOL_ALIAS; |
460 | |
461 | auto Iter = _defines.insert(key: Name).first; |
462 | |
463 | // fill information structure |
464 | NameAndAttributes info; |
465 | StringRef NameRef = Iter->first(); |
466 | info.name = NameRef; |
467 | assert(NameRef.data()[NameRef.size()] == '\0'); |
468 | info.attributes = attr; |
469 | info.isFunction = isFunction; |
470 | info.symbol = def; |
471 | |
472 | // add to table of symbols |
473 | _symbols.push_back(x: info); |
474 | } |
475 | |
476 | /// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the |
477 | /// defined list. |
478 | void LTOModule::addAsmGlobalSymbol(StringRef name, |
479 | lto_symbol_attributes scope) { |
480 | auto IterBool = _defines.insert(key: name); |
481 | |
482 | // only add new define if not already defined |
483 | if (!IterBool.second) |
484 | return; |
485 | |
486 | NameAndAttributes &info = _undefines[IterBool.first->first()]; |
487 | |
488 | if (info.symbol == nullptr) { |
489 | // FIXME: This is trying to take care of module ASM like this: |
490 | // |
491 | // module asm ".zerofill __FOO, __foo, _bar_baz_qux, 0" |
492 | // |
493 | // but is gross and its mother dresses it funny. Have the ASM parser give us |
494 | // more details for this type of situation so that we're not guessing so |
495 | // much. |
496 | |
497 | // fill information structure |
498 | info.name = IterBool.first->first(); |
499 | info.attributes = |
500 | LTO_SYMBOL_PERMISSIONS_DATA | LTO_SYMBOL_DEFINITION_REGULAR | scope; |
501 | info.isFunction = false; |
502 | info.symbol = nullptr; |
503 | |
504 | // add to table of symbols |
505 | _symbols.push_back(x: info); |
506 | return; |
507 | } |
508 | |
509 | if (info.isFunction) |
510 | addDefinedFunctionSymbol(Name: info.name, F: cast<Function>(Val: info.symbol)); |
511 | else |
512 | addDefinedDataSymbol(Name: info.name, v: info.symbol); |
513 | |
514 | _symbols.back().attributes &= ~LTO_SYMBOL_SCOPE_MASK; |
515 | _symbols.back().attributes |= scope; |
516 | } |
517 | |
518 | /// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to the |
519 | /// undefined list. |
520 | void LTOModule::addAsmGlobalSymbolUndef(StringRef name) { |
521 | auto IterBool = _undefines.try_emplace(Key: name); |
522 | |
523 | _asm_undefines.push_back(x: IterBool.first->first()); |
524 | |
525 | // we already have the symbol |
526 | if (!IterBool.second) |
527 | return; |
528 | |
529 | uint32_t attr = LTO_SYMBOL_DEFINITION_UNDEFINED; |
530 | attr |= LTO_SYMBOL_SCOPE_DEFAULT; |
531 | NameAndAttributes &info = IterBool.first->second; |
532 | info.name = IterBool.first->first(); |
533 | info.attributes = attr; |
534 | info.isFunction = false; |
535 | info.symbol = nullptr; |
536 | } |
537 | |
538 | /// Add a symbol which isn't defined just yet to a list to be resolved later. |
539 | void LTOModule::addPotentialUndefinedSymbol(ModuleSymbolTable::Symbol Sym, |
540 | bool isFunc) { |
541 | SmallString<64> name; |
542 | { |
543 | raw_svector_ostream OS(name); |
544 | SymTab.printSymbolName(OS, S: Sym); |
545 | name.c_str(); |
546 | } |
547 | |
548 | auto IterBool = _undefines.try_emplace(Key: name.str()); |
549 | |
550 | // we already have the symbol |
551 | if (!IterBool.second) |
552 | return; |
553 | |
554 | NameAndAttributes &info = IterBool.first->second; |
555 | |
556 | info.name = IterBool.first->first(); |
557 | |
558 | const GlobalValue *decl = dyn_cast_if_present<GlobalValue *>(Val&: Sym); |
559 | |
560 | if (decl->hasExternalWeakLinkage()) |
561 | info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; |
562 | else |
563 | info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; |
564 | |
565 | info.isFunction = isFunc; |
566 | info.symbol = decl; |
567 | } |
568 | |
569 | void LTOModule::parseSymbols() { |
570 | for (auto Sym : SymTab.symbols()) { |
571 | auto *GV = dyn_cast_if_present<GlobalValue *>(Val&: Sym); |
572 | uint32_t Flags = SymTab.getSymbolFlags(S: Sym); |
573 | if (Flags & object::BasicSymbolRef::SF_FormatSpecific) |
574 | continue; |
575 | |
576 | bool IsUndefined = Flags & object::BasicSymbolRef::SF_Undefined; |
577 | |
578 | if (!GV) { |
579 | SmallString<64> Buffer; |
580 | { |
581 | raw_svector_ostream OS(Buffer); |
582 | SymTab.printSymbolName(OS, S: Sym); |
583 | Buffer.c_str(); |
584 | } |
585 | StringRef Name = Buffer; |
586 | |
587 | if (IsUndefined) |
588 | addAsmGlobalSymbolUndef(name: Name); |
589 | else if (Flags & object::BasicSymbolRef::SF_Global) |
590 | addAsmGlobalSymbol(name: Name, scope: LTO_SYMBOL_SCOPE_DEFAULT); |
591 | else |
592 | addAsmGlobalSymbol(name: Name, scope: LTO_SYMBOL_SCOPE_INTERNAL); |
593 | continue; |
594 | } |
595 | |
596 | auto *F = dyn_cast<Function>(Val: GV); |
597 | if (IsUndefined) { |
598 | addPotentialUndefinedSymbol(Sym, isFunc: F != nullptr); |
599 | continue; |
600 | } |
601 | |
602 | if (F) { |
603 | addDefinedFunctionSymbol(Sym); |
604 | continue; |
605 | } |
606 | |
607 | if (isa<GlobalVariable>(Val: GV)) { |
608 | addDefinedDataSymbol(Sym); |
609 | continue; |
610 | } |
611 | |
612 | assert(isa<GlobalAlias>(GV)); |
613 | |
614 | if (isa<Function>(Val: cast<GlobalAlias>(Val: GV)->getAliasee())) |
615 | addDefinedFunctionSymbol(Sym); |
616 | else |
617 | addDefinedDataSymbol(Sym); |
618 | } |
619 | |
620 | // make symbols for all undefines |
621 | for (StringMap<NameAndAttributes>::iterator u =_undefines.begin(), |
622 | e = _undefines.end(); u != e; ++u) { |
623 | // If this symbol also has a definition, then don't make an undefine because |
624 | // it is a tentative definition. |
625 | if (_defines.count(Key: u->getKey())) continue; |
626 | NameAndAttributes info = u->getValue(); |
627 | _symbols.push_back(x: info); |
628 | } |
629 | } |
630 | |
631 | /// parseMetadata - Parse metadata from the module |
632 | void LTOModule::parseMetadata() { |
633 | raw_string_ostream OS(LinkerOpts); |
634 | |
635 | // Linker Options |
636 | if (NamedMDNode *LinkerOptions = |
637 | getModule().getNamedMetadata(Name: "llvm.linker.options" )) { |
638 | for (unsigned i = 0, e = LinkerOptions->getNumOperands(); i != e; ++i) { |
639 | MDNode *MDOptions = LinkerOptions->getOperand(i); |
640 | for (unsigned ii = 0, ie = MDOptions->getNumOperands(); ii != ie; ++ii) { |
641 | MDString *MDOption = cast<MDString>(Val: MDOptions->getOperand(I: ii)); |
642 | OS << " " << MDOption->getString(); |
643 | } |
644 | } |
645 | } |
646 | |
647 | // Globals - we only need to do this for COFF. |
648 | const Triple TT(_target->getTargetTriple()); |
649 | if (!TT.isOSBinFormatCOFF()) |
650 | return; |
651 | Mangler M; |
652 | for (const NameAndAttributes &Sym : _symbols) { |
653 | if (!Sym.symbol) |
654 | continue; |
655 | emitLinkerFlagsForGlobalCOFF(OS, GV: Sym.symbol, TT, Mangler&: M); |
656 | } |
657 | } |
658 | |
659 | lto::InputFile *LTOModule::createInputFile(const void *buffer, |
660 | size_t buffer_size, const char *path, |
661 | std::string &outErr) { |
662 | StringRef Data((const char *)buffer, buffer_size); |
663 | MemoryBufferRef BufferRef(Data, path); |
664 | |
665 | Expected<std::unique_ptr<lto::InputFile>> ObjOrErr = |
666 | lto::InputFile::create(Object: BufferRef); |
667 | |
668 | if (ObjOrErr) |
669 | return ObjOrErr->release(); |
670 | |
671 | outErr = std::string(path) + |
672 | ": Could not read LTO input file: " + toString(E: ObjOrErr.takeError()); |
673 | return nullptr; |
674 | } |
675 | |
676 | size_t LTOModule::getDependentLibraryCount(lto::InputFile *input) { |
677 | return input->getDependentLibraries().size(); |
678 | } |
679 | |
680 | const char *LTOModule::getDependentLibrary(lto::InputFile *input, size_t index, |
681 | size_t *size) { |
682 | StringRef S = input->getDependentLibraries()[index]; |
683 | *size = S.size(); |
684 | return S.data(); |
685 | } |
686 | |
687 | Expected<uint32_t> LTOModule::getMachOCPUType() const { |
688 | return MachO::getCPUType(T: Mod->getTargetTriple()); |
689 | } |
690 | |
691 | Expected<uint32_t> LTOModule::getMachOCPUSubType() const { |
692 | return MachO::getCPUSubType(T: Mod->getTargetTriple()); |
693 | } |
694 | |
695 | bool LTOModule::hasCtorDtor() const { |
696 | for (auto Sym : SymTab.symbols()) { |
697 | if (auto *GV = dyn_cast_if_present<GlobalValue *>(Val&: Sym)) { |
698 | StringRef Name = GV->getName(); |
699 | if (Name.consume_front(Prefix: "llvm.global_" )) { |
700 | if (Name == "ctors" || Name == "dtors" ) |
701 | return true; |
702 | } |
703 | } |
704 | } |
705 | return false; |
706 | } |
707 | |