]> git.saurik.com Git - apple/ld64.git/blame - src/LTOReader.hpp
ld64-85.2.2.tar.gz
[apple/ld64.git] / src / LTOReader.hpp
CommitLineData
2f2f92e4
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2006-2008 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 "ObjectFile.h"
37#include "Options.h"
38
39#include "llvm-c/lto.h"
40
41
42namespace lto {
43
44
45//
46// Reference handles Atom references. These references facilitate
47// symbol resolution.
48//
49
50class Reference : public ObjectFile::Reference
51{
52public:
53 Reference(const char* name) : fTargetName(name), fTargetAtom(NULL) { }
54 Reference(ObjectFile::Atom& atom) : fTargetName(NULL), fTargetAtom(&atom) { }
55
56 bool isTargetUnbound() const { return fTargetAtom == NULL; }
57 bool isFromTargetUnbound() const { return true; }
58 uint8_t getKind() const { return 0; }
59 uint64_t getFixUpOffset() const { return 0; }
60 const char * getTargetName() const { return fTargetName; }
61 ObjectFile::Atom& getTarget() const { return *fTargetAtom; }
62 uint64_t getTargetOffset() const { return 0; }
63 bool hasFromTarget() const { return false; }
64 ObjectFile::Atom& getFromTarget() const { return *((ObjectFile::Atom*)NULL); }
65 const char * getFromTargetName() const { return NULL; }
66 uint64_t getFromTargetOffset() const { return 0; }
67 TargetBinding getTargetBinding() const;
68 TargetBinding getFromTargetBinding() const { return kDontBind; }
69 void setTarget (ObjectFile::Atom& a, uint64_t offset)
70 { fTargetAtom = &a; }
71 void setFromTarget(ObjectFile::Atom &a) { }
72 const char * getDescription() const;
73
74private:
75 const char * fTargetName;
76 ObjectFile::Atom * fTargetAtom;
77};
78
79
80ObjectFile::Reference::TargetBinding Reference::getTargetBinding() const
81{
82 if ( fTargetAtom == NULL )
83 return kUnboundByName;
84 else if ( fTargetName == NULL )
85 return kBoundDirectly;
86 else
87 return kBoundByName;
88}
89
90const char* Reference::getDescription() const
91{
92 static char temp[256];
93 strcpy(temp, "reference to ");
94 if ( fTargetName != NULL )
95 strcat(temp, fTargetName);
96 else
97 strcat(temp, fTargetAtom->getDisplayName());
98 return temp;
99}
100
101
102class Segment : public ObjectFile::Segment
103{
104public:
105 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
106 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
107 virtual const char* getName() const { return fName; }
108 virtual bool isContentReadable() const { return fReadable; }
109 virtual bool isContentWritable() const { return fWritable; }
110 virtual bool isContentExecutable() const { return fExecutable; }
111 virtual bool hasFixedAddress() const { return fFixedAddress; }
112
113 static Segment fgBootstrapSegment;
114
115private:
116 const char* fName;
117 const bool fReadable;
118 const bool fWritable;
119 const bool fExecutable;
120 const bool fFixedAddress;
121};
122
123Segment Segment:: fgBootstrapSegment("__TEMP", true, false, false, false);
124
125
126
127
128//
129// Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially,
130// Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After
131// optimization is performed, real Atoms are created for these symobls. However these real Atoms
132// are not inserted into global symbol table. Atom holds real Atom and forwards appropriate
133// methods to real atom.
134//
135class Atom : public ObjectFile::Atom
136{
137public:
138 Atom(class Reader& owner, const char* name, Scope, DefinitionKind, uint8_t alignment, ObjectFile::Atom& internalAtom);
139
140 ObjectFile::Reader* getFile() const { return (ObjectFile::Reader*)&fOwner; }
141 bool getTranslationUnitSource (const char **dir, const char **name) const
142 { return fRealAtom->getTranslationUnitSource(dir, name); }
143 const char * getName () const { return fName; }
144 const char * getDisplayName() const { return this->getName(); }
145 Scope getScope() const { return fScope; }
146 DefinitionKind getDefinitionKind() const { return (fRealAtom ? fRealAtom->getDefinitionKind() : fKind); }
147 SymbolTableInclusion getSymbolTableInclusion() const
148 { return fRealAtom->getSymbolTableInclusion(); }
149 bool dontDeadStrip() const { return false; }
150 bool isZeroFill() const { return (fRealAtom ? fRealAtom->isZeroFill() : false); }
151 bool isThumb() const { return false; }
152 uint64_t getSize() const { return (fRealAtom ? fRealAtom->getSize() : 0); }
153 std::vector<ObjectFile::Reference*>& getReferences() const
154 { return (fRealAtom ? fRealAtom->getReferences() : (std::vector<ObjectFile::Reference*>&)fReferences); }
155 bool mustRemainInSection() const { return fRealAtom->mustRemainInSection(); }
156 const char * getSectionName() const { return (fRealAtom ? fRealAtom->getSectionName() : NULL); }
157 // Linker::optimize() sets section for this atom, not fRealAtom. Use this Atom's fSection.
158 class ObjectFile::Section * getSection() const { return fSection; }
159 ObjectFile::Segment& getSegment() const { return (fRealAtom ? fRealAtom->getSegment() : Segment::fgBootstrapSegment); }
160 uint32_t getOrdinal() const { return (fRealAtom ? fRealAtom->getOrdinal() : 0); }
161 ObjectFile::Atom& getFollowOnAtom() const { return fRealAtom->getFollowOnAtom(); }
162 std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (fRealAtom ? fRealAtom->getLineInfo() : NULL); }
163 ObjectFile::Alignment getAlignment() const { return (fRealAtom ? fRealAtom->getAlignment() : ObjectFile::Alignment(fAlignment)); }
164 void copyRawContent(uint8_t buffer[]) const
165 { if (fRealAtom) fRealAtom->copyRawContent(buffer); }
166 void setScope(Scope s) { if (fRealAtom) fRealAtom->setScope(s); else fScope = s; }
167
168 void setRealAtom (ObjectFile::Atom *atom)
169 { fRealAtom = atom; }
170 ObjectFile::Atom * getRealAtom() { return fRealAtom; }
171 void addReference(ObjectFile::Reference *ref)
172 { fReferences.push_back(ref); }
173
174 void setSectionOffset(uint64_t offset) { fSectionOffset = offset; if (fRealAtom) fRealAtom->setSectionOffset(offset); }
175 void setSection(class ObjectFile::Section* sect) { fSection = sect; if (fRealAtom) fRealAtom->setSection(sect); }
176
177private:
178 class Reader& fOwner;
179 const char* fName;
180 ObjectFile::Atom::Scope fScope;
181 ObjectFile::Atom::DefinitionKind fKind;
182 uint8_t fAlignment;
183 ObjectFile::Atom* fRealAtom;
184 std::vector<ObjectFile::Reference*> fReferences;
185};
186
187
188Atom::Atom(class Reader& owner, const char* name, Scope scope, DefinitionKind kind, uint8_t alignment, ObjectFile::Atom& internalAtom)
189: fOwner(owner), fName(name), fScope(scope), fKind(kind), fAlignment(alignment), fRealAtom(NULL)
190{
191 // every Atom references the InternalAtom for its reader
192 fReferences.push_back(new Reference(internalAtom));
193}
194
195
196//
197// ld64 only tracks non-internal symbols from an llvm bitcode file.
198// We model this by having an InternalAtom which represent all internal functions and data.
199// All non-interal symbols from a bitcode file are represented by a Atom
200// and each Atom has a reference to the InternalAtom. The InternalAtom
201// also has references to each symbol external to the bitcode file.
202//
203class InternalAtom : public ObjectFile::Atom
204{
205public:
206 InternalAtom(class Reader& owner) : fOwner(owner) {}
207
208 ObjectFile::Reader * getFile() const { return (ObjectFile::Reader*)&fOwner; }
209 bool getTranslationUnitSource (const char **dir, const char **name) const
210 { return false; }
211 const char * getName () const { return "__llvm-internal-atom"; }
9d2e0767 212 const char * getDisplayName() const { return this->getName(); }
2f2f92e4
A
213 Scope getScope() const { return scopeTranslationUnit; }
214 DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
215 SymbolTableInclusion getSymbolTableInclusion() const { return kSymbolTableNotIn; }
216 bool dontDeadStrip() const { return false; }
217 bool isZeroFill() const { return false; }
218 bool isThumb() const { return false; }
219 uint64_t getSize() const { return 0; }
220 std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)fReferences; }
221 bool mustRemainInSection() const { return false; }
222 const char * getSectionName() const { return NULL; }
223 class ObjectFile::Section * getSection() const { return NULL; }
224 ObjectFile::Segment& getSegment() const { return Segment::fgBootstrapSegment; }
225 uint32_t getOrdinal() const { return 0; }
226 ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
227 std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
228 ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
229 void copyRawContent(uint8_t buffer[]) const { }
230 void setScope(Scope s) { }
231
232 void addReference(const char* targetName);
233
234private:
9d2e0767 235 class Reader& fOwner;
2f2f92e4
A
236 std::vector<ObjectFile::Reference*> fReferences;
237};
238
239
240void InternalAtom::addReference(const char* name)
241{
242 fReferences.push_back(new Reference(name));
243}
244
245
246
247
248class RemovableAtoms
249{
250public:
251 RemovableAtoms(std::set<ObjectFile::Atom*>& iAtoms) : fAtoms(iAtoms) {}
252
253 bool operator()(ObjectFile::Atom*& atom) const {
254 return ( fAtoms.count(atom) != 0 );
255 }
256
257private:
258 std::set<ObjectFile::Atom*>& fAtoms;
259};
260
261
262
263//
264// LLVM bitcode file reader
265//
266class Reader : public ObjectFile::Reader
267{
268public:
269 static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture);
270 static bool loaded() { return (::lto_get_version() != NULL); }
271 Reader(const uint8_t* fileContent, uint64_t fileLength,
272 const char* path, time_t modTime,
273 const ObjectFile::ReaderOptions&, cpu_type_t arch);
274 virtual ~Reader();
275
276 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
277 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
278 virtual const char* getPath() { return fPath; }
279 virtual time_t getModificationTime() { return fModTime; }
280 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return kDebugInfoNone; }
281 virtual std::vector<Stab>* getStabs() { return NULL; }
9d2e0767
A
282 virtual void optimize(std::vector<ObjectFile::Atom*> &allAtoms, std::vector<ObjectFile::Atom*> &newAtoms,
283 std::vector<const char*> &additionalUndefines, uint32_t nextInputOrdinal,
284 ObjectFile::Reader* writer, bool allGlobalsAReDeadStripRoots,
2f2f92e4
A
285 int outputKind, bool verbose, bool saveTemps, const char* outputFilePath,
286 bool pie, bool allowTextRelocs);
287
288private:
289
290 class CStringEquals
291 {
292 public:
293 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
294 };
295 typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> CStringSet;
296 typedef __gnu_cxx::hash_map<const char*, Atom*, __gnu_cxx::hash<const char*>, CStringEquals> CStringToAtom;
297
298 ObjectFile::Reader* makeMachOReader(const uint8_t* p, size_t len, uint32_t nextInputOrdinal);
299 static const char* tripletPrefixForArch(cpu_type_t);
300
301 cpu_type_t fArchitecture;
302 const char* fPath;
303 time_t fModTime;
304 lto_module_t fModule;
305 std::vector<ObjectFile::Atom*> fAtoms;
306 InternalAtom fInternalAtom;
307 const ObjectFile::ReaderOptions& fReaderOptions;
308 static std::set<Reader*> fgReaders;
309 static bool fgOptimized;
310};
311
312bool Reader::fgOptimized = false;
313std::set<Reader*> Reader::fgReaders;
314
315
316Reader::~Reader()
317{
318 if ( fModule != NULL )
319 ::lto_module_dispose(fModule);
320}
321
322Reader::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime,
323 const ObjectFile::ReaderOptions& options, cpu_type_t arch)
9d2e0767 324 : fArchitecture(arch), fPath(path), fModTime(modTime), fInternalAtom(*this), fReaderOptions(options)
2f2f92e4
A
325{
326 fgReaders.insert(this);
327
328 fModule = ::lto_module_create_from_memory(fileContent, fileLength);
329 if ( fModule == NULL )
330 throwf("could not parse object file %s: %s", path, lto_get_error_message());
331
332
333 uint32_t count = ::lto_module_get_num_symbols(fModule);
334 for (uint32_t i=0; i < count; ++i) {
335 const char* name = ::lto_module_get_symbol_name(fModule, i);
336 lto_symbol_attributes attr = lto_module_get_symbol_attribute(fModule, i);
337
338 ObjectFile::Atom::DefinitionKind kind;
339 switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) {
340 case LTO_SYMBOL_DEFINITION_REGULAR:
341 kind = ObjectFile::Atom::kRegularDefinition;
342 break;
343 case LTO_SYMBOL_DEFINITION_TENTATIVE:
344 kind = ObjectFile::Atom::kTentativeDefinition;
345 break;
346 case LTO_SYMBOL_DEFINITION_WEAK:
347 kind = ObjectFile::Atom::kWeakDefinition;
348 break;
349 case LTO_SYMBOL_DEFINITION_UNDEFINED:
350 kind = ObjectFile::Atom::kExternalDefinition;
351 break;
352 default:
353 throwf("unknown definition kind for symbol %s in bitcode file %s", name, path);
354 }
355
356 // make LLVM atoms for definitions and a reference for undefines
357 if ( kind != ObjectFile::Atom::kExternalDefinition ) {
358 ObjectFile::Atom::Scope scope;
359 switch ( attr & LTO_SYMBOL_SCOPE_MASK) {
360 case LTO_SYMBOL_SCOPE_INTERNAL:
361 scope = ObjectFile::Atom::scopeTranslationUnit;
362 break;
363 case LTO_SYMBOL_SCOPE_HIDDEN:
364 scope = ObjectFile::Atom::scopeLinkageUnit;
365 break;
366 case LTO_SYMBOL_SCOPE_DEFAULT:
367 scope = ObjectFile::Atom::scopeGlobal;
368 break;
369 default:
370 throwf("unknown scope for symbol %s in bitcode file %s", name, path);
371 }
372 // only make atoms for non-internal symbols
373 if ( scope == ObjectFile::Atom::scopeTranslationUnit )
374 continue;
375 uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK);
376 // make Atom
377 fAtoms.push_back(new Atom(*this, name, scope, kind, alignment, fInternalAtom));
378 }
379 else {
380 // add to list of external references
381 fInternalAtom.addReference(name);
382 }
383 }
384}
385
386const char* Reader::tripletPrefixForArch(cpu_type_t arch)
387{
388 switch (arch) {
389 case CPU_TYPE_POWERPC:
390 return "powerpc-";
391 case CPU_TYPE_POWERPC64:
392 return "powerpc64-";
393 case CPU_TYPE_I386:
394 return "i386-";
395 case CPU_TYPE_X86_64:
396 return "x86_64-";
397 case CPU_TYPE_ARM:
398 return "arm-";
399 }
400 return "";
401}
402
403bool Reader::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture)
404{
405 return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture));
406}
407
408void Reader::optimize(std::vector<ObjectFile::Atom *>& allAtoms, std::vector<ObjectFile::Atom*>& newAtoms,
9d2e0767
A
409 std::vector<const char*>& additionalUndefines, uint32_t nextInputOrdinal,
410 ObjectFile::Reader* writer, bool allGlobalsAReDeadStripRoots,
2f2f92e4
A
411 int okind, bool verbose, bool saveTemps, const char* outputFilePath,
412 bool pie, bool allowTextRelocs)
413{
414 // this method is call on all Readers. We want the first call to trigger optimization
415 // across all Readers and the subsequent calls to do nothing.
416 if ( fgOptimized )
417 return;
418 fgOptimized = true;
419
420 Options::OutputKind outputKind = (Options::OutputKind)okind; // HACK to work around upward dependency
421
422 // print out LTO version string if -v was used
423 if ( verbose )
424 fprintf(stderr, "%s\n", lto_get_version());
425
426 // create optimizer and add each Reader
427 lto_code_gen_t generator = ::lto_codegen_create();
428 for (std::set<Reader*>::iterator it=fgReaders.begin(); it != fgReaders.end(); ++it) {
429 if ( ::lto_codegen_add_module(generator, (*it)->fModule) )
9d2e0767 430 throwf("lto: could not merge in %s", (*it)->fPath);
2f2f92e4
A
431 }
432
433 // the linker must preserve all globals in dylibs and flat images
434 const bool globalsNeedPreserving = allGlobalsAReDeadStripRoots || fReaderOptions.fFlatNamespace;
435
436 // The atom graph uses directed edges (references). Collect all references where
437 // originating atom is not part of any LTO Reader. This allows optimizer to optimize an
438 // external (i.e. not originated from same .o file) reference if all originating atoms are also
439 // defined in llvm bitcode file.
440 CStringSet nonLLVMRefs;
441 CStringToAtom llvmAtoms;
442 bool hasNonllvmAtoms = false;
443 for (std::vector<ObjectFile::Atom*>::iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) {
444 ObjectFile::Atom* atom = *it;
445 // only look at references come from an atom that is not an llvm atom
446 if ( fgReaders.count((Reader*)(atom->getFile())) == 0 ) {
9d2e0767 447 // remember if we've seen an atoms not from an llvm reader and not from the writer
2f2f92e4
A
448 if ( atom->getFile() != writer )
449 hasNonllvmAtoms = true;
450 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
451 for (std::vector<ObjectFile::Reference*>::iterator ri=refs.begin(), re=refs.end(); ri != re; ++ri) {
452 ObjectFile::Reference* ref = *ri;
453 // add target name to set if target is an llvm atom
454 if ( (ref->getTargetName() != NULL) && (fgReaders.count((Reader*)(ref->getTarget().getFile())) != 0) ) {
455 nonLLVMRefs.insert(ref->getTargetName());
456 }
457 }
458 }
459 else {
460 const char* name = atom->getName();
461 if ( name != NULL )
462 llvmAtoms[name] = (Atom*)atom;
463 }
464 }
465 // tell code generator about symbols that must be preserved
466 for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
467 const char* name = it->first;
468 Atom* atom = it->second;
469 // Include llvm Symbol in export list if it meets one of following two conditions
470 // 1 - globals need preserving and atom scope is global (and not linkage unit).
471 // 2 - included in nonLLVMRefs set.
472 // If a symbol is not listed in exportList then LTO is free to optimize it away.
473 if ( globalsNeedPreserving && (atom->getScope() == ObjectFile::Atom::scopeGlobal) )
474 ::lto_codegen_add_must_preserve_symbol(generator, name);
475 else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() )
476 ::lto_codegen_add_must_preserve_symbol(generator, name);
477 }
478
479 // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
480 if ( (outputKind == Options::kObjectFile) && !hasNonllvmAtoms ) {
481 if ( ! ::lto_codegen_write_merged_modules(generator, outputFilePath) ) {
482 // HACK, no good way to tell linker we are all done, so just quit
483 exit(0);
484 }
485 warning("could not produce merged bitcode file");
486 }
487
488 // if requested, save off merged bitcode file
489 if ( saveTemps ) {
490 char tempBitcodePath[MAXPATHLEN];
491 strcpy(tempBitcodePath, outputFilePath);
492 strcat(tempBitcodePath, ".lto.bc");
493 ::lto_codegen_write_merged_modules(generator, tempBitcodePath);
494 }
495
496 // set code-gen model
497 lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
498 switch ( outputKind ) {
499 case Options::kDynamicExecutable:
500 if ( pie )
501 model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
502 else
503 model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
504 break;
505 case Options::kDynamicLibrary:
506 case Options::kDynamicBundle:
507 case Options::kObjectFile: // ?? Is this appropriate ?
508 case Options::kDyld:
509 if ( allowTextRelocs )
510 model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
511 else
512 model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
513 break;
514 case Options::kStaticExecutable:
515 model = LTO_CODEGEN_PIC_MODEL_STATIC;
516 break;
517 }
518 if ( ::lto_codegen_set_pic_model(generator, model) )
519 throwf("could not create set codegen model: %s", lto_get_error_message());
520
521 // run code generator
522 size_t machOFileLen;
523 const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen);
524 if ( machOFile == NULL )
525 throwf("could not do LTO codegen: %s", ::lto_get_error_message());
526
527 // if requested, save off temp mach-o file
528 if ( saveTemps ) {
529 char tempMachoPath[MAXPATHLEN];
530 strcpy(tempMachoPath, outputFilePath);
531 strcat(tempMachoPath, ".lto.o");
532 int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666);
533 if ( fd != -1) {
534 ::write(fd, machOFile, machOFileLen);
535 ::close(fd);
536 }
537 }
538
539 // parse generated mach-o file into a MachOReader
540 ObjectFile::Reader* machoReader = this->makeMachOReader(machOFile, machOFileLen, nextInputOrdinal);
541
9d2e0767 542 // sync generated mach-o atoms with existing atoms ld know about
2f2f92e4
A
543 std::vector<ObjectFile::Atom*> machoAtoms = machoReader->getAtoms();
544 for (std::vector<ObjectFile::Atom *>::iterator it = machoAtoms.begin(); it != machoAtoms.end(); ++it) {
545 ObjectFile::Atom* atom = *it;
546 const char* name = atom->getName();
547 if ( name != NULL ) {
548 CStringToAtom::iterator pos = llvmAtoms.find(name);
549 if ( pos != llvmAtoms.end() ) {
550 // turn Atom into a proxy for this mach-o atom
551 pos->second->setRealAtom(atom);
552 }
553 else {
9d2e0767
A
554 // this atom is did not exist orginally, tell ld about it
555 newAtoms.push_back(atom);
2f2f92e4
A
556 }
557 }
558 else {
559 // ld only knew about named atoms, so this one must be new
560 newAtoms.push_back(atom);
561 }
562 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
563 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); ++rit) {
564 ObjectFile::Reference* ref = *rit;
565 const char* targetName = ref->getTargetName();
566 CStringToAtom::iterator pos;
567 if (targetName != NULL) {
568 switch ( ref->getTargetBinding() ) {
569 case ObjectFile::Reference::kUnboundByName:
570 // accumulate unbounded references so that ld can bound them.
571 additionalUndefines.push_back(targetName);
572 break;
573 case ObjectFile::Reference::kBoundDirectly:
574 case ObjectFile::Reference::kBoundByName:
575 // If mach-o atom is referencing another mach-o atom then
576 // reference is not going through Atom proxy. Fix it here to ensure that all
577 // llvm symbol references always go through Atom proxy.
578 pos = llvmAtoms.find(targetName);
579 if ( pos != llvmAtoms.end() )
580 ref->setTarget(*pos->second, ref->getTargetOffset());
581 break;
582 case ObjectFile::Reference::kDontBind:
583 break;
584 }
585 }
586 }
587 }
588
589 // Remove InternalAtoms from ld
590 std::set<class ObjectFile::Atom*> deletedAtoms;
591 for (std::set<Reader*>::iterator it=fgReaders.begin(); it != fgReaders.end(); ++it) {
592 deletedAtoms.insert(&((*it)->fInternalAtom));
593 }
594 // Remove Atoms from ld if code generator optimized them away
595 for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) {
596 // check if setRealAtom() called on this Atom
597 if ( li->second->getRealAtom() == NULL )
598 deletedAtoms.insert(li->second);
599 }
600 allAtoms.erase(std::remove_if(allAtoms.begin(), allAtoms.end(), RemovableAtoms(deletedAtoms)), allAtoms.end());
601}
602
603
604ObjectFile::Reader* Reader::makeMachOReader(const uint8_t* p, size_t len, uint32_t nextInputOrdinal)
605{
606 switch ( fArchitecture ) {
607 case CPU_TYPE_POWERPC:
608 if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
609 return new mach_o::relocatable::Reader<ppc>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
610 break;
611 case CPU_TYPE_POWERPC64:
612 if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
613 return new mach_o::relocatable::Reader<ppc64>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
614 break;
615 case CPU_TYPE_I386:
616 if ( mach_o::relocatable::Reader<x86>::validFile(p) )
617 return new mach_o::relocatable::Reader<x86>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
618 break;
619 case CPU_TYPE_X86_64:
620 if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
621 return new mach_o::relocatable::Reader<x86_64>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
622 break;
623 case CPU_TYPE_ARM:
624 if ( mach_o::relocatable::Reader<arm>::validFile(p) )
625 return new mach_o::relocatable::Reader<arm>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
626 break;
627 }
628 throw "LLVM LTO, file is not of required architecture";
629}
630
631}; // namespace lto
632
633
634void printLTOVersion(Options &opts) {
635 const char* vers = lto_get_version();
636 if ( vers != NULL )
637 fprintf(stderr, "%s\n", vers);
638}
639
640
641#endif
642