]>
Commit | Line | Data |
---|---|---|
a645023d A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
3 | * Copyright (c) 2006-2010 Apple Inc. All rights reserved. | |
4 | * | |
5 | * @APPLE_LICENSE_HEADER_START@ | |
6 | * | |
7 | * This file contains Original Code and/or Modifications of Original Code | |
8 | * as defined in and that are subject to the Apple Public Source License | |
9 | * Version 2.0 (the 'License'). You may not use this file except in | |
10 | * compliance with the License. Please obtain a copy of the License at | |
11 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
12 | * file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
19 | * Please see the License for the specific language governing rights and | |
20 | * limitations under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | ||
25 | #ifndef __LTO_READER_H__ | |
26 | #define __LTO_READER_H__ | |
27 | ||
28 | #include <stdlib.h> | |
29 | #include <sys/param.h> | |
30 | #include <sys/fcntl.h> | |
82b4b32b | 31 | #include <sys/mman.h> |
a645023d A |
32 | #include <sys/stat.h> |
33 | #include <errno.h> | |
d425e388 | 34 | #include <pthread.h> |
a645023d A |
35 | #include <mach-o/dyld.h> |
36 | #include <vector> | |
eaf282aa | 37 | #include <map> |
d425e388 A |
38 | #include <unordered_set> |
39 | #include <unordered_map> | |
0a8dc3df A |
40 | #include <iostream> |
41 | #include <fstream> | |
a645023d A |
42 | |
43 | #include "MachOFileAbstraction.hpp" | |
44 | #include "Architectures.hpp" | |
45 | #include "ld.hpp" | |
46 | #include "macho_relocatable_file.h" | |
47 | #include "lto_file.h" | |
48 | ||
49 | #include "llvm-c/lto.h" | |
50 | ||
a645023d A |
51 | namespace lto { |
52 | ||
53 | ||
54 | // | |
55 | // ld64 only tracks non-internal symbols from an llvm bitcode file. | |
56 | // We model this by having an InternalAtom which represent all internal functions and data. | |
57 | // All non-interal symbols from a bitcode file are represented by an Atom | |
58 | // and each Atom has a reference to the InternalAtom. The InternalAtom | |
59 | // also has references to each symbol external to the bitcode file. | |
60 | // | |
61 | class InternalAtom : public ld::Atom | |
62 | { | |
63 | public: | |
64 | InternalAtom(class File& f); | |
65 | // overrides of ld::Atom | |
0a8dc3df A |
66 | ld::File* file() const override { return &_file; } |
67 | const char* name() const override { return "import-atom"; } | |
68 | uint64_t size() const override { return 0; } | |
69 | uint64_t objectAddress() const override { return 0; } | |
70 | void copyRawContent(uint8_t buffer[]) const override { } | |
71 | ld::Fixup::iterator fixupsBegin() const override { return &_undefs[0]; } | |
72 | ld::Fixup::iterator fixupsEnd() const override { return &_undefs[_undefs.size()]; } | |
a645023d A |
73 | |
74 | // for adding references to symbols outside bitcode file | |
75 | void addReference(const char* nm) | |
76 | { _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, | |
599556ff | 77 | ld::Fixup::kindNone, false, strdup(nm))); } |
a645023d A |
78 | private: |
79 | ||
80 | ld::File& _file; | |
81 | mutable std::vector<ld::Fixup> _undefs; | |
82 | }; | |
83 | ||
84 | ||
85 | // | |
86 | // LLVM bitcode file | |
87 | // | |
88 | class File : public ld::relocatable::File | |
89 | { | |
90 | public: | |
b1f7435d A |
91 | File(const char* path, time_t mTime, ld::File::Ordinal ordinal, |
92 | const uint8_t* content, uint32_t contentLength, cpu_type_t arch); | |
0a8dc3df | 93 | ~File() override; |
a645023d A |
94 | |
95 | // overrides of ld::File | |
0a8dc3df A |
96 | bool forEachAtom(ld::File::AtomHandler&) const override; |
97 | bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const override | |
a645023d | 98 | { return false; } |
0a8dc3df | 99 | uint32_t cpuSubType() const override { return _cpuSubType; } |
a645023d A |
100 | |
101 | // overrides of ld::relocatable::File | |
0a8dc3df A |
102 | DebugInfoKind debugInfo() const override { return _debugInfo; } |
103 | const char* debugInfoPath() const override { return _debugInfoPath; } | |
104 | time_t debugInfoModificationTime() const override | |
a645023d | 105 | { return _debugInfoModTime; } |
0a8dc3df A |
106 | const std::vector<ld::relocatable::File::Stab>* stabs() const override { return NULL; } |
107 | bool canScatterAtoms() const override { return true; } | |
108 | LinkerOptionsList* linkerOptions() const override { return NULL; } | |
bee7e226 | 109 | const ToolVersionList& toolVersions() const override { return _toolVersions; } |
0a8dc3df A |
110 | bool isThinLTO() const { return _isThinLTO; } |
111 | void setIsThinLTO(bool ThinLTO) { _isThinLTO = ThinLTO; } | |
112 | // fixme rdar://24734472 objCConstraint() and objcHasCategoryClassProperties() | |
599556ff | 113 | void release(); |
a645023d A |
114 | lto_module_t module() { return _module; } |
115 | class InternalAtom& internalAtom() { return _internalAtom; } | |
116 | void setDebugInfo(ld::relocatable::File::DebugInfoKind k, | |
117 | const char* pth, time_t modTime, uint32_t subtype) | |
118 | { _debugInfo = k; | |
119 | _debugInfoPath = pth; | |
120 | _debugInfoModTime = modTime; | |
121 | _cpuSubType = subtype;} | |
122 | ||
eaf282aa A |
123 | static bool sSupportsLocalContext; |
124 | static bool sHasTriedLocalContext; | |
125 | bool mergeIntoGenerator(lto_code_gen_t generator, bool useSetModule); | |
0a8dc3df | 126 | #if LTO_API_VERSION >= 18 |
82b4b32b | 127 | void addToThinGenerator(thinlto_code_gen_t generator, int id); |
0a8dc3df | 128 | #endif |
a645023d A |
129 | private: |
130 | friend class Atom; | |
131 | friend class InternalAtom; | |
132 | friend class Parser; | |
0a8dc3df A |
133 | |
134 | bool _isThinLTO; | |
a645023d A |
135 | cpu_type_t _architecture; |
136 | class InternalAtom _internalAtom; | |
137 | class Atom* _atomArray; | |
138 | uint32_t _atomArrayCount; | |
139 | lto_module_t _module; | |
eaf282aa A |
140 | const char* _path; |
141 | const uint8_t* _content; | |
142 | uint32_t _contentLength; | |
a645023d A |
143 | const char* _debugInfoPath; |
144 | time_t _debugInfoModTime; | |
145 | ld::Section _section; | |
146 | ld::Fixup _fixupToInternal; | |
147 | ld::relocatable::File::DebugInfoKind _debugInfo; | |
148 | uint32_t _cpuSubType; | |
bee7e226 | 149 | ToolVersionList _toolVersions; // unused, may some day contain version of clang the created bitcode |
a645023d A |
150 | }; |
151 | ||
152 | // | |
153 | // Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially, | |
154 | // Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After | |
155 | // optimization is performed, real Atoms are created for these symobls. However these real Atoms | |
156 | // are not inserted into global symbol table. Atom holds real Atom and forwards appropriate | |
157 | // methods to real atom. | |
158 | // | |
159 | class Atom : public ld::Atom | |
160 | { | |
161 | public: | |
162 | Atom(File& f, const char* name, ld::Atom::Scope s, | |
b2fa67a8 | 163 | ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a, bool ah); |
a645023d A |
164 | |
165 | // overrides of ld::Atom | |
0a8dc3df A |
166 | const ld::File* file() const override { return (_compiledAtom ? _compiledAtom->file() : &_file ); } |
167 | const ld::File* originalFile() const override { return &_file; } | |
168 | const char* translationUnitSource() const override | |
b1f7435d | 169 | { return (_compiledAtom ? _compiledAtom->translationUnitSource() : NULL); } |
0a8dc3df A |
170 | const char* name() const override { return _name; } |
171 | uint64_t size() const override { return (_compiledAtom ? _compiledAtom->size() : 0); } | |
172 | uint64_t objectAddress() const override { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); } | |
173 | void copyRawContent(uint8_t buffer[]) const override | |
a645023d | 174 | { if (_compiledAtom) _compiledAtom->copyRawContent(buffer); } |
0a8dc3df | 175 | const uint8_t* rawContentPointer() const override |
a645023d | 176 | { return (_compiledAtom ? _compiledAtom->rawContentPointer() : NULL); } |
0a8dc3df | 177 | unsigned long contentHash(const class ld::IndirectBindingTable& ibt) const override |
a645023d | 178 | { return (_compiledAtom ? _compiledAtom->contentHash(ibt) : 0); } |
0a8dc3df | 179 | bool canCoalesceWith(const ld::Atom& rhs, const class ld::IndirectBindingTable& ibt) const override |
a645023d | 180 | { return (_compiledAtom ? _compiledAtom->canCoalesceWith(rhs,ibt) : false); } |
0a8dc3df | 181 | ld::Fixup::iterator fixupsBegin() const override |
a645023d | 182 | { return (_compiledAtom ? _compiledAtom->fixupsBegin() : (ld::Fixup*)&_file._fixupToInternal); } |
0a8dc3df | 183 | ld::Fixup::iterator fixupsEnd() const override |
a645023d | 184 | { return (_compiledAtom ? _compiledAtom->fixupsEnd() : &((ld::Fixup*)&_file._fixupToInternal)[1]); } |
0a8dc3df | 185 | ld::Atom::UnwindInfo::iterator beginUnwind() const override |
a645023d | 186 | { return (_compiledAtom ? _compiledAtom->beginUnwind() : NULL); } |
0a8dc3df | 187 | ld::Atom::UnwindInfo::iterator endUnwind() const override |
a645023d | 188 | { return (_compiledAtom ? _compiledAtom->endUnwind() : NULL); } |
0a8dc3df | 189 | ld::Atom::LineInfo::iterator beginLineInfo() const override |
a645023d | 190 | { return (_compiledAtom ? _compiledAtom->beginLineInfo() : NULL); } |
0a8dc3df | 191 | ld::Atom::LineInfo::iterator endLineInfo() const override |
a645023d A |
192 | { return (_compiledAtom ? _compiledAtom->endLineInfo() : NULL); } |
193 | ||
194 | const ld::Atom* compiledAtom() { return _compiledAtom; } | |
195 | void setCompiledAtom(const ld::Atom& atom); | |
196 | ||
197 | private: | |
198 | ||
199 | File& _file; | |
200 | const char* _name; | |
201 | const ld::Atom* _compiledAtom; | |
202 | }; | |
203 | ||
204 | ||
205 | ||
206 | ||
207 | ||
208 | ||
209 | ||
210 | class Parser | |
211 | { | |
212 | public: | |
213 | static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch); | |
214 | static const char* fileKind(const uint8_t* fileContent, uint64_t fileLength); | |
215 | static File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, | |
9543cb2f A |
216 | time_t modTime, ld::File::Ordinal ordinal, cpu_type_t architecture, cpu_subtype_t subarch, |
217 | bool logAllFiles, bool verboseOptimizationHints); | |
a645023d A |
218 | static bool libLTOisLoaded() { return (::lto_get_version() != NULL); } |
219 | static bool optimize( const std::vector<const ld::Atom*>& allAtoms, | |
220 | ld::Internal& state, | |
a645023d A |
221 | const OptimizeOptions& options, |
222 | ld::File::AtomHandler& handler, | |
223 | std::vector<const ld::Atom*>& newAtoms, | |
224 | std::vector<const char*>& additionalUndefines); | |
225 | ||
0a8dc3df | 226 | static const char* ltoVersion() { return ::lto_get_version(); } |
a645023d A |
227 | |
228 | private: | |
0a8dc3df | 229 | |
a645023d | 230 | static const char* tripletPrefixForArch(cpu_type_t arch); |
0a8dc3df A |
231 | static ld::relocatable::File* parseMachOFile(const uint8_t* p, size_t len, const std::string &path, const OptimizeOptions& options, |
232 | ld::File::Ordinal ordinal); | |
9543cb2f A |
233 | #if LTO_API_VERSION >= 7 |
234 | static void ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t, const char*, void*); | |
235 | #endif | |
a645023d | 236 | |
d425e388 A |
237 | typedef std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals> CStringSet; |
238 | typedef std::unordered_map<const char*, Atom*, ld::CStringHash, ld::CStringEquals> CStringToAtom; | |
a645023d A |
239 | |
240 | class AtomSyncer : public ld::File::AtomHandler { | |
241 | public: | |
242 | AtomSyncer(std::vector<const char*>& a, std::vector<const ld::Atom*>&na, | |
0a8dc3df A |
243 | const CStringToAtom &la, const CStringToAtom &dla, const OptimizeOptions& options) : |
244 | _options(options), _additionalUndefines(a), _newAtoms(na), _llvmAtoms(la), _deadllvmAtoms(dla), _lastProxiedAtom(NULL), _lastProxiedFile(NULL) {} | |
245 | void doAtom(const class ld::Atom&) override; | |
246 | void doFile(const class ld::File&) override { } | |
a645023d A |
247 | |
248 | const OptimizeOptions& _options; | |
249 | std::vector<const char*>& _additionalUndefines; | |
250 | std::vector<const ld::Atom*>& _newAtoms; | |
0a8dc3df A |
251 | const CStringToAtom &_llvmAtoms; |
252 | const CStringToAtom &_deadllvmAtoms; | |
253 | const ld::Atom* _lastProxiedAtom; | |
254 | const ld::File* _lastProxiedFile; | |
a645023d A |
255 | }; |
256 | ||
0a8dc3df A |
257 | static void setPreservedSymbols(const std::vector<const ld::Atom*>& allAtoms, |
258 | ld::Internal& state, | |
259 | const OptimizeOptions& options, | |
260 | CStringToAtom &deadllvmAtoms, | |
261 | CStringToAtom &llvmAtoms, | |
262 | lto_code_gen_t generator); | |
263 | ||
264 | static std::tuple<uint8_t *, size_t> codegen(const OptimizeOptions& options, | |
265 | ld::Internal& state, | |
266 | lto_code_gen_t generator, | |
267 | std::string& object_path); | |
268 | ||
269 | ||
270 | static void loadMachO(ld::relocatable::File* machoFile, | |
271 | const OptimizeOptions& options, | |
272 | ld::File::AtomHandler& handler, | |
273 | std::vector<const ld::Atom*>& newAtoms, | |
274 | std::vector<const char*>& additionalUndefines, | |
275 | CStringToAtom &llvmAtoms, | |
276 | CStringToAtom &deadllvmAtoms); | |
277 | ||
278 | static bool optimizeLTO(const std::vector<File*> files, | |
279 | const std::vector<const ld::Atom*>& allAtoms, | |
280 | ld::Internal& state, | |
281 | const OptimizeOptions& options, | |
282 | ld::File::AtomHandler& handler, | |
283 | std::vector<const ld::Atom*>& newAtoms, | |
284 | std::vector<const char*>& additionalUndefines); | |
285 | ||
286 | static bool optimizeThinLTO(const std::vector<File*>& Files, | |
287 | const std::vector<const ld::Atom*>& allAtoms, | |
288 | ld::Internal& state, | |
289 | const OptimizeOptions& options, | |
290 | ld::File::AtomHandler& handler, | |
291 | std::vector<const ld::Atom*>& newAtoms, | |
292 | std::vector<const char*>& additionalUndefines); | |
293 | ||
82b4b32b | 294 | #if LTO_API_VERSION >= 18 |
0a8dc3df A |
295 | static thinlto_code_gen_t init_thinlto_codegen(const std::vector<File*>& files, |
296 | const std::vector<const ld::Atom*>& allAtoms, | |
297 | ld::Internal& state, | |
298 | const OptimizeOptions& options, | |
299 | CStringToAtom& deadllvmAtoms, | |
300 | CStringToAtom& llvmAtoms); | |
82b4b32b | 301 | #endif |
0a8dc3df | 302 | |
a645023d | 303 | static std::vector<File*> _s_files; |
0a8dc3df | 304 | static bool _s_llvmOptionsProcessed; |
a645023d A |
305 | }; |
306 | ||
307 | std::vector<File*> Parser::_s_files; | |
0a8dc3df | 308 | bool Parser::_s_llvmOptionsProcessed = false; |
a645023d A |
309 | |
310 | ||
311 | bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch) | |
312 | { | |
ebf6f434 A |
313 | for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) { |
314 | if ( (architecture == t->cpuType) && (!(t->isSubType) || (subarch == t->cpuSubType)) ) { | |
315 | bool result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefix); | |
316 | if ( !result ) { | |
317 | // <rdar://problem/8434487> LTO only supports thumbv7 not armv7 | |
318 | if ( t->llvmTriplePrefixAlt[0] != '\0' ) { | |
319 | result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefixAlt); | |
320 | } | |
a645023d | 321 | } |
ebf6f434 A |
322 | return result; |
323 | } | |
a645023d A |
324 | } |
325 | return false; | |
326 | } | |
327 | ||
328 | const char* Parser::fileKind(const uint8_t* p, uint64_t fileLength) | |
329 | { | |
330 | if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) { | |
ebf6f434 A |
331 | cpu_type_t arch = LittleEndian::get32(*((uint32_t*)(&p[16]))); |
332 | for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) { | |
333 | if ( arch == t->cpuType ) { | |
334 | if ( t->isSubType ) { | |
afe874b1 | 335 | if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, t->llvmTriplePrefix) ) |
ebf6f434 A |
336 | return t->archName; |
337 | } | |
338 | else { | |
339 | return t->archName; | |
afe874b1 | 340 | } |
ebf6f434 | 341 | } |
a645023d A |
342 | } |
343 | return "unknown bitcode architecture"; | |
344 | } | |
345 | return NULL; | |
346 | } | |
347 | ||
b1f7435d | 348 | File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, ld::File::Ordinal ordinal, |
9543cb2f | 349 | cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles, bool verboseOptimizationHints) |
a645023d | 350 | { |
b1f7435d | 351 | File* f = new File(path, modTime, ordinal, fileContent, fileLength, architecture); |
a645023d A |
352 | _s_files.push_back(f); |
353 | if ( logAllFiles ) | |
354 | printf("%s\n", path); | |
355 | return f; | |
356 | } | |
357 | ||
358 | ||
0a8dc3df A |
359 | ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, const std::string &path, const OptimizeOptions& options, |
360 | ld::File::Ordinal ordinal) | |
a645023d A |
361 | { |
362 | mach_o::relocatable::ParserOptions objOpts; | |
363 | objOpts.architecture = options.arch; | |
364 | objOpts.objSubtypeMustMatch = false; | |
365 | objOpts.logAllFiles = false; | |
f80fe69f A |
366 | objOpts.warnUnwindConversionProblems = options.needsUnwindInfoSection; |
367 | objOpts.keepDwarfUnwind = options.keepDwarfUnwind; | |
368 | objOpts.forceDwarfConversion = false; | |
9543cb2f A |
369 | objOpts.neverConvertDwarf = false; |
370 | objOpts.verboseOptimizationHints = options.verboseOptimizationHints; | |
ba348e21 | 371 | objOpts.armUsesZeroCostExceptions = options.armUsesZeroCostExceptions; |
eaf282aa A |
372 | objOpts.simulator = options.simulator; |
373 | objOpts.ignoreMismatchPlatform = options.ignoreMismatchPlatform; | |
e456bf10 A |
374 | #if SUPPORT_ARCH_arm64e |
375 | objOpts.supportsAuthenticatedPointers = options.supportsAuthenticatedPointers; | |
376 | #endif | |
377 | objOpts.platforms = options.platforms; | |
a645023d | 378 | objOpts.subType = 0; |
eaf282aa | 379 | objOpts.srcKind = ld::relocatable::File::kSourceLTO; |
dd9e569f A |
380 | objOpts.treateBitcodeAsData = false; |
381 | objOpts.usingBitcode = options.bitcodeBundle; | |
ec29ba20 A |
382 | objOpts.maxDefaultCommonAlignment = options.maxDefaultCommonAlignment; |
383 | ||
0a8dc3df A |
384 | const char *object_path = path.c_str(); |
385 | if (path.empty()) | |
386 | object_path = "/tmp/lto.o"; | |
387 | ||
a645023d | 388 | time_t modTime = 0; |
0a8dc3df A |
389 | struct stat statBuffer; |
390 | if ( stat(object_path, &statBuffer) == 0 ) | |
391 | modTime = statBuffer.st_mtime; | |
392 | ||
393 | ld::relocatable::File* result = mach_o::relocatable::parse(p, len, strdup(object_path), modTime, ordinal, objOpts); | |
a645023d A |
394 | if ( result != NULL ) |
395 | return result; | |
396 | throw "LLVM LTO, file is not of required architecture"; | |
397 | } | |
398 | ||
399 | ||
400 | ||
b1f7435d | 401 | File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8_t* content, uint32_t contentLength, cpu_type_t arch) |
0a8dc3df | 402 | : ld::relocatable::File(pth,mTime,ordinal), _isThinLTO(false), _architecture(arch), _internalAtom(*this), |
eaf282aa A |
403 | _atomArray(NULL), _atomArrayCount(0), _module(NULL), _path(pth), |
404 | _content(content), _contentLength(contentLength), _debugInfoPath(pth), | |
a645023d A |
405 | _section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO), |
406 | _fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom), | |
407 | _debugInfo(ld::relocatable::File::kDebugInfoNone), _cpuSubType(0) | |
408 | { | |
409 | const bool log = false; | |
410 | ||
411 | // create llvm module | |
eaf282aa A |
412 | #if LTO_API_VERSION >= 11 |
413 | if ( sSupportsLocalContext || !sHasTriedLocalContext ) { | |
414 | _module = ::lto_module_create_in_local_context(content, contentLength, pth); | |
415 | } | |
416 | if ( !sHasTriedLocalContext ) { | |
417 | sHasTriedLocalContext = true; | |
418 | sSupportsLocalContext = (_module != NULL); | |
419 | } | |
420 | if ( (_module == NULL) && !sSupportsLocalContext ) | |
421 | #endif | |
599556ff A |
422 | #if LTO_API_VERSION >= 9 |
423 | _module = ::lto_module_create_from_memory_with_path(content, contentLength, pth); | |
eaf282aa | 424 | if ( _module == NULL && !sSupportsLocalContext ) |
599556ff | 425 | #endif |
a645023d A |
426 | _module = ::lto_module_create_from_memory(content, contentLength); |
427 | if ( _module == NULL ) | |
d425e388 | 428 | throwf("could not parse object file %s: '%s', using libLTO version '%s'", pth, ::lto_get_error_message(), ::lto_get_version()); |
a645023d A |
429 | |
430 | if ( log ) fprintf(stderr, "bitcode file: %s\n", pth); | |
0a8dc3df A |
431 | |
432 | #if LTO_API_VERSION >= 18 | |
433 | _isThinLTO = ::lto_module_is_thinlto(_module); | |
434 | #endif | |
435 | ||
a645023d A |
436 | // create atom for each global symbol in module |
437 | uint32_t count = ::lto_module_get_num_symbols(_module); | |
438 | _atomArray = (Atom*)malloc(sizeof(Atom)*count); | |
439 | for (uint32_t i=0; i < count; ++i) { | |
440 | const char* name = ::lto_module_get_symbol_name(_module, i); | |
441 | lto_symbol_attributes attr = lto_module_get_symbol_attribute(_module, i); | |
442 | ||
443 | // <rdar://problem/6378110> LTO doesn't like dtrace symbols | |
444 | // ignore dtrace static probes for now | |
445 | // later when codegen is done and a mach-o file is produces the probes will be processed | |
446 | if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) ) | |
447 | continue; | |
448 | ||
449 | ld::Atom::Definition def; | |
450 | ld::Atom::Combine combine = ld::Atom::combineNever; | |
451 | switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) { | |
452 | case LTO_SYMBOL_DEFINITION_REGULAR: | |
453 | def = ld::Atom::definitionRegular; | |
454 | break; | |
455 | case LTO_SYMBOL_DEFINITION_TENTATIVE: | |
456 | def = ld::Atom::definitionTentative; | |
457 | break; | |
458 | case LTO_SYMBOL_DEFINITION_WEAK: | |
459 | def = ld::Atom::definitionRegular; | |
460 | combine = ld::Atom::combineByName; | |
461 | break; | |
462 | case LTO_SYMBOL_DEFINITION_UNDEFINED: | |
463 | case LTO_SYMBOL_DEFINITION_WEAKUNDEF: | |
464 | def = ld::Atom::definitionProxy; | |
465 | break; | |
466 | default: | |
467 | throwf("unknown definition kind for symbol %s in bitcode file %s", name, pth); | |
468 | } | |
469 | ||
470 | // make LLVM atoms for definitions and a reference for undefines | |
471 | if ( def != ld::Atom::definitionProxy ) { | |
472 | ld::Atom::Scope scope; | |
b2fa67a8 | 473 | bool autohide = false; |
a645023d A |
474 | switch ( attr & LTO_SYMBOL_SCOPE_MASK) { |
475 | case LTO_SYMBOL_SCOPE_INTERNAL: | |
476 | scope = ld::Atom::scopeTranslationUnit; | |
477 | break; | |
478 | case LTO_SYMBOL_SCOPE_HIDDEN: | |
479 | scope = ld::Atom::scopeLinkageUnit; | |
480 | break; | |
481 | case LTO_SYMBOL_SCOPE_DEFAULT: | |
482 | scope = ld::Atom::scopeGlobal; | |
483 | break; | |
b2fa67a8 A |
484 | #if LTO_API_VERSION >= 4 |
485 | case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN: | |
486 | scope = ld::Atom::scopeGlobal; | |
487 | autohide = true; | |
488 | break; | |
489 | #endif | |
a645023d A |
490 | default: |
491 | throwf("unknown scope for symbol %s in bitcode file %s", name, pth); | |
492 | } | |
493 | // only make atoms for non-internal symbols | |
494 | if ( scope == ld::Atom::scopeTranslationUnit ) | |
495 | continue; | |
496 | uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK); | |
497 | // make Atom using placement new operator | |
b2fa67a8 | 498 | new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment, autohide); |
ebf6f434 | 499 | if ( scope != ld::Atom::scopeTranslationUnit ) |
a645023d A |
500 | _internalAtom.addReference(name); |
501 | if ( log ) fprintf(stderr, "\t0x%08X %s\n", attr, name); | |
502 | } | |
503 | else { | |
504 | // add to list of external references | |
505 | _internalAtom.addReference(name); | |
506 | if ( log ) fprintf(stderr, "\t%s (undefined)\n", name); | |
507 | } | |
508 | } | |
eaf282aa A |
509 | |
510 | #if LTO_API_VERSION >= 11 | |
511 | if ( sSupportsLocalContext ) | |
512 | this->release(); | |
513 | #endif | |
a645023d A |
514 | } |
515 | ||
516 | File::~File() | |
599556ff A |
517 | { |
518 | this->release(); | |
519 | } | |
520 | ||
eaf282aa A |
521 | bool File::mergeIntoGenerator(lto_code_gen_t generator, bool useSetModule) { |
522 | #if LTO_API_VERSION >= 11 | |
523 | if ( sSupportsLocalContext ) { | |
524 | assert(!_module && "Expected module to be disposed"); | |
525 | _module = ::lto_module_create_in_codegen_context(_content, _contentLength, | |
526 | _path, generator); | |
527 | if ( _module == NULL ) | |
528 | throwf("could not reparse object file %s: '%s', using libLTO version '%s'", | |
529 | _path, ::lto_get_error_message(), ::lto_get_version()); | |
530 | } | |
531 | #endif | |
532 | assert(_module && "Expected module to stick around"); | |
533 | #if LTO_API_VERSION >= 13 | |
534 | if (useSetModule) { | |
535 | // lto_codegen_set_module will transfer ownership of the module to LTO code generator, | |
536 | // so we don't need to release the module here. | |
537 | ::lto_codegen_set_module(generator, _module); | |
538 | return false; | |
539 | } | |
540 | #endif | |
541 | if ( ::lto_codegen_add_module(generator, _module) ) | |
542 | return true; | |
543 | ||
544 | // <rdar://problem/15471128> linker should release module as soon as possible | |
545 | this->release(); | |
546 | return false; | |
547 | } | |
548 | ||
0a8dc3df | 549 | #if LTO_API_VERSION >= 18 |
82b4b32b | 550 | void File::addToThinGenerator(thinlto_code_gen_t generator, int id) { |
0a8dc3df | 551 | assert(!_module && "Expected module to be disposed"); |
82b4b32b A |
552 | std::string pathWithID = _path; |
553 | pathWithID += std::to_string(id); | |
bee7e226 | 554 | ::thinlto_codegen_add_module(generator, strdup(pathWithID.c_str()), (const char *)_content, _contentLength); |
0a8dc3df A |
555 | } |
556 | #endif | |
557 | ||
599556ff | 558 | void File::release() |
a645023d A |
559 | { |
560 | if ( _module != NULL ) | |
561 | ::lto_module_dispose(_module); | |
599556ff | 562 | _module = NULL; |
a645023d A |
563 | } |
564 | ||
565 | bool File::forEachAtom(ld::File::AtomHandler& handler) const | |
566 | { | |
567 | handler.doAtom(_internalAtom); | |
568 | for(uint32_t i=0; i < _atomArrayCount; ++i) { | |
569 | handler.doAtom(_atomArray[i]); | |
570 | } | |
571 | return true; | |
572 | } | |
573 | ||
574 | InternalAtom::InternalAtom(File& f) | |
575 | : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, | |
576 | ld::Atom::typeLTOtemporary, ld::Atom::symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)), | |
577 | _file(f) | |
578 | { | |
579 | } | |
580 | ||
b2fa67a8 A |
581 | Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Combine c, |
582 | ld::Atom::Alignment a, bool ah) | |
a645023d A |
583 | : ld::Atom(f._section, d, c, s, ld::Atom::typeLTOtemporary, |
584 | ld::Atom::symbolTableIn, false, false, false, a), | |
599556ff | 585 | _file(f), _name(strdup(nm)), _compiledAtom(NULL) |
a645023d | 586 | { |
b2fa67a8 A |
587 | if ( ah ) |
588 | this->setAutoHide(); | |
a645023d A |
589 | } |
590 | ||
591 | void Atom::setCompiledAtom(const ld::Atom& atom) | |
592 | { | |
593 | // set delegate so virtual methods go to it | |
594 | _compiledAtom = &atom; | |
595 | ||
596 | //fprintf(stderr, "setting lto atom %p to delegate to mach-o atom %p (%s)\n", this, &atom, atom.name()); | |
597 | ||
598 | // update fields in ld::Atom to match newly constructed mach-o atom | |
599 | (const_cast<Atom*>(this))->setAttributesFromAtom(atom); | |
600 | } | |
601 | ||
602 | ||
603 | ||
f80fe69f A |
604 | // <rdar://problem/12379604> The order that files are merged must match command line order |
605 | struct CommandLineOrderFileSorter | |
606 | { | |
607 | bool operator()(File* left, File* right) | |
608 | { | |
609 | return ( left->ordinal() < right->ordinal() ); | |
610 | } | |
611 | }; | |
612 | ||
613 | ||
9543cb2f A |
614 | #if LTO_API_VERSION >= 7 |
615 | void Parser::ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t severity, const char* message, void*) | |
616 | { | |
617 | switch ( severity ) { | |
599556ff A |
618 | #if LTO_API_VERSION >= 10 |
619 | case LTO_DS_REMARK: | |
eaf282aa A |
620 | fprintf(stderr, "ld: LTO remark: %s\n", message); |
621 | break; | |
599556ff | 622 | #endif |
9543cb2f A |
623 | case LTO_DS_NOTE: |
624 | case LTO_DS_WARNING: | |
625 | warning("%s", message); | |
626 | break; | |
627 | case LTO_DS_ERROR: | |
628 | throwf("%s", message); | |
629 | } | |
630 | } | |
631 | #endif | |
632 | ||
a645023d | 633 | |
0a8dc3df A |
634 | /// Instruct libLTO about the list of symbols to preserve, compute deadllvmAtoms and llvmAtoms |
635 | void Parser::setPreservedSymbols( const std::vector<const ld::Atom*>& allAtoms, | |
636 | ld::Internal& state, | |
637 | const OptimizeOptions& options, | |
638 | CStringToAtom &deadllvmAtoms, | |
639 | CStringToAtom &llvmAtoms, | |
640 | lto_code_gen_t generator) { | |
641 | const bool logMustPreserve = false; | |
f80fe69f | 642 | |
0a8dc3df A |
643 | // The atom graph uses directed edges (references). Collect all references where |
644 | // originating atom is not part of any LTO Reader. This allows optimizer to optimize an | |
645 | // external (i.e. not originated from same .o file) reference if all originating atoms are also | |
a645023d A |
646 | // defined in llvm bitcode file. |
647 | CStringSet nonLLVMRefs; | |
0a8dc3df | 648 | bool hasNonllvmAtoms = false; |
a645023d A |
649 | for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { |
650 | const ld::Atom* atom = *it; | |
0a8dc3df A |
651 | // only look at references that come from an atom that is not an LTO atom |
652 | if (atom->contentType() != ld::Atom::typeLTOtemporary || | |
653 | ((lto::File *)atom->file())->isThinLTO()) { | |
a645023d A |
654 | if ( (atom->section().type() != ld::Section::typeMachHeader) && (atom->definition() != ld::Atom::definitionProxy) ) { |
655 | hasNonllvmAtoms = true; | |
656 | } | |
657 | const ld::Atom* target; | |
658 | for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) { | |
659 | switch ( fit->binding ) { | |
660 | case ld::Fixup::bindingDirectlyBound: | |
661 | // that reference an llvm atom | |
0a8dc3df | 662 | if ( fit->u.target->contentType() == ld::Atom::typeLTOtemporary ) |
a645023d A |
663 | nonLLVMRefs.insert(fit->u.target->name()); |
664 | break; | |
665 | case ld::Fixup::bindingsIndirectlyBound: | |
666 | target = state.indirectBindingTable[fit->u.bindingIndex]; | |
9543cb2f | 667 | if ( (target != NULL) && (target->contentType() == ld::Atom::typeLTOtemporary) ) |
a645023d A |
668 | nonLLVMRefs.insert(target->name()); |
669 | default: | |
670 | break; | |
671 | } | |
672 | } | |
673 | } | |
599556ff | 674 | else if ( atom->scope() >= ld::Atom::scopeLinkageUnit ) { |
a645023d A |
675 | llvmAtoms[atom->name()] = (Atom*)atom; |
676 | } | |
677 | } | |
678 | // if entry point is in a llvm bitcode file, it must be preserved by LTO | |
679 | if ( state.entryPoint!= NULL ) { | |
0a8dc3df | 680 | if ( state.entryPoint->contentType() == ld::Atom::typeLTOtemporary ) |
a645023d A |
681 | nonLLVMRefs.insert(state.entryPoint->name()); |
682 | } | |
0a8dc3df | 683 | |
a645023d A |
684 | // deadAtoms are the atoms that the linker coalesced. For instance weak or tentative definitions |
685 | // overriden by another atom. If any of these deadAtoms are llvm atoms and they were replaced | |
0a8dc3df | 686 | // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead |
a645023d | 687 | // atom so that the linker can replace it with the mach-o one later. |
a645023d A |
688 | for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { |
689 | const ld::Atom* atom = *it; | |
690 | if ( atom->coalescedAway() && (atom->contentType() == ld::Atom::typeLTOtemporary) ) { | |
691 | const char* name = atom->name(); | |
692 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name); | |
693 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
694 | deadllvmAtoms[name] = (Atom*)atom; | |
695 | } | |
696 | } | |
697 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
698 | File* file = *it; | |
699 | for(uint32_t i=0; i < file->_atomArrayCount; ++i) { | |
700 | Atom* llvmAtom = &file->_atomArray[i]; | |
701 | if ( llvmAtom->coalescedAway() ) { | |
702 | const char* name = llvmAtom->name(); | |
703 | if ( deadllvmAtoms.find(name) == deadllvmAtoms.end() ) { | |
0a8dc3df | 704 | if ( logMustPreserve ) |
a645023d A |
705 | fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name); |
706 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
707 | deadllvmAtoms[name] = (Atom*)llvmAtom; | |
708 | } | |
709 | } | |
710 | else if ( options.linkerDeadStripping && !llvmAtom->live() ) { | |
711 | const char* name = llvmAtom->name(); | |
712 | deadllvmAtoms[name] = (Atom*)llvmAtom; | |
713 | } | |
714 | } | |
715 | } | |
0a8dc3df | 716 | |
a645023d A |
717 | // tell code generator about symbols that must be preserved |
718 | for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { | |
719 | const char* name = it->first; | |
720 | Atom* atom = it->second; | |
721 | // Include llvm Symbol in export list if it meets one of following two conditions | |
722 | // 1 - atom scope is global (and not linkage unit). | |
723 | // 2 - included in nonLLVMRefs set. | |
724 | // If a symbol is not listed in exportList then LTO is free to optimize it away. | |
0a8dc3df | 725 | if ( (atom->scope() == ld::Atom::scopeGlobal) && options.preserveAllGlobals ) { |
a645023d A |
726 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name); |
727 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
728 | } | |
729 | else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) { | |
730 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because referenced by a mach-o atom\n", name); | |
731 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
732 | } | |
599556ff A |
733 | else if ( options.relocatable && hasNonllvmAtoms ) { |
734 | // <rdar://problem/14334895> ld -r mode but merging in some mach-o files, so need to keep libLTO from optimizing away anything | |
735 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because -r mode disable LTO dead stripping\n", name); | |
736 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
737 | } | |
a645023d | 738 | } |
0a8dc3df | 739 | |
599556ff A |
740 | // <rdar://problem/16165191> tell code generator to preserve initial undefines |
741 | for( std::vector<const char*>::const_iterator it=options.initialUndefines->begin(); it != options.initialUndefines->end(); ++it) { | |
742 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because it is an initial undefine\n", *it); | |
743 | ::lto_codegen_add_must_preserve_symbol(generator, *it); | |
744 | } | |
745 | ||
0a8dc3df A |
746 | // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o) |
747 | if ( options.relocatable && !hasNonllvmAtoms ) { | |
eaf282aa A |
748 | #if LTO_API_VERSION >= 15 |
749 | ::lto_codegen_set_should_embed_uselists(generator, false); | |
750 | #endif | |
a645023d A |
751 | if ( ! ::lto_codegen_write_merged_modules(generator, options.outputFilePath) ) { |
752 | // HACK, no good way to tell linker we are all done, so just quit | |
753 | exit(0); | |
754 | } | |
755 | warning("could not produce merged bitcode file"); | |
0a8dc3df A |
756 | } |
757 | ||
758 | } | |
759 | ||
760 | // Retrieve the codegen model from the options | |
761 | static lto_codegen_model getCodeModel(const OptimizeOptions& options) { | |
a645023d A |
762 | if ( options.mainExecutable ) { |
763 | if ( options.staticExecutable ) { | |
d425e388 A |
764 | // x86_64 "static" or any "-static -pie" is really dynamic code model |
765 | if ( (options.arch == CPU_TYPE_X86_64) || options.pie ) | |
0a8dc3df | 766 | return LTO_CODEGEN_PIC_MODEL_DYNAMIC; |
a645023d | 767 | else |
0a8dc3df | 768 | return LTO_CODEGEN_PIC_MODEL_STATIC; |
a645023d | 769 | } |
82b4b32b A |
770 | else if ( options.preload ) { |
771 | if ( options.pie ) | |
772 | return LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
773 | else | |
774 | return LTO_CODEGEN_PIC_MODEL_STATIC; | |
775 | } | |
a645023d A |
776 | else { |
777 | if ( options.pie ) | |
0a8dc3df | 778 | return LTO_CODEGEN_PIC_MODEL_DYNAMIC; |
a645023d | 779 | else |
0a8dc3df | 780 | return LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; |
a645023d A |
781 | } |
782 | } | |
783 | else { | |
784 | if ( options.allowTextRelocs ) | |
0a8dc3df | 785 | return LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; |
a645023d | 786 | else |
0a8dc3df | 787 | return LTO_CODEGEN_PIC_MODEL_DYNAMIC; |
a645023d | 788 | } |
0a8dc3df A |
789 | |
790 | } | |
791 | ||
792 | std::tuple<uint8_t *, size_t> Parser::codegen(const OptimizeOptions& options, | |
793 | ld::Internal& state, | |
794 | lto_code_gen_t generator, | |
795 | std::string& object_path) { | |
796 | uint8_t *machOFile; | |
797 | size_t machOFileLen; | |
798 | ||
799 | if ( ::lto_codegen_set_pic_model(generator, getCodeModel(options)) ) | |
a645023d A |
800 | throwf("could not create set codegen model: %s", lto_get_error_message()); |
801 | ||
0a8dc3df A |
802 | // if requested, save off merged bitcode file |
803 | if ( options.saveTemps ) { | |
804 | char tempBitcodePath[MAXPATHLEN]; | |
805 | strcpy(tempBitcodePath, options.outputFilePath); | |
806 | strcat(tempBitcodePath, ".lto.bc"); | |
eaf282aa | 807 | #if LTO_API_VERSION >= 15 |
0a8dc3df | 808 | ::lto_codegen_set_should_embed_uselists(generator, true); |
eaf282aa | 809 | #endif |
0a8dc3df A |
810 | ::lto_codegen_write_merged_modules(generator, tempBitcodePath); |
811 | } | |
a645023d A |
812 | |
813 | #if LTO_API_VERSION >= 3 | |
814 | // find assembler next to linker | |
815 | char path[PATH_MAX]; | |
816 | uint32_t bufSize = PATH_MAX; | |
817 | if ( _NSGetExecutablePath(path, &bufSize) != -1 ) { | |
818 | char* lastSlash = strrchr(path, '/'); | |
819 | if ( lastSlash != NULL ) { | |
820 | strcpy(lastSlash+1, "as"); | |
821 | struct stat statInfo; | |
822 | if ( stat(path, &statInfo) == 0 ) | |
823 | ::lto_codegen_set_assembler_path(generator, path); | |
824 | } | |
825 | } | |
826 | #endif | |
eaf282aa A |
827 | |
828 | // When lto API version is greater than or equal to 12, we use lto_codegen_optimize and lto_codegen_compile_optimized | |
829 | // instead of lto_codegen_compile, and we save the merged bitcode file in between. | |
830 | bool useSplitAPI = false; | |
831 | #if LTO_API_VERSION >= 12 | |
832 | if ( ::lto_api_version() >= 12) | |
833 | useSplitAPI = true; | |
834 | #endif | |
835 | ||
eaf282aa A |
836 | if ( useSplitAPI) { |
837 | #if LTO_API_VERSION >= 12 | |
838 | #if LTO_API_VERSION >= 14 | |
0a8dc3df A |
839 | if ( ::lto_api_version() >= 14 && options.ltoCodegenOnly) |
840 | lto_codegen_set_should_internalize(generator, false); | |
eaf282aa A |
841 | #endif |
842 | // run optimizer | |
843 | if ( !options.ltoCodegenOnly && ::lto_codegen_optimize(generator) ) | |
844 | throwf("could not do LTO optimization: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version()); | |
845 | ||
846 | if ( options.saveTemps || options.bitcodeBundle ) { | |
847 | // save off merged bitcode file | |
848 | char tempOptBitcodePath[MAXPATHLEN]; | |
849 | strcpy(tempOptBitcodePath, options.outputFilePath); | |
850 | strcat(tempOptBitcodePath, ".lto.opt.bc"); | |
851 | #if LTO_API_VERSION >= 15 | |
852 | ::lto_codegen_set_should_embed_uselists(generator, true); | |
853 | #endif | |
854 | ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath); | |
855 | if ( options.bitcodeBundle ) | |
0a8dc3df | 856 | state.ltoBitcodePath.push_back(tempOptBitcodePath); |
eaf282aa A |
857 | } |
858 | ||
859 | // run code generator | |
860 | machOFile = (uint8_t*)::lto_codegen_compile_optimized(generator, &machOFileLen); | |
861 | #endif | |
862 | if ( machOFile == NULL ) | |
863 | throwf("could not do LTO codegen: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version()); | |
864 | } | |
865 | else { | |
866 | // run optimizer and code generator | |
867 | machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen); | |
868 | if ( machOFile == NULL ) | |
869 | throwf("could not do LTO codegen: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version()); | |
870 | if ( options.saveTemps ) { | |
871 | // save off merged bitcode file | |
872 | char tempOptBitcodePath[MAXPATHLEN]; | |
873 | strcpy(tempOptBitcodePath, options.outputFilePath); | |
874 | strcat(tempOptBitcodePath, ".lto.opt.bc"); | |
875 | #if LTO_API_VERSION >= 15 | |
876 | ::lto_codegen_set_should_embed_uselists(generator, true); | |
877 | #endif | |
878 | ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath); | |
879 | } | |
880 | } | |
0a8dc3df A |
881 | |
882 | // if requested, save off temp mach-o file | |
883 | if ( options.saveTemps ) { | |
884 | char tempMachoPath[MAXPATHLEN]; | |
885 | strcpy(tempMachoPath, options.outputFilePath); | |
886 | strcat(tempMachoPath, ".lto.o"); | |
887 | int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
a645023d A |
888 | if ( fd != -1) { |
889 | ::write(fd, machOFile, machOFileLen); | |
890 | ::close(fd); | |
891 | } | |
a645023d A |
892 | } |
893 | ||
894 | // if needed, save temp mach-o file to specific location | |
0a8dc3df A |
895 | if ( !object_path.empty() ) { |
896 | int fd = ::open(object_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
a645023d A |
897 | if ( fd != -1) { |
898 | ::write(fd, machOFile, machOFileLen); | |
899 | ::close(fd); | |
900 | } | |
901 | else { | |
0a8dc3df | 902 | warning("could not write LTO temp file '%s', errno=%d", object_path.c_str(), errno); |
a645023d A |
903 | } |
904 | } | |
0a8dc3df A |
905 | return std::make_tuple(machOFile, machOFileLen); |
906 | } | |
907 | ||
908 | /// Load the MachO located in buffer \p machOFile with size \p machOFileLen. | |
909 | /// The loaded atoms are sync'ed using all the supplied lists. | |
910 | void Parser::loadMachO(ld::relocatable::File* machoFile, | |
911 | const OptimizeOptions& options, | |
912 | ld::File::AtomHandler& handler, | |
913 | std::vector<const ld::Atom*>& newAtoms, | |
914 | std::vector<const char*>& additionalUndefines, | |
915 | CStringToAtom &llvmAtoms, | |
916 | CStringToAtom &deadllvmAtoms) { | |
917 | const bool logAtomsBeforeSync = false; | |
918 | ||
a645023d A |
919 | // sync generated mach-o atoms with existing atoms ld knows about |
920 | if ( logAtomsBeforeSync ) { | |
921 | fprintf(stderr, "llvmAtoms:\n"); | |
922 | for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { | |
923 | const char* name = it->first; | |
599556ff A |
924 | Atom* atom = it->second; |
925 | fprintf(stderr, "\t%p\t%s\n", atom, name); | |
a645023d A |
926 | } |
927 | fprintf(stderr, "deadllvmAtoms:\n"); | |
928 | for (CStringToAtom::iterator it = deadllvmAtoms.begin(); it != deadllvmAtoms.end(); ++it) { | |
929 | const char* name = it->first; | |
599556ff A |
930 | Atom* atom = it->second; |
931 | fprintf(stderr, "\t%p\t%s\n", atom, name); | |
a645023d A |
932 | } |
933 | } | |
934 | AtomSyncer syncer(additionalUndefines, newAtoms, llvmAtoms, deadllvmAtoms, options); | |
935 | machoFile->forEachAtom(syncer); | |
0a8dc3df A |
936 | |
937 | // notify about file level attributes | |
938 | handler.doFile(*machoFile); | |
939 | } | |
940 | ||
941 | // Full LTO processing | |
942 | bool Parser::optimizeLTO(const std::vector<File*> files, | |
943 | const std::vector<const ld::Atom*>& allAtoms, | |
944 | ld::Internal& state, | |
945 | const OptimizeOptions& options, | |
946 | ld::File::AtomHandler& handler, | |
947 | std::vector<const ld::Atom*>& newAtoms, | |
948 | std::vector<const char*>& additionalUndefines) { | |
949 | const bool logExtraOptions = false; | |
950 | const bool logBitcodeFiles = false; | |
951 | ||
952 | if (files.empty()) | |
953 | return true; | |
954 | ||
955 | // create optimizer and add each Reader | |
956 | lto_code_gen_t generator = NULL; | |
957 | #if LTO_API_VERSION >= 11 | |
958 | if ( File::sSupportsLocalContext ) | |
959 | generator = ::lto_codegen_create_in_local_context(); | |
960 | else | |
961 | #endif | |
962 | generator = ::lto_codegen_create(); | |
963 | #if LTO_API_VERSION >= 7 | |
964 | lto_codegen_set_diagnostic_handler(generator, ltoDiagnosticHandler, NULL); | |
965 | #endif | |
966 | ||
967 | ld::File::Ordinal lastOrdinal; | |
968 | ||
969 | // When flto_codegen_only is on and we have a single .bc file, use lto_codegen_set_module instead of | |
970 | // lto_codegen_add_module, to make sure the the destination module will be the same as the input .bc file. | |
971 | bool useSetModule = false; | |
972 | #if LTO_API_VERSION >= 13 | |
973 | useSetModule = (files.size() == 1) && options.ltoCodegenOnly && (::lto_api_version() >= 13); | |
974 | #endif | |
975 | for (auto *f : files) { | |
976 | assert(f->ordinal() > lastOrdinal); | |
977 | if ( logBitcodeFiles && !useSetModule ) fprintf(stderr, "lto_codegen_add_module(%s)\n", f->path()); | |
978 | if ( logBitcodeFiles && useSetModule ) fprintf(stderr, "lto_codegen_set_module(%s)\n", f->path()); | |
979 | if ( f->mergeIntoGenerator(generator, useSetModule) ) | |
980 | throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", f->path(), ::lto_get_error_message(), ::lto_get_version()); | |
981 | lastOrdinal = f->ordinal(); | |
982 | } | |
983 | ||
984 | // add any -mllvm command line options | |
985 | if ( !_s_llvmOptionsProcessed ) { | |
986 | for (const char* opt : *options.llvmOptions) { | |
987 | if ( logExtraOptions ) fprintf(stderr, "passing option to llvm: %s\n", opt); | |
988 | ::lto_codegen_debug_options(generator, opt); | |
989 | } | |
990 | _s_llvmOptionsProcessed = true; | |
a645023d | 991 | } |
0a8dc3df A |
992 | |
993 | // <rdar://problem/13687397> Need a way for LTO to get cpu variants (until that info is in bitcode) | |
994 | if ( options.mcpu != NULL ) | |
995 | ::lto_codegen_set_cpu(generator, options.mcpu); | |
996 | ||
997 | // Compute the preserved symbols | |
998 | CStringToAtom deadllvmAtoms, llvmAtoms; | |
999 | setPreservedSymbols(allAtoms, state, options, deadllvmAtoms, llvmAtoms, generator); | |
1000 | ||
1001 | size_t machOFileLen = 0; | |
1002 | const uint8_t* machOFile = NULL; | |
1003 | ||
1004 | // mach-o parsing is done in-memory, but need path for debug notes | |
1005 | std::string object_path; | |
1006 | if ( options.tmpObjectFilePath != NULL ) { | |
1007 | object_path = options.tmpObjectFilePath; | |
1008 | // If the path exists and is a directory (for instance if some files | |
1009 | // were processed with ThinLTO before), we create the LTO file inside | |
1010 | // the directory. | |
1011 | struct stat statBuffer; | |
1012 | if( stat(object_path.c_str(), &statBuffer) == 0 && S_ISDIR(statBuffer.st_mode) ) { | |
1013 | object_path += "/lto.o"; | |
1014 | } | |
1015 | } | |
1016 | ||
1017 | // Codegen Now | |
1018 | std::tie(machOFile, machOFileLen) = codegen(options, state, generator, object_path); | |
1019 | ||
1020 | // parse generated mach-o file into a MachOReader | |
1021 | ld::relocatable::File* machoFile = parseMachOFile(machOFile, machOFileLen, object_path, options, ld::File::Ordinal::LTOOrdinal()); | |
1022 | ||
1023 | // Load the generated MachO file | |
1024 | loadMachO(machoFile, options, handler, newAtoms, additionalUndefines, llvmAtoms, deadllvmAtoms); | |
1025 | ||
a645023d A |
1026 | // Remove Atoms from ld if code generator optimized them away |
1027 | for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) { | |
1028 | // check if setRealAtom() called on this Atom | |
1029 | if ( li->second->compiledAtom() == NULL ) { | |
1030 | //fprintf(stderr, "llvm optimized away %p %s\n", li->second, li->second->name()); | |
1031 | li->second->setCoalescedAway(); | |
1032 | } | |
1033 | } | |
0a8dc3df | 1034 | |
a645023d | 1035 | // if final mach-o file has debug info, update original bitcode files to match |
0a8dc3df A |
1036 | for (auto *f : files) { |
1037 | f->setDebugInfo(machoFile->debugInfo(), machoFile->path(), machoFile->modificationTime(), machoFile->cpuSubType()); | |
a645023d | 1038 | } |
0a8dc3df | 1039 | |
a645023d A |
1040 | return true; |
1041 | } | |
1042 | ||
82b4b32b | 1043 | #if LTO_API_VERSION >= 18 |
0a8dc3df A |
1044 | // Create the ThinLTO codegenerator |
1045 | thinlto_code_gen_t Parser::init_thinlto_codegen(const std::vector<File*>& files, | |
1046 | const std::vector<const ld::Atom*>& allAtoms, | |
1047 | ld::Internal& state, | |
1048 | const OptimizeOptions& options, | |
1049 | CStringToAtom& deadllvmAtoms, | |
1050 | CStringToAtom& llvmAtoms) { | |
1051 | const bool logMustPreserve = false; | |
1052 | ||
1053 | thinlto_code_gen_t thingenerator = ::thinlto_create_codegen(); | |
1054 | ||
1055 | // Caching control | |
1056 | if (options.ltoCachePath && !options.bitcodeBundle) { | |
1057 | struct stat statBuffer; | |
1058 | if( stat(options.ltoCachePath, &statBuffer) != 0 || !S_ISDIR(statBuffer.st_mode) ) { | |
1059 | if ( mkdir(options.ltoCachePath, 0700) !=0 ) { | |
1060 | warning("unable to create ThinLTO cache directory: %s", options.ltoCachePath); | |
1061 | } | |
1062 | } | |
1063 | thinlto_codegen_set_cache_dir(thingenerator, options.ltoCachePath); | |
e456bf10 A |
1064 | if (options.ltoPruneIntervalOverwrite) |
1065 | thinlto_codegen_set_cache_pruning_interval(thingenerator, options.ltoPruneInterval); | |
0a8dc3df A |
1066 | thinlto_codegen_set_cache_entry_expiration(thingenerator, options.ltoPruneAfter); |
1067 | thinlto_codegen_set_final_cache_size_relative_to_available_space(thingenerator, options.ltoMaxCacheSize); | |
1068 | } | |
1069 | ||
1070 | // if requested, ask the code generator to save off intermediate bitcode files | |
1071 | if ( options.saveTemps ) { | |
1072 | std::string tempPath = options.outputFilePath; | |
1073 | tempPath += ".thinlto.bcs/"; | |
1074 | struct stat statBuffer; | |
1075 | if( stat(tempPath.c_str(), &statBuffer) != 0 || !S_ISDIR(statBuffer.st_mode) ) { | |
1076 | if ( mkdir(tempPath.c_str(), 0700) !=0 ) { | |
1077 | warning("unable to create ThinLTO output directory for temporary bitcode files: %s", tempPath.c_str()); | |
1078 | } | |
1079 | } | |
1080 | thinlto_codegen_set_savetemps_dir(thingenerator, tempPath.c_str()); | |
1081 | } | |
1082 | ||
1083 | // Set some codegen options | |
1084 | if ( thinlto_codegen_set_pic_model(thingenerator, getCodeModel(options)) ) | |
1085 | throwf("could not create set codegen model: %s", lto_get_error_message()); | |
1086 | ||
1087 | // Expose reachability informations for internalization in LTO | |
1088 | ||
1089 | // The atom graph uses directed edges (references). Collect all references where | |
1090 | // originating atom is not part of any LTO Reader. This allows optimizer to optimize an | |
1091 | // external (i.e. not originated from same .o file) reference if all originating atoms are also | |
1092 | // defined in llvm bitcode file. | |
1093 | CStringSet nonLLVMRefs; | |
1094 | CStringSet LLVMRefs; | |
1095 | for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { | |
1096 | const ld::Atom* atom = *it; | |
1097 | const ld::Atom* target; | |
1098 | for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) { | |
1099 | switch ( fit->binding ) { | |
1100 | case ld::Fixup::bindingDirectlyBound: | |
1101 | // that reference a ThinLTO llvm atom | |
1102 | target = fit->u.target; | |
1103 | if ( target->contentType() == ld::Atom::typeLTOtemporary && | |
1104 | ((lto::File *)target->file())->isThinLTO() && | |
1105 | atom->file() != target->file() | |
1106 | ) { | |
1107 | if (atom->contentType() != ld::Atom::typeLTOtemporary || | |
1108 | !((lto::File *)atom->file())->isThinLTO()) | |
1109 | nonLLVMRefs.insert(target->name()); | |
1110 | else | |
1111 | LLVMRefs.insert(target->name()); | |
1112 | if ( logMustPreserve ) | |
1113 | fprintf(stderr, "Found a reference from %s -> %s\n", atom->name(), target->name()); | |
1114 | } | |
1115 | break; | |
1116 | case ld::Fixup::bindingsIndirectlyBound: | |
1117 | target = state.indirectBindingTable[fit->u.bindingIndex]; | |
1118 | if ( (target != NULL) && (target->contentType() == ld::Atom::typeLTOtemporary) && | |
1119 | ((lto::File *)target->file())->isThinLTO() && | |
1120 | atom->file() != target->file() | |
1121 | ) { | |
1122 | if (atom->contentType() != ld::Atom::typeLTOtemporary || | |
1123 | !((lto::File *)atom->file())->isThinLTO()) | |
1124 | nonLLVMRefs.insert(target->name()); | |
1125 | else | |
1126 | LLVMRefs.insert(target->name()); | |
1127 | if ( logMustPreserve ) | |
1128 | fprintf(stderr, "Found a reference from %s -> %s\n", atom->name(), target->name()); | |
1129 | } | |
1130 | default: | |
1131 | break; | |
1132 | } | |
1133 | } | |
1134 | if (atom->contentType() == ld::Atom::typeLTOtemporary && | |
e456bf10 A |
1135 | ((lto::File *)atom->file())->isThinLTO() && |
1136 | atom != &((lto::File *)atom->file())->internalAtom()) { | |
1137 | assert(atom->scope() != ld::Atom::scopeTranslationUnit && "LTO should not expose static atoms"); | |
1138 | assert(llvmAtoms.find(atom->name()) == llvmAtoms.end() && "Unexpected llvmAtom with duplicate name"); | |
0a8dc3df A |
1139 | llvmAtoms[atom->name()] = (Atom*)atom; |
1140 | } | |
1141 | } | |
1142 | // if entry point is in a llvm bitcode file, it must be preserved by LTO | |
1143 | if ( state.entryPoint != NULL ) { | |
1144 | if ( state.entryPoint->contentType() == ld::Atom::typeLTOtemporary ) | |
1145 | nonLLVMRefs.insert(state.entryPoint->name()); | |
1146 | } | |
1147 | for (auto file : files) { | |
1148 | for(uint32_t i=0; i < file->_atomArrayCount; ++i) { | |
1149 | Atom* llvmAtom = &file->_atomArray[i]; | |
1150 | if ( llvmAtom->coalescedAway() ) { | |
1151 | const char* name = llvmAtom->name(); | |
1152 | if ( deadllvmAtoms.find(name) == deadllvmAtoms.end() ) { | |
1153 | if ( logMustPreserve ) | |
bee7e226 | 1154 | fprintf(stderr, "thinlto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name); |
0a8dc3df A |
1155 | ::thinlto_codegen_add_must_preserve_symbol(thingenerator, name, strlen(name)); |
1156 | deadllvmAtoms[name] = (Atom*)llvmAtom; | |
1157 | } | |
1158 | } | |
1159 | else if ( options.linkerDeadStripping && !llvmAtom->live() ) { | |
1160 | const char* name = llvmAtom->name(); | |
1161 | deadllvmAtoms[name] = (Atom*)llvmAtom; | |
1162 | } | |
1163 | } | |
1164 | } | |
1165 | ||
1166 | // tell code generator about symbols that must be preserved | |
1167 | for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { | |
1168 | const char* name = it->first; | |
1169 | Atom* atom = it->second; | |
1170 | // Include llvm Symbol in export list if it meets one of following two conditions | |
1171 | // 1 - atom scope is global (and not linkage unit). | |
1172 | // 2 - included in nonLLVMRefs set. | |
1173 | // If a symbol is not listed in exportList then LTO is free to optimize it away. | |
1174 | if ( (atom->scope() == ld::Atom::scopeGlobal) && options.preserveAllGlobals ) { | |
bee7e226 | 1175 | if ( logMustPreserve ) fprintf(stderr, "thinlto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name); |
0a8dc3df A |
1176 | ::thinlto_codegen_add_must_preserve_symbol(thingenerator, name, strlen(name)); |
1177 | } | |
1178 | else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) { | |
bee7e226 | 1179 | if ( logMustPreserve ) fprintf(stderr, "thinlto_codegen_add_must_preserve_symbol(%s) because referenced from outside of ThinLTO\n", name); |
0a8dc3df A |
1180 | ::thinlto_codegen_add_must_preserve_symbol(thingenerator, name, strlen(name)); |
1181 | } | |
1182 | else if ( LLVMRefs.find(name) != LLVMRefs.end() ) { | |
bee7e226 | 1183 | if ( logMustPreserve ) fprintf(stderr, "thinlto_codegen_add_cross_referenced_symbol(%s) because referenced from another file\n", name); |
0a8dc3df A |
1184 | ::thinlto_codegen_add_cross_referenced_symbol(thingenerator, name, strlen(name)); |
1185 | } else { | |
1186 | if ( logMustPreserve ) fprintf(stderr, "NOT preserving(%s)\n", name); | |
1187 | } | |
e456bf10 A |
1188 | |
1189 | // <rdar://problem/16165191> tell code generator to preserve initial undefines | |
1190 | for (const char* undefName : *options.initialUndefines) { | |
1191 | if ( logMustPreserve ) fprintf(stderr, "thinlto_codegen_add_cross_referenced_symbol(%s) because it is an initial undefine\n", undefName); | |
1192 | ::thinlto_codegen_add_cross_referenced_symbol(thingenerator, undefName, strlen(undefName)); | |
1193 | } | |
1194 | ||
0a8dc3df A |
1195 | // FIXME: to be implemented |
1196 | // else if ( options.relocatable && hasNonllvmAtoms ) { | |
1197 | // // <rdar://problem/14334895> ld -r mode but merging in some mach-o files, so need to keep libLTO from optimizing away anything | |
1198 | // if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because -r mode disable LTO dead stripping\n", name); | |
1199 | // ::thinlto_codegen_add_must_preserve_symbol(thingenerator, name, strlen(name)); | |
1200 | // } | |
1201 | } | |
1202 | ||
1203 | return thingenerator; | |
1204 | } | |
82b4b32b | 1205 | #endif |
0a8dc3df A |
1206 | |
1207 | // Full LTO processing | |
1208 | bool Parser::optimizeThinLTO(const std::vector<File*>& files, | |
1209 | const std::vector<const ld::Atom*>& allAtoms, | |
1210 | ld::Internal& state, | |
1211 | const OptimizeOptions& options, | |
1212 | ld::File::AtomHandler& handler, | |
1213 | std::vector<const ld::Atom*>& newAtoms, | |
1214 | std::vector<const char*>& additionalUndefines) { | |
1215 | const bool logBitcodeFiles = false; | |
1216 | ||
1217 | if (files.empty()) | |
1218 | return true; | |
1219 | ||
1220 | #if LTO_API_VERSION >= 18 | |
1221 | ||
1222 | if (::lto_api_version() < 18) | |
1223 | throwf("lto: could not use -thinlto because libLTO is too old (version '%d', >=18 is required)", ::lto_api_version()); | |
1224 | ||
1225 | // Handle -mllvm options | |
1226 | if ( !_s_llvmOptionsProcessed ) { | |
1227 | thinlto_debug_options(options.llvmOptions->data(), options.llvmOptions->size()); | |
1228 | _s_llvmOptionsProcessed = true; | |
1229 | } | |
1230 | ||
1231 | // Create the ThinLTO codegenerator | |
1232 | CStringToAtom deadllvmAtoms; | |
1233 | CStringToAtom llvmAtoms; | |
1234 | thinlto_code_gen_t thingenerator = init_thinlto_codegen(files, allAtoms, state, options, deadllvmAtoms, llvmAtoms); | |
1235 | ||
1236 | ||
1237 | ld::File::Ordinal lastOrdinal; | |
82b4b32b | 1238 | int FileId = 0; |
0a8dc3df A |
1239 | for (auto *f : files) { |
1240 | if ( logBitcodeFiles) fprintf(stderr, "thinlto_codegen_add_module(%s)\n", f->path()); | |
82b4b32b | 1241 | f->addToThinGenerator(thingenerator, FileId++); |
0a8dc3df A |
1242 | lastOrdinal = f->ordinal(); |
1243 | } | |
1244 | ||
1245 | #if LTO_API_VERSION >= 19 | |
1246 | // In the bitcode bundle case, we first run the generator with codegen disabled | |
1247 | // and get the bitcode output. These files are added for later bundling, and a | |
1248 | // new codegenerator is setup with these as input, and the optimizer disabled. | |
1249 | if (options.bitcodeBundle) { | |
1250 | // Bitcode Bundle case | |
1251 | thinlto_codegen_disable_codegen(thingenerator, true); | |
1252 | // Process the optimizer only | |
1253 | thinlto_codegen_process(thingenerator); | |
1254 | auto numObjects = thinlto_module_get_num_objects(thingenerator); | |
1255 | // Save the codegenerator | |
1256 | thinlto_code_gen_t bitcode_generator = thingenerator; | |
1257 | // Create a new codegen generator for the codegen part. | |
e456bf10 A |
1258 | // Clear out the stored atoms so we can recompute them. |
1259 | deadllvmAtoms.clear(); | |
1260 | llvmAtoms.clear(); | |
0a8dc3df A |
1261 | thingenerator = init_thinlto_codegen(files, allAtoms, state, options, deadllvmAtoms, llvmAtoms); |
1262 | // Disable the optimizer | |
1263 | thinlto_codegen_set_codegen_only(thingenerator, true); | |
1264 | ||
1265 | // Save bitcode files for later, and add them to the codegen generator. | |
1266 | for (unsigned bufID = 0; bufID < numObjects; ++bufID) { | |
1267 | auto machOFile = thinlto_module_get_object(bitcode_generator, bufID); | |
1268 | std::string tempMachoPath = options.outputFilePath; | |
1269 | tempMachoPath += "."; | |
1270 | tempMachoPath += std::to_string(bufID); | |
1271 | tempMachoPath += ".thinlto.o.bc"; | |
1272 | state.ltoBitcodePath.push_back(tempMachoPath); | |
1273 | int fd = ::open(tempMachoPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
1274 | if ( fd != -1 ) { | |
1275 | ::write(fd, machOFile.Buffer, machOFile.Size); | |
1276 | ::close(fd); | |
1277 | } else { | |
1278 | throwf("unable to write temporary ThinLTO output: %s", tempMachoPath.c_str()); | |
1279 | } | |
1280 | ||
1281 | // Add the optimized bitcode to the codegen generator now. | |
bee7e226 | 1282 | ::thinlto_codegen_add_module(thingenerator, strdup(tempMachoPath.c_str()), (const char *)machOFile.Buffer, machOFile.Size); |
0a8dc3df A |
1283 | } |
1284 | } | |
1285 | ||
1286 | if (options.ltoCodegenOnly) | |
1287 | // Disable the optimizer | |
1288 | thinlto_codegen_set_codegen_only(thingenerator, true); | |
1289 | #endif | |
1290 | ||
82b4b32b A |
1291 | // If object_path_lto is used, we switch to a file-based API: libLTO will |
1292 | // generate the files on disk and we'll map them on-demand. | |
1293 | ||
1294 | #if LTO_API_VERSION >= 21 | |
1295 | bool useFileBasedAPI = (options.tmpObjectFilePath && ::lto_api_version() >= 21); | |
1296 | if ( useFileBasedAPI ) | |
1297 | thinlto_set_generated_objects_dir(thingenerator, options.tmpObjectFilePath); | |
1298 | #endif | |
1299 | ||
0a8dc3df A |
1300 | // run code generator |
1301 | thinlto_codegen_process(thingenerator); | |
82b4b32b A |
1302 | |
1303 | unsigned numObjects; | |
1304 | #if LTO_API_VERSION >= 21 | |
1305 | if ( useFileBasedAPI ) | |
1306 | numObjects = thinlto_module_get_num_object_files(thingenerator); | |
1307 | else | |
1308 | #endif | |
1309 | numObjects = thinlto_module_get_num_objects(thingenerator); | |
1310 | if ( numObjects == 0 ) | |
0a8dc3df A |
1311 | throwf("could not do ThinLTO codegen (thinlto_codegen_process didn't produce any object): '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version()); |
1312 | ||
bee7e226 A |
1313 | auto get_thinlto_buffer_or_load_file = [&] (unsigned ID) { |
1314 | #if LTO_API_VERSION >= 21 | |
1315 | if ( useFileBasedAPI ) { | |
1316 | const char* path = thinlto_module_get_object_file(thingenerator, ID); | |
1317 | // map in whole file | |
1318 | struct stat stat_buf; | |
1319 | int fd = ::open(path, O_RDONLY, 0); | |
1320 | if ( fd == -1 ) | |
1321 | throwf("can't open thinlto file '%s', errno=%d", path, errno); | |
1322 | if ( ::fstat(fd, &stat_buf) != 0 ) | |
1323 | throwf("fstat thinlto file '%s' failed, errno=%d\n", path, errno); | |
1324 | size_t len = stat_buf.st_size; | |
1325 | if ( len < 20 ) | |
1326 | throwf("ThinLTO file '%s' too small (length=%zu)", path, len); | |
1327 | const char* p = (const char*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); | |
1328 | if ( p == (const char*)(-1) ) | |
1329 | throwf("can't map file, errno=%d", errno); | |
1330 | ::close(fd); | |
1331 | return LTOObjectBuffer{ p, len }; | |
1332 | } | |
1333 | #endif | |
1334 | return thinlto_module_get_object(thingenerator, ID); | |
1335 | }; | |
1336 | ||
0a8dc3df A |
1337 | // if requested, save off objects files |
1338 | if ( options.saveTemps ) { | |
1339 | for (unsigned bufID = 0; bufID < numObjects; ++bufID) { | |
bee7e226 | 1340 | auto machOFile = get_thinlto_buffer_or_load_file(bufID); |
0a8dc3df A |
1341 | std::string tempMachoPath = options.outputFilePath; |
1342 | tempMachoPath += "."; | |
1343 | tempMachoPath += std::to_string(bufID); | |
1344 | tempMachoPath += ".thinlto.o"; | |
1345 | int fd = ::open(tempMachoPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
1346 | if ( fd != -1 ) { | |
1347 | ::write(fd, machOFile.Buffer, machOFile.Size); | |
1348 | ::close(fd); | |
82b4b32b A |
1349 | } |
1350 | else { | |
0a8dc3df A |
1351 | warning("unable to write temporary ThinLTO output: %s", tempMachoPath.c_str()); |
1352 | } | |
1353 | } | |
1354 | } | |
1355 | ||
0a8dc3df A |
1356 | // mach-o parsing is done in-memory, but need path for debug notes |
1357 | std::string macho_dirpath = "/tmp/thinlto.o"; | |
1358 | if ( options.tmpObjectFilePath != NULL ) { | |
1359 | macho_dirpath = options.tmpObjectFilePath; | |
1360 | struct stat statBuffer; | |
1361 | if( stat(macho_dirpath.c_str(), &statBuffer) != 0 || !S_ISDIR(statBuffer.st_mode) ) { | |
82b4b32b | 1362 | unlink(macho_dirpath.c_str()); |
0a8dc3df A |
1363 | if ( mkdir(macho_dirpath.c_str(), 0700) !=0 ) { |
1364 | warning("unable to create ThinLTO output directory for temporary object files: %s", macho_dirpath.c_str()); | |
1365 | } | |
1366 | } | |
1367 | } | |
1368 | ||
1369 | auto ordinal = ld::File::Ordinal::LTOOrdinal().nextFileListOrdinal(); | |
1370 | for (unsigned bufID = 0; bufID < numObjects; ++bufID) { | |
82b4b32b | 1371 | auto machOFile = get_thinlto_buffer_or_load_file(bufID); |
0a8dc3df A |
1372 | if (!machOFile.Size) { |
1373 | warning("Ignoring empty buffer generated by ThinLTO"); | |
1374 | continue; | |
1375 | } | |
1376 | ||
1377 | // mach-o parsing is done in-memory, but need path for debug notes | |
82b4b32b A |
1378 | std::string tmp_path; |
1379 | #if LTO_API_VERSION >= 21 | |
1380 | if ( useFileBasedAPI ) { | |
1381 | tmp_path = thinlto_module_get_object_file(thingenerator, bufID); | |
1382 | } | |
1383 | else | |
1384 | #endif | |
1385 | if ( options.tmpObjectFilePath != NULL) { | |
1386 | tmp_path = macho_dirpath + "/" + std::to_string(bufID) + ".o"; | |
1387 | // if needed, save temp mach-o file to specific location | |
0a8dc3df A |
1388 | int fd = ::open(tmp_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666); |
1389 | if ( fd != -1) { | |
1390 | ::write(fd, (const uint8_t *)machOFile.Buffer, machOFile.Size); | |
1391 | ::close(fd); | |
1392 | } | |
1393 | else { | |
1394 | warning("could not write ThinLTO temp file '%s', errno=%d", tmp_path.c_str(), errno); | |
1395 | } | |
1396 | } | |
1397 | ||
7f09b935 A |
1398 | // parse generated mach-o file into a MachOReader |
1399 | ld::relocatable::File* machoFile = parseMachOFile((const uint8_t *)machOFile.Buffer, machOFile.Size, tmp_path, options, ordinal); | |
1400 | ordinal = ordinal.nextFileListOrdinal(); | |
1401 | ||
0a8dc3df A |
1402 | // Load the generated MachO file |
1403 | loadMachO(machoFile, options, handler, newAtoms, additionalUndefines, llvmAtoms, deadllvmAtoms); | |
1404 | } | |
1405 | ||
1406 | // Remove Atoms from ld if code generator optimized them away | |
1407 | for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) { | |
1408 | // check if setRealAtom() called on this Atom | |
1409 | if ( li->second->compiledAtom() == NULL ) { | |
1410 | //fprintf(stderr, "llvm optimized away %p %s\n", li->second, li->second->name()); | |
1411 | li->second->setCoalescedAway(); | |
1412 | } | |
1413 | } | |
1414 | ||
1415 | return true; | |
1416 | #else // ! (LTO_API_VERSION >= 18) | |
1417 | throwf("lto: could not use -thinlto because ld was built against a version of libLTO too old (version '%d', >=18 is required)", LTO_API_VERSION); | |
1418 | #endif | |
1419 | } | |
1420 | ||
1421 | bool Parser::optimize( const std::vector<const ld::Atom*>& allAtoms, | |
1422 | ld::Internal& state, | |
1423 | const OptimizeOptions& options, | |
1424 | ld::File::AtomHandler& handler, | |
1425 | std::vector<const ld::Atom*>& newAtoms, | |
1426 | std::vector<const char*>& additionalUndefines) | |
1427 | { | |
1428 | ||
1429 | // exit quickly if nothing to do | |
1430 | if ( _s_files.size() == 0 ) | |
1431 | return false; | |
1432 | ||
1433 | // print out LTO version string if -v was used | |
1434 | if ( options.verbose ) | |
1435 | fprintf(stderr, "%s\n", ::lto_get_version()); | |
1436 | ||
1437 | // <rdar://problem/12379604> The order that files are merged must match command line order | |
1438 | std::sort(_s_files.begin(), _s_files.end(), CommandLineOrderFileSorter()); | |
1439 | ||
1440 | #if LTO_API_VERSION >= 19 | |
1441 | // If ltoCodegenOnly is set, we don't want to merge any bitcode files and perform FullLTO | |
1442 | // we just take the ThinLTO path (optimization will be disabled anyway). | |
1443 | if (options.ltoCodegenOnly) { | |
1444 | for (auto *file : _s_files) { | |
1445 | file->setIsThinLTO(true); | |
1446 | } | |
1447 | } | |
1448 | #endif | |
1449 | ||
1450 | std::vector<File *> theLTOFiles; | |
1451 | std::vector<File *> theThinLTOFiles; | |
1452 | for (auto *file : _s_files) { | |
1453 | if (file->isThinLTO()) { | |
1454 | theThinLTOFiles.push_back(file); | |
1455 | } else { | |
1456 | theLTOFiles.push_back(file); | |
1457 | } | |
1458 | } | |
1459 | ||
1460 | auto result = optimizeThinLTO(theThinLTOFiles, allAtoms, state, options, handler, newAtoms, additionalUndefines) && | |
1461 | optimizeLTO(theLTOFiles, allAtoms, state, options, handler, newAtoms, additionalUndefines); | |
1462 | ||
1463 | // Remove InternalAtoms from ld | |
1464 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
1465 | (*it)->internalAtom().setCoalescedAway(); | |
1466 | } | |
1467 | ||
1468 | return result; | |
1469 | } | |
1470 | ||
a645023d A |
1471 | |
1472 | void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom) | |
1473 | { | |
599556ff | 1474 | static const bool log = false; |
a645023d A |
1475 | // update proxy atoms to point to real atoms and find new atoms |
1476 | const char* name = machoAtom.name(); | |
0a8dc3df | 1477 | CStringToAtom::const_iterator pos = _llvmAtoms.find(name); |
f410558f | 1478 | if ( (pos != _llvmAtoms.end()) && (machoAtom.scope() != ld::Atom::scopeTranslationUnit) ) { |
599556ff | 1479 | // turn Atom into a proxy for this mach-o atom |
82b4b32b A |
1480 | if (pos->second->scope() == ld::Atom::scopeLinkageUnit) { |
1481 | if (log) fprintf(stderr, "demote %s to hidden after LTO\n", name); | |
1482 | (const_cast<ld::Atom*>(&machoAtom))->setScope(ld::Atom::scopeLinkageUnit); | |
1483 | } | |
e456bf10 A |
1484 | // If both llvmAtom and machoAtom has the same scope and combine, but machoAtom loses auto hide, add it back. |
1485 | // rdar://problem/38646854 | |
1486 | if (pos->second->scope() == machoAtom.scope() && | |
1487 | pos->second->combine() == machoAtom.combine() && | |
1488 | pos->second->autoHide() && !machoAtom.autoHide()) { | |
1489 | if (log) fprintf(stderr, "set %s to auto hide after LTO\n", name); | |
1490 | (const_cast<ld::Atom*>(&machoAtom))->setAutoHide(); | |
1491 | } | |
599556ff | 1492 | pos->second->setCompiledAtom(machoAtom); |
0a8dc3df A |
1493 | _lastProxiedAtom = &machoAtom; |
1494 | _lastProxiedFile = pos->second->file(); | |
599556ff A |
1495 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p synced to lto atom %p (name=%s)\n", &machoAtom, pos->second, machoAtom.name()); |
1496 | } | |
1497 | else { | |
1498 | // an atom of this name was not in the allAtoms list the linker gave us | |
0a8dc3df A |
1499 | auto llvmAtom = _deadllvmAtoms.find(name); |
1500 | if ( llvmAtom != _deadllvmAtoms.end() ) { | |
599556ff A |
1501 | // this corresponding to an atom that the linker coalesced away or marked not-live |
1502 | if ( _options.linkerDeadStripping ) { | |
1503 | // llvm seems to want this atom and -dead_strip is enabled, so it will be deleted if not needed, so add back | |
0a8dc3df | 1504 | llvmAtom->second->setCompiledAtom(machoAtom); |
a645023d | 1505 | _newAtoms.push_back(&machoAtom); |
0a8dc3df | 1506 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p matches dead lto atom %p but adding back (name=%s)\n", &machoAtom, llvmAtom->second, machoAtom.name()); |
a645023d | 1507 | } |
599556ff A |
1508 | else { |
1509 | // Don't pass it back as a new atom | |
0a8dc3df | 1510 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p matches dead lto atom %p (name=%s)\n", &machoAtom, llvmAtom->second, machoAtom.name()); |
82b4b32b A |
1511 | if ( llvmAtom->second->coalescedAway() ) { |
1512 | if (log) fprintf(stderr, "AtomSyncer: dead coalesced atom %s\n", machoAtom.name()); | |
1513 | // <rdar://problem/28269547> | |
1514 | // We told libLTO to keep a weak atom that will replaced by an native mach-o atom. | |
1515 | // We also need to remove any atoms directly dependent on this (FDE, LSDA). | |
1516 | for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(), fend=machoAtom.fixupsEnd(); fit != fend; ++fit) { | |
1517 | switch ( fit->kind ) { | |
1518 | case ld::Fixup::kindNoneGroupSubordinate: | |
1519 | case ld::Fixup::kindNoneGroupSubordinateFDE: | |
1520 | case ld::Fixup::kindNoneGroupSubordinateLSDA: | |
1521 | assert(fit->binding == ld::Fixup::bindingDirectlyBound); | |
1522 | (const_cast<ld::Atom*>(fit->u.target))->setCoalescedAway(); | |
1523 | if (log) fprintf(stderr, "AtomSyncer: mark coalesced-away subordinate atom %s\n", fit->u.target->name()); | |
1524 | break; | |
1525 | default: | |
1526 | break; | |
1527 | } | |
1528 | } | |
1529 | } | |
599556ff | 1530 | } |
a645023d | 1531 | } |
599556ff A |
1532 | else |
1533 | { | |
1534 | // this is something new that lto conjured up, tell ld its new | |
1535 | _newAtoms.push_back(&machoAtom); | |
1536 | // <rdar://problem/15469363> if new static atom in same section as previous non-static atom, assign to same file as previous | |
0a8dc3df | 1537 | if ( (_lastProxiedAtom != NULL) && (_lastProxiedAtom->section() == machoAtom.section()) ) { |
599556ff | 1538 | ld::Atom* ma = const_cast<ld::Atom*>(&machoAtom); |
0a8dc3df | 1539 | ma->setFile(_lastProxiedFile); |
e456bf10 | 1540 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %s is static and being assigned to %s\n", machoAtom.name(), _lastProxiedFile->path()); |
599556ff A |
1541 | } |
1542 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p is totally new (name=%s)\n", &machoAtom, machoAtom.name()); | |
9543cb2f | 1543 | } |
a645023d A |
1544 | } |
1545 | ||
1546 | // adjust fixups to go through proxy atoms | |
599556ff | 1547 | if (log) fprintf(stderr, " adjusting fixups in atom: %s\n", machoAtom.name()); |
a645023d A |
1548 | for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) { |
1549 | switch ( fit->binding ) { | |
1550 | case ld::Fixup::bindingNone: | |
1551 | break; | |
1552 | case ld::Fixup::bindingByNameUnbound: | |
1553 | // don't know if this target has been seen by linker before or if it is new | |
1554 | // be conservative and tell linker it is new | |
1555 | _additionalUndefines.push_back(fit->u.name); | |
599556ff | 1556 | if (log) fprintf(stderr, " adding by-name symbol %s\n", fit->u.name); |
a645023d A |
1557 | break; |
1558 | case ld::Fixup::bindingDirectlyBound: | |
1559 | // If mach-o atom is referencing another mach-o atom then | |
1560 | // reference is not going through Atom proxy. Fix it here to ensure that all | |
1561 | // llvm symbol references always go through Atom proxy. | |
f410558f | 1562 | if ( fit->u.target->scope() != ld::Atom::scopeTranslationUnit ) |
599556ff | 1563 | { |
a645023d | 1564 | const char* targetName = fit->u.target->name(); |
0a8dc3df | 1565 | CStringToAtom::const_iterator post = _llvmAtoms.find(targetName); |
599556ff A |
1566 | if ( post != _llvmAtoms.end() ) { |
1567 | const ld::Atom* t = post->second; | |
1568 | if (log) fprintf(stderr, " updating direct reference to %p to be ref to %p: %s\n", fit->u.target, t, targetName); | |
1569 | fit->u.target = t; | |
a645023d A |
1570 | } |
1571 | else { | |
f80fe69f | 1572 | // <rdar://problem/12859831> Don't unbind follow-on reference into by-name reference |
eaf282aa | 1573 | if ( (_deadllvmAtoms.find(targetName) != _deadllvmAtoms.end()) && (fit->kind != ld::Fixup::kindNoneFollowOn) && (fit->u.target->scope() != ld::Atom::scopeTranslationUnit) ) { |
a645023d A |
1574 | // target was coalesed away and replace by mach-o atom from a non llvm .o file |
1575 | fit->binding = ld::Fixup::bindingByNameUnbound; | |
1576 | fit->u.name = targetName; | |
1577 | } | |
1578 | } | |
1579 | } | |
1580 | //fprintf(stderr, " direct ref to: %s (scope=%d)\n", fit->u.target->name(), fit->u.target->scope()); | |
1581 | break; | |
1582 | case ld::Fixup::bindingByContentBound: | |
1583 | //fprintf(stderr, " direct by content to: %s\n", fit->u.target->name()); | |
1584 | break; | |
1585 | case ld::Fixup::bindingsIndirectlyBound: | |
1586 | assert(0 && "indirect binding found in initial mach-o file?"); | |
1587 | //fprintf(stderr, " indirect by content to: %u\n", fit->u.bindingIndex); | |
1588 | break; | |
1589 | } | |
1590 | } | |
1591 | ||
1592 | } | |
1593 | ||
ebf6f434 A |
1594 | class Mutex { |
1595 | static pthread_mutex_t lto_lock; | |
1596 | public: | |
1597 | Mutex() { pthread_mutex_lock(<o_lock); } | |
1598 | ~Mutex() { pthread_mutex_unlock(<o_lock); } | |
1599 | }; | |
1600 | pthread_mutex_t Mutex::lto_lock = PTHREAD_MUTEX_INITIALIZER; | |
eaf282aa A |
1601 | bool File::sSupportsLocalContext = false; |
1602 | bool File::sHasTriedLocalContext = false; | |
a645023d A |
1603 | |
1604 | // | |
1605 | // Used by archive reader to see if member is an llvm bitcode file | |
1606 | // | |
1607 | bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch) | |
1608 | { | |
ebf6f434 | 1609 | Mutex lock; |
a645023d A |
1610 | return Parser::validFile(fileContent, fileLength, architecture, subarch); |
1611 | } | |
1612 | ||
0a8dc3df A |
1613 | // |
1614 | // Used by archive reader to see if member defines a Category (for -ObjC semantics) | |
1615 | // | |
1616 | bool hasObjCCategory(const uint8_t* fileContent, uint64_t fileLength) | |
1617 | { | |
1618 | #if LTO_API_VERSION >= 20 | |
1619 | // note: if run with older libLTO.dylib that does not implement | |
1620 | // lto_module_has_objc_category, the call will return 0 which is "false" | |
1621 | return lto_module_has_objc_category(fileContent, fileLength); | |
1622 | #else | |
1623 | return false; | |
1624 | #endif | |
1625 | } | |
1626 | ||
1627 | ||
eaf282aa A |
1628 | static ld::relocatable::File *parseImpl( |
1629 | const uint8_t *fileContent, uint64_t fileLength, const char *path, | |
1630 | time_t modTime, ld::File::Ordinal ordinal, cpu_type_t architecture, | |
1631 | cpu_subtype_t subarch, bool logAllFiles, | |
1632 | bool verboseOptimizationHints) | |
1633 | { | |
1634 | if ( Parser::validFile(fileContent, fileLength, architecture, subarch) ) | |
1635 | return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles, verboseOptimizationHints); | |
1636 | else | |
1637 | return NULL; | |
1638 | } | |
1639 | ||
a645023d A |
1640 | // |
1641 | // main function used by linker to instantiate ld::Files | |
1642 | // | |
1643 | ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, | |
b1f7435d | 1644 | const char* path, time_t modTime, ld::File::Ordinal ordinal, |
9543cb2f A |
1645 | cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles, |
1646 | bool verboseOptimizationHints) | |
a645023d | 1647 | { |
ec29ba20 A |
1648 | // do light weight check before acquiring lock |
1649 | if ( fileLength < 4 ) | |
1650 | return NULL; | |
1651 | if ( (fileContent[0] != 0xDE) || (fileContent[1] != 0xC0) || (fileContent[2] != 0x17) || (fileContent[3] != 0x0B) ) | |
1652 | return NULL; | |
1653 | ||
eaf282aa A |
1654 | // Note: Once lto_module_create_in_local_context() and friends are thread safe |
1655 | // this lock can be removed. | |
ebf6f434 | 1656 | Mutex lock; |
eaf282aa A |
1657 | return parseImpl(fileContent, fileLength, path, modTime, ordinal, |
1658 | architecture, subarch, logAllFiles, | |
1659 | verboseOptimizationHints); | |
a645023d A |
1660 | } |
1661 | ||
1662 | // | |
1663 | // used by "ld -v" to report version of libLTO.dylib being used | |
1664 | // | |
1665 | const char* version() | |
1666 | { | |
ebf6f434 | 1667 | Mutex lock; |
a645023d A |
1668 | return ::lto_get_version(); |
1669 | } | |
1670 | ||
bee7e226 A |
1671 | // |
1672 | // used by "ld -v" to report static version of libLTO.dylib API being compiled | |
1673 | // | |
1674 | unsigned int static_api_version() | |
1675 | { | |
1676 | return LTO_API_VERSION; | |
1677 | } | |
1678 | ||
1679 | // | |
1680 | // used by "ld -v" to report version of libLTO.dylib being used | |
1681 | // | |
1682 | unsigned int runtime_api_version() | |
1683 | { | |
1684 | return ::lto_api_version(); | |
1685 | } | |
1686 | ||
a645023d A |
1687 | |
1688 | // | |
1689 | // used by ld for error reporting | |
1690 | // | |
1691 | bool libLTOisLoaded() | |
1692 | { | |
ebf6f434 | 1693 | Mutex lock; |
a645023d A |
1694 | return (::lto_get_version() != NULL); |
1695 | } | |
1696 | ||
1697 | // | |
1698 | // used by ld for error reporting | |
1699 | // | |
1700 | const char* archName(const uint8_t* fileContent, uint64_t fileLength) | |
1701 | { | |
ebf6f434 | 1702 | Mutex lock; |
a645023d A |
1703 | return Parser::fileKind(fileContent, fileLength); |
1704 | } | |
1705 | ||
1706 | // | |
1707 | // used by ld for doing link time optimization | |
1708 | // | |
1709 | bool optimize( const std::vector<const ld::Atom*>& allAtoms, | |
1710 | ld::Internal& state, | |
a645023d A |
1711 | const OptimizeOptions& options, |
1712 | ld::File::AtomHandler& handler, | |
1713 | std::vector<const ld::Atom*>& newAtoms, | |
1714 | std::vector<const char*>& additionalUndefines) | |
1715 | { | |
ebf6f434 A |
1716 | Mutex lock; |
1717 | return Parser::optimize(allAtoms, state, options, handler, newAtoms, additionalUndefines); | |
a645023d A |
1718 | } |
1719 | ||
1720 | ||
1721 | ||
1722 | }; // namespace lto | |
1723 | ||
1724 | ||
1725 | #endif | |
1726 |