]>
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; | |
599556ff | 305 | |
a645023d A |
306 | objOpts.subType = 0; |
307 | ||
308 | // mach-o parsing is done in-memory, but need path for debug notes | |
309 | const char* path = "/tmp/lto.o"; | |
310 | time_t modTime = 0; | |
311 | if ( options.tmpObjectFilePath != NULL ) { | |
312 | path = options.tmpObjectFilePath; | |
313 | struct stat statBuffer; | |
314 | if ( stat(options.tmpObjectFilePath, &statBuffer) == 0 ) | |
315 | modTime = statBuffer.st_mtime; | |
316 | } | |
317 | ||
ebf6f434 | 318 | ld::relocatable::File* result = mach_o::relocatable::parse(p, len, path, modTime, ld::File::Ordinal::LTOOrdinal(), objOpts); |
a645023d A |
319 | if ( result != NULL ) |
320 | return result; | |
321 | throw "LLVM LTO, file is not of required architecture"; | |
322 | } | |
323 | ||
324 | ||
325 | ||
b1f7435d A |
326 | File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8_t* content, uint32_t contentLength, cpu_type_t arch) |
327 | : ld::relocatable::File(pth,mTime,ordinal), _architecture(arch), _internalAtom(*this), | |
a645023d A |
328 | _atomArray(NULL), _atomArrayCount(0), _module(NULL), _debugInfoPath(pth), |
329 | _section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO), | |
330 | _fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom), | |
331 | _debugInfo(ld::relocatable::File::kDebugInfoNone), _cpuSubType(0) | |
332 | { | |
333 | const bool log = false; | |
334 | ||
335 | // create llvm module | |
599556ff A |
336 | #if LTO_API_VERSION >= 9 |
337 | _module = ::lto_module_create_from_memory_with_path(content, contentLength, pth); | |
338 | if ( _module == NULL ) | |
339 | #endif | |
a645023d A |
340 | _module = ::lto_module_create_from_memory(content, contentLength); |
341 | if ( _module == NULL ) | |
d425e388 | 342 | throwf("could not parse object file %s: '%s', using libLTO version '%s'", pth, ::lto_get_error_message(), ::lto_get_version()); |
a645023d A |
343 | |
344 | if ( log ) fprintf(stderr, "bitcode file: %s\n", pth); | |
345 | ||
346 | // create atom for each global symbol in module | |
347 | uint32_t count = ::lto_module_get_num_symbols(_module); | |
348 | _atomArray = (Atom*)malloc(sizeof(Atom)*count); | |
349 | for (uint32_t i=0; i < count; ++i) { | |
350 | const char* name = ::lto_module_get_symbol_name(_module, i); | |
351 | lto_symbol_attributes attr = lto_module_get_symbol_attribute(_module, i); | |
352 | ||
353 | // <rdar://problem/6378110> LTO doesn't like dtrace symbols | |
354 | // ignore dtrace static probes for now | |
355 | // later when codegen is done and a mach-o file is produces the probes will be processed | |
356 | if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) ) | |
357 | continue; | |
358 | ||
359 | ld::Atom::Definition def; | |
360 | ld::Atom::Combine combine = ld::Atom::combineNever; | |
361 | switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) { | |
362 | case LTO_SYMBOL_DEFINITION_REGULAR: | |
363 | def = ld::Atom::definitionRegular; | |
364 | break; | |
365 | case LTO_SYMBOL_DEFINITION_TENTATIVE: | |
366 | def = ld::Atom::definitionTentative; | |
367 | break; | |
368 | case LTO_SYMBOL_DEFINITION_WEAK: | |
369 | def = ld::Atom::definitionRegular; | |
370 | combine = ld::Atom::combineByName; | |
371 | break; | |
372 | case LTO_SYMBOL_DEFINITION_UNDEFINED: | |
373 | case LTO_SYMBOL_DEFINITION_WEAKUNDEF: | |
374 | def = ld::Atom::definitionProxy; | |
375 | break; | |
376 | default: | |
377 | throwf("unknown definition kind for symbol %s in bitcode file %s", name, pth); | |
378 | } | |
379 | ||
380 | // make LLVM atoms for definitions and a reference for undefines | |
381 | if ( def != ld::Atom::definitionProxy ) { | |
382 | ld::Atom::Scope scope; | |
b2fa67a8 | 383 | bool autohide = false; |
a645023d A |
384 | switch ( attr & LTO_SYMBOL_SCOPE_MASK) { |
385 | case LTO_SYMBOL_SCOPE_INTERNAL: | |
386 | scope = ld::Atom::scopeTranslationUnit; | |
387 | break; | |
388 | case LTO_SYMBOL_SCOPE_HIDDEN: | |
389 | scope = ld::Atom::scopeLinkageUnit; | |
390 | break; | |
391 | case LTO_SYMBOL_SCOPE_DEFAULT: | |
392 | scope = ld::Atom::scopeGlobal; | |
393 | break; | |
b2fa67a8 A |
394 | #if LTO_API_VERSION >= 4 |
395 | case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN: | |
396 | scope = ld::Atom::scopeGlobal; | |
397 | autohide = true; | |
398 | break; | |
399 | #endif | |
a645023d A |
400 | default: |
401 | throwf("unknown scope for symbol %s in bitcode file %s", name, pth); | |
402 | } | |
403 | // only make atoms for non-internal symbols | |
404 | if ( scope == ld::Atom::scopeTranslationUnit ) | |
405 | continue; | |
406 | uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK); | |
407 | // make Atom using placement new operator | |
b2fa67a8 | 408 | new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment, autohide); |
ebf6f434 | 409 | if ( scope != ld::Atom::scopeTranslationUnit ) |
a645023d A |
410 | _internalAtom.addReference(name); |
411 | if ( log ) fprintf(stderr, "\t0x%08X %s\n", attr, name); | |
412 | } | |
413 | else { | |
414 | // add to list of external references | |
415 | _internalAtom.addReference(name); | |
416 | if ( log ) fprintf(stderr, "\t%s (undefined)\n", name); | |
417 | } | |
418 | } | |
419 | } | |
420 | ||
421 | File::~File() | |
599556ff A |
422 | { |
423 | this->release(); | |
424 | } | |
425 | ||
426 | void File::release() | |
a645023d A |
427 | { |
428 | if ( _module != NULL ) | |
429 | ::lto_module_dispose(_module); | |
599556ff | 430 | _module = NULL; |
a645023d A |
431 | } |
432 | ||
433 | bool File::forEachAtom(ld::File::AtomHandler& handler) const | |
434 | { | |
435 | handler.doAtom(_internalAtom); | |
436 | for(uint32_t i=0; i < _atomArrayCount; ++i) { | |
437 | handler.doAtom(_atomArray[i]); | |
438 | } | |
439 | return true; | |
440 | } | |
441 | ||
442 | InternalAtom::InternalAtom(File& f) | |
443 | : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, | |
444 | ld::Atom::typeLTOtemporary, ld::Atom::symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)), | |
445 | _file(f) | |
446 | { | |
447 | } | |
448 | ||
b2fa67a8 A |
449 | Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Combine c, |
450 | ld::Atom::Alignment a, bool ah) | |
a645023d A |
451 | : ld::Atom(f._section, d, c, s, ld::Atom::typeLTOtemporary, |
452 | ld::Atom::symbolTableIn, false, false, false, a), | |
599556ff | 453 | _file(f), _name(strdup(nm)), _compiledAtom(NULL) |
a645023d | 454 | { |
b2fa67a8 A |
455 | if ( ah ) |
456 | this->setAutoHide(); | |
a645023d A |
457 | } |
458 | ||
459 | void Atom::setCompiledAtom(const ld::Atom& atom) | |
460 | { | |
461 | // set delegate so virtual methods go to it | |
462 | _compiledAtom = &atom; | |
463 | ||
464 | //fprintf(stderr, "setting lto atom %p to delegate to mach-o atom %p (%s)\n", this, &atom, atom.name()); | |
465 | ||
466 | // update fields in ld::Atom to match newly constructed mach-o atom | |
467 | (const_cast<Atom*>(this))->setAttributesFromAtom(atom); | |
468 | } | |
469 | ||
470 | ||
471 | ||
f80fe69f A |
472 | // <rdar://problem/12379604> The order that files are merged must match command line order |
473 | struct CommandLineOrderFileSorter | |
474 | { | |
475 | bool operator()(File* left, File* right) | |
476 | { | |
477 | return ( left->ordinal() < right->ordinal() ); | |
478 | } | |
479 | }; | |
480 | ||
481 | ||
9543cb2f A |
482 | #if LTO_API_VERSION >= 7 |
483 | void Parser::ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t severity, const char* message, void*) | |
484 | { | |
485 | switch ( severity ) { | |
599556ff A |
486 | #if LTO_API_VERSION >= 10 |
487 | case LTO_DS_REMARK: | |
488 | fprintf(stderr, "ld: LTO remark: %s\n", message); | |
489 | break; | |
490 | #endif | |
9543cb2f A |
491 | case LTO_DS_NOTE: |
492 | case LTO_DS_WARNING: | |
493 | warning("%s", message); | |
494 | break; | |
495 | case LTO_DS_ERROR: | |
496 | throwf("%s", message); | |
497 | } | |
498 | } | |
499 | #endif | |
500 | ||
a645023d A |
501 | bool Parser::optimize( const std::vector<const ld::Atom*>& allAtoms, |
502 | ld::Internal& state, | |
a645023d A |
503 | const OptimizeOptions& options, |
504 | ld::File::AtomHandler& handler, | |
505 | std::vector<const ld::Atom*>& newAtoms, | |
506 | std::vector<const char*>& additionalUndefines) | |
507 | { | |
508 | const bool logMustPreserve = false; | |
509 | const bool logExtraOptions = false; | |
510 | const bool logBitcodeFiles = false; | |
511 | const bool logAtomsBeforeSync = false; | |
512 | ||
513 | // exit quickly if nothing to do | |
514 | if ( _s_files.size() == 0 ) | |
515 | return false; | |
516 | ||
517 | // print out LTO version string if -v was used | |
518 | if ( options.verbose ) | |
d425e388 | 519 | fprintf(stderr, "%s\n", ::lto_get_version()); |
a645023d A |
520 | |
521 | // create optimizer and add each Reader | |
522 | lto_code_gen_t generator = ::lto_codegen_create(); | |
9543cb2f A |
523 | #if LTO_API_VERSION >= 7 |
524 | lto_codegen_set_diagnostic_handler(generator, ltoDiagnosticHandler, NULL); | |
525 | #endif | |
526 | ||
f80fe69f A |
527 | // <rdar://problem/12379604> The order that files are merged must match command line order |
528 | std::sort(_s_files.begin(), _s_files.end(), CommandLineOrderFileSorter()); | |
529 | ld::File::Ordinal lastOrdinal; | |
a645023d | 530 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { |
f80fe69f A |
531 | File* f = *it; |
532 | assert(f->ordinal() > lastOrdinal); | |
533 | if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", f->path()); | |
534 | if ( ::lto_codegen_add_module(generator, f->module()) ) | |
535 | throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", f->path(), ::lto_get_error_message(), ::lto_get_version()); | |
599556ff A |
536 | // <rdar://problem/15471128> linker should release module as soon as possible |
537 | f->release(); | |
f80fe69f | 538 | lastOrdinal = f->ordinal(); |
a645023d A |
539 | } |
540 | ||
541 | // add any -mllvm command line options | |
542 | for (std::vector<const char*>::const_iterator it=options.llvmOptions->begin(); it != options.llvmOptions->end(); ++it) { | |
543 | if ( logExtraOptions ) fprintf(stderr, "passing option to llvm: %s\n", *it); | |
544 | ::lto_codegen_debug_options(generator, *it); | |
545 | } | |
546 | ||
f80fe69f A |
547 | // <rdar://problem/13687397> Need a way for LTO to get cpu variants (until that info is in bitcode) |
548 | if ( options.mcpu != NULL ) | |
549 | ::lto_codegen_set_cpu(generator, options.mcpu); | |
550 | ||
a645023d A |
551 | // The atom graph uses directed edges (references). Collect all references where |
552 | // originating atom is not part of any LTO Reader. This allows optimizer to optimize an | |
553 | // external (i.e. not originated from same .o file) reference if all originating atoms are also | |
554 | // defined in llvm bitcode file. | |
555 | CStringSet nonLLVMRefs; | |
556 | CStringToAtom llvmAtoms; | |
557 | bool hasNonllvmAtoms = false; | |
558 | for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { | |
559 | const ld::Atom* atom = *it; | |
560 | // only look at references that come from an atom that is not an llvm atom | |
561 | if ( atom->contentType() != ld::Atom::typeLTOtemporary ) { | |
562 | if ( (atom->section().type() != ld::Section::typeMachHeader) && (atom->definition() != ld::Atom::definitionProxy) ) { | |
563 | hasNonllvmAtoms = true; | |
564 | } | |
565 | const ld::Atom* target; | |
566 | for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) { | |
567 | switch ( fit->binding ) { | |
568 | case ld::Fixup::bindingDirectlyBound: | |
569 | // that reference an llvm atom | |
570 | if ( fit->u.target->contentType() == ld::Atom::typeLTOtemporary ) | |
571 | nonLLVMRefs.insert(fit->u.target->name()); | |
572 | break; | |
573 | case ld::Fixup::bindingsIndirectlyBound: | |
574 | target = state.indirectBindingTable[fit->u.bindingIndex]; | |
9543cb2f | 575 | if ( (target != NULL) && (target->contentType() == ld::Atom::typeLTOtemporary) ) |
a645023d A |
576 | nonLLVMRefs.insert(target->name()); |
577 | default: | |
578 | break; | |
579 | } | |
580 | } | |
581 | } | |
599556ff | 582 | else if ( atom->scope() >= ld::Atom::scopeLinkageUnit ) { |
a645023d A |
583 | llvmAtoms[atom->name()] = (Atom*)atom; |
584 | } | |
585 | } | |
586 | // if entry point is in a llvm bitcode file, it must be preserved by LTO | |
587 | if ( state.entryPoint!= NULL ) { | |
588 | if ( state.entryPoint->contentType() == ld::Atom::typeLTOtemporary ) | |
589 | nonLLVMRefs.insert(state.entryPoint->name()); | |
590 | } | |
591 | ||
592 | // deadAtoms are the atoms that the linker coalesced. For instance weak or tentative definitions | |
593 | // overriden by another atom. If any of these deadAtoms are llvm atoms and they were replaced | |
594 | // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead | |
595 | // atom so that the linker can replace it with the mach-o one later. | |
596 | CStringToAtom deadllvmAtoms; | |
597 | for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { | |
598 | const ld::Atom* atom = *it; | |
599 | if ( atom->coalescedAway() && (atom->contentType() == ld::Atom::typeLTOtemporary) ) { | |
600 | const char* name = atom->name(); | |
601 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name); | |
602 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
603 | deadllvmAtoms[name] = (Atom*)atom; | |
604 | } | |
605 | } | |
606 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
607 | File* file = *it; | |
608 | for(uint32_t i=0; i < file->_atomArrayCount; ++i) { | |
609 | Atom* llvmAtom = &file->_atomArray[i]; | |
610 | if ( llvmAtom->coalescedAway() ) { | |
611 | const char* name = llvmAtom->name(); | |
612 | if ( deadllvmAtoms.find(name) == deadllvmAtoms.end() ) { | |
613 | if ( logMustPreserve ) | |
614 | fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name); | |
615 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
616 | deadllvmAtoms[name] = (Atom*)llvmAtom; | |
617 | } | |
618 | } | |
619 | else if ( options.linkerDeadStripping && !llvmAtom->live() ) { | |
620 | const char* name = llvmAtom->name(); | |
621 | deadllvmAtoms[name] = (Atom*)llvmAtom; | |
622 | } | |
623 | } | |
624 | } | |
625 | ||
626 | // tell code generator about symbols that must be preserved | |
627 | for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { | |
628 | const char* name = it->first; | |
629 | Atom* atom = it->second; | |
630 | // Include llvm Symbol in export list if it meets one of following two conditions | |
631 | // 1 - atom scope is global (and not linkage unit). | |
632 | // 2 - included in nonLLVMRefs set. | |
633 | // If a symbol is not listed in exportList then LTO is free to optimize it away. | |
ebf6f434 | 634 | if ( (atom->scope() == ld::Atom::scopeGlobal) && options.preserveAllGlobals ) { |
a645023d A |
635 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name); |
636 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
637 | } | |
638 | else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) { | |
639 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because referenced by a mach-o atom\n", name); | |
640 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
641 | } | |
599556ff A |
642 | else if ( options.relocatable && hasNonllvmAtoms ) { |
643 | // <rdar://problem/14334895> ld -r mode but merging in some mach-o files, so need to keep libLTO from optimizing away anything | |
644 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because -r mode disable LTO dead stripping\n", name); | |
645 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
646 | } | |
a645023d A |
647 | } |
648 | ||
599556ff A |
649 | // <rdar://problem/16165191> tell code generator to preserve initial undefines |
650 | for( std::vector<const char*>::const_iterator it=options.initialUndefines->begin(); it != options.initialUndefines->end(); ++it) { | |
651 | if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because it is an initial undefine\n", *it); | |
652 | ::lto_codegen_add_must_preserve_symbol(generator, *it); | |
653 | } | |
654 | ||
a645023d A |
655 | // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o) |
656 | if ( options.relocatable && !hasNonllvmAtoms ) { | |
657 | if ( ! ::lto_codegen_write_merged_modules(generator, options.outputFilePath) ) { | |
658 | // HACK, no good way to tell linker we are all done, so just quit | |
659 | exit(0); | |
660 | } | |
661 | warning("could not produce merged bitcode file"); | |
662 | } | |
663 | ||
664 | // set code-gen model | |
665 | lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
666 | if ( options.mainExecutable ) { | |
667 | if ( options.staticExecutable ) { | |
d425e388 A |
668 | // x86_64 "static" or any "-static -pie" is really dynamic code model |
669 | if ( (options.arch == CPU_TYPE_X86_64) || options.pie ) | |
a645023d A |
670 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; |
671 | else | |
672 | model = LTO_CODEGEN_PIC_MODEL_STATIC; | |
673 | } | |
674 | else { | |
675 | if ( options.pie ) | |
676 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
677 | else | |
678 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; | |
679 | } | |
680 | } | |
681 | else { | |
682 | if ( options.allowTextRelocs ) | |
683 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; | |
684 | else | |
685 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
686 | } | |
687 | if ( ::lto_codegen_set_pic_model(generator, model) ) | |
688 | throwf("could not create set codegen model: %s", lto_get_error_message()); | |
689 | ||
690 | // if requested, save off merged bitcode file | |
691 | if ( options.saveTemps ) { | |
692 | char tempBitcodePath[MAXPATHLEN]; | |
693 | strcpy(tempBitcodePath, options.outputFilePath); | |
694 | strcat(tempBitcodePath, ".lto.bc"); | |
695 | ::lto_codegen_write_merged_modules(generator, tempBitcodePath); | |
696 | } | |
697 | ||
698 | #if LTO_API_VERSION >= 3 | |
699 | // find assembler next to linker | |
700 | char path[PATH_MAX]; | |
701 | uint32_t bufSize = PATH_MAX; | |
702 | if ( _NSGetExecutablePath(path, &bufSize) != -1 ) { | |
703 | char* lastSlash = strrchr(path, '/'); | |
704 | if ( lastSlash != NULL ) { | |
705 | strcpy(lastSlash+1, "as"); | |
706 | struct stat statInfo; | |
707 | if ( stat(path, &statInfo) == 0 ) | |
708 | ::lto_codegen_set_assembler_path(generator, path); | |
709 | } | |
710 | } | |
711 | #endif | |
712 | // run code generator | |
713 | size_t machOFileLen; | |
714 | const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen); | |
715 | if ( machOFile == NULL ) | |
d425e388 | 716 | throwf("could not do LTO codegen: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version()); |
a645023d A |
717 | |
718 | // if requested, save off temp mach-o file | |
719 | if ( options.saveTemps ) { | |
720 | char tempMachoPath[MAXPATHLEN]; | |
721 | strcpy(tempMachoPath, options.outputFilePath); | |
722 | strcat(tempMachoPath, ".lto.o"); | |
723 | int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
724 | if ( fd != -1) { | |
725 | ::write(fd, machOFile, machOFileLen); | |
726 | ::close(fd); | |
727 | } | |
728 | // save off merged bitcode file | |
729 | char tempOptBitcodePath[MAXPATHLEN]; | |
730 | strcpy(tempOptBitcodePath, options.outputFilePath); | |
731 | strcat(tempOptBitcodePath, ".lto.opt.bc"); | |
732 | ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath); | |
733 | } | |
734 | ||
735 | // if needed, save temp mach-o file to specific location | |
736 | if ( options.tmpObjectFilePath != NULL ) { | |
737 | int fd = ::open(options.tmpObjectFilePath, O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
738 | if ( fd != -1) { | |
739 | ::write(fd, machOFile, machOFileLen); | |
740 | ::close(fd); | |
741 | } | |
742 | else { | |
743 | warning("could not write LTO temp file '%s', errno=%d", options.tmpObjectFilePath, errno); | |
744 | } | |
745 | } | |
746 | ||
747 | // parse generated mach-o file into a MachOReader | |
ebf6f434 | 748 | ld::relocatable::File* machoFile = parseMachOFile(machOFile, machOFileLen, options); |
a645023d A |
749 | |
750 | // sync generated mach-o atoms with existing atoms ld knows about | |
751 | if ( logAtomsBeforeSync ) { | |
752 | fprintf(stderr, "llvmAtoms:\n"); | |
753 | for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { | |
754 | const char* name = it->first; | |
599556ff A |
755 | Atom* atom = it->second; |
756 | fprintf(stderr, "\t%p\t%s\n", atom, name); | |
a645023d A |
757 | } |
758 | fprintf(stderr, "deadllvmAtoms:\n"); | |
759 | for (CStringToAtom::iterator it = deadllvmAtoms.begin(); it != deadllvmAtoms.end(); ++it) { | |
760 | const char* name = it->first; | |
599556ff A |
761 | Atom* atom = it->second; |
762 | fprintf(stderr, "\t%p\t%s\n", atom, name); | |
a645023d A |
763 | } |
764 | } | |
765 | AtomSyncer syncer(additionalUndefines, newAtoms, llvmAtoms, deadllvmAtoms, options); | |
766 | machoFile->forEachAtom(syncer); | |
767 | ||
768 | // Remove InternalAtoms from ld | |
769 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
770 | (*it)->internalAtom().setCoalescedAway(); | |
771 | } | |
772 | // Remove Atoms from ld if code generator optimized them away | |
773 | for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) { | |
774 | // check if setRealAtom() called on this Atom | |
775 | if ( li->second->compiledAtom() == NULL ) { | |
776 | //fprintf(stderr, "llvm optimized away %p %s\n", li->second, li->second->name()); | |
777 | li->second->setCoalescedAway(); | |
778 | } | |
779 | } | |
780 | ||
781 | // notify about file level attributes | |
782 | handler.doFile(*machoFile); | |
783 | ||
784 | // if final mach-o file has debug info, update original bitcode files to match | |
785 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
786 | (*it)->setDebugInfo(machoFile->debugInfo(), machoFile->path(), | |
787 | machoFile->modificationTime(), machoFile->cpuSubType()); | |
788 | } | |
789 | ||
790 | return true; | |
791 | } | |
792 | ||
793 | ||
794 | void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom) | |
795 | { | |
599556ff | 796 | static const bool log = false; |
9543cb2f A |
797 | static const ld::Atom* lastProxiedAtom = NULL; |
798 | static const ld::File* lastProxiedFile = NULL; | |
a645023d A |
799 | // update proxy atoms to point to real atoms and find new atoms |
800 | const char* name = machoAtom.name(); | |
599556ff A |
801 | CStringToAtom::iterator pos = _llvmAtoms.find(name); |
802 | if ( pos != _llvmAtoms.end() ) { | |
803 | // turn Atom into a proxy for this mach-o atom | |
804 | pos->second->setCompiledAtom(machoAtom); | |
805 | lastProxiedAtom = &machoAtom; | |
806 | lastProxiedFile = pos->second->file(); | |
807 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p synced to lto atom %p (name=%s)\n", &machoAtom, pos->second, machoAtom.name()); | |
808 | } | |
809 | else { | |
810 | // an atom of this name was not in the allAtoms list the linker gave us | |
811 | if ( _deadllvmAtoms.find(name) != _deadllvmAtoms.end() ) { | |
812 | // this corresponding to an atom that the linker coalesced away or marked not-live | |
813 | if ( _options.linkerDeadStripping ) { | |
814 | // llvm seems to want this atom and -dead_strip is enabled, so it will be deleted if not needed, so add back | |
815 | Atom* llvmAtom = _deadllvmAtoms[name]; | |
816 | llvmAtom->setCompiledAtom(machoAtom); | |
a645023d | 817 | _newAtoms.push_back(&machoAtom); |
599556ff | 818 | 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 | 819 | } |
599556ff A |
820 | else { |
821 | // Don't pass it back as a new atom | |
822 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p matches dead lto atom %p (name=%s)\n", &machoAtom, _deadllvmAtoms[name], machoAtom.name()); | |
823 | } | |
a645023d | 824 | } |
599556ff A |
825 | else |
826 | { | |
827 | // this is something new that lto conjured up, tell ld its new | |
828 | _newAtoms.push_back(&machoAtom); | |
829 | // <rdar://problem/15469363> if new static atom in same section as previous non-static atom, assign to same file as previous | |
830 | if ( (lastProxiedAtom != NULL) && (lastProxiedAtom->section() == machoAtom.section()) ) { | |
831 | ld::Atom* ma = const_cast<ld::Atom*>(&machoAtom); | |
832 | ma->setFile(lastProxiedFile); | |
833 | } | |
834 | if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p is totally new (name=%s)\n", &machoAtom, machoAtom.name()); | |
9543cb2f | 835 | } |
a645023d A |
836 | } |
837 | ||
838 | // adjust fixups to go through proxy atoms | |
599556ff | 839 | if (log) fprintf(stderr, " adjusting fixups in atom: %s\n", machoAtom.name()); |
a645023d A |
840 | for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) { |
841 | switch ( fit->binding ) { | |
842 | case ld::Fixup::bindingNone: | |
843 | break; | |
844 | case ld::Fixup::bindingByNameUnbound: | |
845 | // don't know if this target has been seen by linker before or if it is new | |
846 | // be conservative and tell linker it is new | |
847 | _additionalUndefines.push_back(fit->u.name); | |
599556ff | 848 | if (log) fprintf(stderr, " adding by-name symbol %s\n", fit->u.name); |
a645023d A |
849 | break; |
850 | case ld::Fixup::bindingDirectlyBound: | |
851 | // If mach-o atom is referencing another mach-o atom then | |
852 | // reference is not going through Atom proxy. Fix it here to ensure that all | |
853 | // llvm symbol references always go through Atom proxy. | |
599556ff | 854 | { |
a645023d | 855 | const char* targetName = fit->u.target->name(); |
599556ff A |
856 | CStringToAtom::iterator post = _llvmAtoms.find(targetName); |
857 | if ( post != _llvmAtoms.end() ) { | |
858 | const ld::Atom* t = post->second; | |
859 | if (log) fprintf(stderr, " updating direct reference to %p to be ref to %p: %s\n", fit->u.target, t, targetName); | |
860 | fit->u.target = t; | |
a645023d A |
861 | } |
862 | else { | |
f80fe69f A |
863 | // <rdar://problem/12859831> Don't unbind follow-on reference into by-name reference |
864 | if ( (_deadllvmAtoms.find(targetName) != _deadllvmAtoms.end()) && (fit->kind != ld::Fixup::kindNoneFollowOn) ) { | |
a645023d A |
865 | // target was coalesed away and replace by mach-o atom from a non llvm .o file |
866 | fit->binding = ld::Fixup::bindingByNameUnbound; | |
867 | fit->u.name = targetName; | |
868 | } | |
869 | } | |
870 | } | |
871 | //fprintf(stderr, " direct ref to: %s (scope=%d)\n", fit->u.target->name(), fit->u.target->scope()); | |
872 | break; | |
873 | case ld::Fixup::bindingByContentBound: | |
874 | //fprintf(stderr, " direct by content to: %s\n", fit->u.target->name()); | |
875 | break; | |
876 | case ld::Fixup::bindingsIndirectlyBound: | |
877 | assert(0 && "indirect binding found in initial mach-o file?"); | |
878 | //fprintf(stderr, " indirect by content to: %u\n", fit->u.bindingIndex); | |
879 | break; | |
880 | } | |
881 | } | |
882 | ||
883 | } | |
884 | ||
ebf6f434 A |
885 | class Mutex { |
886 | static pthread_mutex_t lto_lock; | |
887 | public: | |
888 | Mutex() { pthread_mutex_lock(<o_lock); } | |
889 | ~Mutex() { pthread_mutex_unlock(<o_lock); } | |
890 | }; | |
891 | pthread_mutex_t Mutex::lto_lock = PTHREAD_MUTEX_INITIALIZER; | |
a645023d A |
892 | |
893 | // | |
894 | // Used by archive reader to see if member is an llvm bitcode file | |
895 | // | |
896 | bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch) | |
897 | { | |
ebf6f434 | 898 | Mutex lock; |
a645023d A |
899 | return Parser::validFile(fileContent, fileLength, architecture, subarch); |
900 | } | |
901 | ||
902 | ||
903 | // | |
904 | // main function used by linker to instantiate ld::Files | |
905 | // | |
906 | ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, | |
b1f7435d | 907 | const char* path, time_t modTime, ld::File::Ordinal ordinal, |
9543cb2f A |
908 | cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles, |
909 | bool verboseOptimizationHints) | |
a645023d | 910 | { |
ebf6f434 | 911 | Mutex lock; |
a645023d | 912 | if ( Parser::validFile(fileContent, fileLength, architecture, subarch) ) |
9543cb2f | 913 | return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles, verboseOptimizationHints); |
a645023d A |
914 | else |
915 | return NULL; | |
916 | } | |
917 | ||
918 | // | |
919 | // used by "ld -v" to report version of libLTO.dylib being used | |
920 | // | |
921 | const char* version() | |
922 | { | |
ebf6f434 | 923 | Mutex lock; |
a645023d A |
924 | return ::lto_get_version(); |
925 | } | |
926 | ||
927 | ||
928 | // | |
929 | // used by ld for error reporting | |
930 | // | |
931 | bool libLTOisLoaded() | |
932 | { | |
ebf6f434 | 933 | Mutex lock; |
a645023d A |
934 | return (::lto_get_version() != NULL); |
935 | } | |
936 | ||
937 | // | |
938 | // used by ld for error reporting | |
939 | // | |
940 | const char* archName(const uint8_t* fileContent, uint64_t fileLength) | |
941 | { | |
ebf6f434 | 942 | Mutex lock; |
a645023d A |
943 | return Parser::fileKind(fileContent, fileLength); |
944 | } | |
945 | ||
946 | // | |
947 | // used by ld for doing link time optimization | |
948 | // | |
949 | bool optimize( const std::vector<const ld::Atom*>& allAtoms, | |
950 | ld::Internal& state, | |
a645023d A |
951 | const OptimizeOptions& options, |
952 | ld::File::AtomHandler& handler, | |
953 | std::vector<const ld::Atom*>& newAtoms, | |
954 | std::vector<const char*>& additionalUndefines) | |
955 | { | |
ebf6f434 A |
956 | Mutex lock; |
957 | return Parser::optimize(allAtoms, state, options, handler, newAtoms, additionalUndefines); | |
a645023d A |
958 | } |
959 | ||
960 | ||
961 | ||
962 | }; // namespace lto | |
963 | ||
964 | ||
965 | #endif | |
966 |