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