]>
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> | |
d425e388 A |
36 | #include <unordered_set> |
37 | #include <unordered_map> | |
a645023d A |
38 | |
39 | #include "MachOFileAbstraction.hpp" | |
40 | #include "Architectures.hpp" | |
41 | #include "ld.hpp" | |
42 | #include "macho_relocatable_file.h" | |
43 | #include "lto_file.h" | |
44 | ||
afe874b1 A |
45 | // #defines are a work around for <rdar://problem/8760268> |
46 | #define __STDC_LIMIT_MACROS 1 | |
47 | #define __STDC_CONSTANT_MACROS 1 | |
a645023d A |
48 | #include "llvm-c/lto.h" |
49 | ||
a645023d A |
50 | namespace lto { |
51 | ||
52 | ||
53 | // | |
54 | // ld64 only tracks non-internal symbols from an llvm bitcode file. | |
55 | // We model this by having an InternalAtom which represent all internal functions and data. | |
56 | // All non-interal symbols from a bitcode file are represented by an Atom | |
57 | // and each Atom has a reference to the InternalAtom. The InternalAtom | |
58 | // also has references to each symbol external to the bitcode file. | |
59 | // | |
60 | class InternalAtom : public ld::Atom | |
61 | { | |
62 | public: | |
63 | InternalAtom(class File& f); | |
64 | // overrides of ld::Atom | |
65 | virtual ld::File* file() const { return &_file; } | |
a645023d A |
66 | virtual const char* name() const { return "import-atom"; } |
67 | virtual uint64_t size() const { return 0; } | |
68 | virtual uint64_t objectAddress() const { return 0; } | |
69 | virtual void copyRawContent(uint8_t buffer[]) const { } | |
70 | virtual void setScope(Scope) { } | |
71 | virtual ld::Fixup::iterator fixupsBegin() const { return &_undefs[0]; } | |
72 | virtual ld::Fixup::iterator fixupsEnd() const { return &_undefs[_undefs.size()]; } | |
73 | ||
74 | // for adding references to symbols outside bitcode file | |
75 | void addReference(const char* nm) | |
76 | { _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, | |
599556ff | 77 | ld::Fixup::kindNone, false, strdup(nm))); } |
a645023d A |
78 | private: |
79 | ||
80 | ld::File& _file; | |
81 | mutable std::vector<ld::Fixup> _undefs; | |
82 | }; | |
83 | ||
84 | ||
85 | // | |
86 | // LLVM bitcode file | |
87 | // | |
88 | class File : public ld::relocatable::File | |
89 | { | |
90 | public: | |
b1f7435d A |
91 | File(const char* path, time_t mTime, ld::File::Ordinal ordinal, |
92 | const uint8_t* content, uint32_t contentLength, cpu_type_t arch); | |
a645023d A |
93 | virtual ~File(); |
94 | ||
95 | // overrides of ld::File | |
96 | virtual bool forEachAtom(ld::File::AtomHandler&) const; | |
97 | virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const | |
98 | { return false; } | |
99 | virtual uint32_t cpuSubType() const { return _cpuSubType; } | |
100 | ||
101 | // overrides of ld::relocatable::File | |
a645023d A |
102 | virtual DebugInfoKind debugInfo() const { return _debugInfo; } |
103 | virtual const char* debugInfoPath() const { return _debugInfoPath; } | |
104 | virtual time_t debugInfoModificationTime() const | |
105 | { return _debugInfoModTime; } | |
106 | virtual const std::vector<ld::relocatable::File::Stab>* stabs() const { return NULL; } | |
107 | virtual bool canScatterAtoms() const { return true; } | |
f80fe69f A |
108 | virtual LinkerOptionsList* linkerOptions() const { return NULL; } |
109 | ||
a645023d | 110 | |
599556ff | 111 | void release(); |
a645023d A |
112 | lto_module_t module() { return _module; } |
113 | class InternalAtom& internalAtom() { return _internalAtom; } | |
114 | void setDebugInfo(ld::relocatable::File::DebugInfoKind k, | |
115 | const char* pth, time_t modTime, uint32_t subtype) | |
116 | { _debugInfo = k; | |
117 | _debugInfoPath = pth; | |
118 | _debugInfoModTime = modTime; | |
119 | _cpuSubType = subtype;} | |
120 | ||
121 | private: | |
122 | friend class Atom; | |
123 | friend class InternalAtom; | |
124 | friend class Parser; | |
125 | ||
126 | cpu_type_t _architecture; | |
127 | class InternalAtom _internalAtom; | |
128 | class Atom* _atomArray; | |
129 | uint32_t _atomArrayCount; | |
130 | lto_module_t _module; | |
131 | const char* _debugInfoPath; | |
132 | time_t _debugInfoModTime; | |
133 | ld::Section _section; | |
134 | ld::Fixup _fixupToInternal; | |
135 | ld::relocatable::File::DebugInfoKind _debugInfo; | |
136 | uint32_t _cpuSubType; | |
137 | }; | |
138 | ||
139 | // | |
140 | // Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially, | |
141 | // Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After | |
142 | // optimization is performed, real Atoms are created for these symobls. However these real Atoms | |
143 | // are not inserted into global symbol table. Atom holds real Atom and forwards appropriate | |
144 | // methods to real atom. | |
145 | // | |
146 | class Atom : public ld::Atom | |
147 | { | |
148 | public: | |
149 | Atom(File& f, const char* name, ld::Atom::Scope s, | |
b2fa67a8 | 150 | ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a, bool ah); |
a645023d A |
151 | |
152 | // overrides of ld::Atom | |
153 | virtual ld::File* file() const { return &_file; } | |
b1f7435d A |
154 | virtual const char* translationUnitSource() const |
155 | { return (_compiledAtom ? _compiledAtom->translationUnitSource() : NULL); } | |
a645023d A |
156 | virtual const char* name() const { return _name; } |
157 | virtual uint64_t size() const { return (_compiledAtom ? _compiledAtom->size() : 0); } | |
158 | virtual uint64_t objectAddress() const { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); } | |
159 | virtual void copyRawContent(uint8_t buffer[]) const | |
160 | { if (_compiledAtom) _compiledAtom->copyRawContent(buffer); } | |
161 | virtual const uint8_t* rawContentPointer() const | |
162 | { return (_compiledAtom ? _compiledAtom->rawContentPointer() : NULL); } | |
163 | virtual unsigned long contentHash(const class ld::IndirectBindingTable& ibt) const | |
164 | { return (_compiledAtom ? _compiledAtom->contentHash(ibt) : 0); } | |
165 | virtual bool canCoalesceWith(const ld::Atom& rhs, const class ld::IndirectBindingTable& ibt) const | |
166 | { return (_compiledAtom ? _compiledAtom->canCoalesceWith(rhs,ibt) : false); } | |
167 | virtual ld::Fixup::iterator fixupsBegin() const | |
168 | { return (_compiledAtom ? _compiledAtom->fixupsBegin() : (ld::Fixup*)&_file._fixupToInternal); } | |
169 | virtual ld::Fixup::iterator fixupsEnd() const | |
170 | { return (_compiledAtom ? _compiledAtom->fixupsEnd() : &((ld::Fixup*)&_file._fixupToInternal)[1]); } | |
171 | virtual ld::Atom::UnwindInfo::iterator beginUnwind() const | |
172 | { return (_compiledAtom ? _compiledAtom->beginUnwind() : NULL); } | |
173 | virtual ld::Atom::UnwindInfo::iterator endUnwind() const | |
174 | { return (_compiledAtom ? _compiledAtom->endUnwind() : NULL); } | |
175 | virtual ld::Atom::LineInfo::iterator beginLineInfo() const | |
176 | { return (_compiledAtom ? _compiledAtom->beginLineInfo() : NULL); } | |
177 | virtual ld::Atom::LineInfo::iterator endLineInfo() const | |
178 | { return (_compiledAtom ? _compiledAtom->endLineInfo() : NULL); } | |
179 | ||
180 | const ld::Atom* compiledAtom() { return _compiledAtom; } | |
181 | void setCompiledAtom(const ld::Atom& atom); | |
182 | ||
183 | private: | |
184 | ||
185 | File& _file; | |
186 | const char* _name; | |
187 | const ld::Atom* _compiledAtom; | |
188 | }; | |
189 | ||
190 | ||
191 | ||
192 | ||
193 | ||
194 | ||
195 | ||
196 | class Parser | |
197 | { | |
198 | public: | |
199 | static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch); | |
200 | static const char* fileKind(const uint8_t* fileContent, uint64_t fileLength); | |
201 | static File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, | |
9543cb2f A |
202 | time_t modTime, ld::File::Ordinal ordinal, cpu_type_t architecture, cpu_subtype_t subarch, |
203 | bool logAllFiles, bool verboseOptimizationHints); | |
a645023d A |
204 | static bool libLTOisLoaded() { return (::lto_get_version() != NULL); } |
205 | static bool optimize( const std::vector<const ld::Atom*>& allAtoms, | |
206 | ld::Internal& state, | |
a645023d A |
207 | const OptimizeOptions& options, |
208 | ld::File::AtomHandler& handler, | |
209 | std::vector<const ld::Atom*>& newAtoms, | |
210 | std::vector<const char*>& additionalUndefines); | |
211 | ||
212 | static const char* ltoVersion() { return ::lto_get_version(); } | |
213 | ||
214 | private: | |
215 | static const char* tripletPrefixForArch(cpu_type_t arch); | |
ebf6f434 | 216 | static ld::relocatable::File* parseMachOFile(const uint8_t* p, size_t len, const OptimizeOptions& options); |
9543cb2f A |
217 | #if LTO_API_VERSION >= 7 |
218 | static void ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t, const char*, void*); | |
219 | #endif | |
a645023d | 220 | |
d425e388 A |
221 | typedef std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals> CStringSet; |
222 | typedef std::unordered_map<const char*, Atom*, ld::CStringHash, ld::CStringEquals> CStringToAtom; | |
a645023d A |
223 | |
224 | class AtomSyncer : public ld::File::AtomHandler { | |
225 | public: | |
226 | AtomSyncer(std::vector<const char*>& a, std::vector<const ld::Atom*>&na, | |
227 | CStringToAtom la, CStringToAtom dla, const OptimizeOptions& options) : | |
228 | _options(options), _additionalUndefines(a), _newAtoms(na), _llvmAtoms(la), _deadllvmAtoms(dla) { } | |
229 | virtual void doAtom(const class ld::Atom&); | |
230 | virtual void doFile(const class ld::File&) { } | |
231 | ||
599556ff | 232 | |
a645023d A |
233 | const OptimizeOptions& _options; |
234 | std::vector<const char*>& _additionalUndefines; | |
235 | std::vector<const ld::Atom*>& _newAtoms; | |
236 | CStringToAtom _llvmAtoms; | |
237 | CStringToAtom _deadllvmAtoms; | |
238 | }; | |
239 | ||
240 | static std::vector<File*> _s_files; | |
241 | }; | |
242 | ||
243 | std::vector<File*> Parser::_s_files; | |
244 | ||
245 | ||
246 | bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch) | |
247 | { | |
ebf6f434 A |
248 | for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) { |
249 | if ( (architecture == t->cpuType) && (!(t->isSubType) || (subarch == t->cpuSubType)) ) { | |
250 | bool result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefix); | |
251 | if ( !result ) { | |
252 | // <rdar://problem/8434487> LTO only supports thumbv7 not armv7 | |
253 | if ( t->llvmTriplePrefixAlt[0] != '\0' ) { | |
254 | result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefixAlt); | |
255 | } | |
a645023d | 256 | } |
ebf6f434 A |
257 | return result; |
258 | } | |
a645023d A |
259 | } |
260 | return false; | |
261 | } | |
262 | ||
263 | const char* Parser::fileKind(const uint8_t* p, uint64_t fileLength) | |
264 | { | |
265 | if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) { | |
ebf6f434 A |
266 | cpu_type_t arch = LittleEndian::get32(*((uint32_t*)(&p[16]))); |
267 | for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) { | |
268 | if ( arch == t->cpuType ) { | |
269 | if ( t->isSubType ) { | |
afe874b1 | 270 | if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, t->llvmTriplePrefix) ) |
ebf6f434 A |
271 | return t->archName; |
272 | } | |
273 | else { | |
274 | return t->archName; | |
afe874b1 | 275 | } |
ebf6f434 | 276 | } |
a645023d A |
277 | } |
278 | return "unknown bitcode architecture"; | |
279 | } | |
280 | return NULL; | |
281 | } | |
282 | ||
b1f7435d | 283 | File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, ld::File::Ordinal ordinal, |
9543cb2f | 284 | cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles, bool verboseOptimizationHints) |
a645023d | 285 | { |
b1f7435d | 286 | File* f = new File(path, modTime, ordinal, fileContent, fileLength, architecture); |
a645023d A |
287 | _s_files.push_back(f); |
288 | if ( logAllFiles ) | |
289 | printf("%s\n", path); | |
290 | return f; | |
291 | } | |
292 | ||
293 | ||
ebf6f434 | 294 | ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, const OptimizeOptions& options) |
a645023d A |
295 | { |
296 | mach_o::relocatable::ParserOptions objOpts; | |
297 | objOpts.architecture = options.arch; | |
298 | objOpts.objSubtypeMustMatch = false; | |
299 | objOpts.logAllFiles = false; | |
f80fe69f A |
300 | objOpts.warnUnwindConversionProblems = options.needsUnwindInfoSection; |
301 | objOpts.keepDwarfUnwind = options.keepDwarfUnwind; | |
302 | objOpts.forceDwarfConversion = false; | |
9543cb2f A |
303 | objOpts.neverConvertDwarf = false; |
304 | objOpts.verboseOptimizationHints = options.verboseOptimizationHints; | |
ba348e21 | 305 | objOpts.armUsesZeroCostExceptions = options.armUsesZeroCostExceptions; |
599556ff | 306 | |
a645023d A |
307 | objOpts.subType = 0; |
308 | ||
309 | // mach-o parsing is done in-memory, but need path for debug notes | |
310 | const char* path = "/tmp/lto.o"; | |
311 | time_t modTime = 0; | |
312 | if ( options.tmpObjectFilePath != NULL ) { | |
313 | path = options.tmpObjectFilePath; | |
314 | struct stat statBuffer; | |
315 | if ( stat(options.tmpObjectFilePath, &statBuffer) == 0 ) | |
316 | modTime = statBuffer.st_mtime; | |
317 | } | |
318 | ||
ebf6f434 | 319 | ld::relocatable::File* result = mach_o::relocatable::parse(p, len, path, modTime, ld::File::Ordinal::LTOOrdinal(), objOpts); |
a645023d A |
320 | if ( result != NULL ) |
321 | return result; | |
322 | throw "LLVM LTO, file is not of required architecture"; | |
323 | } | |
324 | ||
325 | ||
326 | ||
b1f7435d A |
327 | File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8_t* content, uint32_t contentLength, cpu_type_t arch) |
328 | : ld::relocatable::File(pth,mTime,ordinal), _architecture(arch), _internalAtom(*this), | |
a645023d A |
329 | _atomArray(NULL), _atomArrayCount(0), _module(NULL), _debugInfoPath(pth), |
330 | _section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO), | |
331 | _fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom), | |
332 | _debugInfo(ld::relocatable::File::kDebugInfoNone), _cpuSubType(0) | |
333 | { | |
334 | const bool log = false; | |
335 | ||
336 | // create llvm module | |
599556ff A |
337 | #if LTO_API_VERSION >= 9 |
338 | _module = ::lto_module_create_from_memory_with_path(content, contentLength, pth); | |
339 | if ( _module == NULL ) | |
340 | #endif | |
a645023d A |
341 | _module = ::lto_module_create_from_memory(content, contentLength); |
342 | if ( _module == NULL ) | |
d425e388 | 343 | throwf("could not parse object file %s: '%s', using libLTO version '%s'", pth, ::lto_get_error_message(), ::lto_get_version()); |
a645023d A |
344 | |
345 | if ( log ) fprintf(stderr, "bitcode file: %s\n", pth); | |
346 | ||
347 | // create atom for each global symbol in module | |
348 | uint32_t count = ::lto_module_get_num_symbols(_module); | |
349 | _atomArray = (Atom*)malloc(sizeof(Atom)*count); | |
350 | for (uint32_t i=0; i < count; ++i) { | |
351 | const char* name = ::lto_module_get_symbol_name(_module, i); | |
352 | lto_symbol_attributes attr = lto_module_get_symbol_attribute(_module, i); | |
353 | ||
354 | // <rdar://problem/6378110> LTO doesn't like dtrace symbols | |
355 | // ignore dtrace static probes for now | |
356 | // later when codegen is done and a mach-o file is produces the probes will be processed | |
357 | if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) ) | |
358 | continue; | |
359 | ||
360 | ld::Atom::Definition def; | |
361 | ld::Atom::Combine combine = ld::Atom::combineNever; | |
362 | switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) { | |
363 | case LTO_SYMBOL_DEFINITION_REGULAR: | |
364 | def = ld::Atom::definitionRegular; | |
365 | break; | |
366 | case LTO_SYMBOL_DEFINITION_TENTATIVE: | |
367 | def = ld::Atom::definitionTentative; | |
368 | break; | |
369 | case LTO_SYMBOL_DEFINITION_WEAK: | |
370 | def = ld::Atom::definitionRegular; | |
371 | combine = ld::Atom::combineByName; | |
372 | break; | |
373 | case LTO_SYMBOL_DEFINITION_UNDEFINED: | |
374 | case LTO_SYMBOL_DEFINITION_WEAKUNDEF: | |
375 | def = ld::Atom::definitionProxy; | |
376 | break; | |
377 | default: | |
378 | throwf("unknown definition kind for symbol %s in bitcode file %s", name, pth); | |
379 | } | |
380 | ||
381 | // make LLVM atoms for definitions and a reference for undefines | |
382 | if ( def != ld::Atom::definitionProxy ) { | |
383 | ld::Atom::Scope scope; | |
b2fa67a8 | 384 | bool autohide = false; |
a645023d A |
385 | switch ( attr & LTO_SYMBOL_SCOPE_MASK) { |
386 | case LTO_SYMBOL_SCOPE_INTERNAL: | |
387 | scope = ld::Atom::scopeTranslationUnit; | |
388 | break; | |
389 | case LTO_SYMBOL_SCOPE_HIDDEN: | |
390 | scope = ld::Atom::scopeLinkageUnit; | |
391 | break; | |
392 | case LTO_SYMBOL_SCOPE_DEFAULT: | |
393 | scope = ld::Atom::scopeGlobal; | |
394 | break; | |
b2fa67a8 A |
395 | #if LTO_API_VERSION >= 4 |
396 | case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN: | |
397 | scope = ld::Atom::scopeGlobal; | |
398 | autohide = true; | |
399 | break; | |
400 | #endif | |
a645023d A |
401 | default: |
402 | throwf("unknown scope for symbol %s in bitcode file %s", name, pth); | |
403 | } | |
404 | // only make atoms for non-internal symbols | |
405 | if ( scope == ld::Atom::scopeTranslationUnit ) | |
406 | continue; | |
407 | uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK); | |
408 | // make Atom using placement new operator | |
b2fa67a8 | 409 | new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment, autohide); |
ebf6f434 | 410 | if ( scope != ld::Atom::scopeTranslationUnit ) |
a645023d A |
411 | _internalAtom.addReference(name); |
412 | if ( log ) fprintf(stderr, "\t0x%08X %s\n", attr, name); | |
413 | } | |
414 | else { | |
415 | // add to list of external references | |
416 | _internalAtom.addReference(name); | |
417 | if ( log ) fprintf(stderr, "\t%s (undefined)\n", name); | |
418 | } | |
419 | } | |
420 | } | |
421 | ||
422 | File::~File() | |
599556ff A |
423 | { |
424 | this->release(); | |
425 | } | |
426 | ||
427 | void File::release() | |
a645023d A |
428 | { |
429 | if ( _module != NULL ) | |
430 | ::lto_module_dispose(_module); | |
599556ff | 431 | _module = NULL; |
a645023d A |
432 | } |
433 | ||
434 | bool File::forEachAtom(ld::File::AtomHandler& handler) const | |
435 | { | |
436 | handler.doAtom(_internalAtom); | |
437 | for(uint32_t i=0; i < _atomArrayCount; ++i) { | |
438 | handler.doAtom(_atomArray[i]); | |
439 | } | |
440 | return true; | |
441 | } | |
442 | ||
443 | InternalAtom::InternalAtom(File& f) | |
444 | : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, | |
445 | ld::Atom::typeLTOtemporary, ld::Atom::symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)), | |
446 | _file(f) | |
447 | { | |
448 | } | |
449 | ||
b2fa67a8 A |
450 | Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Combine c, |
451 | ld::Atom::Alignment a, bool ah) | |
a645023d A |
452 | : ld::Atom(f._section, d, c, s, ld::Atom::typeLTOtemporary, |
453 | ld::Atom::symbolTableIn, false, false, false, a), | |
599556ff | 454 | _file(f), _name(strdup(nm)), _compiledAtom(NULL) |
a645023d | 455 | { |
b2fa67a8 A |
456 | if ( ah ) |
457 | this->setAutoHide(); | |
a645023d A |
458 | } |
459 | ||
460 | void Atom::setCompiledAtom(const ld::Atom& atom) | |
461 | { | |
462 | // set delegate so virtual methods go to it | |
463 | _compiledAtom = &atom; | |
464 | ||
465 | //fprintf(stderr, "setting lto atom %p to delegate to mach-o atom %p (%s)\n", this, &atom, atom.name()); | |
466 | ||
467 | // update fields in ld::Atom to match newly constructed mach-o atom | |
468 | (const_cast<Atom*>(this))->setAttributesFromAtom(atom); | |
469 | } | |
470 | ||
471 | ||
472 | ||
f80fe69f A |
473 | // <rdar://problem/12379604> The order that files are merged must match command line order |
474 | struct CommandLineOrderFileSorter | |
475 | { | |
476 | bool operator()(File* left, File* right) | |
477 | { | |
478 | return ( left->ordinal() < right->ordinal() ); | |
479 | } | |
480 | }; | |
481 | ||
482 | ||
9543cb2f A |
483 | #if LTO_API_VERSION >= 7 |
484 | void Parser::ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t severity, const char* message, void*) | |
485 | { | |
486 | switch ( severity ) { | |
599556ff A |
487 | #if LTO_API_VERSION >= 10 |
488 | case LTO_DS_REMARK: | |
599556ff | 489 | #endif |
9543cb2f A |
490 | case LTO_DS_NOTE: |
491 | case LTO_DS_WARNING: | |
492 | warning("%s", message); | |
493 | break; | |
494 | case LTO_DS_ERROR: | |
495 | throwf("%s", message); | |
496 | } | |
497 | } | |
498 | #endif | |
499 | ||
a645023d A |
500 | bool Parser::optimize( const std::vector<const ld::Atom*>& allAtoms, |
501 | ld::Internal& state, | |
a645023d A |
502 | const OptimizeOptions& options, |
503 | ld::File::AtomHandler& handler, | |
504 | std::vector<const ld::Atom*>& newAtoms, | |
505 | std::vector<const char*>& additionalUndefines) | |
506 | { | |
507 | const bool logMustPreserve = false; | |
508 | const bool logExtraOptions = false; | |
509 | const bool logBitcodeFiles = false; | |
510 | const bool logAtomsBeforeSync = false; | |
511 | ||
512 | // exit quickly if nothing to do | |
513 | if ( _s_files.size() == 0 ) | |
514 | return false; | |
515 | ||
516 | // print out LTO version string if -v was used | |
517 | if ( options.verbose ) | |
d425e388 | 518 | fprintf(stderr, "%s\n", ::lto_get_version()); |
a645023d A |
519 | |
520 | // create optimizer and add each Reader | |
521 | lto_code_gen_t generator = ::lto_codegen_create(); | |
9543cb2f A |
522 | #if LTO_API_VERSION >= 7 |
523 | lto_codegen_set_diagnostic_handler(generator, ltoDiagnosticHandler, NULL); | |
524 | #endif | |
525 | ||
f80fe69f A |
526 | // <rdar://problem/12379604> The order that files are merged must match command line order |
527 | std::sort(_s_files.begin(), _s_files.end(), CommandLineOrderFileSorter()); | |
528 | ld::File::Ordinal lastOrdinal; | |
a645023d | 529 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { |
f80fe69f A |
530 | File* f = *it; |
531 | assert(f->ordinal() > lastOrdinal); | |
532 | if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", f->path()); | |
533 | if ( ::lto_codegen_add_module(generator, f->module()) ) | |
534 | throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", f->path(), ::lto_get_error_message(), ::lto_get_version()); | |
599556ff A |
535 | // <rdar://problem/15471128> linker should release module as soon as possible |
536 | f->release(); | |
f80fe69f | 537 | lastOrdinal = f->ordinal(); |
a645023d A |
538 | } |
539 | ||
540 | // add any -mllvm command line options | |
541 | for (std::vector<const char*>::const_iterator it=options.llvmOptions->begin(); it != options.llvmOptions->end(); ++it) { | |
542 | if ( logExtraOptions ) fprintf(stderr, "passing option to llvm: %s\n", *it); | |
543 | ::lto_codegen_debug_options(generator, *it); | |
544 | } | |
545 | ||
f80fe69f A |
546 | // <rdar://problem/13687397> Need a way for LTO to get cpu variants (until that info is in bitcode) |
547 | if ( options.mcpu != NULL ) | |
548 | ::lto_codegen_set_cpu(generator, options.mcpu); | |
549 | ||
a645023d A |
550 | // The atom graph uses directed edges (references). Collect all references where |
551 | // originating atom is not part of any LTO Reader. This allows optimizer to optimize an | |
552 | // external (i.e. not originated from same .o file) reference if all originating atoms are also | |
553 | // defined in llvm bitcode file. | |
554 | CStringSet nonLLVMRefs; | |
555 | CStringToAtom llvmAtoms; | |
556 | bool hasNonllvmAtoms = false; | |
557 | for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { | |
558 | const ld::Atom* atom = *it; | |
559 | // only look at references that come from an atom that is not an llvm atom | |
560 | if ( atom->contentType() != ld::Atom::typeLTOtemporary ) { | |
561 | if ( (atom->section().type() != ld::Section::typeMachHeader) && (atom->definition() != ld::Atom::definitionProxy) ) { | |
562 | hasNonllvmAtoms = true; | |
563 | } | |
564 | const ld::Atom* target; | |
565 | for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) { | |
566 | switch ( fit->binding ) { | |
567 | case ld::Fixup::bindingDirectlyBound: | |
568 | // that reference an llvm atom | |
569 | if ( fit->u.target->contentType() == ld::Atom::typeLTOtemporary ) | |
570 | nonLLVMRefs.insert(fit->u.target->name()); | |
571 | break; | |
572 | case ld::Fixup::bindingsIndirectlyBound: | |
573 | target = state.indirectBindingTable[fit->u.bindingIndex]; | |
9543cb2f | 574 | if ( (target != NULL) && (target->contentType() == ld::Atom::typeLTOtemporary) ) |
a645023d A |
575 | nonLLVMRefs.insert(target->name()); |
576 | default: | |
577 | break; | |
578 | } | |
579 | } | |
580 | } | |
599556ff | 581 | else if ( atom->scope() >= ld::Atom::scopeLinkageUnit ) { |
a645023d A |
582 | llvmAtoms[atom->name()] = (Atom*)atom; |
583 | } | |
584 | } | |
585 | // if entry point is in a llvm bitcode file, it must be preserved by LTO | |
586 | if ( state.entryPoint!= NULL ) { | |
587 | if ( state.entryPoint->contentType() == ld::Atom::typeLTOtemporary ) | |
588 | nonLLVMRefs.insert(state.entryPoint->name()); | |
589 | } | |
590 | ||
591 | // deadAtoms are the atoms that the linker coalesced. For instance weak or tentative definitions | |
592 | // overriden by another atom. If any of these deadAtoms are llvm atoms and they were replaced | |
593 | // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead | |
594 | // atom so that the linker can replace it with the mach-o one later. | |
595 | CStringToAtom deadllvmAtoms; | |
596 | for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { | |
597 | const ld::Atom* atom = *it; | |
598 | if ( atom->coalescedAway() && (atom->contentType() == ld::Atom::typeLTOtemporary) ) { | |
599 | const char* name = atom->name(); | |
600 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name); | |
601 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
602 | deadllvmAtoms[name] = (Atom*)atom; | |
603 | } | |
604 | } | |
605 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
606 | File* file = *it; | |
607 | for(uint32_t i=0; i < file->_atomArrayCount; ++i) { | |
608 | Atom* llvmAtom = &file->_atomArray[i]; | |
609 | if ( llvmAtom->coalescedAway() ) { | |
610 | const char* name = llvmAtom->name(); | |
611 | if ( deadllvmAtoms.find(name) == deadllvmAtoms.end() ) { | |
612 | if ( logMustPreserve ) | |
613 | fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name); | |
614 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
615 | deadllvmAtoms[name] = (Atom*)llvmAtom; | |
616 | } | |
617 | } | |
618 | else if ( options.linkerDeadStripping && !llvmAtom->live() ) { | |
619 | const char* name = llvmAtom->name(); | |
620 | deadllvmAtoms[name] = (Atom*)llvmAtom; | |
621 | } | |
622 | } | |
623 | } | |
624 | ||
625 | // tell code generator about symbols that must be preserved | |
626 | for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { | |
627 | const char* name = it->first; | |
628 | Atom* atom = it->second; | |
629 | // Include llvm Symbol in export list if it meets one of following two conditions | |
630 | // 1 - atom scope is global (and not linkage unit). | |
631 | // 2 - included in nonLLVMRefs set. | |
632 | // If a symbol is not listed in exportList then LTO is free to optimize it away. | |
ebf6f434 | 633 | if ( (atom->scope() == ld::Atom::scopeGlobal) && options.preserveAllGlobals ) { |
a645023d A |
634 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name); |
635 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
636 | } | |
637 | else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) { | |
638 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because referenced by a mach-o atom\n", name); | |
639 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
640 | } | |
599556ff A |
641 | else if ( options.relocatable && hasNonllvmAtoms ) { |
642 | // <rdar://problem/14334895> ld -r mode but merging in some mach-o files, so need to keep libLTO from optimizing away anything | |
643 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because -r mode disable LTO dead stripping\n", name); | |
644 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
645 | } | |
a645023d A |
646 | } |
647 | ||
599556ff A |
648 | // <rdar://problem/16165191> tell code generator to preserve initial undefines |
649 | for( std::vector<const char*>::const_iterator it=options.initialUndefines->begin(); it != options.initialUndefines->end(); ++it) { | |
650 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because it is an initial undefine\n", *it); | |
651 | ::lto_codegen_add_must_preserve_symbol(generator, *it); | |
652 | } | |
653 | ||
a645023d A |
654 | // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o) |
655 | if ( options.relocatable && !hasNonllvmAtoms ) { | |
656 | if ( ! ::lto_codegen_write_merged_modules(generator, options.outputFilePath) ) { | |
657 | // HACK, no good way to tell linker we are all done, so just quit | |
658 | exit(0); | |
659 | } | |
660 | warning("could not produce merged bitcode file"); | |
661 | } | |
662 | ||
663 | // set code-gen model | |
664 | lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
665 | if ( options.mainExecutable ) { | |
666 | if ( options.staticExecutable ) { | |
d425e388 A |
667 | // x86_64 "static" or any "-static -pie" is really dynamic code model |
668 | if ( (options.arch == CPU_TYPE_X86_64) || options.pie ) | |
a645023d A |
669 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; |
670 | else | |
671 | model = LTO_CODEGEN_PIC_MODEL_STATIC; | |
672 | } | |
673 | else { | |
674 | if ( options.pie ) | |
675 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
676 | else | |
677 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; | |
678 | } | |
679 | } | |
680 | else { | |
681 | if ( options.allowTextRelocs ) | |
682 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; | |
683 | else | |
684 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
685 | } | |
686 | if ( ::lto_codegen_set_pic_model(generator, model) ) | |
687 | throwf("could not create set codegen model: %s", lto_get_error_message()); | |
688 | ||
689 | // if requested, save off merged bitcode file | |
690 | if ( options.saveTemps ) { | |
691 | char tempBitcodePath[MAXPATHLEN]; | |
692 | strcpy(tempBitcodePath, options.outputFilePath); | |
693 | strcat(tempBitcodePath, ".lto.bc"); | |
694 | ::lto_codegen_write_merged_modules(generator, tempBitcodePath); | |
695 | } | |
696 | ||
697 | #if LTO_API_VERSION >= 3 | |
698 | // find assembler next to linker | |
699 | char path[PATH_MAX]; | |
700 | uint32_t bufSize = PATH_MAX; | |
701 | if ( _NSGetExecutablePath(path, &bufSize) != -1 ) { | |
702 | char* lastSlash = strrchr(path, '/'); | |
703 | if ( lastSlash != NULL ) { | |
704 | strcpy(lastSlash+1, "as"); | |
705 | struct stat statInfo; | |
706 | if ( stat(path, &statInfo) == 0 ) | |
707 | ::lto_codegen_set_assembler_path(generator, path); | |
708 | } | |
709 | } | |
710 | #endif | |
711 | // run code generator | |
712 | size_t machOFileLen; | |
713 | const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen); | |
714 | if ( machOFile == NULL ) | |
d425e388 | 715 | throwf("could not do LTO codegen: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version()); |
a645023d A |
716 | |
717 | // if requested, save off temp mach-o file | |
718 | if ( options.saveTemps ) { | |
719 | char tempMachoPath[MAXPATHLEN]; | |
720 | strcpy(tempMachoPath, options.outputFilePath); | |
721 | strcat(tempMachoPath, ".lto.o"); | |
722 | int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
723 | if ( fd != -1) { | |
724 | ::write(fd, machOFile, machOFileLen); | |
725 | ::close(fd); | |
726 | } | |
727 | // save off merged bitcode file | |
728 | char tempOptBitcodePath[MAXPATHLEN]; | |
729 | strcpy(tempOptBitcodePath, options.outputFilePath); | |
730 | strcat(tempOptBitcodePath, ".lto.opt.bc"); | |
731 | ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath); | |
732 | } | |
733 | ||
734 | // if needed, save temp mach-o file to specific location | |
735 | if ( options.tmpObjectFilePath != NULL ) { | |
736 | int fd = ::open(options.tmpObjectFilePath, O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
737 | if ( fd != -1) { | |
738 | ::write(fd, machOFile, machOFileLen); | |
739 | ::close(fd); | |
740 | } | |
741 | else { | |
742 | warning("could not write LTO temp file '%s', errno=%d", options.tmpObjectFilePath, errno); | |
743 | } | |
744 | } | |
745 | ||
746 | // parse generated mach-o file into a MachOReader | |
ebf6f434 | 747 | ld::relocatable::File* machoFile = parseMachOFile(machOFile, machOFileLen, options); |
a645023d A |
748 | |
749 | // sync generated mach-o atoms with existing atoms ld knows about | |
750 | if ( logAtomsBeforeSync ) { | |
751 | fprintf(stderr, "llvmAtoms:\n"); | |
752 | for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { | |
753 | const char* name = it->first; | |
599556ff A |
754 | Atom* atom = it->second; |
755 | fprintf(stderr, "\t%p\t%s\n", atom, name); | |
a645023d A |
756 | } |
757 | fprintf(stderr, "deadllvmAtoms:\n"); | |
758 | for (CStringToAtom::iterator it = deadllvmAtoms.begin(); it != deadllvmAtoms.end(); ++it) { | |
759 | const char* name = it->first; | |
599556ff A |
760 | Atom* atom = it->second; |
761 | fprintf(stderr, "\t%p\t%s\n", atom, name); | |
a645023d A |
762 | } |
763 | } | |
764 | AtomSyncer syncer(additionalUndefines, newAtoms, llvmAtoms, deadllvmAtoms, options); | |
765 | machoFile->forEachAtom(syncer); | |
766 | ||
767 | // Remove InternalAtoms from ld | |
768 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
769 | (*it)->internalAtom().setCoalescedAway(); | |
770 | } | |
771 | // Remove Atoms from ld if code generator optimized them away | |
772 | for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) { | |
773 | // check if setRealAtom() called on this Atom | |
774 | if ( li->second->compiledAtom() == NULL ) { | |
775 | //fprintf(stderr, "llvm optimized away %p %s\n", li->second, li->second->name()); | |
776 | li->second->setCoalescedAway(); | |
777 | } | |
778 | } | |
779 | ||
780 | // notify about file level attributes | |
781 | handler.doFile(*machoFile); | |
782 | ||
783 | // if final mach-o file has debug info, update original bitcode files to match | |
784 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
785 | (*it)->setDebugInfo(machoFile->debugInfo(), machoFile->path(), | |
786 | machoFile->modificationTime(), machoFile->cpuSubType()); | |
787 | } | |
788 | ||
789 | return true; | |
790 | } | |
791 | ||
792 | ||
793 | void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom) | |
794 | { | |
599556ff | 795 | static const bool log = false; |
9543cb2f A |
796 | static const ld::Atom* lastProxiedAtom = NULL; |
797 | static const ld::File* lastProxiedFile = NULL; | |
a645023d A |
798 | // update proxy atoms to point to real atoms and find new atoms |
799 | const char* name = machoAtom.name(); | |
599556ff A |
800 | CStringToAtom::iterator pos = _llvmAtoms.find(name); |
801 | if ( pos != _llvmAtoms.end() ) { | |
802 | // turn Atom into a proxy for this mach-o atom | |
803 | pos->second->setCompiledAtom(machoAtom); | |
804 | lastProxiedAtom = &machoAtom; | |
805 | lastProxiedFile = pos->second->file(); | |
806 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p synced to lto atom %p (name=%s)\n", &machoAtom, pos->second, machoAtom.name()); | |
807 | } | |
808 | else { | |
809 | // an atom of this name was not in the allAtoms list the linker gave us | |
810 | if ( _deadllvmAtoms.find(name) != _deadllvmAtoms.end() ) { | |
811 | // this corresponding to an atom that the linker coalesced away or marked not-live | |
812 | if ( _options.linkerDeadStripping ) { | |
813 | // llvm seems to want this atom and -dead_strip is enabled, so it will be deleted if not needed, so add back | |
814 | Atom* llvmAtom = _deadllvmAtoms[name]; | |
815 | llvmAtom->setCompiledAtom(machoAtom); | |
a645023d | 816 | _newAtoms.push_back(&machoAtom); |
599556ff | 817 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p matches dead lto atom %p but adding back (name=%s)\n", &machoAtom, llvmAtom, machoAtom.name()); |
a645023d | 818 | } |
599556ff A |
819 | else { |
820 | // Don't pass it back as a new atom | |
821 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p matches dead lto atom %p (name=%s)\n", &machoAtom, _deadllvmAtoms[name], machoAtom.name()); | |
822 | } | |
a645023d | 823 | } |
599556ff A |
824 | else |
825 | { | |
826 | // this is something new that lto conjured up, tell ld its new | |
827 | _newAtoms.push_back(&machoAtom); | |
828 | // <rdar://problem/15469363> if new static atom in same section as previous non-static atom, assign to same file as previous | |
829 | if ( (lastProxiedAtom != NULL) && (lastProxiedAtom->section() == machoAtom.section()) ) { | |
830 | ld::Atom* ma = const_cast<ld::Atom*>(&machoAtom); | |
831 | ma->setFile(lastProxiedFile); | |
832 | } | |
833 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p is totally new (name=%s)\n", &machoAtom, machoAtom.name()); | |
9543cb2f | 834 | } |
a645023d A |
835 | } |
836 | ||
837 | // adjust fixups to go through proxy atoms | |
599556ff | 838 | if (log) fprintf(stderr, " adjusting fixups in atom: %s\n", machoAtom.name()); |
a645023d A |
839 | for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) { |
840 | switch ( fit->binding ) { | |
841 | case ld::Fixup::bindingNone: | |
842 | break; | |
843 | case ld::Fixup::bindingByNameUnbound: | |
844 | // don't know if this target has been seen by linker before or if it is new | |
845 | // be conservative and tell linker it is new | |
846 | _additionalUndefines.push_back(fit->u.name); | |
599556ff | 847 | if (log) fprintf(stderr, " adding by-name symbol %s\n", fit->u.name); |
a645023d A |
848 | break; |
849 | case ld::Fixup::bindingDirectlyBound: | |
850 | // If mach-o atom is referencing another mach-o atom then | |
851 | // reference is not going through Atom proxy. Fix it here to ensure that all | |
852 | // llvm symbol references always go through Atom proxy. | |
599556ff | 853 | { |
a645023d | 854 | const char* targetName = fit->u.target->name(); |
599556ff A |
855 | CStringToAtom::iterator post = _llvmAtoms.find(targetName); |
856 | if ( post != _llvmAtoms.end() ) { | |
857 | const ld::Atom* t = post->second; | |
858 | if (log) fprintf(stderr, " updating direct reference to %p to be ref to %p: %s\n", fit->u.target, t, targetName); | |
859 | fit->u.target = t; | |
a645023d A |
860 | } |
861 | else { | |
f80fe69f A |
862 | // <rdar://problem/12859831> Don't unbind follow-on reference into by-name reference |
863 | if ( (_deadllvmAtoms.find(targetName) != _deadllvmAtoms.end()) && (fit->kind != ld::Fixup::kindNoneFollowOn) ) { | |
a645023d A |
864 | // target was coalesed away and replace by mach-o atom from a non llvm .o file |
865 | fit->binding = ld::Fixup::bindingByNameUnbound; | |
866 | fit->u.name = targetName; | |
867 | } | |
868 | } | |
869 | } | |
870 | //fprintf(stderr, " direct ref to: %s (scope=%d)\n", fit->u.target->name(), fit->u.target->scope()); | |
871 | break; | |
872 | case ld::Fixup::bindingByContentBound: | |
873 | //fprintf(stderr, " direct by content to: %s\n", fit->u.target->name()); | |
874 | break; | |
875 | case ld::Fixup::bindingsIndirectlyBound: | |
876 | assert(0 && "indirect binding found in initial mach-o file?"); | |
877 | //fprintf(stderr, " indirect by content to: %u\n", fit->u.bindingIndex); | |
878 | break; | |
879 | } | |
880 | } | |
881 | ||
882 | } | |
883 | ||
ebf6f434 A |
884 | class Mutex { |
885 | static pthread_mutex_t lto_lock; | |
886 | public: | |
887 | Mutex() { pthread_mutex_lock(<o_lock); } | |
888 | ~Mutex() { pthread_mutex_unlock(<o_lock); } | |
889 | }; | |
890 | pthread_mutex_t Mutex::lto_lock = PTHREAD_MUTEX_INITIALIZER; | |
a645023d A |
891 | |
892 | // | |
893 | // Used by archive reader to see if member is an llvm bitcode file | |
894 | // | |
895 | bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch) | |
896 | { | |
ebf6f434 | 897 | Mutex lock; |
a645023d A |
898 | return Parser::validFile(fileContent, fileLength, architecture, subarch); |
899 | } | |
900 | ||
901 | ||
902 | // | |
903 | // main function used by linker to instantiate ld::Files | |
904 | // | |
905 | ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, | |
b1f7435d | 906 | const char* path, time_t modTime, ld::File::Ordinal ordinal, |
9543cb2f A |
907 | cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles, |
908 | bool verboseOptimizationHints) | |
a645023d | 909 | { |
ebf6f434 | 910 | Mutex lock; |
a645023d | 911 | if ( Parser::validFile(fileContent, fileLength, architecture, subarch) ) |
9543cb2f | 912 | return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles, verboseOptimizationHints); |
a645023d A |
913 | else |
914 | return NULL; | |
915 | } | |
916 | ||
917 | // | |
918 | // used by "ld -v" to report version of libLTO.dylib being used | |
919 | // | |
920 | const char* version() | |
921 | { | |
ebf6f434 | 922 | Mutex lock; |
a645023d A |
923 | return ::lto_get_version(); |
924 | } | |
925 | ||
926 | ||
927 | // | |
928 | // used by ld for error reporting | |
929 | // | |
930 | bool libLTOisLoaded() | |
931 | { | |
ebf6f434 | 932 | Mutex lock; |
a645023d A |
933 | return (::lto_get_version() != NULL); |
934 | } | |
935 | ||
936 | // | |
937 | // used by ld for error reporting | |
938 | // | |
939 | const char* archName(const uint8_t* fileContent, uint64_t fileLength) | |
940 | { | |
ebf6f434 | 941 | Mutex lock; |
a645023d A |
942 | return Parser::fileKind(fileContent, fileLength); |
943 | } | |
944 | ||
945 | // | |
946 | // used by ld for doing link time optimization | |
947 | // | |
948 | bool optimize( const std::vector<const ld::Atom*>& allAtoms, | |
949 | ld::Internal& state, | |
a645023d A |
950 | const OptimizeOptions& options, |
951 | ld::File::AtomHandler& handler, | |
952 | std::vector<const ld::Atom*>& newAtoms, | |
953 | std::vector<const char*>& additionalUndefines) | |
954 | { | |
ebf6f434 A |
955 | Mutex lock; |
956 | return Parser::optimize(allAtoms, state, options, handler, newAtoms, additionalUndefines); | |
a645023d A |
957 | } |
958 | ||
959 | ||
960 | ||
961 | }; // namespace lto | |
962 | ||
963 | ||
964 | #endif | |
965 |