1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #ifndef __LTO_READER_H__
26 #define __LTO_READER_H__
29 #include <sys/param.h>
30 #include <sys/fcntl.h>
35 #include <mach-o/dyld.h>
38 #include <unordered_set>
39 #include <unordered_map>
43 #include "MachOFileAbstraction.hpp"
44 #include "Architectures.hpp"
46 #include "macho_relocatable_file.h"
49 #include "llvm-c/lto.h"
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.
61 class InternalAtom
: public ld::Atom
64 InternalAtom(class File
& f
);
65 // overrides of ld::Atom
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()]; }
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
,
77 ld::Fixup::kindNone
, false, strdup(nm
))); }
81 mutable std::vector
<ld::Fixup
> _undefs
;
88 class File
: public ld::relocatable::File
91 File(const char* path
, time_t mTime
, ld::File::Ordinal ordinal
,
92 const uint8_t* content
, uint32_t contentLength
, cpu_type_t arch
);
95 // overrides of ld::File
96 bool forEachAtom(ld::File::AtomHandler
&) const override
;
97 bool justInTimeforEachAtom(const char* name
, ld::File::AtomHandler
&) const override
99 uint32_t cpuSubType() const override
{ return _cpuSubType
; }
101 // overrides of ld::relocatable::File
102 DebugInfoKind
debugInfo() const override
{ return _debugInfo
; }
103 const char* debugInfoPath() const override
{ return _debugInfoPath
; }
104 time_t debugInfoModificationTime() const override
105 { return _debugInfoModTime
; }
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
; }
109 const ToolVersionList
& toolVersions() const override
{ return _toolVersions
; }
110 bool isThinLTO() const { return _isThinLTO
; }
111 void setIsThinLTO(bool ThinLTO
) { _isThinLTO
= ThinLTO
; }
112 // fixme rdar://24734472 objCConstraint() and objcHasCategoryClassProperties()
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
)
119 _debugInfoPath
= pth
;
120 _debugInfoModTime
= modTime
;
121 _cpuSubType
= subtype
;}
123 static bool sSupportsLocalContext
;
124 static bool sHasTriedLocalContext
;
125 bool mergeIntoGenerator(lto_code_gen_t generator
, bool useSetModule
);
126 #if LTO_API_VERSION >= 18
127 void addToThinGenerator(thinlto_code_gen_t generator
, int id
);
131 friend class InternalAtom
;
135 cpu_type_t _architecture
;
136 class InternalAtom _internalAtom
;
137 class Atom
* _atomArray
;
138 uint32_t _atomArrayCount
;
139 lto_module_t _module
;
141 const uint8_t* _content
;
142 uint32_t _contentLength
;
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
;
149 ToolVersionList _toolVersions
; // unused, may some day contain version of clang the created bitcode
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.
159 class Atom
: public ld::Atom
162 Atom(File
& f
, const char* name
, ld::Atom::Scope s
,
163 ld::Atom::Definition d
, ld::Atom::Combine c
, ld::Atom::Alignment a
, bool ah
);
165 // overrides of ld::Atom
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
169 { return (_compiledAtom
? _compiledAtom
->translationUnitSource() : NULL
); }
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
174 { if (_compiledAtom
) _compiledAtom
->copyRawContent(buffer
); }
175 const uint8_t* rawContentPointer() const override
176 { return (_compiledAtom
? _compiledAtom
->rawContentPointer() : NULL
); }
177 unsigned long contentHash(const class ld::IndirectBindingTable
& ibt
) const override
178 { return (_compiledAtom
? _compiledAtom
->contentHash(ibt
) : 0); }
179 bool canCoalesceWith(const ld::Atom
& rhs
, const class ld::IndirectBindingTable
& ibt
) const override
180 { return (_compiledAtom
? _compiledAtom
->canCoalesceWith(rhs
,ibt
) : false); }
181 ld::Fixup::iterator
fixupsBegin() const override
182 { return (_compiledAtom
? _compiledAtom
->fixupsBegin() : (ld::Fixup
*)&_file
._fixupToInternal
); }
183 ld::Fixup::iterator
fixupsEnd() const override
184 { return (_compiledAtom
? _compiledAtom
->fixupsEnd() : &((ld::Fixup
*)&_file
._fixupToInternal
)[1]); }
185 ld::Atom::UnwindInfo::iterator
beginUnwind() const override
186 { return (_compiledAtom
? _compiledAtom
->beginUnwind() : NULL
); }
187 ld::Atom::UnwindInfo::iterator
endUnwind() const override
188 { return (_compiledAtom
? _compiledAtom
->endUnwind() : NULL
); }
189 ld::Atom::LineInfo::iterator
beginLineInfo() const override
190 { return (_compiledAtom
? _compiledAtom
->beginLineInfo() : NULL
); }
191 ld::Atom::LineInfo::iterator
endLineInfo() const override
192 { return (_compiledAtom
? _compiledAtom
->endLineInfo() : NULL
); }
194 const ld::Atom
* compiledAtom() { return _compiledAtom
; }
195 void setCompiledAtom(const ld::Atom
& atom
);
201 const ld::Atom
* _compiledAtom
;
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
,
216 time_t modTime
, ld::File::Ordinal ordinal
, cpu_type_t architecture
, cpu_subtype_t subarch
,
217 bool logAllFiles
, bool verboseOptimizationHints
);
218 static bool libLTOisLoaded() { return (::lto_get_version() != NULL
); }
219 static bool optimize( const std::vector
<const ld::Atom
*>& allAtoms
,
221 const OptimizeOptions
& options
,
222 ld::File::AtomHandler
& handler
,
223 std::vector
<const ld::Atom
*>& newAtoms
,
224 std::vector
<const char*>& additionalUndefines
);
226 static const char* ltoVersion() { return ::lto_get_version(); }
230 static const char* tripletPrefixForArch(cpu_type_t arch
);
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
);
233 #if LTO_API_VERSION >= 7
234 static void ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t
, const char*, void*);
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
;
240 class AtomSyncer
: public ld::File::AtomHandler
{
242 AtomSyncer(std::vector
<const char*>& a
, std::vector
<const ld::Atom
*>&na
,
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
{ }
248 const OptimizeOptions
& _options
;
249 std::vector
<const char*>& _additionalUndefines
;
250 std::vector
<const ld::Atom
*>& _newAtoms
;
251 const CStringToAtom
&_llvmAtoms
;
252 const CStringToAtom
&_deadllvmAtoms
;
253 const ld::Atom
* _lastProxiedAtom
;
254 const ld::File
* _lastProxiedFile
;
257 static void setPreservedSymbols(const std::vector
<const ld::Atom
*>& allAtoms
,
259 const OptimizeOptions
& options
,
260 CStringToAtom
&deadllvmAtoms
,
261 CStringToAtom
&llvmAtoms
,
262 lto_code_gen_t generator
);
264 static std::tuple
<uint8_t *, size_t> codegen(const OptimizeOptions
& options
,
266 lto_code_gen_t generator
,
267 std::string
& object_path
);
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
);
278 static bool optimizeLTO(const std::vector
<File
*> files
,
279 const std::vector
<const ld::Atom
*>& allAtoms
,
281 const OptimizeOptions
& options
,
282 ld::File::AtomHandler
& handler
,
283 std::vector
<const ld::Atom
*>& newAtoms
,
284 std::vector
<const char*>& additionalUndefines
);
286 static bool optimizeThinLTO(const std::vector
<File
*>& Files
,
287 const std::vector
<const ld::Atom
*>& allAtoms
,
289 const OptimizeOptions
& options
,
290 ld::File::AtomHandler
& handler
,
291 std::vector
<const ld::Atom
*>& newAtoms
,
292 std::vector
<const char*>& additionalUndefines
);
294 #if LTO_API_VERSION >= 18
295 static thinlto_code_gen_t
init_thinlto_codegen(const std::vector
<File
*>& files
,
296 const std::vector
<const ld::Atom
*>& allAtoms
,
298 const OptimizeOptions
& options
,
299 CStringToAtom
& deadllvmAtoms
,
300 CStringToAtom
& llvmAtoms
);
303 static std::vector
<File
*> _s_files
;
304 static bool _s_llvmOptionsProcessed
;
307 std::vector
<File
*> Parser::_s_files
;
308 bool Parser::_s_llvmOptionsProcessed
= false;
311 bool Parser::validFile(const uint8_t* fileContent
, uint64_t fileLength
, cpu_type_t architecture
, cpu_subtype_t subarch
)
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
);
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
);
328 const char* Parser::fileKind(const uint8_t* p
, uint64_t fileLength
)
330 if ( (p
[0] == 0xDE) && (p
[1] == 0xC0) && (p
[2] == 0x17) && (p
[3] == 0x0B) ) {
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
) {
335 if ( ::lto_module_is_object_file_in_memory_for_target(p
, fileLength
, t
->llvmTriplePrefix
) )
343 return "unknown bitcode architecture";
348 File
* Parser::parse(const uint8_t* fileContent
, uint64_t fileLength
, const char* path
, time_t modTime
, ld::File::Ordinal ordinal
,
349 cpu_type_t architecture
, cpu_subtype_t subarch
, bool logAllFiles
, bool verboseOptimizationHints
)
351 File
* f
= new File(path
, modTime
, ordinal
, fileContent
, fileLength
, architecture
);
352 _s_files
.push_back(f
);
354 printf("%s\n", path
);
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
)
362 mach_o::relocatable::ParserOptions objOpts
;
363 objOpts
.architecture
= options
.arch
;
364 objOpts
.objSubtypeMustMatch
= false;
365 objOpts
.logAllFiles
= false;
366 objOpts
.warnUnwindConversionProblems
= options
.needsUnwindInfoSection
;
367 objOpts
.keepDwarfUnwind
= options
.keepDwarfUnwind
;
368 objOpts
.forceDwarfConversion
= false;
369 objOpts
.neverConvertDwarf
= false;
370 objOpts
.verboseOptimizationHints
= options
.verboseOptimizationHints
;
371 objOpts
.armUsesZeroCostExceptions
= options
.armUsesZeroCostExceptions
;
372 objOpts
.simulator
= options
.simulator
;
373 objOpts
.ignoreMismatchPlatform
= options
.ignoreMismatchPlatform
;
374 objOpts
.platform
= options
.platform
;
375 objOpts
.minOSVersion
= options
.minOSVersion
;
377 objOpts
.srcKind
= ld::relocatable::File::kSourceLTO
;
378 objOpts
.treateBitcodeAsData
= false;
379 objOpts
.usingBitcode
= options
.bitcodeBundle
;
380 objOpts
.maxDefaultCommonAlignment
= options
.maxDefaultCommonAlignment
;
382 const char *object_path
= path
.c_str();
384 object_path
= "/tmp/lto.o";
387 struct stat statBuffer
;
388 if ( stat(object_path
, &statBuffer
) == 0 )
389 modTime
= statBuffer
.st_mtime
;
391 ld::relocatable::File
* result
= mach_o::relocatable::parse(p
, len
, strdup(object_path
), modTime
, ordinal
, objOpts
);
392 if ( result
!= NULL
)
394 throw "LLVM LTO, file is not of required architecture";
399 File::File(const char* pth
, time_t mTime
, ld::File::Ordinal ordinal
, const uint8_t* content
, uint32_t contentLength
, cpu_type_t arch
)
400 : ld::relocatable::File(pth
,mTime
,ordinal
), _isThinLTO(false), _architecture(arch
), _internalAtom(*this),
401 _atomArray(NULL
), _atomArrayCount(0), _module(NULL
), _path(pth
),
402 _content(content
), _contentLength(contentLength
), _debugInfoPath(pth
),
403 _section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO
),
404 _fixupToInternal(0, ld::Fixup::k1of1
, ld::Fixup::kindNone
, &_internalAtom
),
405 _debugInfo(ld::relocatable::File::kDebugInfoNone
), _cpuSubType(0)
407 const bool log
= false;
409 // create llvm module
410 #if LTO_API_VERSION >= 11
411 if ( sSupportsLocalContext
|| !sHasTriedLocalContext
) {
412 _module
= ::lto_module_create_in_local_context(content
, contentLength
, pth
);
414 if ( !sHasTriedLocalContext
) {
415 sHasTriedLocalContext
= true;
416 sSupportsLocalContext
= (_module
!= NULL
);
418 if ( (_module
== NULL
) && !sSupportsLocalContext
)
420 #if LTO_API_VERSION >= 9
421 _module
= ::lto_module_create_from_memory_with_path(content
, contentLength
, pth
);
422 if ( _module
== NULL
&& !sSupportsLocalContext
)
424 _module
= ::lto_module_create_from_memory(content
, contentLength
);
425 if ( _module
== NULL
)
426 throwf("could not parse object file %s: '%s', using libLTO version '%s'", pth
, ::lto_get_error_message(), ::lto_get_version());
428 if ( log
) fprintf(stderr
, "bitcode file: %s\n", pth
);
430 #if LTO_API_VERSION >= 18
431 _isThinLTO
= ::lto_module_is_thinlto(_module
);
434 // create atom for each global symbol in module
435 uint32_t count
= ::lto_module_get_num_symbols(_module
);
436 _atomArray
= (Atom
*)malloc(sizeof(Atom
)*count
);
437 for (uint32_t i
=0; i
< count
; ++i
) {
438 const char* name
= ::lto_module_get_symbol_name(_module
, i
);
439 lto_symbol_attributes attr
= lto_module_get_symbol_attribute(_module
, i
);
441 // <rdar://problem/6378110> LTO doesn't like dtrace symbols
442 // ignore dtrace static probes for now
443 // later when codegen is done and a mach-o file is produces the probes will be processed
444 if ( (strncmp(name
, "___dtrace_probe$", 16) == 0) || (strncmp(name
, "___dtrace_isenabled$", 20) == 0) )
447 ld::Atom::Definition def
;
448 ld::Atom::Combine combine
= ld::Atom::combineNever
;
449 switch ( attr
& LTO_SYMBOL_DEFINITION_MASK
) {
450 case LTO_SYMBOL_DEFINITION_REGULAR
:
451 def
= ld::Atom::definitionRegular
;
453 case LTO_SYMBOL_DEFINITION_TENTATIVE
:
454 def
= ld::Atom::definitionTentative
;
456 case LTO_SYMBOL_DEFINITION_WEAK
:
457 def
= ld::Atom::definitionRegular
;
458 combine
= ld::Atom::combineByName
;
460 case LTO_SYMBOL_DEFINITION_UNDEFINED
:
461 case LTO_SYMBOL_DEFINITION_WEAKUNDEF
:
462 def
= ld::Atom::definitionProxy
;
465 throwf("unknown definition kind for symbol %s in bitcode file %s", name
, pth
);
468 // make LLVM atoms for definitions and a reference for undefines
469 if ( def
!= ld::Atom::definitionProxy
) {
470 ld::Atom::Scope scope
;
471 bool autohide
= false;
472 switch ( attr
& LTO_SYMBOL_SCOPE_MASK
) {
473 case LTO_SYMBOL_SCOPE_INTERNAL
:
474 scope
= ld::Atom::scopeTranslationUnit
;
476 case LTO_SYMBOL_SCOPE_HIDDEN
:
477 scope
= ld::Atom::scopeLinkageUnit
;
479 case LTO_SYMBOL_SCOPE_DEFAULT
:
480 scope
= ld::Atom::scopeGlobal
;
482 #if LTO_API_VERSION >= 4
483 case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN
:
484 scope
= ld::Atom::scopeGlobal
;
489 throwf("unknown scope for symbol %s in bitcode file %s", name
, pth
);
491 // only make atoms for non-internal symbols
492 if ( scope
== ld::Atom::scopeTranslationUnit
)
494 uint8_t alignment
= (attr
& LTO_SYMBOL_ALIGNMENT_MASK
);
495 // make Atom using placement new operator
496 new (&_atomArray
[_atomArrayCount
++]) Atom(*this, name
, scope
, def
, combine
, alignment
, autohide
);
497 if ( scope
!= ld::Atom::scopeTranslationUnit
)
498 _internalAtom
.addReference(name
);
499 if ( log
) fprintf(stderr
, "\t0x%08X %s\n", attr
, name
);
502 // add to list of external references
503 _internalAtom
.addReference(name
);
504 if ( log
) fprintf(stderr
, "\t%s (undefined)\n", name
);
508 #if LTO_API_VERSION >= 11
509 if ( sSupportsLocalContext
)
519 bool File::mergeIntoGenerator(lto_code_gen_t generator
, bool useSetModule
) {
520 #if LTO_API_VERSION >= 11
521 if ( sSupportsLocalContext
) {
522 assert(!_module
&& "Expected module to be disposed");
523 _module
= ::lto_module_create_in_codegen_context(_content
, _contentLength
,
525 if ( _module
== NULL
)
526 throwf("could not reparse object file %s: '%s', using libLTO version '%s'",
527 _path
, ::lto_get_error_message(), ::lto_get_version());
530 assert(_module
&& "Expected module to stick around");
531 #if LTO_API_VERSION >= 13
533 // lto_codegen_set_module will transfer ownership of the module to LTO code generator,
534 // so we don't need to release the module here.
535 ::lto_codegen_set_module(generator
, _module
);
539 if ( ::lto_codegen_add_module(generator
, _module
) )
542 // <rdar://problem/15471128> linker should release module as soon as possible
547 #if LTO_API_VERSION >= 18
548 void File::addToThinGenerator(thinlto_code_gen_t generator
, int id
) {
549 assert(!_module
&& "Expected module to be disposed");
550 std::string pathWithID
= _path
;
551 pathWithID
+= std::to_string(id
);
552 ::thinlto_codegen_add_module(generator
, strdup(pathWithID
.c_str()), (const char *)_content
, _contentLength
);
558 if ( _module
!= NULL
)
559 ::lto_module_dispose(_module
);
563 bool File::forEachAtom(ld::File::AtomHandler
& handler
) const
565 handler
.doAtom(_internalAtom
);
566 for(uint32_t i
=0; i
< _atomArrayCount
; ++i
) {
567 handler
.doAtom(_atomArray
[i
]);
572 InternalAtom::InternalAtom(File
& f
)
573 : ld::Atom(f
._section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
, ld::Atom::scopeTranslationUnit
,
574 ld::Atom::typeLTOtemporary
, ld::Atom::symbolTableNotIn
, true, false, false, ld::Atom::Alignment(0)),
579 Atom::Atom(File
& f
, const char* nm
, ld::Atom::Scope s
, ld::Atom::Definition d
, ld::Atom::Combine c
,
580 ld::Atom::Alignment a
, bool ah
)
581 : ld::Atom(f
._section
, d
, c
, s
, ld::Atom::typeLTOtemporary
,
582 ld::Atom::symbolTableIn
, false, false, false, a
),
583 _file(f
), _name(strdup(nm
)), _compiledAtom(NULL
)
589 void Atom::setCompiledAtom(const ld::Atom
& atom
)
591 // set delegate so virtual methods go to it
592 _compiledAtom
= &atom
;
594 //fprintf(stderr, "setting lto atom %p to delegate to mach-o atom %p (%s)\n", this, &atom, atom.name());
596 // update fields in ld::Atom to match newly constructed mach-o atom
597 (const_cast<Atom
*>(this))->setAttributesFromAtom(atom
);
602 // <rdar://problem/12379604> The order that files are merged must match command line order
603 struct CommandLineOrderFileSorter
605 bool operator()(File
* left
, File
* right
)
607 return ( left
->ordinal() < right
->ordinal() );
612 #if LTO_API_VERSION >= 7
613 void Parser::ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t severity
, const char* message
, void*)
615 switch ( severity
) {
616 #if LTO_API_VERSION >= 10
618 fprintf(stderr
, "ld: LTO remark: %s\n", message
);
623 warning("%s", message
);
626 throwf("%s", message
);
632 /// Instruct libLTO about the list of symbols to preserve, compute deadllvmAtoms and llvmAtoms
633 void Parser::setPreservedSymbols( const std::vector
<const ld::Atom
*>& allAtoms
,
635 const OptimizeOptions
& options
,
636 CStringToAtom
&deadllvmAtoms
,
637 CStringToAtom
&llvmAtoms
,
638 lto_code_gen_t generator
) {
639 const bool logMustPreserve
= false;
641 // The atom graph uses directed edges (references). Collect all references where
642 // originating atom is not part of any LTO Reader. This allows optimizer to optimize an
643 // external (i.e. not originated from same .o file) reference if all originating atoms are also
644 // defined in llvm bitcode file.
645 CStringSet nonLLVMRefs
;
646 bool hasNonllvmAtoms
= false;
647 for (std::vector
<const ld::Atom
*>::const_iterator it
= allAtoms
.begin(); it
!= allAtoms
.end(); ++it
) {
648 const ld::Atom
* atom
= *it
;
649 // only look at references that come from an atom that is not an LTO atom
650 if (atom
->contentType() != ld::Atom::typeLTOtemporary
||
651 ((lto::File
*)atom
->file())->isThinLTO()) {
652 if ( (atom
->section().type() != ld::Section::typeMachHeader
) && (atom
->definition() != ld::Atom::definitionProxy
) ) {
653 hasNonllvmAtoms
= true;
655 const ld::Atom
* target
;
656 for (ld::Fixup::iterator fit
=atom
->fixupsBegin(); fit
!= atom
->fixupsEnd(); ++fit
) {
657 switch ( fit
->binding
) {
658 case ld::Fixup::bindingDirectlyBound
:
659 // that reference an llvm atom
660 if ( fit
->u
.target
->contentType() == ld::Atom::typeLTOtemporary
)
661 nonLLVMRefs
.insert(fit
->u
.target
->name());
663 case ld::Fixup::bindingsIndirectlyBound
:
664 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
665 if ( (target
!= NULL
) && (target
->contentType() == ld::Atom::typeLTOtemporary
) )
666 nonLLVMRefs
.insert(target
->name());
672 else if ( atom
->scope() >= ld::Atom::scopeLinkageUnit
) {
673 llvmAtoms
[atom
->name()] = (Atom
*)atom
;
676 // if entry point is in a llvm bitcode file, it must be preserved by LTO
677 if ( state
.entryPoint
!= NULL
) {
678 if ( state
.entryPoint
->contentType() == ld::Atom::typeLTOtemporary
)
679 nonLLVMRefs
.insert(state
.entryPoint
->name());
682 // deadAtoms are the atoms that the linker coalesced. For instance weak or tentative definitions
683 // overriden by another atom. If any of these deadAtoms are llvm atoms and they were replaced
684 // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead
685 // atom so that the linker can replace it with the mach-o one later.
686 for (std::vector
<const ld::Atom
*>::const_iterator it
= allAtoms
.begin(); it
!= allAtoms
.end(); ++it
) {
687 const ld::Atom
* atom
= *it
;
688 if ( atom
->coalescedAway() && (atom
->contentType() == ld::Atom::typeLTOtemporary
) ) {
689 const char* name
= atom
->name();
690 if ( logMustPreserve
) fprintf(stderr
, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name
);
691 ::lto_codegen_add_must_preserve_symbol(generator
, name
);
692 deadllvmAtoms
[name
] = (Atom
*)atom
;
695 for (std::vector
<File
*>::iterator it
=_s_files
.begin(); it
!= _s_files
.end(); ++it
) {
697 for(uint32_t i
=0; i
< file
->_atomArrayCount
; ++i
) {
698 Atom
* llvmAtom
= &file
->_atomArray
[i
];
699 if ( llvmAtom
->coalescedAway() ) {
700 const char* name
= llvmAtom
->name();
701 if ( deadllvmAtoms
.find(name
) == deadllvmAtoms
.end() ) {
702 if ( logMustPreserve
)
703 fprintf(stderr
, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name
);
704 ::lto_codegen_add_must_preserve_symbol(generator
, name
);
705 deadllvmAtoms
[name
] = (Atom
*)llvmAtom
;
708 else if ( options
.linkerDeadStripping
&& !llvmAtom
->live() ) {
709 const char* name
= llvmAtom
->name();
710 deadllvmAtoms
[name
] = (Atom
*)llvmAtom
;
715 // tell code generator about symbols that must be preserved
716 for (CStringToAtom::iterator it
= llvmAtoms
.begin(); it
!= llvmAtoms
.end(); ++it
) {
717 const char* name
= it
->first
;
718 Atom
* atom
= it
->second
;
719 // Include llvm Symbol in export list if it meets one of following two conditions
720 // 1 - atom scope is global (and not linkage unit).
721 // 2 - included in nonLLVMRefs set.
722 // If a symbol is not listed in exportList then LTO is free to optimize it away.
723 if ( (atom
->scope() == ld::Atom::scopeGlobal
) && options
.preserveAllGlobals
) {
724 if ( logMustPreserve
) fprintf(stderr
, "lto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name
);
725 ::lto_codegen_add_must_preserve_symbol(generator
, name
);
727 else if ( nonLLVMRefs
.find(name
) != nonLLVMRefs
.end() ) {
728 if ( logMustPreserve
) fprintf(stderr
, "lto_codegen_add_must_preserve_symbol(%s) because referenced by a mach-o atom\n", name
);
729 ::lto_codegen_add_must_preserve_symbol(generator
, name
);
731 else if ( options
.relocatable
&& hasNonllvmAtoms
) {
732 // <rdar://problem/14334895> ld -r mode but merging in some mach-o files, so need to keep libLTO from optimizing away anything
733 if ( logMustPreserve
) fprintf(stderr
, "lto_codegen_add_must_preserve_symbol(%s) because -r mode disable LTO dead stripping\n", name
);
734 ::lto_codegen_add_must_preserve_symbol(generator
, name
);
738 // <rdar://problem/16165191> tell code generator to preserve initial undefines
739 for( std::vector
<const char*>::const_iterator it
=options
.initialUndefines
->begin(); it
!= options
.initialUndefines
->end(); ++it
) {
740 if ( logMustPreserve
) fprintf(stderr
, "lto_codegen_add_must_preserve_symbol(%s) because it is an initial undefine\n", *it
);
741 ::lto_codegen_add_must_preserve_symbol(generator
, *it
);
744 // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
745 if ( options
.relocatable
&& !hasNonllvmAtoms
) {
746 #if LTO_API_VERSION >= 15
747 ::lto_codegen_set_should_embed_uselists(generator
, false);
749 if ( ! ::lto_codegen_write_merged_modules(generator
, options
.outputFilePath
) ) {
750 // HACK, no good way to tell linker we are all done, so just quit
753 warning("could not produce merged bitcode file");
758 // Retrieve the codegen model from the options
759 static lto_codegen_model
getCodeModel(const OptimizeOptions
& options
) {
760 if ( options
.mainExecutable
) {
761 if ( options
.staticExecutable
) {
762 // x86_64 "static" or any "-static -pie" is really dynamic code model
763 if ( (options
.arch
== CPU_TYPE_X86_64
) || options
.pie
)
764 return LTO_CODEGEN_PIC_MODEL_DYNAMIC
;
766 return LTO_CODEGEN_PIC_MODEL_STATIC
;
768 else if ( options
.preload
) {
770 return LTO_CODEGEN_PIC_MODEL_DYNAMIC
;
772 return LTO_CODEGEN_PIC_MODEL_STATIC
;
776 return LTO_CODEGEN_PIC_MODEL_DYNAMIC
;
778 return LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC
;
782 if ( options
.allowTextRelocs
)
783 return LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC
;
785 return LTO_CODEGEN_PIC_MODEL_DYNAMIC
;
790 std::tuple
<uint8_t *, size_t> Parser::codegen(const OptimizeOptions
& options
,
792 lto_code_gen_t generator
,
793 std::string
& object_path
) {
797 if ( ::lto_codegen_set_pic_model(generator
, getCodeModel(options
)) )
798 throwf("could not create set codegen model: %s", lto_get_error_message());
800 // if requested, save off merged bitcode file
801 if ( options
.saveTemps
) {
802 char tempBitcodePath
[MAXPATHLEN
];
803 strcpy(tempBitcodePath
, options
.outputFilePath
);
804 strcat(tempBitcodePath
, ".lto.bc");
805 #if LTO_API_VERSION >= 15
806 ::lto_codegen_set_should_embed_uselists(generator
, true);
808 ::lto_codegen_write_merged_modules(generator
, tempBitcodePath
);
811 #if LTO_API_VERSION >= 3
812 // find assembler next to linker
814 uint32_t bufSize
= PATH_MAX
;
815 if ( _NSGetExecutablePath(path
, &bufSize
) != -1 ) {
816 char* lastSlash
= strrchr(path
, '/');
817 if ( lastSlash
!= NULL
) {
818 strcpy(lastSlash
+1, "as");
819 struct stat statInfo
;
820 if ( stat(path
, &statInfo
) == 0 )
821 ::lto_codegen_set_assembler_path(generator
, path
);
826 // When lto API version is greater than or equal to 12, we use lto_codegen_optimize and lto_codegen_compile_optimized
827 // instead of lto_codegen_compile, and we save the merged bitcode file in between.
828 bool useSplitAPI
= false;
829 #if LTO_API_VERSION >= 12
830 if ( ::lto_api_version() >= 12)
835 #if LTO_API_VERSION >= 12
836 #if LTO_API_VERSION >= 14
837 if ( ::lto_api_version() >= 14 && options
.ltoCodegenOnly
)
838 lto_codegen_set_should_internalize(generator
, false);
841 if ( !options
.ltoCodegenOnly
&& ::lto_codegen_optimize(generator
) )
842 throwf("could not do LTO optimization: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version());
844 if ( options
.saveTemps
|| options
.bitcodeBundle
) {
845 // save off merged bitcode file
846 char tempOptBitcodePath
[MAXPATHLEN
];
847 strcpy(tempOptBitcodePath
, options
.outputFilePath
);
848 strcat(tempOptBitcodePath
, ".lto.opt.bc");
849 #if LTO_API_VERSION >= 15
850 ::lto_codegen_set_should_embed_uselists(generator
, true);
852 ::lto_codegen_write_merged_modules(generator
, tempOptBitcodePath
);
853 if ( options
.bitcodeBundle
)
854 state
.ltoBitcodePath
.push_back(tempOptBitcodePath
);
857 // run code generator
858 machOFile
= (uint8_t*)::lto_codegen_compile_optimized(generator
, &machOFileLen
);
860 if ( machOFile
== NULL
)
861 throwf("could not do LTO codegen: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version());
864 // run optimizer and code generator
865 machOFile
= (uint8_t*)::lto_codegen_compile(generator
, &machOFileLen
);
866 if ( machOFile
== NULL
)
867 throwf("could not do LTO codegen: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version());
868 if ( options
.saveTemps
) {
869 // save off merged bitcode file
870 char tempOptBitcodePath
[MAXPATHLEN
];
871 strcpy(tempOptBitcodePath
, options
.outputFilePath
);
872 strcat(tempOptBitcodePath
, ".lto.opt.bc");
873 #if LTO_API_VERSION >= 15
874 ::lto_codegen_set_should_embed_uselists(generator
, true);
876 ::lto_codegen_write_merged_modules(generator
, tempOptBitcodePath
);
880 // if requested, save off temp mach-o file
881 if ( options
.saveTemps
) {
882 char tempMachoPath
[MAXPATHLEN
];
883 strcpy(tempMachoPath
, options
.outputFilePath
);
884 strcat(tempMachoPath
, ".lto.o");
885 int fd
= ::open(tempMachoPath
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
887 ::write(fd
, machOFile
, machOFileLen
);
892 // if needed, save temp mach-o file to specific location
893 if ( !object_path
.empty() ) {
894 int fd
= ::open(object_path
.c_str(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
896 ::write(fd
, machOFile
, machOFileLen
);
900 warning("could not write LTO temp file '%s', errno=%d", object_path
.c_str(), errno
);
903 return std::make_tuple(machOFile
, machOFileLen
);
906 /// Load the MachO located in buffer \p machOFile with size \p machOFileLen.
907 /// The loaded atoms are sync'ed using all the supplied lists.
908 void Parser::loadMachO(ld::relocatable::File
* machoFile
,
909 const OptimizeOptions
& options
,
910 ld::File::AtomHandler
& handler
,
911 std::vector
<const ld::Atom
*>& newAtoms
,
912 std::vector
<const char*>& additionalUndefines
,
913 CStringToAtom
&llvmAtoms
,
914 CStringToAtom
&deadllvmAtoms
) {
915 const bool logAtomsBeforeSync
= false;
917 // sync generated mach-o atoms with existing atoms ld knows about
918 if ( logAtomsBeforeSync
) {
919 fprintf(stderr
, "llvmAtoms:\n");
920 for (CStringToAtom::iterator it
= llvmAtoms
.begin(); it
!= llvmAtoms
.end(); ++it
) {
921 const char* name
= it
->first
;
922 Atom
* atom
= it
->second
;
923 fprintf(stderr
, "\t%p\t%s\n", atom
, name
);
925 fprintf(stderr
, "deadllvmAtoms:\n");
926 for (CStringToAtom::iterator it
= deadllvmAtoms
.begin(); it
!= deadllvmAtoms
.end(); ++it
) {
927 const char* name
= it
->first
;
928 Atom
* atom
= it
->second
;
929 fprintf(stderr
, "\t%p\t%s\n", atom
, name
);
932 AtomSyncer
syncer(additionalUndefines
, newAtoms
, llvmAtoms
, deadllvmAtoms
, options
);
933 machoFile
->forEachAtom(syncer
);
935 // notify about file level attributes
936 handler
.doFile(*machoFile
);
939 // Full LTO processing
940 bool Parser::optimizeLTO(const std::vector
<File
*> files
,
941 const std::vector
<const ld::Atom
*>& allAtoms
,
943 const OptimizeOptions
& options
,
944 ld::File::AtomHandler
& handler
,
945 std::vector
<const ld::Atom
*>& newAtoms
,
946 std::vector
<const char*>& additionalUndefines
) {
947 const bool logExtraOptions
= false;
948 const bool logBitcodeFiles
= false;
953 // create optimizer and add each Reader
954 lto_code_gen_t generator
= NULL
;
955 #if LTO_API_VERSION >= 11
956 if ( File::sSupportsLocalContext
)
957 generator
= ::lto_codegen_create_in_local_context();
960 generator
= ::lto_codegen_create();
961 #if LTO_API_VERSION >= 7
962 lto_codegen_set_diagnostic_handler(generator
, ltoDiagnosticHandler
, NULL
);
965 ld::File::Ordinal lastOrdinal
;
967 // When flto_codegen_only is on and we have a single .bc file, use lto_codegen_set_module instead of
968 // lto_codegen_add_module, to make sure the the destination module will be the same as the input .bc file.
969 bool useSetModule
= false;
970 #if LTO_API_VERSION >= 13
971 useSetModule
= (files
.size() == 1) && options
.ltoCodegenOnly
&& (::lto_api_version() >= 13);
973 for (auto *f
: files
) {
974 assert(f
->ordinal() > lastOrdinal
);
975 if ( logBitcodeFiles
&& !useSetModule
) fprintf(stderr
, "lto_codegen_add_module(%s)\n", f
->path());
976 if ( logBitcodeFiles
&& useSetModule
) fprintf(stderr
, "lto_codegen_set_module(%s)\n", f
->path());
977 if ( f
->mergeIntoGenerator(generator
, useSetModule
) )
978 throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", f
->path(), ::lto_get_error_message(), ::lto_get_version());
979 lastOrdinal
= f
->ordinal();
982 // add any -mllvm command line options
983 if ( !_s_llvmOptionsProcessed
) {
984 for (const char* opt
: *options
.llvmOptions
) {
985 if ( logExtraOptions
) fprintf(stderr
, "passing option to llvm: %s\n", opt
);
986 ::lto_codegen_debug_options(generator
, opt
);
988 _s_llvmOptionsProcessed
= true;
991 // <rdar://problem/13687397> Need a way for LTO to get cpu variants (until that info is in bitcode)
992 if ( options
.mcpu
!= NULL
)
993 ::lto_codegen_set_cpu(generator
, options
.mcpu
);
995 // Compute the preserved symbols
996 CStringToAtom deadllvmAtoms
, llvmAtoms
;
997 setPreservedSymbols(allAtoms
, state
, options
, deadllvmAtoms
, llvmAtoms
, generator
);
999 size_t machOFileLen
= 0;
1000 const uint8_t* machOFile
= NULL
;
1002 // mach-o parsing is done in-memory, but need path for debug notes
1003 std::string object_path
;
1004 if ( options
.tmpObjectFilePath
!= NULL
) {
1005 object_path
= options
.tmpObjectFilePath
;
1006 // If the path exists and is a directory (for instance if some files
1007 // were processed with ThinLTO before), we create the LTO file inside
1009 struct stat statBuffer
;
1010 if( stat(object_path
.c_str(), &statBuffer
) == 0 && S_ISDIR(statBuffer
.st_mode
) ) {
1011 object_path
+= "/lto.o";
1016 std::tie(machOFile
, machOFileLen
) = codegen(options
, state
, generator
, object_path
);
1018 // parse generated mach-o file into a MachOReader
1019 ld::relocatable::File
* machoFile
= parseMachOFile(machOFile
, machOFileLen
, object_path
, options
, ld::File::Ordinal::LTOOrdinal());
1021 // Load the generated MachO file
1022 loadMachO(machoFile
, options
, handler
, newAtoms
, additionalUndefines
, llvmAtoms
, deadllvmAtoms
);
1024 // Remove Atoms from ld if code generator optimized them away
1025 for (CStringToAtom::iterator li
= llvmAtoms
.begin(), le
= llvmAtoms
.end(); li
!= le
; ++li
) {
1026 // check if setRealAtom() called on this Atom
1027 if ( li
->second
->compiledAtom() == NULL
) {
1028 //fprintf(stderr, "llvm optimized away %p %s\n", li->second, li->second->name());
1029 li
->second
->setCoalescedAway();
1033 // if final mach-o file has debug info, update original bitcode files to match
1034 for (auto *f
: files
) {
1035 f
->setDebugInfo(machoFile
->debugInfo(), machoFile
->path(), machoFile
->modificationTime(), machoFile
->cpuSubType());
1041 #if LTO_API_VERSION >= 18
1042 // Create the ThinLTO codegenerator
1043 thinlto_code_gen_t
Parser::init_thinlto_codegen(const std::vector
<File
*>& files
,
1044 const std::vector
<const ld::Atom
*>& allAtoms
,
1045 ld::Internal
& state
,
1046 const OptimizeOptions
& options
,
1047 CStringToAtom
& deadllvmAtoms
,
1048 CStringToAtom
& llvmAtoms
) {
1049 const bool logMustPreserve
= false;
1051 thinlto_code_gen_t thingenerator
= ::thinlto_create_codegen();
1054 if (options
.ltoCachePath
&& !options
.bitcodeBundle
) {
1055 struct stat statBuffer
;
1056 if( stat(options
.ltoCachePath
, &statBuffer
) != 0 || !S_ISDIR(statBuffer
.st_mode
) ) {
1057 if ( mkdir(options
.ltoCachePath
, 0700) !=0 ) {
1058 warning("unable to create ThinLTO cache directory: %s", options
.ltoCachePath
);
1061 thinlto_codegen_set_cache_dir(thingenerator
, options
.ltoCachePath
);
1062 thinlto_codegen_set_cache_pruning_interval(thingenerator
, options
.ltoPruneInterval
);
1063 thinlto_codegen_set_cache_entry_expiration(thingenerator
, options
.ltoPruneAfter
);
1064 thinlto_codegen_set_final_cache_size_relative_to_available_space(thingenerator
, options
.ltoMaxCacheSize
);
1067 // if requested, ask the code generator to save off intermediate bitcode files
1068 if ( options
.saveTemps
) {
1069 std::string tempPath
= options
.outputFilePath
;
1070 tempPath
+= ".thinlto.bcs/";
1071 struct stat statBuffer
;
1072 if( stat(tempPath
.c_str(), &statBuffer
) != 0 || !S_ISDIR(statBuffer
.st_mode
) ) {
1073 if ( mkdir(tempPath
.c_str(), 0700) !=0 ) {
1074 warning("unable to create ThinLTO output directory for temporary bitcode files: %s", tempPath
.c_str());
1077 thinlto_codegen_set_savetemps_dir(thingenerator
, tempPath
.c_str());
1080 // Set some codegen options
1081 if ( thinlto_codegen_set_pic_model(thingenerator
, getCodeModel(options
)) )
1082 throwf("could not create set codegen model: %s", lto_get_error_message());
1084 // Expose reachability informations for internalization in LTO
1086 // The atom graph uses directed edges (references). Collect all references where
1087 // originating atom is not part of any LTO Reader. This allows optimizer to optimize an
1088 // external (i.e. not originated from same .o file) reference if all originating atoms are also
1089 // defined in llvm bitcode file.
1090 CStringSet nonLLVMRefs
;
1091 CStringSet LLVMRefs
;
1092 for (std::vector
<const ld::Atom
*>::const_iterator it
= allAtoms
.begin(); it
!= allAtoms
.end(); ++it
) {
1093 const ld::Atom
* atom
= *it
;
1094 const ld::Atom
* target
;
1095 for (ld::Fixup::iterator fit
=atom
->fixupsBegin(); fit
!= atom
->fixupsEnd(); ++fit
) {
1096 switch ( fit
->binding
) {
1097 case ld::Fixup::bindingDirectlyBound
:
1098 // that reference a ThinLTO llvm atom
1099 target
= fit
->u
.target
;
1100 if ( target
->contentType() == ld::Atom::typeLTOtemporary
&&
1101 ((lto::File
*)target
->file())->isThinLTO() &&
1102 atom
->file() != target
->file()
1104 if (atom
->contentType() != ld::Atom::typeLTOtemporary
||
1105 !((lto::File
*)atom
->file())->isThinLTO())
1106 nonLLVMRefs
.insert(target
->name());
1108 LLVMRefs
.insert(target
->name());
1109 if ( logMustPreserve
)
1110 fprintf(stderr
, "Found a reference from %s -> %s\n", atom
->name(), target
->name());
1113 case ld::Fixup::bindingsIndirectlyBound
:
1114 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
1115 if ( (target
!= NULL
) && (target
->contentType() == ld::Atom::typeLTOtemporary
) &&
1116 ((lto::File
*)target
->file())->isThinLTO() &&
1117 atom
->file() != target
->file()
1119 if (atom
->contentType() != ld::Atom::typeLTOtemporary
||
1120 !((lto::File
*)atom
->file())->isThinLTO())
1121 nonLLVMRefs
.insert(target
->name());
1123 LLVMRefs
.insert(target
->name());
1124 if ( logMustPreserve
)
1125 fprintf(stderr
, "Found a reference from %s -> %s\n", atom
->name(), target
->name());
1131 if (atom
->contentType() == ld::Atom::typeLTOtemporary
&&
1132 ((lto::File
*)atom
->file())->isThinLTO()) {
1133 llvmAtoms
[atom
->name()] = (Atom
*)atom
;
1136 // if entry point is in a llvm bitcode file, it must be preserved by LTO
1137 if ( state
.entryPoint
!= NULL
) {
1138 if ( state
.entryPoint
->contentType() == ld::Atom::typeLTOtemporary
)
1139 nonLLVMRefs
.insert(state
.entryPoint
->name());
1141 for (auto file
: files
) {
1142 for(uint32_t i
=0; i
< file
->_atomArrayCount
; ++i
) {
1143 Atom
* llvmAtom
= &file
->_atomArray
[i
];
1144 if ( llvmAtom
->coalescedAway() ) {
1145 const char* name
= llvmAtom
->name();
1146 if ( deadllvmAtoms
.find(name
) == deadllvmAtoms
.end() ) {
1147 if ( logMustPreserve
)
1148 fprintf(stderr
, "thinlto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name
);
1149 ::thinlto_codegen_add_must_preserve_symbol(thingenerator
, name
, strlen(name
));
1150 deadllvmAtoms
[name
] = (Atom
*)llvmAtom
;
1153 else if ( options
.linkerDeadStripping
&& !llvmAtom
->live() ) {
1154 const char* name
= llvmAtom
->name();
1155 deadllvmAtoms
[name
] = (Atom
*)llvmAtom
;
1160 // tell code generator about symbols that must be preserved
1161 for (CStringToAtom::iterator it
= llvmAtoms
.begin(); it
!= llvmAtoms
.end(); ++it
) {
1162 const char* name
= it
->first
;
1163 Atom
* atom
= it
->second
;
1164 // Include llvm Symbol in export list if it meets one of following two conditions
1165 // 1 - atom scope is global (and not linkage unit).
1166 // 2 - included in nonLLVMRefs set.
1167 // If a symbol is not listed in exportList then LTO is free to optimize it away.
1168 if ( (atom
->scope() == ld::Atom::scopeGlobal
) && options
.preserveAllGlobals
) {
1169 if ( logMustPreserve
) fprintf(stderr
, "thinlto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name
);
1170 ::thinlto_codegen_add_must_preserve_symbol(thingenerator
, name
, strlen(name
));
1172 else if ( nonLLVMRefs
.find(name
) != nonLLVMRefs
.end() ) {
1173 if ( logMustPreserve
) fprintf(stderr
, "thinlto_codegen_add_must_preserve_symbol(%s) because referenced from outside of ThinLTO\n", name
);
1174 ::thinlto_codegen_add_must_preserve_symbol(thingenerator
, name
, strlen(name
));
1176 else if ( LLVMRefs
.find(name
) != LLVMRefs
.end() ) {
1177 if ( logMustPreserve
) fprintf(stderr
, "thinlto_codegen_add_cross_referenced_symbol(%s) because referenced from another file\n", name
);
1178 ::thinlto_codegen_add_cross_referenced_symbol(thingenerator
, name
, strlen(name
));
1180 if ( logMustPreserve
) fprintf(stderr
, "NOT preserving(%s)\n", name
);
1182 // FIXME: to be implemented
1183 // else if ( options.relocatable && hasNonllvmAtoms ) {
1184 // // <rdar://problem/14334895> ld -r mode but merging in some mach-o files, so need to keep libLTO from optimizing away anything
1185 // if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because -r mode disable LTO dead stripping\n", name);
1186 // ::thinlto_codegen_add_must_preserve_symbol(thingenerator, name, strlen(name));
1190 return thingenerator
;
1194 // Full LTO processing
1195 bool Parser::optimizeThinLTO(const std::vector
<File
*>& files
,
1196 const std::vector
<const ld::Atom
*>& allAtoms
,
1197 ld::Internal
& state
,
1198 const OptimizeOptions
& options
,
1199 ld::File::AtomHandler
& handler
,
1200 std::vector
<const ld::Atom
*>& newAtoms
,
1201 std::vector
<const char*>& additionalUndefines
) {
1202 const bool logBitcodeFiles
= false;
1207 #if LTO_API_VERSION >= 18
1209 if (::lto_api_version() < 18)
1210 throwf("lto: could not use -thinlto because libLTO is too old (version '%d', >=18 is required)", ::lto_api_version());
1212 // Handle -mllvm options
1213 if ( !_s_llvmOptionsProcessed
) {
1214 thinlto_debug_options(options
.llvmOptions
->data(), options
.llvmOptions
->size());
1215 _s_llvmOptionsProcessed
= true;
1218 // Create the ThinLTO codegenerator
1219 CStringToAtom deadllvmAtoms
;
1220 CStringToAtom llvmAtoms
;
1221 thinlto_code_gen_t thingenerator
= init_thinlto_codegen(files
, allAtoms
, state
, options
, deadllvmAtoms
, llvmAtoms
);
1224 ld::File::Ordinal lastOrdinal
;
1226 for (auto *f
: files
) {
1227 if ( logBitcodeFiles
) fprintf(stderr
, "thinlto_codegen_add_module(%s)\n", f
->path());
1228 f
->addToThinGenerator(thingenerator
, FileId
++);
1229 lastOrdinal
= f
->ordinal();
1232 #if LTO_API_VERSION >= 19
1233 // In the bitcode bundle case, we first run the generator with codegen disabled
1234 // and get the bitcode output. These files are added for later bundling, and a
1235 // new codegenerator is setup with these as input, and the optimizer disabled.
1236 if (options
.bitcodeBundle
) {
1237 // Bitcode Bundle case
1238 thinlto_codegen_disable_codegen(thingenerator
, true);
1239 // Process the optimizer only
1240 thinlto_codegen_process(thingenerator
);
1241 auto numObjects
= thinlto_module_get_num_objects(thingenerator
);
1242 // Save the codegenerator
1243 thinlto_code_gen_t bitcode_generator
= thingenerator
;
1244 // Create a new codegen generator for the codegen part.
1245 thingenerator
= init_thinlto_codegen(files
, allAtoms
, state
, options
, deadllvmAtoms
, llvmAtoms
);
1246 // Disable the optimizer
1247 thinlto_codegen_set_codegen_only(thingenerator
, true);
1249 // Save bitcode files for later, and add them to the codegen generator.
1250 for (unsigned bufID
= 0; bufID
< numObjects
; ++bufID
) {
1251 auto machOFile
= thinlto_module_get_object(bitcode_generator
, bufID
);
1252 std::string tempMachoPath
= options
.outputFilePath
;
1253 tempMachoPath
+= ".";
1254 tempMachoPath
+= std::to_string(bufID
);
1255 tempMachoPath
+= ".thinlto.o.bc";
1256 state
.ltoBitcodePath
.push_back(tempMachoPath
);
1257 int fd
= ::open(tempMachoPath
.c_str(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
1259 ::write(fd
, machOFile
.Buffer
, machOFile
.Size
);
1262 throwf("unable to write temporary ThinLTO output: %s", tempMachoPath
.c_str());
1265 // Add the optimized bitcode to the codegen generator now.
1266 ::thinlto_codegen_add_module(thingenerator
, strdup(tempMachoPath
.c_str()), (const char *)machOFile
.Buffer
, machOFile
.Size
);
1270 if (options
.ltoCodegenOnly
)
1271 // Disable the optimizer
1272 thinlto_codegen_set_codegen_only(thingenerator
, true);
1275 // If object_path_lto is used, we switch to a file-based API: libLTO will
1276 // generate the files on disk and we'll map them on-demand.
1278 #if LTO_API_VERSION >= 21
1279 bool useFileBasedAPI
= (options
.tmpObjectFilePath
&& ::lto_api_version() >= 21);
1280 if ( useFileBasedAPI
)
1281 thinlto_set_generated_objects_dir(thingenerator
, options
.tmpObjectFilePath
);
1284 // run code generator
1285 thinlto_codegen_process(thingenerator
);
1287 unsigned numObjects
;
1288 #if LTO_API_VERSION >= 21
1289 if ( useFileBasedAPI
)
1290 numObjects
= thinlto_module_get_num_object_files(thingenerator
);
1293 numObjects
= thinlto_module_get_num_objects(thingenerator
);
1294 if ( numObjects
== 0 )
1295 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());
1297 auto get_thinlto_buffer_or_load_file
= [&] (unsigned ID
) {
1298 #if LTO_API_VERSION >= 21
1299 if ( useFileBasedAPI
) {
1300 const char* path
= thinlto_module_get_object_file(thingenerator
, ID
);
1301 // map in whole file
1302 struct stat stat_buf
;
1303 int fd
= ::open(path
, O_RDONLY
, 0);
1305 throwf("can't open thinlto file '%s', errno=%d", path
, errno
);
1306 if ( ::fstat(fd
, &stat_buf
) != 0 )
1307 throwf("fstat thinlto file '%s' failed, errno=%d\n", path
, errno
);
1308 size_t len
= stat_buf
.st_size
;
1310 throwf("ThinLTO file '%s' too small (length=%zu)", path
, len
);
1311 const char* p
= (const char*)::mmap(NULL
, len
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1312 if ( p
== (const char*)(-1) )
1313 throwf("can't map file, errno=%d", errno
);
1315 return LTOObjectBuffer
{ p
, len
};
1318 return thinlto_module_get_object(thingenerator
, ID
);
1321 // if requested, save off objects files
1322 if ( options
.saveTemps
) {
1323 for (unsigned bufID
= 0; bufID
< numObjects
; ++bufID
) {
1324 auto machOFile
= get_thinlto_buffer_or_load_file(bufID
);
1325 std::string tempMachoPath
= options
.outputFilePath
;
1326 tempMachoPath
+= ".";
1327 tempMachoPath
+= std::to_string(bufID
);
1328 tempMachoPath
+= ".thinlto.o";
1329 int fd
= ::open(tempMachoPath
.c_str(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
1331 ::write(fd
, machOFile
.Buffer
, machOFile
.Size
);
1335 warning("unable to write temporary ThinLTO output: %s", tempMachoPath
.c_str());
1340 // mach-o parsing is done in-memory, but need path for debug notes
1341 std::string macho_dirpath
= "/tmp/thinlto.o";
1342 if ( options
.tmpObjectFilePath
!= NULL
) {
1343 macho_dirpath
= options
.tmpObjectFilePath
;
1344 struct stat statBuffer
;
1345 if( stat(macho_dirpath
.c_str(), &statBuffer
) != 0 || !S_ISDIR(statBuffer
.st_mode
) ) {
1346 unlink(macho_dirpath
.c_str());
1347 if ( mkdir(macho_dirpath
.c_str(), 0700) !=0 ) {
1348 warning("unable to create ThinLTO output directory for temporary object files: %s", macho_dirpath
.c_str());
1353 auto ordinal
= ld::File::Ordinal::LTOOrdinal().nextFileListOrdinal();
1354 for (unsigned bufID
= 0; bufID
< numObjects
; ++bufID
) {
1355 auto machOFile
= get_thinlto_buffer_or_load_file(bufID
);
1356 if (!machOFile
.Size
) {
1357 warning("Ignoring empty buffer generated by ThinLTO");
1361 // mach-o parsing is done in-memory, but need path for debug notes
1362 std::string tmp_path
;
1363 #if LTO_API_VERSION >= 21
1364 if ( useFileBasedAPI
) {
1365 tmp_path
= thinlto_module_get_object_file(thingenerator
, bufID
);
1369 if ( options
.tmpObjectFilePath
!= NULL
) {
1370 tmp_path
= macho_dirpath
+ "/" + std::to_string(bufID
) + ".o";
1371 // if needed, save temp mach-o file to specific location
1372 int fd
= ::open(tmp_path
.c_str(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
1374 ::write(fd
, (const uint8_t *)machOFile
.Buffer
, machOFile
.Size
);
1378 warning("could not write ThinLTO temp file '%s', errno=%d", tmp_path
.c_str(), errno
);
1382 // parse generated mach-o file into a MachOReader
1383 ld::relocatable::File
* machoFile
= parseMachOFile((const uint8_t *)machOFile
.Buffer
, machOFile
.Size
, tmp_path
, options
, ordinal
);
1384 ordinal
= ordinal
.nextFileListOrdinal();
1386 // Load the generated MachO file
1387 loadMachO(machoFile
, options
, handler
, newAtoms
, additionalUndefines
, llvmAtoms
, deadllvmAtoms
);
1390 // Remove Atoms from ld if code generator optimized them away
1391 for (CStringToAtom::iterator li
= llvmAtoms
.begin(), le
= llvmAtoms
.end(); li
!= le
; ++li
) {
1392 // check if setRealAtom() called on this Atom
1393 if ( li
->second
->compiledAtom() == NULL
) {
1394 //fprintf(stderr, "llvm optimized away %p %s\n", li->second, li->second->name());
1395 li
->second
->setCoalescedAway();
1400 #else // ! (LTO_API_VERSION >= 18)
1401 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
);
1405 bool Parser::optimize( const std::vector
<const ld::Atom
*>& allAtoms
,
1406 ld::Internal
& state
,
1407 const OptimizeOptions
& options
,
1408 ld::File::AtomHandler
& handler
,
1409 std::vector
<const ld::Atom
*>& newAtoms
,
1410 std::vector
<const char*>& additionalUndefines
)
1413 // exit quickly if nothing to do
1414 if ( _s_files
.size() == 0 )
1417 // print out LTO version string if -v was used
1418 if ( options
.verbose
)
1419 fprintf(stderr
, "%s\n", ::lto_get_version());
1421 // <rdar://problem/12379604> The order that files are merged must match command line order
1422 std::sort(_s_files
.begin(), _s_files
.end(), CommandLineOrderFileSorter());
1424 #if LTO_API_VERSION >= 19
1425 // If ltoCodegenOnly is set, we don't want to merge any bitcode files and perform FullLTO
1426 // we just take the ThinLTO path (optimization will be disabled anyway).
1427 if (options
.ltoCodegenOnly
) {
1428 for (auto *file
: _s_files
) {
1429 file
->setIsThinLTO(true);
1434 std::vector
<File
*> theLTOFiles
;
1435 std::vector
<File
*> theThinLTOFiles
;
1436 for (auto *file
: _s_files
) {
1437 if (file
->isThinLTO()) {
1438 theThinLTOFiles
.push_back(file
);
1440 theLTOFiles
.push_back(file
);
1444 auto result
= optimizeThinLTO(theThinLTOFiles
, allAtoms
, state
, options
, handler
, newAtoms
, additionalUndefines
) &&
1445 optimizeLTO(theLTOFiles
, allAtoms
, state
, options
, handler
, newAtoms
, additionalUndefines
);
1447 // Remove InternalAtoms from ld
1448 for (std::vector
<File
*>::iterator it
=_s_files
.begin(); it
!= _s_files
.end(); ++it
) {
1449 (*it
)->internalAtom().setCoalescedAway();
1456 void Parser::AtomSyncer::doAtom(const ld::Atom
& machoAtom
)
1458 static const bool log
= false;
1459 // update proxy atoms to point to real atoms and find new atoms
1460 const char* name
= machoAtom
.name();
1461 CStringToAtom::const_iterator pos
= _llvmAtoms
.find(name
);
1462 if ( pos
!= _llvmAtoms
.end() ) {
1463 // turn Atom into a proxy for this mach-o atom
1464 if (pos
->second
->scope() == ld::Atom::scopeLinkageUnit
) {
1465 if (log
) fprintf(stderr
, "demote %s to hidden after LTO\n", name
);
1466 (const_cast<ld::Atom
*>(&machoAtom
))->setScope(ld::Atom::scopeLinkageUnit
);
1468 pos
->second
->setCompiledAtom(machoAtom
);
1469 _lastProxiedAtom
= &machoAtom
;
1470 _lastProxiedFile
= pos
->second
->file();
1471 if (log
) fprintf(stderr
, "AtomSyncer, mach-o atom %p synced to lto atom %p (name=%s)\n", &machoAtom
, pos
->second
, machoAtom
.name());
1474 // an atom of this name was not in the allAtoms list the linker gave us
1475 auto llvmAtom
= _deadllvmAtoms
.find(name
);
1476 if ( llvmAtom
!= _deadllvmAtoms
.end() ) {
1477 // this corresponding to an atom that the linker coalesced away or marked not-live
1478 if ( _options
.linkerDeadStripping
) {
1479 // llvm seems to want this atom and -dead_strip is enabled, so it will be deleted if not needed, so add back
1480 llvmAtom
->second
->setCompiledAtom(machoAtom
);
1481 _newAtoms
.push_back(&machoAtom
);
1482 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());
1485 // Don't pass it back as a new atom
1486 if (log
) fprintf(stderr
, "AtomSyncer, mach-o atom %p matches dead lto atom %p (name=%s)\n", &machoAtom
, llvmAtom
->second
, machoAtom
.name());
1487 if ( llvmAtom
->second
->coalescedAway() ) {
1488 if (log
) fprintf(stderr
, "AtomSyncer: dead coalesced atom %s\n", machoAtom
.name());
1489 // <rdar://problem/28269547>
1490 // We told libLTO to keep a weak atom that will replaced by an native mach-o atom.
1491 // We also need to remove any atoms directly dependent on this (FDE, LSDA).
1492 for (ld::Fixup::iterator fit
=machoAtom
.fixupsBegin(), fend
=machoAtom
.fixupsEnd(); fit
!= fend
; ++fit
) {
1493 switch ( fit
->kind
) {
1494 case ld::Fixup::kindNoneGroupSubordinate
:
1495 case ld::Fixup::kindNoneGroupSubordinateFDE
:
1496 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
1497 assert(fit
->binding
== ld::Fixup::bindingDirectlyBound
);
1498 (const_cast<ld::Atom
*>(fit
->u
.target
))->setCoalescedAway();
1499 if (log
) fprintf(stderr
, "AtomSyncer: mark coalesced-away subordinate atom %s\n", fit
->u
.target
->name());
1510 // this is something new that lto conjured up, tell ld its new
1511 _newAtoms
.push_back(&machoAtom
);
1512 // <rdar://problem/15469363> if new static atom in same section as previous non-static atom, assign to same file as previous
1513 if ( (_lastProxiedAtom
!= NULL
) && (_lastProxiedAtom
->section() == machoAtom
.section()) ) {
1514 ld::Atom
* ma
= const_cast<ld::Atom
*>(&machoAtom
);
1515 ma
->setFile(_lastProxiedFile
);
1516 if (log
) fprintf(stderr
, "AtomSyncer, mach-o atom %s is proxied to %s (path=%s)\n", machoAtom
.name(), _lastProxiedAtom
->name(), _lastProxiedFile
->path());
1518 if (log
) fprintf(stderr
, "AtomSyncer, mach-o atom %p is totally new (name=%s)\n", &machoAtom
, machoAtom
.name());
1522 // adjust fixups to go through proxy atoms
1523 if (log
) fprintf(stderr
, " adjusting fixups in atom: %s\n", machoAtom
.name());
1524 for (ld::Fixup::iterator fit
=machoAtom
.fixupsBegin(); fit
!= machoAtom
.fixupsEnd(); ++fit
) {
1525 switch ( fit
->binding
) {
1526 case ld::Fixup::bindingNone
:
1528 case ld::Fixup::bindingByNameUnbound
:
1529 // don't know if this target has been seen by linker before or if it is new
1530 // be conservative and tell linker it is new
1531 _additionalUndefines
.push_back(fit
->u
.name
);
1532 if (log
) fprintf(stderr
, " adding by-name symbol %s\n", fit
->u
.name
);
1534 case ld::Fixup::bindingDirectlyBound
:
1535 // If mach-o atom is referencing another mach-o atom then
1536 // reference is not going through Atom proxy. Fix it here to ensure that all
1537 // llvm symbol references always go through Atom proxy.
1539 const char* targetName
= fit
->u
.target
->name();
1540 CStringToAtom::const_iterator post
= _llvmAtoms
.find(targetName
);
1541 if ( post
!= _llvmAtoms
.end() ) {
1542 const ld::Atom
* t
= post
->second
;
1543 if (log
) fprintf(stderr
, " updating direct reference to %p to be ref to %p: %s\n", fit
->u
.target
, t
, targetName
);
1547 // <rdar://problem/12859831> Don't unbind follow-on reference into by-name reference
1548 if ( (_deadllvmAtoms
.find(targetName
) != _deadllvmAtoms
.end()) && (fit
->kind
!= ld::Fixup::kindNoneFollowOn
) && (fit
->u
.target
->scope() != ld::Atom::scopeTranslationUnit
) ) {
1549 // target was coalesed away and replace by mach-o atom from a non llvm .o file
1550 fit
->binding
= ld::Fixup::bindingByNameUnbound
;
1551 fit
->u
.name
= targetName
;
1555 //fprintf(stderr, " direct ref to: %s (scope=%d)\n", fit->u.target->name(), fit->u.target->scope());
1557 case ld::Fixup::bindingByContentBound
:
1558 //fprintf(stderr, " direct by content to: %s\n", fit->u.target->name());
1560 case ld::Fixup::bindingsIndirectlyBound
:
1561 assert(0 && "indirect binding found in initial mach-o file?");
1562 //fprintf(stderr, " indirect by content to: %u\n", fit->u.bindingIndex);
1570 static pthread_mutex_t lto_lock
;
1572 Mutex() { pthread_mutex_lock(<o_lock
); }
1573 ~Mutex() { pthread_mutex_unlock(<o_lock
); }
1575 pthread_mutex_t
Mutex::lto_lock
= PTHREAD_MUTEX_INITIALIZER
;
1576 bool File::sSupportsLocalContext
= false;
1577 bool File::sHasTriedLocalContext
= false;
1580 // Used by archive reader to see if member is an llvm bitcode file
1582 bool isObjectFile(const uint8_t* fileContent
, uint64_t fileLength
, cpu_type_t architecture
, cpu_subtype_t subarch
)
1585 return Parser::validFile(fileContent
, fileLength
, architecture
, subarch
);
1589 // Used by archive reader to see if member defines a Category (for -ObjC semantics)
1591 bool hasObjCCategory(const uint8_t* fileContent
, uint64_t fileLength
)
1593 #if LTO_API_VERSION >= 20
1594 // note: if run with older libLTO.dylib that does not implement
1595 // lto_module_has_objc_category, the call will return 0 which is "false"
1596 return lto_module_has_objc_category(fileContent
, fileLength
);
1603 static ld::relocatable::File
*parseImpl(
1604 const uint8_t *fileContent
, uint64_t fileLength
, const char *path
,
1605 time_t modTime
, ld::File::Ordinal ordinal
, cpu_type_t architecture
,
1606 cpu_subtype_t subarch
, bool logAllFiles
,
1607 bool verboseOptimizationHints
)
1609 if ( Parser::validFile(fileContent
, fileLength
, architecture
, subarch
) )
1610 return Parser::parse(fileContent
, fileLength
, path
, modTime
, ordinal
, architecture
, subarch
, logAllFiles
, verboseOptimizationHints
);
1616 // main function used by linker to instantiate ld::Files
1618 ld::relocatable::File
* parse(const uint8_t* fileContent
, uint64_t fileLength
,
1619 const char* path
, time_t modTime
, ld::File::Ordinal ordinal
,
1620 cpu_type_t architecture
, cpu_subtype_t subarch
, bool logAllFiles
,
1621 bool verboseOptimizationHints
)
1623 // do light weight check before acquiring lock
1624 if ( fileLength
< 4 )
1626 if ( (fileContent
[0] != 0xDE) || (fileContent
[1] != 0xC0) || (fileContent
[2] != 0x17) || (fileContent
[3] != 0x0B) )
1629 // Note: Once lto_module_create_in_local_context() and friends are thread safe
1630 // this lock can be removed.
1632 return parseImpl(fileContent
, fileLength
, path
, modTime
, ordinal
,
1633 architecture
, subarch
, logAllFiles
,
1634 verboseOptimizationHints
);
1638 // used by "ld -v" to report version of libLTO.dylib being used
1640 const char* version()
1643 return ::lto_get_version();
1647 // used by "ld -v" to report static version of libLTO.dylib API being compiled
1649 unsigned int static_api_version()
1651 return LTO_API_VERSION
;
1655 // used by "ld -v" to report version of libLTO.dylib being used
1657 unsigned int runtime_api_version()
1659 return ::lto_api_version();
1664 // used by ld for error reporting
1666 bool libLTOisLoaded()
1669 return (::lto_get_version() != NULL
);
1673 // used by ld for error reporting
1675 const char* archName(const uint8_t* fileContent
, uint64_t fileLength
)
1678 return Parser::fileKind(fileContent
, fileLength
);
1682 // used by ld for doing link time optimization
1684 bool optimize( const std::vector
<const ld::Atom
*>& allAtoms
,
1685 ld::Internal
& state
,
1686 const OptimizeOptions
& options
,
1687 ld::File::AtomHandler
& handler
,
1688 std::vector
<const ld::Atom
*>& newAtoms
,
1689 std::vector
<const char*>& additionalUndefines
)
1692 return Parser::optimize(allAtoms
, state
, options
, handler
, newAtoms
, additionalUndefines
);