]>
Commit | Line | Data |
---|---|---|
b1f7435d A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
3 | * Copyright (c) 2006-2009 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 <mach-o/dyld.h> | |
30 | #include <vector> | |
31 | #include <ext/hash_set> | |
32 | #include <ext/hash_map> | |
33 | ||
34 | #include "MachOFileAbstraction.hpp" | |
35 | #include "Architectures.hpp" | |
36 | #include "ld.hpp" | |
37 | ||
38 | #include "llvm-c/lto.h" | |
39 | ||
40 | ||
41 | namespace lto { | |
42 | ||
43 | ||
44 | // | |
45 | // ld64 only tracks non-internal symbols from an llvm bitcode file. | |
46 | // We model this by having an InternalAtom which represent all internal functions and data. | |
47 | // All non-interal symbols from a bitcode file are represented by an Atom | |
48 | // and each Atom has a reference to the InternalAtom. The InternalAtom | |
49 | // also has references to each symbol external to the bitcode file. | |
50 | // | |
51 | class InternalAtom : public ld::Atom | |
52 | { | |
53 | public: | |
54 | InternalAtom(class File& f); | |
55 | // overrides of ld::Atom | |
56 | virtual ld::File* file() const { return &_file; } | |
57 | virtual bool translationUnitSource(const char** dir, const char** nm) const | |
58 | { return false; } | |
59 | virtual const char* name() const { return "import-atom"; } | |
60 | virtual uint64_t size() const { return 0; } | |
61 | virtual uint64_t objectAddress() const { return 0; } | |
62 | virtual void copyRawContent(uint8_t buffer[]) const { } | |
63 | virtual void setScope(Scope) { } | |
64 | virtual ld::Fixup::iterator fixupsBegin() { return &_undefs[0]; } | |
65 | virtual ld::Fixup::iterator fixupsEnd() { return &_undefs[_undefs.size()]; } | |
66 | ||
67 | // for adding references to symbols outside bitcode file | |
68 | void addReference(const char* name) | |
69 | { _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, | |
70 | ld::Fixup::fixupNone, false, name)); } | |
71 | private: | |
72 | ||
73 | ld::File& _file; | |
74 | std::vector<ld::Fixup> _undefs; | |
75 | }; | |
76 | ||
77 | ||
78 | // | |
79 | // LLVM bitcode file | |
80 | // | |
81 | class File : public ld::relocatable::File | |
82 | { | |
83 | public: | |
84 | File(const char* path, time_t mTime, const uint8_t* content, | |
85 | uint32_t contentLength, uint32_t ordinal, cpu_type_t arch); | |
86 | virtual ~File(); | |
87 | ||
88 | // overrides of ld::File | |
89 | virtual bool forEachAtom(ld::File::AtomHandler&); | |
90 | virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) | |
91 | { return false; } | |
92 | ||
93 | // overrides of ld::relocatable::File | |
94 | virtual bool objcReplacementClasses() { return false; } | |
95 | virtual DebugInfoKind debugInfo() { return ld::relocatable::File::kDebugInfoNone; } | |
96 | virtual std::vector<ld::relocatable::File::Stab>* stabs() { return NULL; } | |
97 | virtual bool canScatterAtoms() { return true; } | |
98 | ||
99 | lto_module_t module() { return _module; } | |
100 | class InternalAtom& internalAtom() { return _internalAtom; } | |
101 | private: | |
102 | friend class Atom; | |
103 | friend class InternalAtom; | |
104 | ||
105 | cpu_type_t _architecture; | |
106 | class InternalAtom _internalAtom; | |
107 | class Atom* _atomArray; | |
108 | uint32_t _atomArrayCount; | |
109 | lto_module_t _module; | |
110 | ld::Section _section; | |
111 | }; | |
112 | ||
113 | // | |
114 | // Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially, | |
115 | // Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After | |
116 | // optimization is performed, real Atoms are created for these symobls. However these real Atoms | |
117 | // are not inserted into global symbol table. Atom holds real Atom and forwards appropriate | |
118 | // methods to real atom. | |
119 | // | |
120 | class Atom : public ld::Atom | |
121 | { | |
122 | public: | |
123 | Atom(File& f, const char* name, ld::Atom::Scope s, | |
124 | ld::Atom::Definition d, ld::Atom::Alignment a); | |
125 | ||
126 | // overrides of ld::Atom | |
127 | virtual ld::File* file() const { return &_file; } | |
128 | virtual bool translationUnitSource(const char** dir, const char** nm) const | |
129 | { return (_compiledAtom ? _compiledAtom->translationUnitSource(dir, nm) : false); } | |
130 | virtual const char* name() const { return _name; } | |
131 | virtual uint64_t size() const { return (_compiledAtom ? _compiledAtom->size() : 0); } | |
132 | virtual uint64_t objectAddress() const { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); } | |
133 | virtual void copyRawContent(uint8_t buffer[]) const | |
134 | { if (_compiledAtom) _compiledAtom->copyRawContent(buffer); } | |
135 | ||
136 | ld::Atom* compiledAtom() { return _compiledAtom; } | |
137 | void setCompiledAtom(ld::Atom& atom) | |
138 | { _compiledAtom = &atom; } | |
139 | private: | |
140 | ||
141 | File& _file; | |
142 | const char* _name; | |
143 | ld::Atom* _compiledAtom; | |
144 | }; | |
145 | ||
146 | ||
147 | ||
148 | ||
149 | ||
150 | ||
151 | ||
152 | class Parser | |
153 | { | |
154 | public: | |
155 | static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture); | |
156 | static const char* fileKind(const uint8_t* fileContent); | |
157 | static File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, | |
158 | time_t modTime, uint32_t ordinal, cpu_type_t architecture); | |
159 | static bool libLTOisLoaded() { return (::lto_get_version() != NULL); } | |
160 | static bool optimize(const std::vector<ld::Atom*>& allAtoms, std::vector<ld::Atom*>& newAtoms, | |
161 | std::vector<const char*>& additionalUndefines, | |
162 | const std::set<ld::Atom*>&, | |
163 | std::vector<ld::Atom*>& newDeadAtoms, | |
164 | uint32_t nextInputOrdinal, | |
165 | ld::OutFile* writer, ld::Atom* entryPointAtom, | |
166 | const std::vector<const char*>& llvmOptions, | |
167 | bool allGlobalsAReDeadStripRoots, | |
168 | bool verbose, bool saveTemps, | |
169 | const char* outputFilePath, | |
170 | bool pie, bool mainExecutable, bool staticExecutable, bool relocatable, | |
171 | bool allowTextRelocs, cpu_type_t arch); | |
172 | ||
173 | static const char* ltoVersion() { return ::lto_get_version(); } | |
174 | ||
175 | private: | |
176 | static const char* tripletPrefixForArch(cpu_type_t arch); | |
177 | static ld::relocatable::File* parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, cpu_type_t arch); | |
178 | ||
179 | class CStringEquals | |
180 | { | |
181 | public: | |
182 | bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } | |
183 | }; | |
184 | typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> CStringSet; | |
185 | typedef __gnu_cxx::hash_map<const char*, Atom*, __gnu_cxx::hash<const char*>, CStringEquals> CStringToAtom; | |
186 | ||
187 | class AtomSyncer : public ld::File::AtomHandler { | |
188 | public: | |
189 | AtomSyncer(std::vector<const char*>& a, std::vector<ld::Atom*>&na, | |
190 | CStringToAtom la, CStringToAtom dla) : | |
191 | additionalUndefines(a), newAtoms(na), llvmAtoms(la), deadllvmAtoms(dla) { } | |
192 | virtual void doAtom(class ld::Atom&); | |
193 | ||
194 | std::vector<const char*>& additionalUndefines; | |
195 | std::vector<ld::Atom*>& newAtoms; | |
196 | CStringToAtom llvmAtoms; | |
197 | CStringToAtom deadllvmAtoms; | |
198 | }; | |
199 | ||
200 | static std::vector<File*> _s_files; | |
201 | }; | |
202 | ||
203 | std::vector<File*> Parser::_s_files; | |
204 | ||
205 | ||
206 | const char* Parser::tripletPrefixForArch(cpu_type_t arch) | |
207 | { | |
208 | switch (arch) { | |
209 | case CPU_TYPE_POWERPC: | |
210 | return "powerpc-"; | |
211 | case CPU_TYPE_POWERPC64: | |
212 | return "powerpc64-"; | |
213 | case CPU_TYPE_I386: | |
214 | return "i386-"; | |
215 | case CPU_TYPE_X86_64: | |
216 | return "x86_64-"; | |
217 | case CPU_TYPE_ARM: | |
218 | return "arm"; | |
219 | } | |
220 | return ""; | |
221 | } | |
222 | ||
223 | bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture) | |
224 | { | |
225 | return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture)); | |
226 | } | |
227 | ||
228 | const char* Parser::fileKind(const uint8_t* p) | |
229 | { | |
230 | if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) { | |
231 | uint32_t arch = LittleEndian::get32(*((uint32_t*)(&p[16]))); | |
232 | switch (arch) { | |
233 | case CPU_TYPE_POWERPC: | |
234 | return "ppc"; | |
235 | case CPU_TYPE_I386: | |
236 | return "i386"; | |
237 | case CPU_TYPE_X86_64: | |
238 | return "x86_64"; | |
239 | case CPU_TYPE_ARM: | |
240 | return "arm"; | |
241 | } | |
242 | return "unknown bitcode architecture"; | |
243 | } | |
244 | return NULL; | |
245 | } | |
246 | ||
247 | File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, | |
248 | uint32_t ordinal, cpu_type_t architecture) | |
249 | { | |
250 | File* f = new File(path, modTime, fileContent, fileLength, ordinal, architecture); | |
251 | _s_files.push_back(f); | |
252 | return f; | |
253 | } | |
254 | ||
255 | ||
256 | ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, cpu_type_t arch) | |
257 | { | |
258 | switch ( arch ) { | |
259 | case CPU_TYPE_POWERPC: | |
260 | if ( mach_o::relocatable::Parser<ppc>::validFile(p) ) | |
261 | return mach_o::relocatable::Parser<ppc>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal); | |
262 | break; | |
263 | case CPU_TYPE_POWERPC64: | |
264 | if ( mach_o::relocatable::Parser<ppc64>::validFile(p) ) | |
265 | return mach_o::relocatable::Parser<ppc64>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal); | |
266 | break; | |
267 | case CPU_TYPE_I386: | |
268 | if ( mach_o::relocatable::Parser<x86>::validFile(p) ) | |
269 | return mach_o::relocatable::Parser<x86>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal); | |
270 | break; | |
271 | case CPU_TYPE_X86_64: | |
272 | if ( mach_o::relocatable::Parser<x86_64>::validFile(p) ) | |
273 | return mach_o::relocatable::Parser<x86_64>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal); | |
274 | break; | |
275 | case CPU_TYPE_ARM: | |
276 | if ( mach_o::relocatable::Parser<arm>::validFile(p) ) | |
277 | return mach_o::relocatable::Parser<arm>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal); | |
278 | break; | |
279 | } | |
280 | throw "LLVM LTO, file is not of required architecture"; | |
281 | } | |
282 | ||
283 | ||
284 | ||
285 | File::File(const char* path, time_t mTime, const uint8_t* content, uint32_t contentLength, uint32_t ordinal, cpu_type_t arch) | |
286 | : ld::relocatable::File(path,mTime,ordinal), _architecture(arch), _internalAtom(*this), | |
287 | _atomArray(NULL), _atomArrayCount(0), _module(NULL), | |
288 | _section("__TEXT_", "__tmp_lto", ld::Section::typeUnclassified) | |
289 | { | |
290 | // create llvm module | |
291 | _module = ::lto_module_create_from_memory(content, contentLength); | |
292 | if ( _module == NULL ) | |
293 | throwf("could not parse object file %s: %s", path, lto_get_error_message()); | |
294 | ||
295 | // create atom for each global symbol in module | |
296 | uint32_t count = ::lto_module_get_num_symbols(_module); | |
297 | _atomArray = (Atom*)malloc(sizeof(Atom)*count); | |
298 | for (uint32_t i=0; i < count; ++i) { | |
299 | const char* name = ::lto_module_get_symbol_name(_module, i); | |
300 | lto_symbol_attributes attr = lto_module_get_symbol_attribute(_module, i); | |
301 | ||
302 | // <rdar://problem/6378110> LTO doesn't like dtrace symbols | |
303 | // ignore dtrace static probes for now | |
304 | // later when codegen is done and a mach-o file is produces the probes will be processed | |
305 | if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) ) | |
306 | continue; | |
307 | ||
308 | ld::Atom::Definition def; | |
309 | switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) { | |
310 | case LTO_SYMBOL_DEFINITION_REGULAR: | |
311 | def = ld::Atom::definitionRegular; | |
312 | break; | |
313 | case LTO_SYMBOL_DEFINITION_TENTATIVE: | |
314 | def = ld::Atom::definitionTentative; | |
315 | break; | |
316 | case LTO_SYMBOL_DEFINITION_WEAK: | |
317 | def = ld::Atom::definitionRegular; | |
318 | break; | |
319 | case LTO_SYMBOL_DEFINITION_UNDEFINED: | |
320 | case LTO_SYMBOL_DEFINITION_WEAKUNDEF: | |
321 | def = ld::Atom::definitionProxy; | |
322 | break; | |
323 | default: | |
324 | throwf("unknown definition kind for symbol %s in bitcode file %s", name, path); | |
325 | } | |
326 | ||
327 | // make LLVM atoms for definitions and a reference for undefines | |
328 | if ( def != ld::Atom::definitionProxy ) { | |
329 | ld::Atom::Scope scope; | |
330 | switch ( attr & LTO_SYMBOL_SCOPE_MASK) { | |
331 | case LTO_SYMBOL_SCOPE_INTERNAL: | |
332 | scope = ld::Atom::scopeTranslationUnit; | |
333 | break; | |
334 | case LTO_SYMBOL_SCOPE_HIDDEN: | |
335 | scope = ld::Atom::scopeLinkageUnit; | |
336 | break; | |
337 | case LTO_SYMBOL_SCOPE_DEFAULT: | |
338 | scope = ld::Atom::scopeGlobal; | |
339 | break; | |
340 | default: | |
341 | throwf("unknown scope for symbol %s in bitcode file %s", name, path); | |
342 | } | |
343 | // only make atoms for non-internal symbols | |
344 | if ( scope == ld::Atom::scopeTranslationUnit ) | |
345 | continue; | |
346 | uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK); | |
347 | // make Atom using placement new operator | |
348 | new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, alignment); | |
349 | } | |
350 | else { | |
351 | // add to list of external references | |
352 | _internalAtom.addReference(name); | |
353 | } | |
354 | } | |
355 | } | |
356 | ||
357 | File::~File() | |
358 | { | |
359 | if ( _module != NULL ) | |
360 | ::lto_module_dispose(_module); | |
361 | } | |
362 | ||
363 | bool File::forEachAtom(ld::File::AtomHandler& handler) | |
364 | { | |
365 | handler.doAtom(_internalAtom); | |
366 | for(uint32_t i=0; i < _atomArrayCount; ++i) { | |
367 | handler.doAtom(_atomArray[i]); | |
368 | } | |
369 | return true; | |
370 | } | |
371 | ||
372 | InternalAtom::InternalAtom(File& f) | |
373 | : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, | |
374 | ld::Atom::typeLTOtemporary, ld::Atom::symbolTableNotIn, false, false, ld::Atom::Alignment(0)), | |
375 | _file(f) | |
376 | { | |
377 | } | |
378 | ||
379 | Atom::Atom(File& f, const char* name, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Alignment a) | |
380 | : ld::Atom(f._section, d, ld::Atom::combineNever, s, ld::Atom::typeLTOtemporary, ld::Atom::symbolTableIn, false, false, a), | |
381 | _file(f), _name(name), _compiledAtom(NULL) | |
382 | { | |
383 | } | |
384 | ||
385 | ||
386 | ||
387 | ||
388 | bool Parser::optimize(const std::vector<ld::Atom*>& allAtoms, std::vector<ld::Atom*>& newAtoms, | |
389 | std::vector<const char*>& additionalUndefines, | |
390 | const std::set<ld::Atom*>& deadAtoms, | |
391 | std::vector<ld::Atom*>& newlyDeadAtoms, | |
392 | uint32_t nextInputOrdinal, | |
393 | ld::OutFile* writer, ld::Atom* entryPointAtom, | |
394 | const std::vector<const char*>& llvmOptions, | |
395 | bool allGlobalsAReDeadStripRoots, | |
396 | bool verbose, bool saveTemps, | |
397 | const char* outputFilePath, | |
398 | bool pie, bool mainExecutable, bool staticExecutable, bool relocatable, | |
399 | bool allowTextRelocs, cpu_type_t arch) | |
400 | { | |
401 | // exit quickly if nothing to do | |
402 | if ( _s_files.size() == 0 ) | |
403 | return false; | |
404 | ||
405 | // print out LTO version string if -v was used | |
406 | if ( verbose ) | |
407 | fprintf(stderr, "%s\n", lto_get_version()); | |
408 | ||
409 | // create optimizer and add each Reader | |
410 | lto_code_gen_t generator = ::lto_codegen_create(); | |
411 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
412 | if ( ::lto_codegen_add_module(generator, (*it)->module()) ) | |
413 | throwf("lto: could not merge in %s because %s", (*it)->path(), ::lto_get_error_message()); | |
414 | } | |
415 | ||
416 | // add any -mllvm command line options | |
417 | for (std::vector<const char*>::const_iterator it=llvmOptions.begin(); it != llvmOptions.end(); ++it) { | |
418 | ::lto_codegen_debug_options(generator, *it); | |
419 | } | |
420 | ||
421 | // The atom graph uses directed edges (references). Collect all references where | |
422 | // originating atom is not part of any LTO Reader. This allows optimizer to optimize an | |
423 | // external (i.e. not originated from same .o file) reference if all originating atoms are also | |
424 | // defined in llvm bitcode file. | |
425 | CStringSet nonLLVMRefs; | |
426 | CStringToAtom llvmAtoms; | |
427 | bool hasNonllvmAtoms = false; | |
428 | for (std::vector<ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { | |
429 | ld::Atom* atom = *it; | |
430 | // only look at references that come from an atom that is not an llvm atom | |
431 | if ( atom->contentType() != ld::Atom::typeLTOtemporary ) { | |
432 | // remember if we've seen any atoms not from an llvm reader and not from the writer | |
433 | // if ( atom->getFile() != writer ) | |
434 | // hasNonllvmAtoms = true; | |
435 | for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) { | |
436 | if ( fit->binding != ld::Fixup::bindingByNameBound ) | |
437 | continue; | |
438 | // and reference an llvm atom | |
439 | if ( fit->u.target->contentType() == ld::Atom::typeLTOtemporary ) | |
440 | nonLLVMRefs.insert(fit->u.target->name()); | |
441 | } | |
442 | } | |
443 | else { | |
444 | llvmAtoms[atom->name()] = (Atom*)atom; | |
445 | } | |
446 | } | |
447 | // if entry point is in a llvm bitcode file, it must be preserved by LTO | |
448 | if ( entryPointAtom != NULL ) { | |
449 | if ( entryPointAtom->contentType() == ld::Atom::typeLTOtemporary ) | |
450 | nonLLVMRefs.insert(entryPointAtom->name()); | |
451 | } | |
452 | ||
453 | // deadAtoms are the atoms that the linker coalesced. For instance weak or tentative definitions | |
454 | // overriden by another atom. If any of these deadAtoms are llvm atoms and they were replaced | |
455 | // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead | |
456 | // atom so that the linker can replace it with the mach-o one later. | |
457 | CStringToAtom deadllvmAtoms; | |
458 | for (std::set<ld::Atom*>::iterator it = deadAtoms.begin(); it != deadAtoms.end(); ++it) { | |
459 | ld::Atom* atom = *it; | |
460 | if ( atom->contentType() == ld::Atom::typeLTOtemporary ) { | |
461 | const char* name = atom->name(); | |
462 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
463 | deadllvmAtoms[name] = (Atom*)atom; | |
464 | } | |
465 | } | |
466 | ||
467 | ||
468 | // tell code generator about symbols that must be preserved | |
469 | for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { | |
470 | const char* name = it->first; | |
471 | Atom* atom = it->second; | |
472 | // Include llvm Symbol in export list if it meets one of following two conditions | |
473 | // 1 - atom scope is global (and not linkage unit). | |
474 | // 2 - included in nonLLVMRefs set. | |
475 | // If a symbol is not listed in exportList then LTO is free to optimize it away. | |
476 | if ( (atom->scope() == ld::Atom::scopeGlobal) ) | |
477 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
478 | else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) | |
479 | ::lto_codegen_add_must_preserve_symbol(generator, name); | |
480 | } | |
481 | ||
482 | // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o) | |
483 | if ( relocatable && !hasNonllvmAtoms ) { | |
484 | if ( ! ::lto_codegen_write_merged_modules(generator, outputFilePath) ) { | |
485 | // HACK, no good way to tell linker we are all done, so just quit | |
486 | exit(0); | |
487 | } | |
488 | warning("could not produce merged bitcode file"); | |
489 | } | |
490 | ||
491 | // set code-gen model | |
492 | lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
493 | if ( mainExecutable ) { | |
494 | if ( staticExecutable ) { | |
495 | // darwin x86_64 "static" code model is really dynamic code model | |
496 | if ( arch == CPU_TYPE_X86_64 ) | |
497 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
498 | else | |
499 | model = LTO_CODEGEN_PIC_MODEL_STATIC; | |
500 | } | |
501 | else { | |
502 | if ( pie ) | |
503 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
504 | else | |
505 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; | |
506 | } | |
507 | } | |
508 | else { | |
509 | if ( allowTextRelocs ) | |
510 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; | |
511 | else | |
512 | model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; | |
513 | } | |
514 | if ( ::lto_codegen_set_pic_model(generator, model) ) | |
515 | throwf("could not create set codegen model: %s", lto_get_error_message()); | |
516 | ||
517 | // if requested, save off merged bitcode file | |
518 | if ( saveTemps ) { | |
519 | char tempBitcodePath[MAXPATHLEN]; | |
520 | strcpy(tempBitcodePath, outputFilePath); | |
521 | strcat(tempBitcodePath, ".lto.bc"); | |
522 | ::lto_codegen_write_merged_modules(generator, tempBitcodePath); | |
523 | } | |
524 | ||
525 | #if LTO_API_VERSION >= 3 | |
526 | // find assembler next to linker | |
527 | char path[PATH_MAX]; | |
528 | uint32_t bufSize = PATH_MAX; | |
529 | if ( _NSGetExecutablePath(path, &bufSize) != -1 ) { | |
530 | char* lastSlash = strrchr(path, '/'); | |
531 | if ( lastSlash != NULL ) { | |
532 | strcpy(lastSlash+1, "as"); | |
533 | struct stat statInfo; | |
534 | if ( stat(path, &statInfo) == 0 ) | |
535 | ::lto_codegen_set_assembler_path(generator, path); | |
536 | } | |
537 | } | |
538 | #endif | |
539 | // run code generator | |
540 | size_t machOFileLen; | |
541 | const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen); | |
542 | if ( machOFile == NULL ) | |
543 | throwf("could not do LTO codegen: %s", ::lto_get_error_message()); | |
544 | ||
545 | // if requested, save off temp mach-o file | |
546 | if ( saveTemps ) { | |
547 | char tempMachoPath[MAXPATHLEN]; | |
548 | strcpy(tempMachoPath, outputFilePath); | |
549 | strcat(tempMachoPath, ".lto.o"); | |
550 | int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
551 | if ( fd != -1) { | |
552 | ::write(fd, machOFile, machOFileLen); | |
553 | ::close(fd); | |
554 | } | |
555 | // save off merged bitcode file | |
556 | char tempOptBitcodePath[MAXPATHLEN]; | |
557 | strcpy(tempOptBitcodePath, outputFilePath); | |
558 | strcat(tempOptBitcodePath, ".lto.opt.bc"); | |
559 | ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath); | |
560 | } | |
561 | ||
562 | // parse generated mach-o file into a MachOReader | |
563 | ld::File* machoFile = parseMachOFile(machOFile, machOFileLen, nextInputOrdinal, arch); | |
564 | ||
565 | // sync generated mach-o atoms with existing atoms ld knows about | |
566 | AtomSyncer syncer(additionalUndefines,newAtoms,llvmAtoms,deadllvmAtoms); | |
567 | machoFile->forEachAtom(syncer); | |
568 | ||
569 | // Remove InternalAtoms from ld | |
570 | for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) { | |
571 | newlyDeadAtoms.push_back(&((*it)->internalAtom())); | |
572 | } | |
573 | // Remove Atoms from ld if code generator optimized them away | |
574 | for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) { | |
575 | // check if setRealAtom() called on this Atom | |
576 | if ( li->second->compiledAtom() == NULL ) | |
577 | newlyDeadAtoms.push_back(li->second); | |
578 | } | |
579 | ||
580 | return true; | |
581 | } | |
582 | ||
583 | ||
584 | void Parser::AtomSyncer::doAtom(ld::Atom& machoAtom) | |
585 | { | |
586 | // update proxy atoms to point to real atoms and find new atoms | |
587 | const char* name = machoAtom.name(); | |
588 | if ( machoAtom.scope() >= ld::Atom::scopeLinkageUnit ) { | |
589 | CStringToAtom::iterator pos = llvmAtoms.find(name); | |
590 | if ( pos != llvmAtoms.end() ) { | |
591 | // turn Atom into a proxy for this mach-o atom | |
592 | pos->second->setCompiledAtom(machoAtom); | |
593 | } | |
594 | else { | |
595 | // an atom of this name was not in the allAtoms list the linker gave us | |
596 | if ( deadllvmAtoms.find(name) != deadllvmAtoms.end() ) { | |
597 | // this corresponding to an atom that the linker coalesced away. | |
598 | // Don't pass it back as a new atom | |
599 | } | |
600 | else | |
601 | { | |
602 | // this is something new that lto conjured up, tell ld its new | |
603 | newAtoms.push_back(&machoAtom); | |
604 | } | |
605 | } | |
606 | } | |
607 | else { | |
608 | // ld only knew about non-satic atoms, so this one must be new | |
609 | newAtoms.push_back(&machoAtom); | |
610 | } | |
611 | ||
612 | // adjust fixups to go through proxy atoms | |
613 | for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) { | |
614 | switch ( fit->binding ) { | |
615 | case ld::Fixup::bindingNone: | |
616 | break; | |
617 | case ld::Fixup::bindingByNameUnbound: | |
618 | // don't know if this target has been seen by linker before or if it is new | |
619 | // be conservitive and tell linker it is new | |
620 | additionalUndefines.push_back(fit->u.name); | |
621 | break; | |
622 | case ld::Fixup::bindingByNameBound: | |
623 | break; | |
624 | case ld::Fixup::bindingDirectlyBound: | |
625 | // If mach-o atom is referencing another mach-o atom then | |
626 | // reference is not going through Atom proxy. Fix it here to ensure that all | |
627 | // llvm symbol references always go through Atom proxy. | |
628 | break; | |
629 | case ld::Fixup::bindingByContentBound: | |
630 | break; | |
631 | } | |
632 | } | |
633 | ||
634 | } | |
635 | ||
636 | ||
637 | ||
638 | }; // namespace lto | |
639 | ||
640 | ||
641 | #endif | |
642 |