1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005 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>
30 #include <mach-o/loader.h>
31 #include <mach-o/fat.h>
39 #include <ext/hash_map>
43 #include "ObjectFile.h"
44 #include "ObjectFileMachO-all.h"
46 #include "ExecutableFile.h"
47 #include "ExecutableFileMachO-all.h"
49 #include "SectCreate.h"
52 static void dumpAtom(ObjectFile::Atom
* atom
)
54 //printf("atom: %p\n", atom);
57 printf("name: %s\n", atom
->getDisplayName());
60 switch ( atom
->getScope() ) {
61 case ObjectFile::Atom::scopeTranslationUnit
:
62 printf("scope: translation unit\n");
64 case ObjectFile::Atom::scopeLinkageUnit
:
65 printf("scope: linkage unit\n");
67 case ObjectFile::Atom::scopeGlobal
:
68 printf("scope: global\n");
71 printf("scope: unknown\n");
74 // segment and section
75 printf("section: %s,%s\n", atom
->getSegment().getName(), atom
->getSectionName());
79 if ( atom
->isTentativekDefinition() )
81 else if ( atom
->isWeakDefinition() )
83 if ( atom
->isCoalesableByName() )
84 printf("coalesce-by-name ");
85 if ( atom
->isCoalesableByValue() )
86 printf("coalesce-by-value ");
87 if ( atom
->dontDeadStrip() )
88 printf("dont-dead-strip ");
89 if ( atom
->isZeroFill() )
94 printf("size: 0x%012llX\n", atom
->getSize());
97 uint8_t content
[atom
->getSize()];
98 atom
->copyRawContent(content
);
100 if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
101 printf("\"%s\"", content
);
104 for (unsigned int i
=0; i
< sizeof(content
); ++i
)
105 printf("%02X ", content
[i
]);
110 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
111 const int refCount
= references
.size();
112 printf("references: (%u)\n", refCount
);
113 for (int i
=0; i
< refCount
; ++i
) {
114 ObjectFile::Reference
* ref
= references
[i
];
115 printf(" %s\n", ref
->getDescription());
124 class CStringComparor
127 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) < 0); }
133 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
136 class Section
: public ObjectFile::Section
139 static Section
* find(const char* sectionName
, const char* segmentName
, bool zeroFill
);
140 static void assignIndexes();
143 Section(const char* sectionName
, const char* segmentName
, bool zeroFill
);
146 static int segmentOrdinal(const char* segName
);
147 bool operator()(Section
* left
, Section
* right
);
150 typedef __gnu_cxx::hash_map
<const char*, class Section
*, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToSection
;
151 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
153 const char* fSectionName
;
154 const char* fSegmentName
;
157 static NameToSection fgMapping
;
158 static std::vector
<Section
*> fgSections
;
161 Section::NameToSection
Section::fgMapping
;
162 std::vector
<Section
*> Section::fgSections
;
164 Section::Section(const char* sectionName
, const char* segmentName
, bool zeroFill
)
165 : fSectionName(sectionName
), fSegmentName(segmentName
), fZeroFill(zeroFill
)
167 //fprintf(stderr, "new Section(%s, %s)\n", sectionName, segmentName);
170 Section
* Section::find(const char* sectionName
, const char* segmentName
, bool zeroFill
)
173 std::pair
<NameToSection::iterator
, NameToSection::iterator
> range
= fgMapping
.equal_range(sectionName
);
174 for (NameToSection::iterator it
=range
.first
; it
!= range
.second
; it
++) {
175 if ( strcmp(it
->second
->fSegmentName
, segmentName
) == 0 )
179 NameToSection::iterator pos
= fgMapping
.find(sectionName
);
180 if ( pos
!= fgMapping
.end() ) {
181 if ( strcmp(pos
->second
->fSegmentName
, segmentName
) == 0 )
183 // otherwise same section name is used in different segments, look slow way
184 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++) {
185 if ( (strcmp((*it
)->fSectionName
, sectionName
) == 0) && (strcmp((*it
)->fSegmentName
, segmentName
) == 0) )
190 // does not exist, so make a new one
191 Section
* sect
= new Section(sectionName
, segmentName
, zeroFill
);
192 sect
->fIndex
= fgMapping
.size();
193 fgMapping
[sectionName
] = sect
;
194 fgSections
.push_back(sect
);
198 int Section::Sorter::segmentOrdinal(const char* segName
)
200 if ( strcmp(segName
, "__PAGEZERO") == 0 )
202 if ( strcmp(segName
, "__TEXT") == 0 )
204 if ( strcmp(segName
, "__DATA") == 0 )
206 if ( strcmp(segName
, "__OBJC") == 0 )
208 if ( strcmp(segName
, "__LINKEDIT") == 0 )
209 return INT_MAX
; // linkedit segment should always sort last
215 bool Section::Sorter::operator()(Section
* left
, Section
* right
)
217 // Segment is primary sort key
218 const char* leftSegName
= left
->fSegmentName
;
219 const char* rightSegName
= right
->fSegmentName
;
220 int segNameCmp
= strcmp(leftSegName
, rightSegName
);
221 if ( segNameCmp
!= 0 )
223 int leftSegOrdinal
= segmentOrdinal(leftSegName
);
224 int rightSegOrdinal
= segmentOrdinal(rightSegName
);
225 if ( leftSegOrdinal
< rightSegOrdinal
)
227 if ( leftSegOrdinal
== rightSegOrdinal
)
228 return segNameCmp
< 0;
232 // zerofill section sort to the end
233 if ( !left
->fZeroFill
&& right
->fZeroFill
)
235 if ( left
->fZeroFill
&& !right
->fZeroFill
)
238 // section discovery order is last sort key
239 return left
->fIndex
< right
->fIndex
;
242 void Section::assignIndexes()
244 //printf("unsorted:\n");
245 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
246 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
250 std::sort(fgSections
.begin(), fgSections
.end(), Section::Sorter());
252 // assign correct section ordering to each Section object
253 unsigned int newOrder
= 1;
254 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++)
255 (*it
)->fIndex
= newOrder
++;
257 //printf("sorted:\n");
258 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
259 // printf("section: name=%s\n", (*it)->fSectionName);
265 Linker(int argc
, const char* argv
[]);
267 void createReaders();
269 void addInputFile(ObjectFile::Reader
* reader
);
270 void setOutputFile(ExecutableFile::Writer
* writer
);
275 ObjectFile::Reader
* createReader(const Options::FileInfo
&);
276 void addAtom(ObjectFile::Atom
& atom
);
277 void addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
);
278 void buildAtomList();
279 void loadUndefines();
280 void addWeakAtomOverrides();
281 void resolveReferences();
287 void resolve(ObjectFile::Reference
* reference
);
288 void resolveFrom(ObjectFile::Reference
* reference
);
289 void addJustInTimeAtoms(const char* name
);
291 void addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
);
292 void addIndirectLibraries(ObjectFile::Reader
* reader
);
293 bool haveIndirectLibrary(const char* path
, ObjectFile::Reader
* reader
);
294 bool haveDirectLibrary(const char* path
);
299 SymbolTable(Linker
&);
300 void require(const char* name
);
301 bool add(ObjectFile::Atom
& atom
);
302 ObjectFile::Atom
* find(const char* name
);
303 unsigned int getRequireCount() { return fRequireCount
; }
304 void getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
);
306 typedef std::map
<const char*, ObjectFile::Atom
*, CStringComparor
> Mapper
;
309 unsigned int fRequireCount
;
314 bool operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
);
317 typedef std::map
<const char*, uint32_t, CStringComparor
> SectionOrder
;
319 struct IndirectLibrary
{
322 ObjectFile::Reader
* reader
;
323 std::set
<ObjectFile::Reader
*> parents
;
324 ObjectFile::Reader
* reExportParent
;
328 SymbolTable fGlobalSymbolTable
;
329 unsigned int fWeakSymbolsAddedCount
;
330 std::vector
<class ObjectFile::Reader
*> fInputFiles
;
331 ExecutableFile::Writer
* fOutputFile
;
332 std::vector
<ExecutableFile::DyLibUsed
> fDynamicLibraries
;
333 std::list
<IndirectLibrary
> fIndirectDynamicLibraries
;
334 std::vector
<class ObjectFile::Atom
*> fAllAtoms
;
335 std::set
<class ObjectFile::Atom
*> fDeadAtoms
;
336 SectionOrder fSectionOrder
;
337 unsigned int fNextSortOrder
;
338 bool fDirectLibrariesComplete
;
343 Linker::Linker(int argc
, const char* argv
[])
344 : fOptions(argc
, argv
), fGlobalSymbolTable(*this), fOutputFile(NULL
), fNextSortOrder(1), fDirectLibrariesComplete(false)
348 void Linker::addInputFile(ObjectFile::Reader
* reader
)
350 fInputFiles
.push_back(reader
);
353 void Linker::setOutputFile(ExecutableFile::Writer
* writer
)
355 fOutputFile
= writer
;
360 this->buildAtomList();
361 this->loadUndefines();
362 this->resolveReferences();
369 inline void Linker::addAtom(ObjectFile::Atom
& atom
)
371 // add to list of all atoms
372 fAllAtoms
.push_back(&atom
);
374 // add atom's references's names to symbol table as to-be-resolved-later
375 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
376 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
377 ObjectFile::Reference
* reference
= *it
;
378 if ( reference
->isTargetUnbound() ) {
379 fGlobalSymbolTable
.require(reference
->getTargetName());
381 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() )
382 fGlobalSymbolTable
.require(reference
->getFromTargetName());
385 // if in global namespace, add atom itself to symbol table
386 ObjectFile::Atom::Scope scope
= atom
.getScope();
387 const char* name
= atom
.getName();
388 if ( (scope
!= ObjectFile::Atom::scopeTranslationUnit
) && (name
!= NULL
) ) {
389 fGlobalSymbolTable
.add(atom
);
391 // update scope based on export list (possible that globals are downgraded to private_extern)
392 if ( (scope
== ObjectFile::Atom::scopeGlobal
) && fOptions
.hasExportRestrictList() ) {
393 bool doExport
= fOptions
.shouldExport(name
);
395 atom
.setScope(ObjectFile::Atom::scopeLinkageUnit
);
400 // record section orders so output file can have same order
401 atom
.setSection(Section::find(atom
.getSectionName(), atom
.getSegment().getName(), atom
.isZeroFill()));
403 // assign order in which this atom was originally seen
404 if ( atom
.getSortOrder() == 0 )
405 fNextSortOrder
= atom
.setSortOrder(fNextSortOrder
);
408 inline void Linker::addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
)
410 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
.begin(); it
!= atoms
.end(); it
++) {
415 void Linker::buildAtomList()
417 // add initial undefines from -u option
418 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
419 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++) {
420 fGlobalSymbolTable
.require(*it
);
423 // writer can contribute atoms
424 this->addAtoms(fOutputFile
->getAtoms());
426 // each reader contributes atoms
427 const int readerCount
= fInputFiles
.size();
428 for (int i
=0; i
< readerCount
; ++i
) {
429 this->addAtoms(fInputFiles
[i
]->getAtoms());
432 // extra command line section always at end
433 std::vector
<Options::ExtraSection
>& extraSections
= fOptions
.extraSections();
434 for( std::vector
<Options::ExtraSection
>::iterator it
=extraSections
.begin(); it
!= extraSections
.end(); ++it
) {
435 this->addAtoms(SectCreate::MakeReader(it
->segmentName
, it
->sectionName
, it
->path
, it
->data
, it
->dataLen
)->getAtoms());
439 void Linker::loadUndefines()
441 // keep looping until no more undefines were added in last loop
442 unsigned int undefineCount
= 0xFFFFFFFF;
443 while ( undefineCount
!= fGlobalSymbolTable
.getRequireCount() ) {
444 undefineCount
= fGlobalSymbolTable
.getRequireCount();
445 std::vector
<const char*> undefineNames
;
446 fGlobalSymbolTable
.getNeededNames(true, undefineNames
);
447 const int undefineCount
= undefineNames
.size();
448 for (int i
=0; i
< undefineCount
; ++i
) {
449 const char* name
= undefineNames
[i
];
450 ObjectFile::Atom
* possibleAtom
= fGlobalSymbolTable
.find(name
);
451 if ( (possibleAtom
== NULL
) || (possibleAtom
->isWeakDefinition() && (fOptions
.outputKind() != Options::kObjectFile
)) )
452 this->addJustInTimeAtoms(name
);
456 if ( fOptions
.outputKind() != Options::kObjectFile
) {
457 // error out on any remaining undefines
460 switch ( fOptions
.undefinedTreatment() ) {
461 case Options::kUndefinedError
:
463 case Options::kUndefinedDynamicLookup
:
466 case Options::kUndefinedWarning
:
469 case Options::kUndefinedSuppress
:
474 std::vector
<const char*> unresolvableUndefines
;
475 fGlobalSymbolTable
.getNeededNames(false, unresolvableUndefines
);
476 const int unresolvableCount
= unresolvableUndefines
.size();
477 int unresolvableExportsCount
= 0;
478 if ( unresolvableCount
!= 0 ) {
480 fprintf(stderr
, "can't resolve symbols:\n");
481 for (int i
=0; i
< unresolvableCount
; ++i
) {
482 const char* name
= unresolvableUndefines
[i
];
483 const unsigned int nameLen
= strlen(name
);
484 fprintf(stderr
, " %s, referenced from:\n", name
);
485 char stubName
[nameLen
+6];
486 strcpy(stubName
, name
);
487 strcat(stubName
, "$stub");
488 char nonLazyName
[nameLen
+16];
489 strcpy(nonLazyName
, name
);
490 strcat(nonLazyName
, "$non_lazy_ptr");
491 ObjectFile::Atom
* lastStubAtomWithUnresolved
= NULL
;
492 ObjectFile::Atom
* lastNonLazyAtomWithUnresolved
= NULL
;
493 // scan all atoms for references
494 bool foundAtomReference
= false;
495 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
496 ObjectFile::Atom
* atom
= *it
;
497 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
498 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
499 ObjectFile::Reference
* reference
= *rit
;
500 if ( reference
->isTargetUnbound() ) {
501 if ( (atom
!= lastStubAtomWithUnresolved
) && (strcmp(reference
->getTargetName(), stubName
) == 0) ) {
502 const char* path
= atom
->getFile()->getPath();
503 const char* shortPath
= strrchr(path
, '/');
504 if ( shortPath
== NULL
)
507 shortPath
= &shortPath
[1];
508 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), shortPath
);
509 lastStubAtomWithUnresolved
= atom
;
510 foundAtomReference
= true;
512 else if ( (atom
!= lastNonLazyAtomWithUnresolved
) && (strcmp(reference
->getTargetName(), nonLazyName
) == 0) ) {
513 const char* path
= atom
->getFile()->getPath();
514 const char* shortPath
= strrchr(path
, '/');
515 if ( shortPath
== NULL
)
518 shortPath
= &shortPath
[1];
519 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), shortPath
);
520 lastNonLazyAtomWithUnresolved
= atom
;
521 foundAtomReference
= true;
524 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() ) {
525 if ( (atom
!= lastStubAtomWithUnresolved
) && (strcmp(reference
->getFromTargetName(), stubName
) == 0) ) {
526 const char* path
= atom
->getFile()->getPath();
527 const char* shortPath
= strrchr(path
, '/');
528 if ( shortPath
== NULL
)
531 shortPath
= &shortPath
[1];
532 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), shortPath
);
533 lastStubAtomWithUnresolved
= atom
;
534 foundAtomReference
= true;
536 else if ( (atom
!= lastNonLazyAtomWithUnresolved
) && (strcmp(reference
->getFromTargetName(), nonLazyName
) == 0) ) {
537 const char* path
= atom
->getFile()->getPath();
538 const char* shortPath
= strrchr(path
, '/');
539 if ( shortPath
== NULL
)
542 shortPath
= &shortPath
[1];
543 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), shortPath
);
544 lastNonLazyAtomWithUnresolved
= atom
;
545 foundAtomReference
= true;
550 // scan command line options
551 if ( !foundAtomReference
&& fOptions
.hasExportRestrictList() && fOptions
.shouldExport(name
) ) {
552 fprintf(stderr
, " -exported_symbols_list command line option\n");
553 ++unresolvableExportsCount
;
557 if ( doError
&& (unresolvableCount
> unresolvableExportsCount
) ) // last check should be removed. It exists so broken projects still build
558 throw "symbol(s) not found";
561 // now verify that -init routine exists
562 if ( fOptions
.initFunctionName() != NULL
) {
563 if ( fGlobalSymbolTable
.find(fOptions
.initFunctionName()) == NULL
)
564 throwf("symbol %s not found for -init", fOptions
.initFunctionName());
571 void Linker::addJustInTimeAtoms(const char* name
)
573 // when creating final linked image, write gets first chance
574 if ( fOptions
.outputKind() != Options::kObjectFile
) {
575 ObjectFile::Atom
* atom
= fOutputFile
->getUndefinedProxyAtom(name
);
576 if ( atom
!= NULL
) {
577 this->addAtom(*atom
);\
582 // give direct readers a chance
583 const int readerCount
= fInputFiles
.size();
584 for (int i
=0; i
< readerCount
; ++i
) {
585 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
586 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
587 std::vector
<class ObjectFile::Atom
*>* atoms
= fInputFiles
[i
]->getJustInTimeAtomsFor(name
);
588 if ( atoms
!= NULL
) {
589 this->addAtoms(*atoms
);
591 return; // found a definition, no need to search anymore
592 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
596 // give indirect readers a chance
597 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
598 ObjectFile::Reader
* reader
= it
->reader
;
599 if ( reader
!= NULL
) {
600 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
601 if ( atoms
!= NULL
) {
602 this->addAtoms(*atoms
);
605 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
610 // when creating .o file, writer goes last (this is so any static archives will be searched above)
611 if ( fOptions
.outputKind() == Options::kObjectFile
) {
612 ObjectFile::Atom
* atom
= fOutputFile
->getUndefinedProxyAtom(name
);
613 if ( atom
!= NULL
) {
614 this->addAtom(*atom
);
621 void Linker::resolve(ObjectFile::Reference
* reference
)
623 ObjectFile::Atom
* target
= NULL
;
624 const char* targetName
= reference
->getTargetName();
625 const int targetNameLen
= strlen(targetName
);
626 if ( (targetNameLen
> 5) && (strcmp(&targetName
[targetNameLen
-5], "$stub") == 0) ) {
627 // when looking up "_foo$stub", first look for "_foo"
628 char nonStubTarget
[targetNameLen
+1];
629 strcpy(nonStubTarget
, targetName
);
630 nonStubTarget
[targetNameLen
-5] = '\0';
631 // unless interposing and the symbol is exported
632 if ( !fOptions
.interposable() || !fOptions
.shouldExport(nonStubTarget
) ) {
633 target
= fGlobalSymbolTable
.find(nonStubTarget
);
634 // also need indirection to all exported weak symbols for C++ support
635 if ( (target
!= NULL
) && !target
->isImportProxy() && (!target
->isWeakDefinition() || (target
->getScope() != ObjectFile::Atom::scopeGlobal
)) ) {
636 reference
->setTarget(*target
, reference
->getTargetOffset());
637 // mark stub as no longer being needed
638 ObjectFile::Atom
* stub
= fGlobalSymbolTable
.find(targetName
);
639 if ( stub
!= NULL
) {
640 char lazySymbol
[targetNameLen
+8];
641 strcpy(lazySymbol
, nonStubTarget
);
642 strcat(lazySymbol
, "$lazy_ptr");
643 ObjectFile::Atom
* lazyPtr
= fGlobalSymbolTable
.find(lazySymbol
);
644 fDeadAtoms
.insert(stub
);
645 if ( lazyPtr
!= NULL
)
646 fDeadAtoms
.insert(lazyPtr
);
653 // look in global symbol table
654 target
= fGlobalSymbolTable
.find(targetName
);
655 if ( target
== NULL
) {
656 fprintf(stderr
, "can't resolve: %s\n", targetName
);
658 reference
->setTarget(*target
, reference
->getTargetOffset());
660 // handle weak-imports
661 if ( target
->isImportProxy() ) {
662 bool mismatch
= false;
663 if ( reference
->isWeakReference() ) {
664 switch(target
->getImportWeakness()) {
665 case ObjectFile::Atom::kWeakUnset
:
666 target
->setImportWeakness(true);
668 case ObjectFile::Atom::kWeakImport
:
670 case ObjectFile::Atom::kNonWeakImport
:
676 switch(target
->getImportWeakness()) {
677 case ObjectFile::Atom::kWeakUnset
:
678 target
->setImportWeakness(false);
680 case ObjectFile::Atom::kWeakImport
:
683 case ObjectFile::Atom::kNonWeakImport
:
688 switch ( fOptions
.weakReferenceMismatchTreatment() ) {
689 case Options::kWeakReferenceMismatchError
:
690 throwf("mismatching weak references for symbol: %s", target
->getName());
691 case Options::kWeakReferenceMismatchWeak
:
692 target
->setImportWeakness(true);
694 case Options::kWeakReferenceMismatchNonWeak
:
695 target
->setImportWeakness(false);
702 void Linker::resolveFrom(ObjectFile::Reference
* reference
)
704 // handle references that have two (from and to) targets
705 const char* fromTargetName
= reference
->getFromTargetName();
706 ObjectFile::Atom
* fromTarget
= fGlobalSymbolTable
.find(fromTargetName
);
707 if ( fromTarget
== NULL
) {
708 fprintf(stderr
, "can't resolve: %s\n", fromTargetName
);
710 reference
->setFromTarget(*fromTarget
);
714 void Linker::resolveReferences()
716 // note: the atom list may grow during this loop as libraries supply needed atoms
717 for (unsigned int j
=0; j
< fAllAtoms
.size(); ++j
) {
718 ObjectFile::Atom
* atom
= fAllAtoms
[j
];
719 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
720 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
721 ObjectFile::Reference
* reference
= *it
;
722 if ( reference
->isTargetUnbound() )
723 this->resolve(reference
);
724 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() )
725 this->resolveFrom(reference
);
733 InSet(std::set
<ObjectFile::Atom
*>& deadAtoms
) : fDeadAtoms(deadAtoms
) {}
735 bool operator()(ObjectFile::Atom
*& atom
) const {
736 return ( fDeadAtoms
.count(atom
) != 0 );
740 std::set
<ObjectFile::Atom
*>& fDeadAtoms
;
744 void Linker::deadStrip()
746 //printf("Stripping atoms:\n");
747 //for (std::set<ObjectFile::Atom*>::iterator it=fDeadAtoms.begin(); it != fDeadAtoms.end(); it++) {
748 // printf("\t%s\n", (*it)->getDisplayName());
751 // for now, just remove atoms weak atoms that have been overridden
752 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fDeadAtoms
)), fAllAtoms
.end());
757 void Linker::sortAtoms()
759 Section::assignIndexes();
760 std::sort(fAllAtoms
.begin(), fAllAtoms
.end(), Linker::AtomSorter());
761 //fprintf(stderr, "Sorted atoms:\n");
762 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
763 // fprintf(stderr, "\t%s\n", (*it)->getDisplayName());
769 // make sure given addresses are within reach of branches, etc
770 void Linker::tweakLayout()
774 void Linker::writeOutput()
776 // if main executable, find entry point atom
777 ObjectFile::Atom
* entryPoint
= NULL
;
778 switch ( fOptions
.outputKind() ) {
779 case Options::kDynamicExecutable
:
780 case Options::kStaticExecutable
:
782 entryPoint
= fGlobalSymbolTable
.find(fOptions
.entryName());
783 if ( entryPoint
== NULL
) {
784 throwf("could not find entry point: %s", fOptions
.entryName());
787 case Options::kDynamicLibrary
:
788 if ( fOptions
.initFunctionName() != NULL
) {
789 entryPoint
= fGlobalSymbolTable
.find(fOptions
.initFunctionName());
790 if ( entryPoint
== NULL
) {
791 throwf("could not find -init function: %s", fOptions
.initFunctionName());
795 case Options::kObjectFile
:
796 case Options::kDynamicBundle
:
801 // tell writer about each segment's atoms
802 fOutputFile
->write(fAllAtoms
, entryPoint
);
808 ObjectFile::Reader
* Linker::createReader(const Options::FileInfo
& info
)
811 uint64_t len
= info
.fileLen
;
812 int fd
= ::open(info
.path
, O_RDONLY
, 0);
814 throwf("can't open file, errno=%d", errno
);
815 if ( info
.fileLen
< 20 )
816 throw "file too small";
818 char* p
= (char*)::mmap(NULL
, info
.fileLen
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
819 if ( p
== (char*)(-1) )
820 throwf("can't map file, errno=%d", errno
);
823 // if fat file, skip to architecture we want
824 const mach_header
* mh
= (mach_header
*)p
;
825 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
826 // Fat header is always big-endian
827 const struct fat_header
* fh
= (struct fat_header
*)p
;
828 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
829 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
830 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)fOptions
.architecture() ) {
831 mh
= (struct mach_header
*)((char*)p
+ OSSwapBigToHostInt32(archs
[i
].offset
));
832 len
= OSSwapBigToHostInt32(archs
[i
].size
);
838 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
839 const char* archName
= "unknown";
840 switch (fOptions
.architecture()) {
841 case CPU_TYPE_POWERPC
:
844 case CPU_TYPE_POWERPC64
:
851 throwf("missing required architecture %s in fat file", archName
);
854 // pull out cpu-type and file-type in endian-safe way
855 cpu_type_t cpuType
= 0;
856 uint32_t fileType
= 0;
857 if ( mh
->magic
== MH_MAGIC
) {
858 fileType
= mh
->filetype
;
859 cpuType
= mh
->cputype
;
861 else if ( mh
->magic
== OSSwapInt32(MH_MAGIC
) ) {
862 fileType
= OSSwapInt32(mh
->filetype
);
863 cpuType
= OSSwapInt32(mh
->cputype
);
865 else if ( mh
->magic
== MH_MAGIC_64
) {
866 fileType
= ((mach_header_64
*)mh
)->filetype
;
867 cpuType
= ((mach_header_64
*)mh
)->cputype
;
869 else if ( mh
->magic
== OSSwapInt32(MH_MAGIC_64
) ) {
870 fileType
= OSSwapInt32(((mach_header_64
*)mh
)->filetype
);
871 cpuType
= OSSwapInt32(((mach_header_64
*)mh
)->cputype
);
873 else if ( strncmp((const char*)mh
, "!<arch>\n", 8) == 0 ) {
875 switch ( fOptions
.architecture() ) {
876 case CPU_TYPE_POWERPC
:
877 return ppc::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh
, len
, info
.path
, fOptions
.readerOptions());
878 case CPU_TYPE_POWERPC64
:
879 return ppc64::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh
, len
, info
.path
, fOptions
.readerOptions());
881 return i386::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh
, len
, info
.path
, fOptions
.readerOptions());
883 throw "no matching archive reader";
886 throw "unknown file type";
889 // bail out if cpu-type does not match requrired architecture
890 if ( fOptions
.architecture() == cpuType
) {
891 // make appropriate reader object
892 if ( fileType
== MH_OBJECT
) {
894 case CPU_TYPE_POWERPC
:
895 return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header
*)mh
, info
.path
, fOptions
.readerOptions());
896 case CPU_TYPE_POWERPC64
:
897 return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header
*)mh
, info
.path
, fOptions
.readerOptions());
899 return i386::ObjectFileMachO::MakeReader((class i386::macho_header
*)mh
, info
.path
, fOptions
.readerOptions());
901 throw "wrong architecture in object file";
904 else if ( (fileType
== MH_DYLIB
) || (fileType
== MH_DYLIB_STUB
) ) {
905 ObjectFile::Reader
* dylibReader
= NULL
;
907 case CPU_TYPE_POWERPC
:
908 dylibReader
= ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header
*)mh
, info
.path
, fOptions
.readerOptions());
910 case CPU_TYPE_POWERPC64
:
911 dylibReader
= ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header
*)mh
, info
.path
, fOptions
.readerOptions());
914 dylibReader
= i386::ObjectFileDylibMachO::MakeReader((class i386::macho_header
*)mh
, info
.path
, fOptions
.readerOptions());
917 throw "wrong architecture in dylib";
919 this->addDylib(dylibReader
, info
);
922 throw "unknown mach-o file type";
925 throw "file does not contain requested architecture";
931 void Linker::createReaders()
933 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
934 const int count
= files
.size();
936 throw "no object files specified";
937 // add all direct object, archives, and dylibs
938 for (int i
=0; i
< count
; ++i
) {
939 Options::FileInfo
& entry
= files
[i
];
940 // ignore /usr/lib/dyld on command line in crt.o build
941 if ( strcmp(entry
.path
, "/usr/lib/dyld") != 0 ) {
943 this->addInputFile(this->createReader(entry
));
945 catch (const char* msg
) {
946 if ( strstr(msg
, "architecture") != NULL
) {
947 if ( fOptions
.ignoreOtherArchInputFiles() ) {
948 // ignore, because this is about an architecture not in use
951 fprintf(stderr
, "ld64 warning: in %s, %s\n", entry
.path
, msg
);
955 throwf("in %s, %s", entry
.path
, msg
);
961 // add first level of indirect dylibs
962 fDirectLibrariesComplete
= true;
963 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator it
=fDynamicLibraries
.begin(); it
!= fDynamicLibraries
.end(); it
++) {
964 this->addIndirectLibraries(it
->reader
);
967 // indirect handling depends on namespace
968 switch ( fOptions
.nameSpace() ) {
969 case Options::kFlatNameSpace
:
970 case Options::kForceFlatNameSpace
:
971 // with flat namespace, blindly load all indirect libraries
972 // the indirect list will grow as indirect libraries are loaded
973 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
975 it
->reader
= this->createReader(fOptions
.findFile(it
->path
));
977 catch (const char* msg
) {
978 fprintf(stderr
, "ld64 warning: indirect library %s could not be loaded: %s\n", it
->path
, msg
);
983 case Options::kTwoLevelNameSpace
:
984 // with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
986 bool indirectAdded
= true;
987 while ( indirectAdded
) {
988 indirectAdded
= false;
989 // instantiate a reader for each indirect library and try to find parent that re-exports it
990 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
991 if ( it
->reader
== NULL
) {
993 it
->reader
= this->createReader(fOptions
.findFile(it
->path
));
994 indirectAdded
= true;
996 catch (const char* msg
) {
997 fprintf(stderr
, "ld64 warning: indirect library %s could not be loaded: %s\n", it
->path
, msg
);
1000 // if an indirect library does not have an assigned parent, look for one
1001 if ( (it
->reader
!= NULL
) && (it
->reExportParent
== NULL
) ) {
1002 // ask each parent if they re-export this dylib
1003 for (std::set
<ObjectFile::Reader
*>::iterator pit
=it
->parents
.begin(); pit
!= it
->parents
.end(); pit
++) {
1004 if ( (*pit
)->reExports(it
->reader
) ) {
1005 it
->reExportParent
= *pit
;
1016 // add relevant indirect libraries to the end of fDynamicLibraries
1017 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
1018 if ( (it
->reExportParent
!= NULL
) || (fOptions
.nameSpace() != Options::kTwoLevelNameSpace
) ) {
1019 ExecutableFile::DyLibUsed dylibInfo
;
1020 dylibInfo
.reader
= it
->reader
;
1021 dylibInfo
.options
.fWeakImport
= false;
1022 dylibInfo
.options
.fReExport
= false;
1023 dylibInfo
.options
.fInstallPathOverride
= NULL
;
1024 dylibInfo
.indirect
= true;
1025 dylibInfo
.directReader
= it
->reExportParent
;
1026 fDynamicLibraries
.push_back(dylibInfo
);
1027 if ( fOptions
.readerOptions().fTraceIndirectDylibs
)
1028 printf("[Logging for Build & Integration] Used indirect dynamic library: %s\n", it
->reader
->getPath());
1035 void Linker::addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
)
1037 if ( fDirectLibrariesComplete
) {
1038 this->addIndirectLibraries(reader
);
1041 if ( fOptions
.readerOptions().fTraceDylibs
)
1042 printf("[Logging for Build & Integration] Used dynamic library: %s\n", reader
->getPath());
1043 ExecutableFile::DyLibUsed dylibInfo
;
1044 dylibInfo
.reader
= reader
;
1045 dylibInfo
.options
= info
.options
;
1046 dylibInfo
.indirect
= false;
1047 dylibInfo
.directReader
= NULL
;
1048 fDynamicLibraries
.push_back(dylibInfo
);
1053 void Linker::addIndirectLibraries(ObjectFile::Reader
* reader
)
1055 std::vector
<const char*>* dependentLibs
= reader
->getDependentLibraryPaths();
1056 if ( dependentLibs
!= NULL
) {
1057 for (std::vector
<const char*>::iterator it
=dependentLibs
->begin(); it
!= dependentLibs
->end(); it
++) {
1058 if ( this->haveDirectLibrary(*it
) ) {
1059 // do nothing, direct library already exists
1061 else if ( this->haveIndirectLibrary(*it
, reader
) ) {
1062 // side effect of haveIndirectLibrary() added reader to parent list
1065 // add to list of indirect libraries
1066 IndirectLibrary indirectLib
;
1067 indirectLib
.path
= *it
;
1068 indirectLib
.fileLen
= 0;
1069 indirectLib
.reader
= NULL
;
1070 indirectLib
.parents
.insert(reader
);
1071 indirectLib
.reExportParent
= NULL
;
1072 fIndirectDynamicLibraries
.push_back(indirectLib
);
1073 //fprintf(stderr, "add indirect library: %s\n", *it);
1079 bool Linker::haveIndirectLibrary(const char* path
, ObjectFile::Reader
* parentReader
)
1081 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
1082 if ( strcmp(path
, it
->path
) == 0 ) {
1083 it
->parents
.insert(parentReader
);
1086 if ( it
->reader
!= NULL
) {
1087 const char* installPath
= it
->reader
->getInstallPath();
1088 if ( (installPath
!= NULL
) && (strcmp(path
, installPath
) == 0) )
1095 bool Linker::haveDirectLibrary(const char* path
)
1097 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator it
=fDynamicLibraries
.begin(); it
!= fDynamicLibraries
.end(); it
++) {
1098 if ( strcmp(path
, it
->reader
->getPath()) == 0 )
1100 const char* installPath
= it
->reader
->getInstallPath();
1101 if ( (installPath
!= NULL
) && (strcmp(path
, installPath
) == 0) )
1110 void Linker::createWriter()
1112 const char* path
= fOptions
.getOutputFilePath();
1113 switch ( fOptions
.architecture() ) {
1114 case CPU_TYPE_POWERPC
:
1115 this->setOutputFile(ppc::ExecutableFileMachO::MakeWriter(path
, fOptions
, fDynamicLibraries
));
1117 case CPU_TYPE_POWERPC64
:
1118 this->setOutputFile(ppc64::ExecutableFileMachO::MakeWriter(path
, fOptions
, fDynamicLibraries
));
1121 this->setOutputFile(i386::ExecutableFileMachO::MakeWriter(path
, fOptions
, fDynamicLibraries
));
1124 throw "unknown architecture";
1129 Linker::SymbolTable::SymbolTable(Linker
& owner
)
1130 : fOwner(owner
), fRequireCount(0)
1134 void Linker::SymbolTable::require(const char* name
)
1136 //fprintf(stderr, "require(%s)\n", name);
1137 Mapper::iterator pos
= fTable
.find(name
);
1138 if ( pos
== fTable
.end() ) {
1139 fTable
[name
] = NULL
;
1144 bool Linker::SymbolTable::add(ObjectFile::Atom
& atom
)
1146 const bool log
= false;
1147 const char* name
= atom
.getName();
1148 //fprintf(stderr, "map.add(%p: %s => %p)\n", &fTable, name, &atom);
1149 Mapper::iterator pos
= fTable
.find(name
);
1150 if ( pos
!= fTable
.end() ) {
1151 ObjectFile::Atom
* existingAtom
= pos
->second
;
1152 if ( existingAtom
!= NULL
) {
1153 if ( existingAtom
->isTentativeDefinition() ) {
1154 if ( atom
.isTentativeDefinition() ) {
1155 if ( atom
.getSize() > existingAtom
->getSize() ) {
1156 // replace common-symbol atom with another larger common-symbol
1157 if ( fOwner
.fOptions
.warnCommons() )
1158 fprintf(stderr
, "ld64: replacing common symbol %s size %lld from %s with larger symbol size %lld from %s\n",
1159 existingAtom
->getName(), existingAtom
->getSize(), existingAtom
->getFile()->getPath(), atom
.getSize(), atom
.getFile()->getPath());
1160 fOwner
.fDeadAtoms
.insert(existingAtom
);
1161 fTable
[name
] = &atom
;
1165 // keep existing common-symbol atom
1166 if ( fOwner
.fOptions
.warnCommons() ) {
1167 if ( atom
.getSize() == existingAtom
->getSize() )
1168 fprintf(stderr
, "ld64: ignoring common symbol %s from %s because already have common from %s with same size\n",
1169 atom
.getName(), atom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
1171 fprintf(stderr
, "ld64: ignoring common symbol %s size %lld from %s because already have larger symbol size %lld from %s\n",
1172 atom
.getName(), atom
.getSize(), atom
.getFile()->getPath(), existingAtom
->getSize(), existingAtom
->getFile()->getPath());
1174 fOwner
.fDeadAtoms
.insert(&atom
);
1179 // have common symbol, now found true defintion
1180 if ( atom
.isImportProxy() ) {
1181 // definition is in a dylib, so commons-mode decides how to handle
1182 switch ( fOwner
.fOptions
.commonsMode() ) {
1183 case Options::kCommonsIgnoreDylibs
:
1184 if ( fOwner
.fOptions
.warnCommons() )
1185 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
1186 existingAtom
->getName(), existingAtom
->getFile()->getPath(), atom
.getFile()->getPath());
1187 fOwner
.fDeadAtoms
.insert(&atom
);
1189 case Options::kCommonsOverriddenByDylibs
:
1190 if ( fOwner
.fOptions
.warnCommons() )
1191 fprintf(stderr
, "ld64: replacing common symbol %s from %s with true definition from %s\n",
1192 existingAtom
->getName(), existingAtom
->getFile()->getPath(), atom
.getFile()->getPath());
1193 fOwner
.fDeadAtoms
.insert(existingAtom
);
1194 fTable
[name
] = &atom
;
1196 case Options::kCommonsConflictsDylibsError
:
1197 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
1198 existingAtom
->getName(), existingAtom
->getFile()->getPath(), atom
.getFile()->getPath());
1202 // replace common-symbol atom with true definition from .o file
1203 if ( fOwner
.fOptions
.warnCommons() ) {
1204 if ( atom
.getSize() < existingAtom
->getSize() )
1205 fprintf(stderr
, "ld64: warning: replacing common symbol %s size %lld from %s with smaller true definition size %lld from %s\n",
1206 existingAtom
->getName(), existingAtom
->getSize(), existingAtom
->getFile()->getPath(), atom
.getSize(), atom
.getFile()->getPath());
1208 fprintf(stderr
, "ld64: replacing common symbol %s from %s with true definition from %s\n",
1209 existingAtom
->getName(), existingAtom
->getFile()->getPath(), atom
.getFile()->getPath());
1211 fOwner
.fDeadAtoms
.insert(existingAtom
);
1212 fTable
[name
] = &atom
;
1217 else if ( atom
.isTentativeDefinition() ) {
1218 // keep existing true definition, ignore new tentative definition
1219 if ( fOwner
.fOptions
.warnCommons() ) {
1220 if ( atom
.getSize() > existingAtom
->getSize() )
1221 fprintf(stderr
, "ld64: warning: ignoring common symbol %s size %lld from %s because already have definition from %s size %lld, even though definition is smaller\n",
1222 atom
.getName(), atom
.getSize(), atom
.getFile()->getPath(), existingAtom
->getFile()->getPath(), existingAtom
->getSize());
1224 fprintf(stderr
, "ld64: ignoring common symbol %s from %s because already have definition from %s\n",
1225 atom
.getName(), atom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
1227 fOwner
.fDeadAtoms
.insert(&atom
);
1231 // neither existing nor new atom are tentative definitions
1232 // if existing is weak, we may replace it
1233 if ( existingAtom
->isWeakDefinition() ) {
1234 if ( atom
.isImportProxy() ) {
1235 // keep weak definition even though one exists in a dylib, because coalescing means dylib's copy may not be used
1236 if ( log
) fprintf(stderr
, "keep weak atom even though also in a dylib: %s\n", atom
.getName());
1237 fOwner
.fDeadAtoms
.insert(&atom
);
1240 else if ( atom
.isWeakDefinition() ) {
1241 // have another weak atom, use existing, mark new as dead
1242 if ( log
) fprintf(stderr
, "already have weak atom: %s\n", atom
.getName());
1243 fOwner
.fDeadAtoms
.insert(&atom
);
1247 // replace weak atom with non-weak atom
1248 if ( log
) fprintf(stderr
, "replacing weak atom %p from %s with %p from %s: %s\n", existingAtom
, existingAtom
->getFile()->getPath(), &atom
, atom
.getFile()->getPath(), atom
.getName());
1249 fOwner
.fDeadAtoms
.insert(existingAtom
);
1250 fTable
[name
] = &atom
;
1255 if ( atom
.isWeakDefinition() ) {
1256 // ignore new weak atom, because we already have a non-weak one
1259 if ( atom
.isCoalesableByName() && existingAtom
->isCoalesableByName() ) {
1260 // both coalesable, so ignore duplicate
1263 fprintf(stderr
, "duplicate symbol %s in %s and %s\n", name
, atom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
1266 fTable
[name
] = &atom
;
1270 ObjectFile::Atom
* Linker::SymbolTable::find(const char* name
)
1272 Mapper::iterator pos
= fTable
.find(name
);
1273 if ( pos
!= fTable
.end() ) {
1280 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
)
1282 for (Mapper::iterator it
=fTable
.begin(); it
!= fTable
.end(); it
++) {
1283 if ( (it
->second
== NULL
) || (andWeakDefintions
&& it
->second
->isWeakDefinition()) ) {
1284 undefines
.push_back(it
->first
);
1292 bool Linker::AtomSorter::operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
)
1294 // first sort by section order (which is already sorted by segment)
1295 unsigned int leftSectionIndex
= left
->getSection()->getIndex();
1296 unsigned int rightSectionIndex
= right
->getSection()->getIndex();
1297 if ( leftSectionIndex
!= rightSectionIndex
)
1298 return (leftSectionIndex
< rightSectionIndex
);
1300 // with a section, sort by original atom order (.o file order and atom order in .o files)
1301 return left
->getSortOrder() < right
->getSortOrder();
1305 int main(int argc
, const char* argv
[])
1308 // create linker object given command line arguments
1309 Linker
ld(argc
, argv
);
1311 // open all input files
1320 catch (const char* msg
) {
1321 fprintf(stderr
, "ld64 failed: %s\n", msg
);