1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
28 #include <sys/sysctl.h>
33 #include <mach/mach_time.h>
34 #include <mach/vm_statistics.h>
35 #include <mach/mach_init.h>
36 #include <mach/mach_host.h>
37 #include <mach-o/fat.h>
46 #include <ext/hash_map>
50 #include "ObjectFile.h"
52 #include "MachOReaderRelocatable.hpp"
53 #include "MachOReaderArchive.hpp"
54 #include "MachOReaderDylib.hpp"
55 #include "MachOWriterExecutable.hpp"
57 #include "SectCreate.h"
60 static void dumpAtom(ObjectFile::Atom
* atom
)
62 //printf("atom: %p\n", atom);
65 printf("name: %s\n", atom
->getDisplayName());
68 switch ( atom
->getScope() ) {
69 case ObjectFile::Atom::scopeTranslationUnit
:
70 printf("scope: translation unit\n");
72 case ObjectFile::Atom::scopeLinkageUnit
:
73 printf("scope: linkage unit\n");
75 case ObjectFile::Atom::scopeGlobal
:
76 printf("scope: global\n");
79 printf("scope: unknown\n");
83 switch ( atom
->getDefinitinonKind() ) {
84 case ObjectFile::Atom::kRegularDefinition
:
85 printf("kind: regular\n");
87 case ObjectFile::Atom::kWeakDefinition
:
88 printf("kind: weak\n");
90 case ObjectFile::Atom::kTentativeDefinition
:
91 printf("kind: tentative\n");
93 case ObjectFile::Atom::kExternalDefinition
:
94 printf("kind: import\n");
96 case ObjectFile::Atom::kExternalWeakDefinition
:
97 printf("kind: weak import\n");
100 printf("scope: unknown\n");
103 // segment and section
104 printf("section: %s,%s\n", atom
->getSegment().getName(), atom
->getSectionName());
108 if ( atom
->dontDeadStrip() )
109 printf("dont-dead-strip ");
110 if ( atom
->isZeroFill() )
111 printf("zero-fill ");
115 printf("size: 0x%012llX\n", atom
->getSize());
118 uint8_t content
[atom
->getSize()];
119 atom
->copyRawContent(content
);
121 if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
122 printf("\"%s\"", content
);
125 for (unsigned int i
=0; i
< sizeof(content
); ++i
)
126 printf("%02X ", content
[i
]);
131 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
132 const int refCount
= references
.size();
133 printf("references: (%u)\n", refCount
);
134 for (int i
=0; i
< refCount
; ++i
) {
135 ObjectFile::Reference
* ref
= references
[i
];
136 printf(" %s\n", ref
->getDescription());
145 class CStringComparor
148 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) < 0); }
154 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
157 class Section
: public ObjectFile::Section
160 static Section
* find(const char* sectionName
, const char* segmentName
, bool zeroFill
);
161 static void assignIndexes();
164 Section(const char* sectionName
, const char* segmentName
, bool zeroFill
);
167 static int segmentOrdinal(const char* segName
);
168 bool operator()(Section
* left
, Section
* right
);
171 typedef __gnu_cxx::hash_map
<const char*, class Section
*, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToSection
;
172 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
174 const char* fSectionName
;
175 const char* fSegmentName
;
178 static NameToSection fgMapping
;
179 static std::vector
<Section
*> fgSections
;
182 Section::NameToSection
Section::fgMapping
;
183 std::vector
<Section
*> Section::fgSections
;
185 Section::Section(const char* sectionName
, const char* segmentName
, bool zeroFill
)
186 : fSectionName(sectionName
), fSegmentName(segmentName
), fZeroFill(zeroFill
)
188 //fprintf(stderr, "new Section(%s, %s)\n", sectionName, segmentName);
191 Section
* Section::find(const char* sectionName
, const char* segmentName
, bool zeroFill
)
193 NameToSection::iterator pos
= fgMapping
.find(sectionName
);
194 if ( pos
!= fgMapping
.end() ) {
195 if ( strcmp(pos
->second
->fSegmentName
, segmentName
) == 0 )
197 // otherwise same section name is used in different segments, look slow way
198 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++) {
199 if ( (strcmp((*it
)->fSectionName
, sectionName
) == 0) && (strcmp((*it
)->fSegmentName
, segmentName
) == 0) )
204 // does not exist, so make a new one
205 Section
* sect
= new Section(sectionName
, segmentName
, zeroFill
);
206 sect
->fIndex
= fgMapping
.size();
207 fgMapping
[sectionName
] = sect
;
208 fgSections
.push_back(sect
);
210 if ( (strcmp(sectionName
, "__text") == 0) && (strcmp(segmentName
, "__TEXT") == 0) ) {
211 // special case __textcoal_nt to be right after __text
212 find("__textcoal_nt", "__TEXT", false);
218 int Section::Sorter::segmentOrdinal(const char* segName
)
220 if ( strcmp(segName
, "__PAGEZERO") == 0 )
222 if ( strcmp(segName
, "__TEXT") == 0 )
224 if ( strcmp(segName
, "__DATA") == 0 )
226 if ( strcmp(segName
, "__OBJC") == 0 )
228 if ( strcmp(segName
, "__LINKEDIT") == 0 )
229 return INT_MAX
; // linkedit segment should always sort last
235 bool Section::Sorter::operator()(Section
* left
, Section
* right
)
237 // Segment is primary sort key
238 const char* leftSegName
= left
->fSegmentName
;
239 const char* rightSegName
= right
->fSegmentName
;
240 int segNameCmp
= strcmp(leftSegName
, rightSegName
);
241 if ( segNameCmp
!= 0 )
243 int leftSegOrdinal
= segmentOrdinal(leftSegName
);
244 int rightSegOrdinal
= segmentOrdinal(rightSegName
);
245 if ( leftSegOrdinal
< rightSegOrdinal
)
247 if ( leftSegOrdinal
== rightSegOrdinal
)
248 return segNameCmp
< 0;
252 // zerofill section sort to the end
253 if ( !left
->fZeroFill
&& right
->fZeroFill
)
255 if ( left
->fZeroFill
&& !right
->fZeroFill
)
258 // section discovery order is last sort key
259 return left
->fIndex
< right
->fIndex
;
262 void Section::assignIndexes()
264 //printf("unsorted:\n");
265 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
266 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
270 std::sort(fgSections
.begin(), fgSections
.end(), Section::Sorter());
272 // assign correct section ordering to each Section object
273 unsigned int newOrder
= 1;
274 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++)
275 (*it
)->fIndex
= newOrder
++;
277 //printf("sorted:\n");
278 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
279 // printf("section: name=%s\n", (*it)->fSectionName);
285 Linker(int argc
, const char* argv
[]);
287 const char* getArchPrefix();
288 const char* architectureName();
289 bool showArchitectureInErrors();
290 bool isInferredArchitecture();
291 void createReaders();
293 void addInputFile(ObjectFile::Reader
* reader
);
294 void setOutputFile(ExecutableFile::Writer
* writer
);
299 struct WhyLiveBackChain
301 WhyLiveBackChain
* previous
;
305 ObjectFile::Reader
* createReader(const Options::FileInfo
&);
306 void addAtom(ObjectFile::Atom
& atom
);
307 void addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
);
308 void buildAtomList();
309 void loadAndResolve();
310 void loadUndefines();
311 void checkUndefines();
312 void addWeakAtomOverrides();
313 void resolveReferences();
314 void deadStripResolve();
315 void addLiveRoot(const char* name
);
318 void writeDotOutput();
319 static bool minimizeStab(ObjectFile::Reader::Stab
& stab
);
320 static const char* truncateStabString(const char* str
);
323 ObjectFile::Atom
* entryPoint();
324 ObjectFile::Atom
* dyldHelper();
325 const char* assureFullPath(const char* path
);
326 void markLive(ObjectFile::Atom
& atom
, Linker::WhyLiveBackChain
* previous
);
327 void collectStabs(ObjectFile::Reader
* reader
, std::map
<class ObjectFile::Atom
*, uint32_t>& atomOrdinals
);
328 void synthesizeStabs(ObjectFile::Reader
* reader
);
329 void printStatistics();
330 void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
);
331 char* commatize(uint64_t in
, char* out
);
332 void getVMInfo(vm_statistics_data_t
& info
);
333 cpu_type_t
inferArchitecture();
335 void resolve(ObjectFile::Reference
* reference
);
336 void resolveFrom(ObjectFile::Reference
* reference
);
337 void addJustInTimeAtoms(const char* name
);
339 ObjectFile::Reader
* addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
340 ObjectFile::Reader
* addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
341 ObjectFile::Reader
* addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
342 void addIndirectLibraries(ObjectFile::Reader
* reader
);
343 bool haveIndirectLibrary(const char* path
, ObjectFile::Reader
* reader
);
344 bool haveDirectLibrary(const char* path
);
346 void logTraceInfo(const char* format
, ...);
352 SymbolTable(Linker
&);
353 void require(const char* name
);
354 bool add(ObjectFile::Atom
& atom
);
355 ObjectFile::Atom
* find(const char* name
);
356 unsigned int getRequireCount() { return fRequireCount
; }
357 void getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
);
359 typedef __gnu_cxx::hash_map
<const char*, ObjectFile::Atom
*, __gnu_cxx::hash
<const char*>, CStringEquals
> Mapper
;
362 unsigned int fRequireCount
;
367 bool operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
);
370 typedef std::map
<const char*, uint32_t, CStringComparor
> SectionOrder
;
372 struct IndirectLibrary
{
375 ObjectFile::Reader
* reader
;
376 std::set
<ObjectFile::Reader
*> parents
;
377 ObjectFile::Reader
* reExportedViaDirectLibrary
;
380 ObjectFile::Reader
* findDirectLibraryWhichReExports(struct IndirectLibrary
& indirectLib
);
383 SymbolTable fGlobalSymbolTable
;
384 unsigned int fWeakSymbolsAddedCount
;
385 std::vector
<class ObjectFile::Reader
*> fInputFiles
;
386 ExecutableFile::Writer
* fOutputFile
;
387 std::vector
<ExecutableFile::DyLibUsed
> fDynamicLibraries
;
388 std::list
<IndirectLibrary
> fIndirectDynamicLibraries
;
389 std::vector
<class ObjectFile::Reader
*> fReadersThatHaveSuppliedAtoms
;
390 std::vector
<class ObjectFile::Atom
*> fAllAtoms
;
391 std::set
<class ObjectFile::Atom
*> fDeadAtoms
;
392 std::set
<ObjectFile::Atom
*> fLiveAtoms
;
393 std::set
<ObjectFile::Atom
*> fLiveRootAtoms
;
394 std::vector
<class ObjectFile::Reader::Stab
> fStabs
;
396 SectionOrder fSectionOrder
;
397 unsigned int fNextSortOrder
;
398 unsigned int fNextObjectFileOrder
;
399 cpu_type_t fArchitecture
;
400 const char* fArchitectureName
;
401 bool fArchitectureInferred
;
402 bool fDirectLibrariesComplete
;
403 uint64_t fOutputFileSize
;
405 uint64_t fStartCreateReadersTime
;
406 uint64_t fStartCreateWriterTime
;
407 uint64_t fStartBuildAtomsTime
;
408 uint64_t fStartLoadUndefinesTime
;
409 uint64_t fStartResolveTime
;
410 uint64_t fStartSortTime
;
411 uint64_t fStartWriteTime
;
413 uint64_t fTotalObjectSize
;
414 uint64_t fTotalArchiveSize
;
415 uint32_t fTotalObjectLoaded
;
416 uint32_t fTotalArchivesLoaded
;
417 uint32_t fTotalDylibsLoaded
;
418 vm_statistics_data_t fStartVMInfo
;
422 Linker::Linker(int argc
, const char* argv
[])
423 : fOptions(argc
, argv
), fGlobalSymbolTable(*this), fOutputFile(NULL
), fCreateUUID(false), fNextSortOrder(1),
424 fNextObjectFileOrder(1), fArchitecture(0), fArchitectureInferred(false), fDirectLibrariesComplete(false),
425 fOutputFileSize(0), fTotalObjectSize(0),
426 fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0)
428 fStartTime
= mach_absolute_time();
429 if ( fOptions
.printStatistics() )
430 getVMInfo(fStartVMInfo
);
432 fArchitecture
= fOptions
.architecture();
433 if ( fArchitecture
== 0 ) {
434 // -arch not specified, scan .o files to figure out what it should be
435 fArchitecture
= inferArchitecture();
436 fArchitectureInferred
= true;
438 switch (fArchitecture
) {
439 case CPU_TYPE_POWERPC
:
440 fArchitectureName
= "ppc";
442 case CPU_TYPE_POWERPC64
:
443 fArchitectureName
= "ppc64";
446 fArchitectureName
= "i386";
448 case CPU_TYPE_X86_64
:
449 fArchitectureName
= "x86_64";
452 fArchitectureName
= "unknown architecture";
457 const char* Linker::architectureName()
459 return fArchitectureName
;
462 bool Linker::showArchitectureInErrors()
464 return fOptions
.printArchPrefix();
467 bool Linker::isInferredArchitecture()
469 return fArchitectureInferred
;
472 cpu_type_t
Linker::inferArchitecture()
474 // scan all input files, looking for a thin .o file.
475 // the first one found is presumably the architecture to link
476 uint8_t buffer
[sizeof(mach_header_64
)];
477 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
478 for (std::vector
<Options::FileInfo
>::iterator it
= files
.begin(); it
!= files
.end(); ++it
) {
479 int fd
= ::open(it
->path
, O_RDONLY
, 0);
481 ssize_t amount
= read(fd
, buffer
, sizeof(buffer
));
483 if ( amount
>= (ssize_t
)sizeof(buffer
) ) {
484 if ( mach_o::relocatable::Reader
<ppc
>::validFile(buffer
) ) {
485 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc based on %s\n", it->path);
486 return CPU_TYPE_POWERPC
;
488 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(buffer
) ) {
489 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc64 based on %s\n", it->path);
490 return CPU_TYPE_POWERPC64
;
492 else if ( mach_o::relocatable::Reader
<x86
>::validFile(buffer
) ) {
493 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch i386 based on %s\n", it->path);
494 return CPU_TYPE_I386
;
496 else if ( mach_o::relocatable::Reader
<x86_64
>::validFile(buffer
) ) {
497 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch x86_64 based on %s\n", it->path);
498 return CPU_TYPE_X86_64
;
504 // no thin .o files found, so default to same architecture this was built as
505 fprintf(stderr
, "ld64 warning: -arch not specified\n");
507 return CPU_TYPE_POWERPC
;
509 return CPU_TYPE_I386
;
511 return CPU_TYPE_POWERPC64
;
513 return CPU_TYPE_X86_64
;
515 #error unknown default architecture
520 void Linker::addInputFile(ObjectFile::Reader
* reader
)
522 reader
->setSortOrder(fNextObjectFileOrder
++);
523 fInputFiles
.push_back(reader
);
526 void Linker::setOutputFile(ExecutableFile::Writer
* writer
)
528 fOutputFile
= writer
;
534 InSet(std::set
<ObjectFile::Atom
*>& deadAtoms
) : fDeadAtoms(deadAtoms
) {}
536 bool operator()(ObjectFile::Atom
*& atom
) const {
537 return ( fDeadAtoms
.count(atom
) != 0 );
541 std::set
<ObjectFile::Atom
*>& fDeadAtoms
;
544 void Linker::loadAndResolve()
546 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
547 // without dead-code-stripping:
548 // find atoms to resolve all undefines
549 this->loadUndefines();
550 // verify nothing is missing
551 this->checkUndefines();
552 // once all undefines fulfill, then bind all references
553 this->resolveReferences();
554 // remove atoms weak atoms that have been overridden
555 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fDeadAtoms
)), fAllAtoms
.end());
558 // with dead code stripping:
559 // start binding references from roots,
560 this->deadStripResolve();
561 // verify nothing is missing
562 this->checkUndefines();
568 this->buildAtomList();
569 this->loadAndResolve();
572 this->writeDotOutput();
573 this->collectStabs();
575 this->printStatistics();
577 if ( fOptions
.pauseAtEnd() )
581 void Linker::printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
)
583 static uint64_t sUnitsPerSecond
= 0;
584 if ( sUnitsPerSecond
== 0 ) {
585 struct mach_timebase_info timeBaseInfo
;
586 if ( mach_timebase_info(&timeBaseInfo
) == KERN_SUCCESS
) {
587 sUnitsPerSecond
= 1000000000LL * timeBaseInfo
.denom
/ timeBaseInfo
.numer
;
588 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
591 if ( partTime
< sUnitsPerSecond
) {
592 uint32_t milliSecondsTimeTen
= (partTime
*10000)/sUnitsPerSecond
;
593 uint32_t milliSeconds
= milliSecondsTimeTen
/10;
594 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
595 uint32_t percent
= percentTimesTen
/10;
596 fprintf(stderr
, "%s: %u.%u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimeTen
-milliSeconds
*10, percent
, percentTimesTen
-percent
*10);
599 uint32_t secondsTimeTen
= (partTime
*10)/sUnitsPerSecond
;
600 uint32_t seconds
= secondsTimeTen
/10;
601 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
602 uint32_t percent
= percentTimesTen
/10;
603 fprintf(stderr
, "%s: %u.%u seconds (%u.%u%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10);
607 char* Linker::commatize(uint64_t in
, char* out
)
611 sprintf(rawNum
, "%llu", in
);
612 const int rawNumLen
= strlen(rawNum
);
613 for(int i
=0; i
< rawNumLen
-1; ++i
) {
615 if ( ((rawNumLen
-i
) % 3) == 1 )
618 *out
++ = rawNum
[rawNumLen
-1];
623 void Linker::getVMInfo(vm_statistics_data_t
& info
)
625 mach_msg_type_number_t count
= sizeof(vm_statistics_data_t
) / sizeof(natural_t
);
626 kern_return_t error
= host_statistics(mach_host_self(), HOST_VM_INFO
,
627 (host_info_t
)&info
, &count
);
628 if (error
!= KERN_SUCCESS
) {
629 bzero(&info
, sizeof(vm_statistics_data_t
));
633 void Linker::printStatistics()
635 fEndTime
= mach_absolute_time();
636 if ( fOptions
.printStatistics() ) {
637 vm_statistics_data_t endVMInfo
;
638 getVMInfo(endVMInfo
);
640 uint64_t totalTime
= fEndTime
- fStartTime
;
641 printTime("ld64 total time", totalTime
, totalTime
);
642 printTime(" option parsing time", fStartCreateReadersTime
- fStartTime
, totalTime
);
643 printTime(" object file processing",fStartCreateWriterTime
- fStartCreateReadersTime
, totalTime
);
644 printTime(" output file setup", fStartBuildAtomsTime
- fStartCreateWriterTime
, totalTime
);
645 printTime(" build atom list", fStartLoadUndefinesTime
- fStartBuildAtomsTime
, totalTime
);
646 printTime(" load undefines", fStartResolveTime
- fStartLoadUndefinesTime
, totalTime
);
647 printTime(" resolve references", fStartSortTime
- fStartResolveTime
, totalTime
);
648 printTime(" sort output", fStartWriteTime
- fStartSortTime
, totalTime
);
649 printTime(" write output", fEndTime
- fStartWriteTime
, totalTime
);
650 fprintf(stderr
, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo
.pageins
-fStartVMInfo
.pageins
,
651 endVMInfo
.pageouts
-fStartVMInfo
.pageouts
, endVMInfo
.faults
-fStartVMInfo
.faults
);
653 fprintf(stderr
, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded
, commatize(fTotalObjectSize
, temp
));
654 fprintf(stderr
, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded
, commatize(fTotalArchiveSize
, temp
));
655 fprintf(stderr
, "processed %3u dylib files\n", fTotalDylibsLoaded
);
656 fprintf(stderr
, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize
, temp
));
660 inline void Linker::addAtom(ObjectFile::Atom
& atom
)
662 // add to list of all atoms
663 fAllAtoms
.push_back(&atom
);
665 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
666 // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later
667 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
668 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
669 ObjectFile::Reference
* reference
= *it
;
670 if ( reference
->isTargetUnbound() ) {
671 fGlobalSymbolTable
.require(reference
->getTargetName());
673 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() )
674 fGlobalSymbolTable
.require(reference
->getFromTargetName());
678 if ( atom
.dontDeadStrip() )
679 fLiveRootAtoms
.insert(&atom
);
682 // if in global namespace, add atom itself to symbol table
683 ObjectFile::Atom::Scope scope
= atom
.getScope();
684 const char* name
= atom
.getName();
685 if ( (scope
!= ObjectFile::Atom::scopeTranslationUnit
) && (name
!= NULL
) ) {
686 fGlobalSymbolTable
.add(atom
);
688 // update scope based on export list (possible that globals are downgraded to private_extern)
689 if ( (scope
== ObjectFile::Atom::scopeGlobal
) && fOptions
.hasExportRestrictList() ) {
690 bool doExport
= fOptions
.shouldExport(name
);
692 atom
.setScope(ObjectFile::Atom::scopeLinkageUnit
);
697 // record section orders so output file can have same order
698 atom
.setSection(Section::find(atom
.getSectionName(), atom
.getSegment().getName(), atom
.isZeroFill()));
700 // assign order in which this atom was originally seen
701 if ( atom
.getSortOrder() == 0 )
702 fNextSortOrder
= atom
.setSortOrder(fNextSortOrder
);
705 inline void Linker::addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
)
707 bool first
= true; // assume all atoms are from same reader
708 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
.begin(); it
!= atoms
.end(); it
++) {
710 // update fReadersThatHaveSuppliedAtoms
711 ObjectFile::Reader
* reader
= (*it
)->getFile();
712 if ( std::find(fReadersThatHaveSuppliedAtoms
.begin(), fReadersThatHaveSuppliedAtoms
.end(), reader
)
713 == fReadersThatHaveSuppliedAtoms
.end() ) {
714 fReadersThatHaveSuppliedAtoms
.push_back(reader
);
722 void Linker::buildAtomList()
724 fStartBuildAtomsTime
= mach_absolute_time();
725 // add initial undefines from -u option
726 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
727 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++) {
728 fGlobalSymbolTable
.require(*it
);
731 // writer can contribute atoms
732 this->addAtoms(fOutputFile
->getAtoms());
734 // each reader contributes atoms
735 const int readerCount
= fInputFiles
.size();
736 for (int i
=0; i
< readerCount
; ++i
) {
737 this->addAtoms(fInputFiles
[i
]->getAtoms());
740 // extra command line section always at end
741 std::vector
<Options::ExtraSection
>& extraSections
= fOptions
.extraSections();
742 for( std::vector
<Options::ExtraSection
>::iterator it
=extraSections
.begin(); it
!= extraSections
.end(); ++it
) {
743 this->addAtoms(SectCreate::MakeReader(it
->segmentName
, it
->sectionName
, it
->path
, it
->data
, it
->dataLen
)->getAtoms());
747 static const char* pathLeafName(const char* path
)
749 const char* shortPath
= strrchr(path
, '/');
750 if ( shortPath
== NULL
)
753 return &shortPath
[1];
756 void Linker::loadUndefines()
758 fStartLoadUndefinesTime
= mach_absolute_time();
759 // keep looping until no more undefines were added in last loop
760 unsigned int undefineCount
= 0xFFFFFFFF;
761 while ( undefineCount
!= fGlobalSymbolTable
.getRequireCount() ) {
762 undefineCount
= fGlobalSymbolTable
.getRequireCount();
763 std::vector
<const char*> undefineNames
;
764 fGlobalSymbolTable
.getNeededNames(false, undefineNames
);
765 for(std::vector
<const char*>::iterator it
= undefineNames
.begin(); it
!= undefineNames
.end(); ++it
) {
766 const char* name
= *it
;
767 ObjectFile::Atom
* possibleAtom
= fGlobalSymbolTable
.find(name
);
768 if ( (possibleAtom
== NULL
)
769 || ((possibleAtom
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
) && (fOptions
.outputKind() != Options::kObjectFile
) && (possibleAtom
->getScope() == ObjectFile::Atom::scopeGlobal
)) )
770 this->addJustInTimeAtoms(name
);
775 void Linker::checkUndefines()
777 if ( fOptions
.outputKind() != Options::kObjectFile
) {
778 // error out on any remaining undefines
781 switch ( fOptions
.undefinedTreatment() ) {
782 case Options::kUndefinedError
:
784 case Options::kUndefinedDynamicLookup
:
787 case Options::kUndefinedWarning
:
790 case Options::kUndefinedSuppress
:
795 std::vector
<const char*> unresolvableUndefines
;
796 fGlobalSymbolTable
.getNeededNames(false, unresolvableUndefines
);
797 const int unresolvableCount
= unresolvableUndefines
.size();
798 int unresolvableExportsCount
= 0;
799 if ( unresolvableCount
!= 0 ) {
801 if ( fOptions
.printArchPrefix() )
802 fprintf(stderr
, "Undefined symbols for architecture %s:\n", fArchitectureName
);
804 fprintf(stderr
, "Undefined symbols:\n");
805 for (int i
=0; i
< unresolvableCount
; ++i
) {
806 const char* name
= unresolvableUndefines
[i
];
807 fprintf(stderr
, " %s, referenced from:\n", name
);
808 // scan all atoms for references
809 bool foundAtomReference
= false;
810 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
811 ObjectFile::Atom
* atom
= *it
;
812 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
813 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
814 ObjectFile::Reference
* reference
= *rit
;
815 if ( reference
->isTargetUnbound() ) {
816 if ( strcmp(reference
->getTargetName(), name
) == 0 ) {
817 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
818 foundAtomReference
= true;
821 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() ) {
822 if ( strcmp(reference
->getFromTargetName(), name
) == 0 ) {
823 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
824 foundAtomReference
= true;
829 // scan command line options
830 if ( !foundAtomReference
&& fOptions
.hasExportRestrictList() && fOptions
.shouldExport(name
) ) {
831 fprintf(stderr
, " -exported_symbols_list command line option\n");
832 ++unresolvableExportsCount
;
836 if ( doError
&& (unresolvableCount
> unresolvableExportsCount
) ) // last check should be removed. It exists so broken projects still build
837 throw "symbol(s) not found";
844 void Linker::addJustInTimeAtoms(const char* name
)
846 // when creating final linked image, writer gets first chance
847 if ( fOptions
.outputKind() != Options::kObjectFile
) {
848 std::vector
<class ObjectFile::Atom
*>* atoms
= fOutputFile
->getJustInTimeAtomsFor(name
);
849 if ( atoms
!= NULL
) {
850 this->addAtoms(*atoms
);
852 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
853 return; // found a definition, no need to search anymore
857 // give direct readers a chance
858 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
859 ObjectFile::Reader
* reader
= *it
;
860 if ( reader
!= NULL
) {
861 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
862 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
863 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
864 if ( atoms
!= NULL
) {
865 this->addAtoms(*atoms
);
867 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fInputFiles[i]->getPath() );
868 return; // found a definition, no need to search anymore
873 // give indirect readers a chance
874 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
875 ObjectFile::Reader
* reader
= it
->reader
;
876 if ( reader
!= NULL
) {
877 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
878 if ( atoms
!= NULL
) {
879 this->addAtoms(*atoms
);
880 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
882 return; // found a definition, no need to search anymore
887 // when creating .o file, writer goes last (this is so any static archives will be searched above)
888 if ( (fOptions
.outputKind() == Options::kObjectFile
) || (fOptions
.undefinedTreatment() != Options::kUndefinedError
) ) {
889 ObjectFile::Atom
* atom
= fOutputFile
->getUndefinedProxyAtom(name
);
890 if ( atom
!= NULL
) {
891 this->addAtom(*atom
);
895 //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
898 void Linker::resolve(ObjectFile::Reference
* reference
)
900 // look in global symbol table
901 const char* targetName
= reference
->getTargetName();
902 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
903 if ( target
== NULL
) {
904 fprintf(stderr
, "Undefined symbol: %s\n", targetName
);
906 reference
->setTarget(*target
, reference
->getTargetOffset());
909 void Linker::resolveFrom(ObjectFile::Reference
* reference
)
911 // handle references that have two (from and to) targets
912 const char* fromTargetName
= reference
->getFromTargetName();
913 ObjectFile::Atom
* fromTarget
= fGlobalSymbolTable
.find(fromTargetName
);
914 if ( fromTarget
== NULL
) {
915 fprintf(stderr
, "Undefined symbol: %s\n", fromTargetName
);
917 reference
->setFromTarget(*fromTarget
);
921 void Linker::resolveReferences()
923 fStartResolveTime
= mach_absolute_time();
924 // note: the atom list may grow during this loop as libraries supply needed atoms
925 for (unsigned int j
=0; j
< fAllAtoms
.size(); ++j
) {
926 ObjectFile::Atom
* atom
= fAllAtoms
[j
];
927 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
928 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
929 ObjectFile::Reference
* reference
= *it
;
930 if ( reference
->isTargetUnbound() )
931 this->resolve(reference
);
932 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() )
933 this->resolveFrom(reference
);
939 // used to remove stabs associated with atoms that won't be in output file
943 NotInSet(std::set
<ObjectFile::Atom
*>& theSet
) : fSet(theSet
) {}
945 bool operator()(const ObjectFile::Reader::Stab
& stab
) const {
946 if ( stab
.atom
== NULL
)
947 return false; // leave stabs that are not associated with any atome
949 return ( fSet
.count(stab
.atom
) == 0 );
953 std::set
<ObjectFile::Atom
*>& fSet
;
960 NotLive(std::set
<ObjectFile::Atom
*>& set
) : fLiveAtoms(set
) {}
962 bool operator()(ObjectFile::Atom
*& atom
) const {
963 //if ( fLiveAtoms.count(atom) == 0 )
964 // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
965 return ( fLiveAtoms
.count(atom
) == 0 );
968 std::set
<ObjectFile::Atom
*>& fLiveAtoms
;
973 void Linker::markLive(ObjectFile::Atom
& atom
, struct Linker::WhyLiveBackChain
* previous
)
975 if ( fLiveAtoms
.count(&atom
) == 0 ) {
976 // if -whylive cares about this symbol, then dump chain
977 if ( (previous
->name
!= NULL
) && fOptions
.printWhyLive(previous
->name
) ) {
979 for(WhyLiveBackChain
* p
= previous
; p
!= NULL
; p
= p
->previous
, ++depth
) {
980 for(int i
=depth
; i
> 0; --i
)
981 fprintf(stderr
, " ");
982 fprintf(stderr
, "%s\n", p
->name
);
986 WhyLiveBackChain thisChain
;
987 thisChain
.previous
= previous
;
989 fLiveAtoms
.insert(&atom
);
990 // and all atoms it references
991 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
992 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
993 ObjectFile::Reference
* reference
= *it
;
994 if ( reference
->isTargetUnbound() ) {
995 // look in global symbol table
996 const char* targetName
= reference
->getTargetName();
997 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
998 if ( target
== NULL
) {
999 // load archives or dylibs
1000 this->addJustInTimeAtoms(targetName
);
1003 target
= fGlobalSymbolTable
.find(targetName
);
1004 if ( target
!= NULL
) {
1005 reference
->setTarget(*target
, reference
->getTargetOffset());
1008 // mark as undefined, for later error processing
1009 fGlobalSymbolTable
.require(targetName
);
1012 if ( ! reference
->isTargetUnbound() ) {
1013 thisChain
.name
= reference
->getTargetName();
1014 markLive(reference
->getTarget(), &thisChain
);
1016 if ( reference
->hasFromTarget() ) {
1017 // do the same as above, for from target
1018 if ( reference
->isFromTargetUnbound() ) {
1019 // look in global symbol table
1020 const char* targetName
= reference
->getFromTargetName();
1021 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1022 if ( target
== NULL
) {
1023 // load archives or dylibs
1024 this->addJustInTimeAtoms(targetName
);
1027 target
= fGlobalSymbolTable
.find(targetName
);
1028 if ( target
!= NULL
) {
1029 reference
->setFromTarget(*target
);
1032 // mark as undefined, for later error processing
1033 fGlobalSymbolTable
.require(targetName
);
1036 if ( ! reference
->isFromTargetUnbound() ) {
1037 thisChain
.name
= reference
->getFromTargetName();
1038 markLive(reference
->getFromTarget(), &thisChain
);
1046 void Linker::addLiveRoot(const char* name
)
1048 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(name
);
1049 if ( target
== NULL
) {
1050 this->addJustInTimeAtoms(name
);
1051 target
= fGlobalSymbolTable
.find(name
);
1053 if ( target
!= NULL
)
1054 fLiveRootAtoms
.insert(target
);
1058 void Linker::deadStripResolve()
1060 // add main() to live roots
1061 ObjectFile::Atom
* entryPoint
= this->entryPoint();
1062 if ( entryPoint
!= NULL
)
1063 fLiveRootAtoms
.insert(entryPoint
);
1065 // add dyld_stub_binding_helper() to live roots
1066 ObjectFile::Atom
* dyldHelper
= this->dyldHelper();
1067 if ( dyldHelper
!= NULL
)
1068 fLiveRootAtoms
.insert(dyldHelper
);
1070 // add -exported_symbols_list, -init, and -u entries to live roots
1071 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
1072 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++)
1075 // in some cases, every global scope atom in initial .o files is a root
1076 if ( fOptions
.allGlobalsAreDeadStripRoots() ) {
1077 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1078 ObjectFile::Atom
* atom
= *it
;
1079 if ( atom
->getScope() == ObjectFile::Atom::scopeGlobal
)
1080 fLiveRootAtoms
.insert(atom
);
1084 // mark all roots as live, and all atoms they reference
1085 for (std::set
<ObjectFile::Atom
*>::iterator it
=fLiveRootAtoms
.begin(); it
!= fLiveRootAtoms
.end(); it
++) {
1086 WhyLiveBackChain rootChain
;
1087 rootChain
.previous
= NULL
;
1088 rootChain
.name
= (*it
)->getDisplayName();
1089 markLive(**it
, &rootChain
);
1092 // now remove all non-live atoms from fAllAtoms
1093 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), NotLive(fLiveAtoms
)), fAllAtoms
.end());
1096 void Linker::sortAtoms()
1098 fStartSortTime
= mach_absolute_time();
1099 Section::assignIndexes();
1100 std::sort(fAllAtoms
.begin(), fAllAtoms
.end(), Linker::AtomSorter());
1101 //fprintf(stderr, "Sorted atoms:\n");
1102 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1103 // fprintf(stderr, "\t%s\n", (*it)->getDisplayName());
1109 // make sure given addresses are within reach of branches, etc
1110 void Linker::tweakLayout()
1115 void Linker::writeDotOutput()
1117 const char* dotOutFilePath
= fOptions
.dotOutputFile();
1118 if ( dotOutFilePath
!= NULL
) {
1119 FILE* out
= fopen(dotOutFilePath
, "w");
1120 if ( out
!= NULL
) {
1122 fprintf(out
, "digraph dg\n{\n");
1123 fprintf(out
, "\tconcentrate = true;\n");
1124 fprintf(out
, "\trankdir = LR;\n");
1126 // print each atom as a node
1127 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1128 ObjectFile::Atom
* atom
= *it
;
1129 if ( atom
->getFile() != fOutputFile
) {
1130 const char* name
= atom
->getDisplayName();
1131 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
1132 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1133 fprintf(out
, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom
, name
);
1135 else if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
1136 char cstring
[atom
->getSize()+2];
1137 atom
->copyRawContent((uint8_t*)cstring
);
1138 fprintf(out
, "\taddr%p [ label = \"string: '", atom
);
1139 for (const char* s
=cstring
; *s
!= '\0'; ++s
) {
1141 fprintf(out
, "\\\\n");
1145 fprintf(out
, "'\" ];\n");
1148 fprintf(out
, "\taddr%p [ label = \"%s\" ];\n", atom
, name
);
1154 // print each reference as an edge
1155 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1156 ObjectFile::Atom
* fromAtom
= *it
;
1157 if ( fromAtom
->getFile() != fOutputFile
) {
1158 std::vector
<ObjectFile::Reference
*>& references
= fromAtom
->getReferences();
1159 std::set
<ObjectFile::Atom
*> seenTargets
;
1160 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1161 ObjectFile::Reference
* reference
= *rit
;
1162 ObjectFile::Atom
* toAtom
= &(reference
->getTarget());
1163 if ( seenTargets
.count(toAtom
) == 0 ) {
1164 seenTargets
.insert(toAtom
);
1165 fprintf(out
, "\taddr%p -> addr%p;\n", fromAtom
, toAtom
);
1172 // push all imports to bottom of graph
1173 fprintf(out
, "{ rank = same; ");
1174 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1175 ObjectFile::Atom
* atom
= *it
;
1176 if ( atom
->getFile() != fOutputFile
)
1177 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
1178 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1179 fprintf(out
, "addr%p; ", atom
);
1182 fprintf(out
, "};\n ");
1185 fprintf(out
, "}\n");
1189 fprintf(stderr
, "ld64 warning: could not write dot output file: %s\n", dotOutFilePath
);
1194 ObjectFile::Atom
* Linker::entryPoint()
1196 // if main executable, find entry point atom
1197 ObjectFile::Atom
* entryPoint
= NULL
;
1198 switch ( fOptions
.outputKind() ) {
1199 case Options::kDynamicExecutable
:
1200 case Options::kStaticExecutable
:
1201 case Options::kDyld
:
1202 entryPoint
= fGlobalSymbolTable
.find(fOptions
.entryName());
1203 if ( entryPoint
== NULL
) {
1204 throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions
.entryName());
1207 case Options::kDynamicLibrary
:
1208 if ( fOptions
.initFunctionName() != NULL
) {
1209 entryPoint
= fGlobalSymbolTable
.find(fOptions
.initFunctionName());
1210 if ( entryPoint
== NULL
) {
1211 throwf("could not find -init function: \"%s\"", fOptions
.initFunctionName());
1215 case Options::kObjectFile
:
1216 case Options::kDynamicBundle
:
1223 ObjectFile::Atom
* Linker::dyldHelper()
1225 return fGlobalSymbolTable
.find("dyld_stub_binding_helper");
1228 const char* Linker::assureFullPath(const char* path
)
1230 if ( path
[0] == '/' )
1232 char cwdbuff
[MAXPATHLEN
];
1233 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
1235 asprintf(&result
, "%s/%s", cwdbuff
, path
);
1236 if ( result
!= NULL
)
1244 // The stab strings are of the form:
1245 // <name> ':' <type-code> <number-pari>
1246 // but the <name> contain a colon.
1247 // For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
1248 // For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
1250 const char* Linker::truncateStabString(const char* str
)
1252 enum { start
, inObjc
} state
= start
;
1253 for (const char* s
= str
; *s
!= 0; ++s
) {
1262 if ( s
[1] == ':' ) {
1267 // Duplicate strndup behavior here.
1268 int trunStrLen
= s
-str
+2;
1269 char* temp
= new char[trunStrLen
+1];
1270 memcpy(temp
, str
, trunStrLen
);
1271 temp
[trunStrLen
] = '\0';
1289 bool Linker::minimizeStab(ObjectFile::Reader::Stab
& stab
)
1296 // these all need truncated strings
1297 stab
.string
= truncateStabString(stab
.string
);
1303 // these are included in the minimal stabs, but they keep their full string
1311 struct HeaderRange
{
1312 std::vector
<ObjectFile::Reader::Stab
>::iterator begin
;
1313 std::vector
<ObjectFile::Reader::Stab
>::iterator end
;
1314 int parentRangeIndex
;
1316 bool sumPrecomputed
;
1318 bool cannotEXCL
; // because of SLINE, etc stabs
1322 typedef __gnu_cxx::hash_map
<const char*, std::vector
<uint32_t>, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToSums
;
1324 // hash table that maps header path to a vector of known checksums for that path
1325 static PathToSums sKnownBINCLs
;
1328 void Linker::collectStabs(ObjectFile::Reader
* reader
, std::map
<class ObjectFile::Atom
*, uint32_t>& atomOrdinals
)
1331 bool minimal
= ( fOptions
.readerOptions().fDebugInfoStripping
== ObjectFile::ReaderOptions::kDebugInfoMinimal
);
1332 std::vector
<class ObjectFile::Reader::Stab
>* readerStabs
= reader
->getStabs();
1333 if ( readerStabs
== NULL
)
1336 if ( log
) fprintf(stderr
, "processesing %lu stabs for %s\n", readerStabs
->size(), reader
->getPath());
1337 std::vector
<HeaderRange
> ranges
;
1338 int curRangeIndex
= -1;
1340 ObjectFile::Atom
* atomWithLowestOrdinal
= NULL
;
1341 ObjectFile::Atom
* atomWithHighestOrdinal
= NULL
;
1342 uint32_t highestOrdinal
= 0;
1343 uint32_t lowestOrdinal
= UINT_MAX
;
1344 std::vector
<std::pair
<ObjectFile::Atom
*,ObjectFile::Atom
*> > soRanges
;
1345 // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums
1346 // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein
1347 for(std::vector
<class ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
1349 switch ( it
->type
) {
1354 range
.end
= readerStabs
->end();
1355 range
.parentRangeIndex
= curRangeIndex
;
1356 range
.sum
= it
->value
;
1357 range
.sumPrecomputed
= (range
.sum
!= 0);
1358 range
.useEXCL
= false;
1359 range
.cannotEXCL
= false;
1360 curRangeIndex
= ranges
.size();
1361 if ( log
) fprintf(stderr
, "[%d]BINCL %s\n", curRangeIndex
, it
->string
);
1362 ranges
.push_back(range
);
1366 if ( curRangeIndex
== -1 ) {
1367 fprintf(stderr
, "ld64 warning: EINCL missing BINCL in %s\n", reader
->getPath());
1370 ranges
[curRangeIndex
].end
= it
+1;
1371 if ( log
) fprintf(stderr
, "[%d->%d]EINCL %s\n", curRangeIndex
, ranges
[curRangeIndex
].parentRangeIndex
, it
->string
);
1372 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
1377 std::map
<class ObjectFile::Atom
*, uint32_t>::iterator pos
= atomOrdinals
.find(it
->atom
);
1378 if ( pos
!= atomOrdinals
.end() ) {
1379 uint32_t ordinal
= pos
->second
;
1380 if ( ordinal
> highestOrdinal
) {
1381 highestOrdinal
= ordinal
;
1382 atomWithHighestOrdinal
= it
->atom
;
1384 if ( ordinal
< lowestOrdinal
) {
1385 lowestOrdinal
= ordinal
;
1386 atomWithLowestOrdinal
= it
->atom
;
1398 if ( curRangeIndex
!= -1 ) {
1399 ranges
[curRangeIndex
].cannotEXCL
= true;
1400 if ( fOptions
.warnStabs() )
1401 fprintf(stderr
, "ld64: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
1405 if ( (it
->string
!= NULL
) && (strlen(it
->string
) > 0) ) {
1406 // start SO, reset hi/low FUN tracking
1407 atomWithLowestOrdinal
= NULL
;
1408 atomWithHighestOrdinal
= NULL
;
1410 lowestOrdinal
= UINT_MAX
;
1413 // end SO, record hi/low atoms for this SO range
1414 soRanges
.push_back(std::make_pair
<ObjectFile::Atom
*,ObjectFile::Atom
*>(atomWithLowestOrdinal
, atomWithHighestOrdinal
));
1418 if ( curRangeIndex
!= -1 ) {
1419 if ( ! ranges
[curRangeIndex
].sumPrecomputed
) {
1421 const char* s
= it
->string
;
1423 while ( (c
= *s
++) != 0 ) {
1425 // don't checkusm first number (file index) after open paren in string
1431 ranges
[curRangeIndex
].sum
+= sum
;
1437 if ( log
) fprintf(stderr
, "processesed %d stabs for %s\n", count
, reader
->getPath());
1438 if ( curRangeIndex
!= -1 )
1439 fprintf(stderr
, "ld64 warning: BINCL (%s) missing EINCL in %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
1442 if ( ranges
.size() == 0 ) {
1444 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
1445 // copy minimal or all stabs
1446 ObjectFile::Reader::Stab stab
= *it
;
1447 if ( !minimal
|| minimizeStab(stab
) ) {
1448 if ( stab
.type
== N_SO
) {
1449 if ( (stab
.string
!= NULL
) && (strlen(stab
.string
) > 0) ) {
1450 // starting SO is associated with first atom
1451 stab
.atom
= soRanges
[soIndex
].first
;
1454 // ending SO is associated with last atom
1455 stab
.atom
= soRanges
[soIndex
].second
;
1459 fStabs
.push_back(stab
);
1465 //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
1466 //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
1467 // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
1470 // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
1471 for(std::vector
<HeaderRange
>::iterator it
=ranges
.begin(); it
!= ranges
.end(); ++it
) {
1472 if ( ! it
->cannotEXCL
) {
1473 const char* header
= it
->begin
->string
;
1474 uint32_t sum
= it
->sum
;
1475 PathToSums::iterator pos
= sKnownBINCLs
.find(header
);
1476 if ( pos
!= sKnownBINCLs
.end() ) {
1477 std::vector
<uint32_t>& sums
= pos
->second
;
1478 for(std::vector
<uint32_t>::iterator sit
=sums
.begin(); sit
!= sums
.end(); ++sit
) {
1480 //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
1485 if ( ! it
->useEXCL
) {
1486 // have seen this path, but not this checksum
1487 //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
1488 sums
.push_back(sum
);
1492 // have not seen this path, so add to known BINCLs
1493 std::vector
<uint32_t> empty
;
1494 sKnownBINCLs
[header
] = empty
;
1495 sKnownBINCLs
[header
].push_back(sum
);
1496 //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
1501 // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
1503 const int maxRangeIndex
= ranges
.size();
1505 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
1506 switch ( it
->type
) {
1508 for(int i
=curRangeIndex
+1; i
< maxRangeIndex
; ++i
) {
1509 if ( ranges
[i
].begin
== it
) {
1511 HeaderRange
& range
= ranges
[curRangeIndex
];
1512 ObjectFile::Reader::Stab stab
= *it
;
1513 stab
.value
= range
.sum
; // BINCL and EXCL have n_value set to checksum
1514 if ( range
.useEXCL
)
1515 stab
.type
= N_EXCL
; // transform BINCL into EXCL
1517 fStabs
.push_back(stab
);
1523 if ( curRangeIndex
!= -1 ) {
1524 if ( !ranges
[curRangeIndex
].useEXCL
&& !minimal
)
1525 fStabs
.push_back(*it
);
1526 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
1530 if ( (curRangeIndex
== -1) || !ranges
[curRangeIndex
].useEXCL
) {
1531 ObjectFile::Reader::Stab stab
= *it
;
1532 if ( !minimal
|| minimizeStab(stab
) ) {
1533 if ( stab
.type
== N_SO
) {
1534 if ( (stab
.string
!= NULL
) || (strlen(stab
.string
) > 0) ) {
1535 // starting SO is associated with first atom
1536 stab
.atom
= soRanges
[soIndex
].first
;
1539 // ending SO is associated with last atom
1540 stab
.atom
= soRanges
[soIndex
].second
;
1544 fStabs
.push_back(stab
);
1553 void Linker::synthesizeStabs(ObjectFile::Reader
* reader
)
1555 // synthesize "debug notes" and add them to master stabs vector
1556 const char* dirPath
= NULL
;
1557 const char* filename
= NULL
;
1558 bool wroteStartSO
= false;
1559 std::vector
<const char*> seenFiles
;
1560 for (std::vector
<class ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); ++it
) {
1561 ObjectFile::Atom
* atom
= *it
;
1562 if ( atom
->getFile() == reader
) {
1563 const char* name
= atom
->getName();
1564 if ( (name
!= NULL
) && (atom
->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn
) ) {
1565 const char* newDirPath
;
1566 const char* newFilename
;
1567 if ( atom
->getTranslationUnitSource(&newDirPath
, &newFilename
) ) {
1568 // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
1569 if ( (newDirPath
!= NULL
) && (strlen(newDirPath
) > 1 ) && (newDirPath
[strlen(newDirPath
)-1] != '/') )
1570 asprintf((char**)&newDirPath
, "%s/", newDirPath
);
1571 // need SO's whenever the translation unit source file changes
1572 if ( newFilename
!= filename
) {
1573 if ( filename
!= NULL
) {
1574 // translation unit change, emit ending SO
1575 ObjectFile::Reader::Stab endFileStab
;
1576 endFileStab
.atom
= NULL
;
1577 endFileStab
.type
= N_SO
;
1578 endFileStab
.other
= 1;
1579 endFileStab
.desc
= 0;
1580 endFileStab
.value
= 0;
1581 endFileStab
.string
= "";
1582 fStabs
.push_back(endFileStab
);
1584 // new translation unit, emit start SO's
1585 ObjectFile::Reader::Stab dirPathStab
;
1586 dirPathStab
.atom
= NULL
;
1587 dirPathStab
.type
= N_SO
;
1588 dirPathStab
.other
= 0;
1589 dirPathStab
.desc
= 0;
1590 dirPathStab
.value
= 0;
1591 dirPathStab
.string
= newDirPath
;
1592 fStabs
.push_back(dirPathStab
);
1593 ObjectFile::Reader::Stab fileStab
;
1594 fileStab
.atom
= NULL
;
1595 fileStab
.type
= N_SO
;
1599 fileStab
.string
= newFilename
;
1600 fStabs
.push_back(fileStab
);
1601 // Synthesize OSO for start of file
1602 ObjectFile::Reader::Stab objStab
;
1603 objStab
.atom
= NULL
;
1604 objStab
.type
= N_OSO
;
1607 objStab
.value
= reader
->getModificationTime();
1608 objStab
.string
= assureFullPath(reader
->getPath());
1609 fStabs
.push_back(objStab
);
1610 wroteStartSO
= true;
1612 filename
= newFilename
;
1613 dirPath
= newDirPath
;
1614 seenFiles
.push_back(filename
);
1615 if ( atom
->getSegment().isContentExecutable() && (strncmp(atom
->getSectionName(), "__text", 6) == 0) ) {
1616 // Synthesize BNSYM and start FUN stabs
1617 ObjectFile::Reader::Stab beginSym
;
1618 beginSym
.atom
= atom
;
1619 beginSym
.type
= N_BNSYM
;
1623 beginSym
.string
= "";
1624 fStabs
.push_back(beginSym
);
1625 ObjectFile::Reader::Stab startFun
;
1626 startFun
.atom
= atom
;
1627 startFun
.type
= N_FUN
;
1631 startFun
.string
= name
;
1632 fStabs
.push_back(startFun
);
1633 // Synthesize any SOL stabs needed
1634 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
1635 if ( lineInfo
!= NULL
) {
1636 // might be nice to set the source file path to seenFiles so it does not show up in SOLs
1637 const char* curFile
= NULL
;
1638 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
1639 if ( it
->fileName
!= curFile
) {
1640 bool alreadySeen
= false;
1641 for (std::vector
<const char*>::iterator sit
= seenFiles
.begin(); sit
!= seenFiles
.end(); ++sit
) {
1642 if ( strcmp(it
->fileName
, *sit
) == 0 ) {
1647 if ( ! alreadySeen
) {
1648 seenFiles
.push_back(it
->fileName
);
1649 ObjectFile::Reader::Stab sol
;
1655 sol
.string
= it
->fileName
;
1656 fStabs
.push_back(sol
);
1658 curFile
= it
->fileName
;
1662 // Synthesize end FUN and ENSYM stabs
1663 ObjectFile::Reader::Stab endFun
;
1665 endFun
.type
= N_FUN
;
1670 fStabs
.push_back(endFun
);
1671 ObjectFile::Reader::Stab endSym
;
1673 endSym
.type
= N_ENSYM
;
1678 fStabs
.push_back(endSym
);
1681 ObjectFile::Reader::Stab globalsStab
;
1682 if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
1683 // Synthesize STSYM stab for statics
1684 const char* name
= atom
->getName();
1685 if ( name
[0] == '_' ) {
1686 globalsStab
.atom
= atom
;
1687 globalsStab
.type
= N_STSYM
;
1688 globalsStab
.other
= 1;
1689 globalsStab
.desc
= 0;
1690 globalsStab
.value
= 0;
1691 globalsStab
.string
= name
;
1692 fStabs
.push_back(globalsStab
);
1696 // Synthesize GSYM stab for other globals (but not .eh exception frame symbols)
1697 const char* name
= atom
->getName();
1698 if ( (name
[0] == '_') && (strcmp(atom
->getSectionName(), "__eh_frame") != 0) ) {
1699 globalsStab
.atom
= atom
;
1700 globalsStab
.type
= N_GSYM
;
1701 globalsStab
.other
= 1;
1702 globalsStab
.desc
= 0;
1703 globalsStab
.value
= 0;
1704 globalsStab
.string
= name
;
1705 fStabs
.push_back(globalsStab
);
1713 if ( wroteStartSO
) {
1715 ObjectFile::Reader::Stab endFileStab
;
1716 endFileStab
.atom
= NULL
;
1717 endFileStab
.type
= N_SO
;
1718 endFileStab
.other
= 1;
1719 endFileStab
.desc
= 0;
1720 endFileStab
.value
= 0;
1721 endFileStab
.string
= "";
1722 fStabs
.push_back(endFileStab
);
1726 void Linker::collectStabs()
1728 if ( fOptions
.readerOptions().fDebugInfoStripping
!= ObjectFile::ReaderOptions::kDebugInfoNone
) {
1730 // make mapping from atoms to ordinal
1731 std::map
<class ObjectFile::Atom
*, uint32_t> atomOrdinals
;
1732 uint32_t ordinal
= 1;
1733 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1734 atomOrdinals
[*it
] = ordinal
++;
1737 fStabs
.reserve(1024); // try to minimize re-allocations
1738 // get stabs from each reader, in command line order
1739 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
1740 it
!= fReadersThatHaveSuppliedAtoms
.end();
1742 ObjectFile::Reader
* reader
= *it
;
1743 if ( reader
!= NULL
) {
1744 switch ( reader
->getDebugInfoKind() ) {
1745 case ObjectFile::Reader::kDebugInfoNone
:
1748 case ObjectFile::Reader::kDebugInfoStabs
:
1749 collectStabs(reader
, atomOrdinals
);
1751 case ObjectFile::Reader::kDebugInfoDwarf
:
1752 synthesizeStabs(reader
);
1755 case ObjectFile::Reader::kDebugInfoStabsUUID
:
1756 collectStabs(reader
, atomOrdinals
);
1760 throw "Unhandled type of debug information";
1764 // remove stabs associated with atoms that won't be in output
1765 std::set
<class ObjectFile::Atom
*> allAtomsSet
;
1766 allAtomsSet
.insert(fAllAtoms
.begin(), fAllAtoms
.end());
1767 fStabs
.erase(std::remove_if(fStabs
.begin(), fStabs
.end(), NotInSet(allAtomsSet
)), fStabs
.end());
1771 void Linker::writeOutput()
1773 fStartWriteTime
= mach_absolute_time();
1774 // tell writer about each segment's atoms
1775 fOutputFileSize
= fOutputFile
->write(fAllAtoms
, fStabs
, this->entryPoint(), this->dyldHelper(), (fCreateUUID
&& fOptions
.emitUUID()));
1778 ObjectFile::Reader
* Linker::createReader(const Options::FileInfo
& info
)
1780 // map in whole file
1781 uint64_t len
= info
.fileLen
;
1782 int fd
= ::open(info
.path
, O_RDONLY
, 0);
1784 throwf("can't open file, errno=%d", errno
);
1785 if ( info
.fileLen
< 20 )
1786 throw "file too small";
1788 uint8_t* p
= (uint8_t*)::mmap(NULL
, info
.fileLen
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1789 if ( p
== (uint8_t*)(-1) )
1790 throwf("can't map file, errno=%d", errno
);
1792 // if fat file, skip to architecture we want
1793 const fat_header
* fh
= (fat_header
*)p
;
1794 if ( fh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1795 // Fat header is always big-endian
1796 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1797 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1798 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)fArchitecture
) {
1799 uint32_t fileOffset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1800 len
= OSSwapBigToHostInt32(archs
[i
].size
);
1801 // if requested architecture is page aligned within fat file, then remap just that portion of file
1802 if ( (fileOffset
&& 0x00000FFF) == 0 ) {
1804 munmap((caddr_t
)p
, info
.fileLen
);
1805 // re-map just part we need
1806 p
= (uint8_t*)::mmap(NULL
, len
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, fileOffset
);
1807 if ( p
== (uint8_t*)(-1) )
1808 throwf("can't re-map file, errno=%d", errno
);
1819 switch (fArchitecture
) {
1820 case CPU_TYPE_POWERPC
:
1821 if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
1822 return this->addObject(mach_o::relocatable::Reader
<ppc
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1823 else if ( mach_o::dylib::Reader
<ppc
>::validFile(p
, info
.options
.fBundleLoader
) )
1824 return this->addDylib(mach_o::dylib::Reader
<ppc
>::make(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions()), info
, len
);
1825 else if ( mach_o::archive::Reader
<ppc
>::validFile(p
, len
) )
1826 return this->addArchive(mach_o::archive::Reader
<ppc
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1828 case CPU_TYPE_POWERPC64
:
1829 if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
1830 return this->addObject(mach_o::relocatable::Reader
<ppc64
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1831 else if ( mach_o::dylib::Reader
<ppc64
>::validFile(p
, info
.options
.fBundleLoader
) )
1832 return this->addDylib(mach_o::dylib::Reader
<ppc64
>::make(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions()), info
, len
);
1833 else if ( mach_o::archive::Reader
<ppc64
>::validFile(p
, len
) )
1834 return this->addArchive(mach_o::archive::Reader
<ppc64
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1837 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
1838 return this->addObject(mach_o::relocatable::Reader
<x86
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1839 else if ( mach_o::dylib::Reader
<x86
>::validFile(p
, info
.options
.fBundleLoader
) )
1840 return this->addDylib(mach_o::dylib::Reader
<x86
>::make(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions()), info
, len
);
1841 else if ( mach_o::archive::Reader
<x86
>::validFile(p
, len
) )
1842 return this->addArchive(mach_o::archive::Reader
<x86
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1844 case CPU_TYPE_X86_64
:
1845 if ( mach_o::relocatable::Reader
<x86_64
>::validFile(p
) )
1846 return this->addObject(mach_o::relocatable::Reader
<x86_64
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1847 else if ( mach_o::dylib::Reader
<x86_64
>::validFile(p
, info
.options
.fBundleLoader
) )
1848 return this->addDylib(mach_o::dylib::Reader
<x86_64
>::make(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions()), info
, len
);
1849 else if ( mach_o::archive::Reader
<x86_64
>::validFile(p
, len
) )
1850 return this->addArchive(mach_o::archive::Reader
<x86_64
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1855 if ( ((fat_header
*)p
)->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1856 throwf("missing required architecture %s in file", fArchitectureName
);
1859 throw "file is not of required architecture";
1864 void Linker::createReaders()
1866 fStartCreateReadersTime
= mach_absolute_time();
1867 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
1868 const int count
= files
.size();
1870 throw "no object files specified";
1871 // add all direct object, archives, and dylibs
1872 for (int i
=0; i
< count
; ++i
) {
1873 Options::FileInfo
& entry
= files
[i
];
1874 // ignore /usr/lib/dyld on command line in crt.o build
1875 if ( strcmp(entry
.path
, "/usr/lib/dyld") != 0 ) {
1877 this->addInputFile(this->createReader(entry
));
1879 catch (const char* msg
) {
1880 if ( strstr(msg
, "architecture") != NULL
) {
1881 if ( fOptions
.ignoreOtherArchInputFiles() ) {
1882 // ignore, because this is about an architecture not in use
1885 fprintf(stderr
, "ld64 warning: in %s, %s\n", entry
.path
, msg
);
1889 throwf("in %s, %s", entry
.path
, msg
);
1895 // add first level of indirect dylibs
1896 fDirectLibrariesComplete
= true;
1897 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator it
=fDynamicLibraries
.begin(); it
!= fDynamicLibraries
.end(); it
++) {
1898 this->addIndirectLibraries(it
->reader
);
1901 // indirect handling depends on namespace
1902 switch ( fOptions
.nameSpace() ) {
1903 case Options::kFlatNameSpace
:
1904 case Options::kForceFlatNameSpace
:
1905 // with flat namespace, blindly load all indirect libraries
1906 // the indirect list will grow as indirect libraries are loaded
1907 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
1909 it
->reader
= this->createReader(fOptions
.findFile(it
->path
));
1910 it
->reader
->setSortOrder(fNextObjectFileOrder
++);
1912 catch (const char* msg
) {
1913 fprintf(stderr
, "ld64 warning: indirect library %s could not be loaded: %s\n", it
->path
, msg
);
1918 case Options::kTwoLevelNameSpace
:
1919 // with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
1921 bool indirectAdded
= true;
1922 while ( indirectAdded
) {
1923 indirectAdded
= false;
1924 // instantiate a reader for each indirect library and try to find parent that re-exports it
1925 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
1926 if ( it
->reader
== NULL
) {
1928 it
->reader
= this->createReader(fOptions
.findFile(it
->path
));
1929 it
->reader
->setSortOrder(fNextObjectFileOrder
++);
1930 indirectAdded
= true;
1932 catch (const char* msg
) {
1933 fprintf(stderr
, "ld64 warning: indirect library %s could not be loaded: %s\n", it
->path
, msg
);
1936 // if an indirect library does not have an assigned parent, look for one
1937 if ( (it
->reader
!= NULL
) && (it
->reExportedViaDirectLibrary
== NULL
) ) {
1938 it
->reExportedViaDirectLibrary
= this->findDirectLibraryWhichReExports(*it
);
1946 // add relevant indirect libraries to the end of fDynamicLibraries
1947 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
1948 if ( (it
->reader
!= NULL
) && (it
->reExportedViaDirectLibrary
!= NULL
) || (fOptions
.nameSpace() != Options::kTwoLevelNameSpace
) ) {
1949 ExecutableFile::DyLibUsed dylibInfo
;
1950 dylibInfo
.reader
= it
->reader
;
1951 dylibInfo
.options
.fWeakImport
= false;
1952 dylibInfo
.options
.fReExport
= false;
1953 dylibInfo
.options
.fInstallPathOverride
= NULL
;
1954 dylibInfo
.indirect
= true;
1955 dylibInfo
.directReader
= it
->reExportedViaDirectLibrary
;
1956 fDynamicLibraries
.push_back(dylibInfo
);
1957 if ( fOptions
.readerOptions().fTraceIndirectDylibs
) {
1958 const char* fullPath
= it
->reader
->getPath();
1959 char realName
[MAXPATHLEN
];
1960 if ( realpath(fullPath
, realName
) != NULL
)
1961 fullPath
= realName
;
1962 logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath
);
1969 ObjectFile::Reader
* Linker::findDirectLibraryWhichReExports(IndirectLibrary
& indirectLib
)
1971 // ask each parent if they re-export this dylib
1972 for (std::set
<ObjectFile::Reader
*>::iterator pit
=indirectLib
.parents
.begin(); pit
!= indirectLib
.parents
.end(); pit
++) {
1973 if ( (*pit
)->reExports(indirectLib
.reader
) ) {
1974 ObjectFile::Reader
* lib
= *pit
;
1975 // first check if we found a direct library, if so return it
1976 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator dit
=fDynamicLibraries
.begin(); dit
!= fDynamicLibraries
.end(); dit
++) {
1977 if ( dit
->reader
== lib
&& dit
->indirect
== false )
1980 // otherwise search indirects for parent and see how it is reexported
1981 for (std::list
<IndirectLibrary
>::iterator iit
=fIndirectDynamicLibraries
.begin(); iit
!= fIndirectDynamicLibraries
.end(); iit
++) {
1982 if ( iit
->reader
== lib
) {
1983 ObjectFile::Reader
* lib2
= this->findDirectLibraryWhichReExports(*iit
);
1995 ObjectFile::Reader
* Linker::addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
1997 if (fOptions
.readerOptions().fTraceArchives
) {
1998 const char* fullPath
= reader
->getPath();
1999 char realName
[MAXPATHLEN
];
2000 if ( realpath(fullPath
, realName
) != NULL
)
2001 fullPath
= realName
;
2002 logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath
);
2006 fTotalArchiveSize
+= mappedLen
;
2007 ++fTotalArchivesLoaded
;
2011 ObjectFile::Reader
* Linker::addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
2014 fTotalObjectSize
+= mappedLen
;
2015 ++fTotalObjectLoaded
;
2019 ObjectFile::Reader
* Linker::addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
2021 if ( (reader
->getInstallPath() == NULL
) && !info
.options
.fBundleLoader
) {
2022 // this is a "blank" stub
2023 // silently ignore it
2027 if ( fDirectLibrariesComplete
) {
2028 this->addIndirectLibraries(reader
);
2031 if ( fOptions
.readerOptions().fTraceDylibs
) {
2032 const char* fullPath
= reader
->getPath();
2033 char realName
[MAXPATHLEN
];
2034 if ( realpath(fullPath
, realName
) != NULL
)
2035 fullPath
= realName
;
2036 logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath
);
2038 ExecutableFile::DyLibUsed dylibInfo
;
2039 dylibInfo
.reader
= reader
;
2040 dylibInfo
.options
= info
.options
;
2041 dylibInfo
.indirect
= false;
2042 dylibInfo
.directReader
= NULL
;
2043 fDynamicLibraries
.push_back(dylibInfo
);
2046 // Verify that a client is allowed to link to this dylib. There are three cases.
2047 bool okToLink
= true;
2048 const char* outputFilePath
= fOptions
.installPath();
2049 const char* outputFilePathLastSlash
= strrchr(outputFilePath
, '/');
2050 if ( reader
->parentUmbrella() != NULL
) {
2051 // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
2052 okToLink
= ( (outputFilePathLastSlash
!= NULL
) && (strcmp(&outputFilePathLastSlash
[1], reader
->parentUmbrella()) == 0) );
2055 if ( !okToLink
&& (reader
->parentUmbrella() != NULL
) ) {
2056 // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
2057 okToLink
= ( (outputFilePathLastSlash
!= NULL
)
2058 && (fOptions
.umbrellaName() != NULL
)
2059 && (strcmp(fOptions
.umbrellaName(), reader
->parentUmbrella()) == 0) );
2062 std::vector
<const char*>* clients
= reader
->getAllowableClients();
2063 if ( !okToLink
&& (clients
!= NULL
) ) {
2064 // case 3) the dylib has a list of allowable clients, and we are creating one of them
2065 const char* clientName
= fOptions
.clientName();
2066 int clientNameLen
= 0;
2067 if ( clientName
!= NULL
) {
2068 // use client name as specified on command line
2069 clientNameLen
= strlen(clientName
);
2072 // infer client name from output path (e.g. xxx/libfoo.A.dylib --> foo, Bar.framework/Bar --> Bar)
2073 clientName
= outputFilePath
;
2074 // starts after last slash
2075 if ( outputFilePathLastSlash
!= NULL
)
2076 clientName
= &outputFilePathLastSlash
[1];
2077 if ( strncmp(clientName
, "lib", 3) == 0 )
2078 clientName
= &clientName
[3];
2080 const char* firstDot
= strchr(clientName
, '.');
2081 if ( firstDot
== NULL
)
2082 clientNameLen
= strlen(clientName
);
2084 clientNameLen
= firstDot
- clientName
;
2087 // Use clientName to check if this dylib is able to link against the allowable clients.
2088 for (std::vector
<const char*>::iterator it
= clients
->begin(); it
!= clients
->end(); it
++) {
2089 if ( strncmp(*it
, clientName
, clientNameLen
) == 0 )
2094 // error out if we are not allowed to link
2096 //throwf("'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
2097 fprintf(stderr
, "'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
2098 reader
->getPath(), reader
->parentUmbrella());
2102 ++fTotalDylibsLoaded
;
2108 void Linker::addIndirectLibraries(ObjectFile::Reader
* reader
)
2110 std::vector
<const char*>* dependentLibs
= reader
->getDependentLibraryPaths();
2111 if ( dependentLibs
!= NULL
) {
2112 for (std::vector
<const char*>::iterator it
=dependentLibs
->begin(); it
!= dependentLibs
->end(); it
++) {
2113 if ( this->haveDirectLibrary(*it
) ) {
2114 // do nothing, direct library already exists
2116 else if ( this->haveIndirectLibrary(*it
, reader
) ) {
2117 // side effect of haveIndirectLibrary() added reader to parent list
2120 // add to list of indirect libraries
2121 IndirectLibrary indirectLib
;
2122 indirectLib
.path
= *it
;
2123 indirectLib
.fileLen
= 0;
2124 indirectLib
.reader
= NULL
;
2125 indirectLib
.parents
.insert(reader
);
2126 indirectLib
.reExportedViaDirectLibrary
= NULL
;
2127 fIndirectDynamicLibraries
.push_back(indirectLib
);
2128 //fprintf(stderr, "add indirect library: %s\n", *it);
2134 bool Linker::haveIndirectLibrary(const char* path
, ObjectFile::Reader
* parentReader
)
2136 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
2137 if ( strcmp(path
, it
->path
) == 0 ) {
2138 it
->parents
.insert(parentReader
);
2141 if ( it
->reader
!= NULL
) {
2142 const char* installPath
= it
->reader
->getInstallPath();
2143 if ( (installPath
!= NULL
) && (strcmp(path
, installPath
) == 0) )
2150 bool Linker::haveDirectLibrary(const char* path
)
2152 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator it
=fDynamicLibraries
.begin(); it
!= fDynamicLibraries
.end(); it
++) {
2153 if ( strcmp(path
, it
->reader
->getPath()) == 0 )
2155 const char* installPath
= it
->reader
->getInstallPath();
2156 if ( (installPath
!= NULL
) && (strcmp(path
, installPath
) == 0) )
2162 void Linker::logTraceInfo (const char* format
, ...)
2164 static int trace_file
= -1;
2165 char trace_buffer
[MAXPATHLEN
* 2];
2168 ssize_t amount_written
;
2169 const char *trace_file_path
= fOptions
.readerOptions().fTraceOutputFile
;
2171 if(trace_file
== -1) {
2172 if(trace_file_path
!= NULL
) {
2173 trace_file
= open(trace_file_path
, O_WRONLY
| O_APPEND
| O_CREAT
, 0666);
2174 if(trace_file
== -1)
2175 throwf("Could not open or create trace file: %s\n", trace_file_path
);
2178 trace_file
= fileno(stderr
);
2183 va_start(ap
, format
);
2184 length
= vsnprintf(trace_buffer
, sizeof(trace_buffer
), format
, ap
);
2186 buffer_ptr
= trace_buffer
;
2189 amount_written
= write(trace_file
, buffer_ptr
, length
);
2190 if(amount_written
== -1)
2191 /* Failure to write shouldn't fail the build. */
2193 buffer_ptr
+= amount_written
;
2194 length
-= amount_written
;
2200 void Linker::createWriter()
2202 fStartCreateWriterTime
= mach_absolute_time();
2203 const char* path
= fOptions
.getOutputFilePath();
2204 switch ( fArchitecture
) {
2205 case CPU_TYPE_POWERPC
:
2206 this->setOutputFile(new mach_o::executable::Writer
<ppc
>(path
, fOptions
, fDynamicLibraries
));
2208 case CPU_TYPE_POWERPC64
:
2209 this->setOutputFile(new mach_o::executable::Writer
<ppc64
>(path
, fOptions
, fDynamicLibraries
));
2212 this->setOutputFile(new mach_o::executable::Writer
<x86
>(path
, fOptions
, fDynamicLibraries
));
2214 case CPU_TYPE_X86_64
:
2215 this->setOutputFile(new mach_o::executable::Writer
<x86_64
>(path
, fOptions
, fDynamicLibraries
));
2218 throw "unknown architecture";
2223 Linker::SymbolTable::SymbolTable(Linker
& owner
)
2224 : fOwner(owner
), fRequireCount(0)
2228 void Linker::SymbolTable::require(const char* name
)
2230 //fprintf(stderr, "require(%s)\n", name);
2231 Mapper::iterator pos
= fTable
.find(name
);
2232 if ( pos
== fTable
.end() ) {
2233 fTable
[name
] = NULL
;
2238 // convenience labels for 2-dimensional switch statement
2240 kRegAndReg
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2241 kRegAndWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2242 kRegAndTent
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2243 kRegAndExtern
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2244 kRegAndExternWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2245 kWeakAndReg
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2246 kWeakAndWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2247 kWeakAndTent
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2248 kWeakAndExtern
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2249 kWeakAndExternWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2250 kTentAndReg
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2251 kTentAndWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2252 kTentAndTent
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2253 kTentAndExtern
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2254 kTentAndExternWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2255 kExternAndReg
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2256 kExternAndWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2257 kExternAndTent
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2258 kExternAndExtern
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2259 kExternAndExternWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2260 kExternWeakAndReg
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2261 kExternWeakAndWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2262 kExternWeakAndTent
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2263 kExternWeakAndExtern
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2264 kExternWeakAndExternWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
2267 bool Linker::SymbolTable::add(ObjectFile::Atom
& newAtom
)
2270 const char* name
= newAtom
.getName();
2271 //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
2272 Mapper::iterator pos
= fTable
.find(name
);
2273 ObjectFile::Atom
* existingAtom
= NULL
;
2274 if ( pos
!= fTable
.end() )
2275 existingAtom
= pos
->second
;
2276 if ( existingAtom
!= NULL
) {
2277 // already have atom with same name in symbol table
2278 switch ( (existingAtom
->getDefinitionKind() << 3) | newAtom
.getDefinitionKind() ) {
2280 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2282 // ignore new weak atom, because we already have a non-weak one
2286 // ignore new tentative atom, because we already have a regular one
2290 // ignore external atom, because we already have a one
2293 case kRegAndExternWeak
:
2294 // ignore external atom, because we already have a one
2298 // replace existing weak atom with regular one
2301 // have another weak atom, use whichever has largest alignment requirement
2302 // because codegen of some client may require alignment
2303 useNew
= ( newAtom
.getAlignment() > existingAtom
->getAlignment() );
2306 // replace existing weak atom with tentative one ???
2308 case kWeakAndExtern
:
2309 // keep weak atom, at runtime external one may override
2312 case kWeakAndExternWeak
:
2313 // keep weak atom, at runtime external one may override
2317 // replace existing tentative atom with regular one
2320 // replace existing tentative atom with weak one ???
2324 if ( newAtom
.getSize() < existingAtom
->getSize() ) {
2328 case kTentAndExtern
:
2329 case kTentAndExternWeak
:
2330 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2331 switch ( fOwner
.fOptions
.commonsMode() ) {
2332 case Options::kCommonsIgnoreDylibs
:
2333 if ( fOwner
.fOptions
.warnCommons() )
2334 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2335 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2338 case Options::kCommonsOverriddenByDylibs
:
2339 if ( fOwner
.fOptions
.warnCommons() )
2340 fprintf(stderr
, "ld64: replacing common symbol %s from %s with true definition from dylib %s\n",
2341 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2343 case Options::kCommonsConflictsDylibsError
:
2344 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2345 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2349 // replace external atom with regular one
2351 case kExternAndWeak
:
2352 // replace external atom with weak one
2354 case kExternAndTent
:
2355 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2356 switch ( fOwner
.fOptions
.commonsMode() ) {
2357 case Options::kCommonsIgnoreDylibs
:
2358 if ( fOwner
.fOptions
.warnCommons() )
2359 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2360 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2362 case Options::kCommonsOverriddenByDylibs
:
2363 if ( fOwner
.fOptions
.warnCommons() )
2364 fprintf(stderr
, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2365 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2368 case Options::kCommonsConflictsDylibsError
:
2369 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2370 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2373 case kExternAndExtern
:
2374 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2375 case kExternAndExternWeak
:
2376 // keep strong dylib atom, ignore weak one
2379 case kExternWeakAndReg
:
2380 // replace existing weak external with regular
2382 case kExternWeakAndWeak
:
2383 // replace existing weak external with weak (let dyld decide at runtime which to use)
2385 case kExternWeakAndTent
:
2386 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2387 switch ( fOwner
.fOptions
.commonsMode() ) {
2388 case Options::kCommonsIgnoreDylibs
:
2389 if ( fOwner
.fOptions
.warnCommons() )
2390 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2391 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2393 case Options::kCommonsOverriddenByDylibs
:
2394 if ( fOwner
.fOptions
.warnCommons() )
2395 fprintf(stderr
, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2396 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2399 case Options::kCommonsConflictsDylibsError
:
2400 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2401 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2404 case kExternWeakAndExtern
:
2405 // replace existing weak external with external
2407 case kExternWeakAndExternWeak
:
2408 // keep existing external weak
2414 fTable
[name
] = &newAtom
;
2415 if ( existingAtom
!= NULL
)
2416 fOwner
.fDeadAtoms
.insert(existingAtom
);
2419 fOwner
.fDeadAtoms
.insert(&newAtom
);
2426 ObjectFile::Atom
* Linker::SymbolTable::find(const char* name
)
2428 Mapper::iterator pos
= fTable
.find(name
);
2429 if ( pos
!= fTable
.end() ) {
2436 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
)
2438 for (Mapper::iterator it
=fTable
.begin(); it
!= fTable
.end(); it
++) {
2439 if ( (it
->second
== NULL
) || (andWeakDefintions
&& (it
->second
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
)) ) {
2440 undefines
.push_back(it
->first
);
2448 bool Linker::AtomSorter::operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
)
2450 // first sort by section order (which is already sorted by segment)
2451 unsigned int leftSectionIndex
= left
->getSection()->getIndex();
2452 unsigned int rightSectionIndex
= right
->getSection()->getIndex();
2453 if ( leftSectionIndex
!= rightSectionIndex
)
2454 return (leftSectionIndex
< rightSectionIndex
);
2456 // then sort by .o file order
2457 ObjectFile::Reader
* leftReader
= left
->getFile();
2458 ObjectFile::Reader
* rightReader
= right
->getFile();
2459 if ( leftReader
!= rightReader
)
2460 return leftReader
->getSortOrder() < rightReader
->getSortOrder();
2462 // lastly sort by atom within a .o file
2463 return left
->getSortOrder() < right
->getSortOrder();
2467 int main(int argc
, const char* argv
[])
2469 const char* archName
= NULL
;
2470 bool showArch
= false;
2471 bool archInferred
= false;
2473 // create linker object given command line arguments
2474 Linker
ld(argc
, argv
);
2476 // save error message prefix
2477 archName
= ld
.architectureName();
2478 archInferred
= ld
.isInferredArchitecture();
2479 showArch
= ld
.showArchitectureInErrors();
2481 // open all input files
2490 catch (const char* msg
) {
2491 extern const double ld64VersionNumber
;
2493 fprintf(stderr
, "ld64-%g failed: %s for inferred architecture %s\n", ld64VersionNumber
, msg
, archName
);
2494 else if ( showArch
)
2495 fprintf(stderr
, "ld64-%g failed: %s for architecture %s\n", ld64VersionNumber
, msg
, archName
);
2497 fprintf(stderr
, "ld64-%g failed: %s\n", ld64VersionNumber
, msg
);