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