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>
47 #include <ext/hash_map>
51 #include "ObjectFile.h"
53 #include "MachOReaderRelocatable.hpp"
54 #include "MachOReaderArchive.hpp"
55 #include "MachOReaderDylib.hpp"
56 #include "MachOWriterExecutable.hpp"
58 #include "SectCreate.h"
61 static void dumpAtom(ObjectFile::Atom
* atom
)
63 //printf("atom: %p\n", atom);
66 printf("name: %s\n", atom
->getDisplayName());
69 switch ( atom
->getScope() ) {
70 case ObjectFile::Atom::scopeTranslationUnit
:
71 printf("scope: translation unit\n");
73 case ObjectFile::Atom::scopeLinkageUnit
:
74 printf("scope: linkage unit\n");
76 case ObjectFile::Atom::scopeGlobal
:
77 printf("scope: global\n");
80 printf("scope: unknown\n");
84 switch ( atom
->getDefinitinonKind() ) {
85 case ObjectFile::Atom::kRegularDefinition
:
86 printf("kind: regular\n");
88 case ObjectFile::Atom::kWeakDefinition
:
89 printf("kind: weak\n");
91 case ObjectFile::Atom::kTentativeDefinition
:
92 printf("kind: tentative\n");
94 case ObjectFile::Atom::kExternalDefinition
:
95 printf("kind: import\n");
97 case ObjectFile::Atom::kExternalWeakDefinition
:
98 printf("kind: weak import\n");
101 printf("scope: unknown\n");
104 // segment and section
105 printf("section: %s,%s\n", atom
->getSegment().getName(), atom
->getSectionName());
109 if ( atom
->dontDeadStrip() )
110 printf("dont-dead-strip ");
111 if ( atom
->isZeroFill() )
112 printf("zero-fill ");
116 printf("size: 0x%012llX\n", atom
->getSize());
119 uint8_t content
[atom
->getSize()];
120 atom
->copyRawContent(content
);
122 if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
123 printf("\"%s\"", content
);
126 for (unsigned int i
=0; i
< sizeof(content
); ++i
)
127 printf("%02X ", content
[i
]);
132 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
133 const int refCount
= references
.size();
134 printf("references: (%u)\n", refCount
);
135 for (int i
=0; i
< refCount
; ++i
) {
136 ObjectFile::Reference
* ref
= references
[i
];
137 printf(" %s\n", ref
->getDescription());
146 class CStringComparor
149 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) < 0); }
155 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
158 class Section
: public ObjectFile::Section
161 static Section
* find(const char* sectionName
, const char* segmentName
, bool zeroFill
);
162 static void assignIndexes();
165 Section(const char* sectionName
, const char* segmentName
, bool zeroFill
);
168 static int segmentOrdinal(const char* segName
);
169 bool operator()(Section
* left
, Section
* right
);
172 typedef __gnu_cxx::hash_map
<const char*, class Section
*, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToSection
;
173 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
175 const char* fSectionName
;
176 const char* fSegmentName
;
179 static NameToSection fgMapping
;
180 static std::vector
<Section
*> fgSections
;
183 Section::NameToSection
Section::fgMapping
;
184 std::vector
<Section
*> Section::fgSections
;
186 Section::Section(const char* sectionName
, const char* segmentName
, bool zeroFill
)
187 : fSectionName(sectionName
), fSegmentName(segmentName
), fZeroFill(zeroFill
)
189 //fprintf(stderr, "new Section(%s, %s)\n", sectionName, segmentName);
192 Section
* Section::find(const char* sectionName
, const char* segmentName
, bool zeroFill
)
194 NameToSection::iterator pos
= fgMapping
.find(sectionName
);
195 if ( pos
!= fgMapping
.end() ) {
196 if ( strcmp(pos
->second
->fSegmentName
, segmentName
) == 0 )
198 // otherwise same section name is used in different segments, look slow way
199 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++) {
200 if ( (strcmp((*it
)->fSectionName
, sectionName
) == 0) && (strcmp((*it
)->fSegmentName
, segmentName
) == 0) )
205 // does not exist, so make a new one
206 Section
* sect
= new Section(sectionName
, segmentName
, zeroFill
);
207 sect
->fIndex
= fgMapping
.size();
208 fgMapping
[sectionName
] = sect
;
209 fgSections
.push_back(sect
);
211 if ( (strcmp(sectionName
, "__text") == 0) && (strcmp(segmentName
, "__TEXT") == 0) ) {
212 // special case __textcoal_nt to be right after __text
213 find("__textcoal_nt", "__TEXT", false);
219 int Section::Sorter::segmentOrdinal(const char* segName
)
221 if ( strcmp(segName
, "__PAGEZERO") == 0 )
223 if ( strcmp(segName
, "__TEXT") == 0 )
225 if ( strcmp(segName
, "__DATA") == 0 )
227 if ( strcmp(segName
, "__OBJC") == 0 )
229 if ( strcmp(segName
, "__LINKEDIT") == 0 )
230 return INT_MAX
; // linkedit segment should always sort last
236 bool Section::Sorter::operator()(Section
* left
, Section
* right
)
238 // Segment is primary sort key
239 const char* leftSegName
= left
->fSegmentName
;
240 const char* rightSegName
= right
->fSegmentName
;
241 int segNameCmp
= strcmp(leftSegName
, rightSegName
);
242 if ( segNameCmp
!= 0 )
244 int leftSegOrdinal
= segmentOrdinal(leftSegName
);
245 int rightSegOrdinal
= segmentOrdinal(rightSegName
);
246 if ( leftSegOrdinal
< rightSegOrdinal
)
248 if ( leftSegOrdinal
== rightSegOrdinal
)
249 return segNameCmp
< 0;
253 // zerofill section sort to the end
254 if ( !left
->fZeroFill
&& right
->fZeroFill
)
256 if ( left
->fZeroFill
&& !right
->fZeroFill
)
259 // section discovery order is last sort key
260 return left
->fIndex
< right
->fIndex
;
263 void Section::assignIndexes()
265 //printf("unsorted:\n");
266 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
267 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
271 std::sort(fgSections
.begin(), fgSections
.end(), Section::Sorter());
273 // assign correct section ordering to each Section object
274 unsigned int newOrder
= 1;
275 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++)
276 (*it
)->fIndex
= newOrder
++;
278 //printf("sorted:\n");
279 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
280 // printf("section: name=%s\n", (*it)->fSectionName);
286 Linker(int argc
, const char* argv
[]);
288 const char* getArchPrefix();
289 const char* architectureName();
290 bool showArchitectureInErrors();
291 bool isInferredArchitecture();
292 void createReaders();
294 void addInputFile(ObjectFile::Reader
* reader
);
295 void setOutputFile(ExecutableFile::Writer
* writer
);
300 struct WhyLiveBackChain
302 WhyLiveBackChain
* previous
;
306 ObjectFile::Reader
* createReader(const Options::FileInfo
&);
307 void addAtom(ObjectFile::Atom
& atom
);
308 void addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
);
309 void buildAtomList();
310 void loadAndResolve();
311 void loadUndefines();
312 void checkUndefines();
313 void addWeakAtomOverrides();
314 void resolveReferences();
315 void deadStripResolve();
316 void addLiveRoot(const char* name
);
319 void writeDotOutput();
320 static bool minimizeStab(ObjectFile::Reader::Stab
& stab
);
321 static const char* truncateStabString(const char* str
);
322 void collectDebugInfo();
324 ObjectFile::Atom
* entryPoint();
325 ObjectFile::Atom
* dyldHelper();
326 const char* assureFullPath(const char* path
);
327 void markLive(ObjectFile::Atom
& atom
, Linker::WhyLiveBackChain
* previous
);
328 void collectStabs(ObjectFile::Reader
* reader
, std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
);
329 void synthesizeDebugNotes(std::vector
<class ObjectFile::Atom
*>& allAtomsByReader
);
330 void printStatistics();
331 void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
);
332 char* commatize(uint64_t in
, char* out
);
333 void getVMInfo(vm_statistics_data_t
& info
);
334 cpu_type_t
inferArchitecture();
336 void resolve(ObjectFile::Reference
* reference
);
337 void resolveFrom(ObjectFile::Reference
* reference
);
338 void addJustInTimeAtoms(const char* name
);
340 ObjectFile::Reader
* addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
341 ObjectFile::Reader
* addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
342 ObjectFile::Reader
* addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
343 void addIndirectLibraries(ObjectFile::Reader
* reader
);
344 bool haveIndirectLibrary(const char* path
, ObjectFile::Reader
* reader
);
345 bool haveDirectLibrary(const char* path
);
347 void logTraceInfo(const char* format
, ...);
353 SymbolTable(Linker
&);
354 void require(const char* name
);
355 bool add(ObjectFile::Atom
& atom
);
356 ObjectFile::Atom
* find(const char* name
);
357 unsigned int getRequireCount() { return fRequireCount
; }
358 void getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
);
360 typedef __gnu_cxx::hash_map
<const char*, ObjectFile::Atom
*, __gnu_cxx::hash
<const char*>, CStringEquals
> Mapper
;
363 unsigned int fRequireCount
;
368 bool operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
);
371 typedef std::map
<const char*, uint32_t, CStringComparor
> SectionOrder
;
373 struct IndirectLibrary
{
376 ObjectFile::Reader
* reader
;
377 std::set
<ObjectFile::Reader
*> parents
;
378 ObjectFile::Reader
* reExportedViaDirectLibrary
;
381 ObjectFile::Reader
* findDirectLibraryWhichReExports(struct IndirectLibrary
& indirectLib
);
384 SymbolTable fGlobalSymbolTable
;
385 unsigned int fWeakSymbolsAddedCount
;
386 std::vector
<class ObjectFile::Reader
*> fInputFiles
;
387 ExecutableFile::Writer
* fOutputFile
;
388 std::vector
<ExecutableFile::DyLibUsed
> fDynamicLibraries
;
389 std::list
<IndirectLibrary
> fIndirectDynamicLibraries
;
390 std::vector
<class ObjectFile::Reader
*> fReadersThatHaveSuppliedAtoms
;
391 std::vector
<class ObjectFile::Atom
*> fAllAtoms
;
392 std::set
<class ObjectFile::Atom
*> fDeadAtoms
;
393 std::set
<ObjectFile::Atom
*> fLiveAtoms
;
394 std::set
<ObjectFile::Atom
*> fLiveRootAtoms
;
395 std::vector
<class ObjectFile::Reader::Stab
> fStabs
;
396 std::vector
<class ObjectFile::Atom
*> fAtomsWithUnresolvedReferences
;
398 SectionOrder fSectionOrder
;
399 unsigned int fNextSortOrder
;
400 unsigned int fNextObjectFileOrder
;
401 cpu_type_t fArchitecture
;
402 const char* fArchitectureName
;
403 bool fArchitectureInferred
;
404 bool fDirectLibrariesComplete
;
405 uint64_t fOutputFileSize
;
407 uint64_t fStartCreateReadersTime
;
408 uint64_t fStartCreateWriterTime
;
409 uint64_t fStartBuildAtomsTime
;
410 uint64_t fStartLoadUndefinesTime
;
411 uint64_t fStartResolveTime
;
412 uint64_t fStartSortTime
;
413 uint64_t fStartDebugTime
;
414 uint64_t fStartWriteTime
;
416 uint64_t fTotalObjectSize
;
417 uint64_t fTotalArchiveSize
;
418 uint32_t fTotalObjectLoaded
;
419 uint32_t fTotalArchivesLoaded
;
420 uint32_t fTotalDylibsLoaded
;
421 vm_statistics_data_t fStartVMInfo
;
425 Linker::Linker(int argc
, const char* argv
[])
426 : fOptions(argc
, argv
), fGlobalSymbolTable(*this), fOutputFile(NULL
), fCreateUUID(false), fNextSortOrder(1),
427 fNextObjectFileOrder(1), fArchitecture(0), fArchitectureInferred(false), fDirectLibrariesComplete(false),
428 fOutputFileSize(0), fTotalObjectSize(0),
429 fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0)
431 fStartTime
= mach_absolute_time();
432 if ( fOptions
.printStatistics() )
433 getVMInfo(fStartVMInfo
);
435 fArchitecture
= fOptions
.architecture();
436 if ( fArchitecture
== 0 ) {
437 // -arch not specified, scan .o files to figure out what it should be
438 fArchitecture
= inferArchitecture();
439 fArchitectureInferred
= true;
441 switch (fArchitecture
) {
442 case CPU_TYPE_POWERPC
:
443 fArchitectureName
= "ppc";
445 case CPU_TYPE_POWERPC64
:
446 fArchitectureName
= "ppc64";
449 fArchitectureName
= "i386";
451 case CPU_TYPE_X86_64
:
452 fArchitectureName
= "x86_64";
455 fArchitectureName
= "unknown architecture";
460 const char* Linker::architectureName()
462 return fArchitectureName
;
465 bool Linker::showArchitectureInErrors()
467 return fOptions
.printArchPrefix();
470 bool Linker::isInferredArchitecture()
472 return fArchitectureInferred
;
475 cpu_type_t
Linker::inferArchitecture()
477 // scan all input files, looking for a thin .o file.
478 // the first one found is presumably the architecture to link
479 uint8_t buffer
[sizeof(mach_header_64
)];
480 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
481 for (std::vector
<Options::FileInfo
>::iterator it
= files
.begin(); it
!= files
.end(); ++it
) {
482 int fd
= ::open(it
->path
, O_RDONLY
, 0);
484 ssize_t amount
= read(fd
, buffer
, sizeof(buffer
));
486 if ( amount
>= (ssize_t
)sizeof(buffer
) ) {
487 if ( mach_o::relocatable::Reader
<ppc
>::validFile(buffer
) ) {
488 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc based on %s\n", it->path);
489 return CPU_TYPE_POWERPC
;
491 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(buffer
) ) {
492 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc64 based on %s\n", it->path);
493 return CPU_TYPE_POWERPC64
;
495 else if ( mach_o::relocatable::Reader
<x86
>::validFile(buffer
) ) {
496 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch i386 based on %s\n", it->path);
497 return CPU_TYPE_I386
;
499 else if ( mach_o::relocatable::Reader
<x86_64
>::validFile(buffer
) ) {
500 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch x86_64 based on %s\n", it->path);
501 return CPU_TYPE_X86_64
;
507 // no thin .o files found, so default to same architecture this was built as
508 fprintf(stderr
, "ld64 warning: -arch not specified\n");
510 return CPU_TYPE_POWERPC
;
512 return CPU_TYPE_I386
;
514 return CPU_TYPE_POWERPC64
;
516 return CPU_TYPE_X86_64
;
518 #error unknown default architecture
523 void Linker::addInputFile(ObjectFile::Reader
* reader
)
525 reader
->setSortOrder(fNextObjectFileOrder
++);
526 fInputFiles
.push_back(reader
);
529 void Linker::setOutputFile(ExecutableFile::Writer
* writer
)
531 fOutputFile
= writer
;
537 InSet(std::set
<ObjectFile::Atom
*>& deadAtoms
) : fDeadAtoms(deadAtoms
) {}
539 bool operator()(ObjectFile::Atom
*& atom
) const {
540 return ( fDeadAtoms
.count(atom
) != 0 );
544 std::set
<ObjectFile::Atom
*>& fDeadAtoms
;
547 void Linker::loadAndResolve()
549 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
550 // without dead-code-stripping:
551 // find atoms to resolve all undefines
552 this->loadUndefines();
553 // verify nothing is missing
554 this->checkUndefines();
555 // once all undefines fulfill, then bind all references
556 this->resolveReferences();
557 // remove atoms weak atoms that have been overridden
558 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fDeadAtoms
)), fAllAtoms
.end());
561 // with dead code stripping:
562 // start binding references from roots,
563 this->deadStripResolve();
564 // verify nothing is missing
565 this->checkUndefines();
571 this->buildAtomList();
572 this->loadAndResolve();
575 this->writeDotOutput();
576 this->collectDebugInfo();
578 this->printStatistics();
580 if ( fOptions
.pauseAtEnd() )
584 void Linker::printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
)
586 static uint64_t sUnitsPerSecond
= 0;
587 if ( sUnitsPerSecond
== 0 ) {
588 struct mach_timebase_info timeBaseInfo
;
589 if ( mach_timebase_info(&timeBaseInfo
) == KERN_SUCCESS
) {
590 sUnitsPerSecond
= 1000000000LL * timeBaseInfo
.denom
/ timeBaseInfo
.numer
;
591 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
594 if ( partTime
< sUnitsPerSecond
) {
595 uint32_t milliSecondsTimeTen
= (partTime
*10000)/sUnitsPerSecond
;
596 uint32_t milliSeconds
= milliSecondsTimeTen
/10;
597 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
598 uint32_t percent
= percentTimesTen
/10;
599 fprintf(stderr
, "%s: %u.%u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimeTen
-milliSeconds
*10, percent
, percentTimesTen
-percent
*10);
602 uint32_t secondsTimeTen
= (partTime
*10)/sUnitsPerSecond
;
603 uint32_t seconds
= secondsTimeTen
/10;
604 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
605 uint32_t percent
= percentTimesTen
/10;
606 fprintf(stderr
, "%s: %u.%u seconds (%u.%u%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10);
610 char* Linker::commatize(uint64_t in
, char* out
)
614 sprintf(rawNum
, "%llu", in
);
615 const int rawNumLen
= strlen(rawNum
);
616 for(int i
=0; i
< rawNumLen
-1; ++i
) {
618 if ( ((rawNumLen
-i
) % 3) == 1 )
621 *out
++ = rawNum
[rawNumLen
-1];
626 void Linker::getVMInfo(vm_statistics_data_t
& info
)
628 mach_msg_type_number_t count
= sizeof(vm_statistics_data_t
) / sizeof(natural_t
);
629 kern_return_t error
= host_statistics(mach_host_self(), HOST_VM_INFO
,
630 (host_info_t
)&info
, &count
);
631 if (error
!= KERN_SUCCESS
) {
632 bzero(&info
, sizeof(vm_statistics_data_t
));
636 void Linker::printStatistics()
638 fEndTime
= mach_absolute_time();
639 if ( fOptions
.printStatistics() ) {
640 vm_statistics_data_t endVMInfo
;
641 getVMInfo(endVMInfo
);
643 uint64_t totalTime
= fEndTime
- fStartTime
;
644 printTime("ld64 total time", totalTime
, totalTime
);
645 printTime(" option parsing time", fStartCreateReadersTime
- fStartTime
, totalTime
);
646 printTime(" object file processing",fStartCreateWriterTime
- fStartCreateReadersTime
, totalTime
);
647 printTime(" output file setup", fStartBuildAtomsTime
- fStartCreateWriterTime
, totalTime
);
648 printTime(" build atom list", fStartLoadUndefinesTime
- fStartBuildAtomsTime
, totalTime
);
649 printTime(" load undefines", fStartResolveTime
- fStartLoadUndefinesTime
, totalTime
);
650 printTime(" resolve references", fStartSortTime
- fStartResolveTime
, totalTime
);
651 printTime(" sort output", fStartDebugTime
- fStartSortTime
, totalTime
);
652 printTime(" process debug info", fStartWriteTime
- fStartDebugTime
, totalTime
);
653 printTime(" write output", fEndTime
- fStartWriteTime
, totalTime
);
654 fprintf(stderr
, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo
.pageins
-fStartVMInfo
.pageins
,
655 endVMInfo
.pageouts
-fStartVMInfo
.pageouts
, endVMInfo
.faults
-fStartVMInfo
.faults
);
657 fprintf(stderr
, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded
, commatize(fTotalObjectSize
, temp
));
658 fprintf(stderr
, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded
, commatize(fTotalArchiveSize
, temp
));
659 fprintf(stderr
, "processed %3u dylib files\n", fTotalDylibsLoaded
);
660 fprintf(stderr
, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize
, temp
));
664 inline void Linker::addAtom(ObjectFile::Atom
& atom
)
666 // add to list of all atoms
667 fAllAtoms
.push_back(&atom
);
669 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
670 // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later
671 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
672 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
673 ObjectFile::Reference
* reference
= *it
;
674 if ( reference
->isTargetUnbound() ) {
675 fGlobalSymbolTable
.require(reference
->getTargetName());
677 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() )
678 fGlobalSymbolTable
.require(reference
->getFromTargetName());
682 if ( atom
.dontDeadStrip() )
683 fLiveRootAtoms
.insert(&atom
);
686 // if in global namespace, add atom itself to symbol table
687 ObjectFile::Atom::Scope scope
= atom
.getScope();
688 const char* name
= atom
.getName();
689 if ( (scope
!= ObjectFile::Atom::scopeTranslationUnit
) && (name
!= NULL
) ) {
690 fGlobalSymbolTable
.add(atom
);
692 // update scope based on export list (possible that globals are downgraded to private_extern)
693 if ( (scope
== ObjectFile::Atom::scopeGlobal
) && fOptions
.hasExportRestrictList() ) {
694 bool doExport
= fOptions
.shouldExport(name
);
696 atom
.setScope(ObjectFile::Atom::scopeLinkageUnit
);
701 // record section orders so output file can have same order
702 atom
.setSection(Section::find(atom
.getSectionName(), atom
.getSegment().getName(), atom
.isZeroFill()));
704 // assign order in which this atom was originally seen
705 if ( atom
.getSortOrder() == 0 )
706 fNextSortOrder
= atom
.setSortOrder(fNextSortOrder
);
709 inline void Linker::addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
)
711 bool first
= true; // assume all atoms are from same reader
712 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
.begin(); it
!= atoms
.end(); it
++) {
714 // update fReadersThatHaveSuppliedAtoms
715 ObjectFile::Reader
* reader
= (*it
)->getFile();
716 if ( std::find(fReadersThatHaveSuppliedAtoms
.begin(), fReadersThatHaveSuppliedAtoms
.end(), reader
)
717 == fReadersThatHaveSuppliedAtoms
.end() ) {
718 fReadersThatHaveSuppliedAtoms
.push_back(reader
);
726 void Linker::buildAtomList()
728 fStartBuildAtomsTime
= mach_absolute_time();
729 // add initial undefines from -u option
730 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
731 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++) {
732 fGlobalSymbolTable
.require(*it
);
735 // writer can contribute atoms
736 this->addAtoms(fOutputFile
->getAtoms());
738 // each reader contributes atoms
739 const int readerCount
= fInputFiles
.size();
740 for (int i
=0; i
< readerCount
; ++i
) {
741 this->addAtoms(fInputFiles
[i
]->getAtoms());
744 // extra command line section always at end
745 std::vector
<Options::ExtraSection
>& extraSections
= fOptions
.extraSections();
746 for( std::vector
<Options::ExtraSection
>::iterator it
=extraSections
.begin(); it
!= extraSections
.end(); ++it
) {
747 this->addAtoms(SectCreate::MakeReader(it
->segmentName
, it
->sectionName
, it
->path
, it
->data
, it
->dataLen
)->getAtoms());
751 static const char* pathLeafName(const char* path
)
753 const char* shortPath
= strrchr(path
, '/');
754 if ( shortPath
== NULL
)
757 return &shortPath
[1];
760 void Linker::loadUndefines()
762 fStartLoadUndefinesTime
= mach_absolute_time();
763 // keep looping until no more undefines were added in last loop
764 unsigned int undefineCount
= 0xFFFFFFFF;
765 while ( undefineCount
!= fGlobalSymbolTable
.getRequireCount() ) {
766 undefineCount
= fGlobalSymbolTable
.getRequireCount();
767 std::vector
<const char*> undefineNames
;
768 fGlobalSymbolTable
.getNeededNames(false, undefineNames
);
769 for(std::vector
<const char*>::iterator it
= undefineNames
.begin(); it
!= undefineNames
.end(); ++it
) {
770 const char* name
= *it
;
771 ObjectFile::Atom
* possibleAtom
= fGlobalSymbolTable
.find(name
);
772 if ( (possibleAtom
== NULL
)
773 || ((possibleAtom
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
) && (fOptions
.outputKind() != Options::kObjectFile
) && (possibleAtom
->getScope() == ObjectFile::Atom::scopeGlobal
)) )
774 this->addJustInTimeAtoms(name
);
779 void Linker::checkUndefines()
781 if ( fOptions
.outputKind() != Options::kObjectFile
) {
782 // error out on any remaining undefines
785 switch ( fOptions
.undefinedTreatment() ) {
786 case Options::kUndefinedError
:
788 case Options::kUndefinedDynamicLookup
:
791 case Options::kUndefinedWarning
:
794 case Options::kUndefinedSuppress
:
799 std::vector
<const char*> unresolvableUndefines
;
800 fGlobalSymbolTable
.getNeededNames(false, unresolvableUndefines
);
801 const int unresolvableCount
= unresolvableUndefines
.size();
802 int unresolvableExportsCount
= 0;
803 if ( unresolvableCount
!= 0 ) {
805 if ( fOptions
.printArchPrefix() )
806 fprintf(stderr
, "Undefined symbols for architecture %s:\n", fArchitectureName
);
808 fprintf(stderr
, "Undefined symbols:\n");
809 for (int i
=0; i
< unresolvableCount
; ++i
) {
810 const char* name
= unresolvableUndefines
[i
];
811 fprintf(stderr
, " %s, referenced from:\n", name
);
812 // scan all atoms for references
813 bool foundAtomReference
= false;
814 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
815 ObjectFile::Atom
* atom
= *it
;
816 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
817 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
818 ObjectFile::Reference
* reference
= *rit
;
819 if ( reference
->isTargetUnbound() ) {
820 if ( strcmp(reference
->getTargetName(), name
) == 0 ) {
821 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
822 foundAtomReference
= true;
825 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() ) {
826 if ( strcmp(reference
->getFromTargetName(), name
) == 0 ) {
827 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
828 foundAtomReference
= true;
833 // scan command line options
834 if ( !foundAtomReference
&& fOptions
.hasExportRestrictList() && fOptions
.shouldExport(name
) ) {
835 fprintf(stderr
, " -exported_symbols_list command line option\n");
836 ++unresolvableExportsCount
;
840 if ( doError
&& (unresolvableCount
> unresolvableExportsCount
) ) // last check should be removed. It exists so broken projects still build
841 throw "symbol(s) not found";
848 void Linker::addJustInTimeAtoms(const char* name
)
850 // when creating final linked image, writer gets first chance
851 if ( fOptions
.outputKind() != Options::kObjectFile
) {
852 std::vector
<class ObjectFile::Atom
*>* atoms
= fOutputFile
->getJustInTimeAtomsFor(name
);
853 if ( atoms
!= NULL
) {
854 this->addAtoms(*atoms
);
856 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
857 return; // found a definition, no need to search anymore
861 // give direct readers a chance
862 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
863 ObjectFile::Reader
* reader
= *it
;
864 if ( reader
!= NULL
) {
865 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
866 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
867 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
868 if ( atoms
!= NULL
) {
869 this->addAtoms(*atoms
);
871 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fInputFiles[i]->getPath() );
872 return; // found a definition, no need to search anymore
877 // give indirect readers a chance
878 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
879 ObjectFile::Reader
* reader
= it
->reader
;
880 // for two-level namespace, only search re-exported indirect libraries
881 if ( (reader
!= NULL
) && ((it
->reExportedViaDirectLibrary
!= NULL
) || (fOptions
.nameSpace() != Options::kTwoLevelNameSpace
)) ) {
882 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
883 if ( atoms
!= NULL
) {
884 this->addAtoms(*atoms
);
885 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
887 return; // found a definition, no need to search anymore
892 // when creating .o file, writer goes last (this is so any static archives will be searched above)
893 if ( (fOptions
.outputKind() == Options::kObjectFile
) || (fOptions
.undefinedTreatment() != Options::kUndefinedError
) ) {
894 ObjectFile::Atom
* atom
= fOutputFile
->getUndefinedProxyAtom(name
);
895 if ( atom
!= NULL
) {
896 this->addAtom(*atom
);
900 //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
903 void Linker::resolve(ObjectFile::Reference
* reference
)
905 // look in global symbol table
906 const char* targetName
= reference
->getTargetName();
907 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
908 if ( target
== NULL
) {
909 fprintf(stderr
, "Undefined symbol: %s\n", targetName
);
911 reference
->setTarget(*target
, reference
->getTargetOffset());
914 void Linker::resolveFrom(ObjectFile::Reference
* reference
)
916 // handle references that have two (from and to) targets
917 const char* fromTargetName
= reference
->getFromTargetName();
918 ObjectFile::Atom
* fromTarget
= fGlobalSymbolTable
.find(fromTargetName
);
919 if ( fromTarget
== NULL
) {
920 fprintf(stderr
, "Undefined symbol: %s\n", fromTargetName
);
922 reference
->setFromTarget(*fromTarget
);
926 void Linker::resolveReferences()
928 fStartResolveTime
= mach_absolute_time();
929 // note: the atom list may grow during this loop as libraries supply needed atoms
930 for (unsigned int j
=0; j
< fAllAtoms
.size(); ++j
) {
931 ObjectFile::Atom
* atom
= fAllAtoms
[j
];
932 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
933 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
934 ObjectFile::Reference
* reference
= *it
;
935 if ( reference
->isTargetUnbound() )
936 this->resolve(reference
);
937 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() )
938 this->resolveFrom(reference
);
944 // used to remove stabs associated with atoms that won't be in output file
948 NotInSet(std::set
<ObjectFile::Atom
*>& theSet
) : fSet(theSet
) {}
950 bool operator()(const ObjectFile::Reader::Stab
& stab
) const {
951 if ( stab
.atom
== NULL
)
952 return false; // leave stabs that are not associated with any atome
954 return ( fSet
.count(stab
.atom
) == 0 );
958 std::set
<ObjectFile::Atom
*>& fSet
;
965 NotLive(std::set
<ObjectFile::Atom
*>& set
) : fLiveAtoms(set
) {}
967 bool operator()(ObjectFile::Atom
*& atom
) const {
968 //if ( fLiveAtoms.count(atom) == 0 )
969 // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
970 return ( fLiveAtoms
.count(atom
) == 0 );
973 std::set
<ObjectFile::Atom
*>& fLiveAtoms
;
978 void Linker::markLive(ObjectFile::Atom
& atom
, struct Linker::WhyLiveBackChain
* previous
)
980 if ( fLiveAtoms
.count(&atom
) == 0 ) {
981 // if -whylive cares about this symbol, then dump chain
982 if ( (previous
->name
!= NULL
) && fOptions
.printWhyLive(previous
->name
) ) {
984 for(WhyLiveBackChain
* p
= previous
; p
!= NULL
; p
= p
->previous
, ++depth
) {
985 for(int i
=depth
; i
> 0; --i
)
986 fprintf(stderr
, " ");
987 fprintf(stderr
, "%s\n", p
->name
);
991 WhyLiveBackChain thisChain
;
992 thisChain
.previous
= previous
;
994 fLiveAtoms
.insert(&atom
);
995 // and all atoms it references
996 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
997 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
998 ObjectFile::Reference
* reference
= *it
;
999 if ( reference
->isTargetUnbound() ) {
1000 // look in global symbol table
1001 const char* targetName
= reference
->getTargetName();
1002 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1003 if ( target
== NULL
) {
1004 // load archives or dylibs
1005 this->addJustInTimeAtoms(targetName
);
1008 target
= fGlobalSymbolTable
.find(targetName
);
1009 if ( target
!= NULL
) {
1010 reference
->setTarget(*target
, reference
->getTargetOffset());
1013 // mark as undefined, for later error processing
1014 fAtomsWithUnresolvedReferences
.push_back(&atom
);
1015 fGlobalSymbolTable
.require(targetName
);
1018 if ( ! reference
->isTargetUnbound() ) {
1019 thisChain
.name
= reference
->getTargetName();
1020 markLive(reference
->getTarget(), &thisChain
);
1022 if ( reference
->hasFromTarget() ) {
1023 // do the same as above, for from target
1024 if ( reference
->isFromTargetUnbound() ) {
1025 // look in global symbol table
1026 const char* targetName
= reference
->getFromTargetName();
1027 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1028 if ( target
== NULL
) {
1029 // load archives or dylibs
1030 this->addJustInTimeAtoms(targetName
);
1033 target
= fGlobalSymbolTable
.find(targetName
);
1034 if ( target
!= NULL
) {
1035 reference
->setFromTarget(*target
);
1038 // mark as undefined, for later error processing
1039 fGlobalSymbolTable
.require(targetName
);
1042 if ( ! reference
->isFromTargetUnbound() ) {
1043 thisChain
.name
= reference
->getFromTargetName();
1044 markLive(reference
->getFromTarget(), &thisChain
);
1052 void Linker::addLiveRoot(const char* name
)
1054 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(name
);
1055 if ( target
== NULL
) {
1056 this->addJustInTimeAtoms(name
);
1057 target
= fGlobalSymbolTable
.find(name
);
1059 if ( target
!= NULL
)
1060 fLiveRootAtoms
.insert(target
);
1064 void Linker::deadStripResolve()
1066 // add main() to live roots
1067 ObjectFile::Atom
* entryPoint
= this->entryPoint();
1068 if ( entryPoint
!= NULL
)
1069 fLiveRootAtoms
.insert(entryPoint
);
1071 // add dyld_stub_binding_helper() to live roots
1072 ObjectFile::Atom
* dyldHelper
= this->dyldHelper();
1073 if ( dyldHelper
!= NULL
)
1074 fLiveRootAtoms
.insert(dyldHelper
);
1076 // add -exported_symbols_list, -init, and -u entries to live roots
1077 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
1078 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++)
1081 // in some cases, every global scope atom in initial .o files is a root
1082 if ( fOptions
.allGlobalsAreDeadStripRoots() ) {
1083 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1084 ObjectFile::Atom
* atom
= *it
;
1085 if ( atom
->getScope() == ObjectFile::Atom::scopeGlobal
)
1086 fLiveRootAtoms
.insert(atom
);
1090 // mark all roots as live, and all atoms they reference
1091 for (std::set
<ObjectFile::Atom
*>::iterator it
=fLiveRootAtoms
.begin(); it
!= fLiveRootAtoms
.end(); it
++) {
1092 WhyLiveBackChain rootChain
;
1093 rootChain
.previous
= NULL
;
1094 rootChain
.name
= (*it
)->getDisplayName();
1095 markLive(**it
, &rootChain
);
1098 // it is possible that there are unresolved references that can be resolved now
1099 // this can happen if the first reference to a common symbol in an archive.
1100 // common symbols are not in the archive TOC, but the .o could have been pulled in later.
1101 // <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
1102 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAtomsWithUnresolvedReferences
.begin(); it
!= fAtomsWithUnresolvedReferences
.end(); it
++) {
1103 std::vector
<class ObjectFile::Reference
*>& references
= (*it
)->getReferences();
1104 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1105 ObjectFile::Reference
* reference
= *rit
;
1106 if ( reference
->isTargetUnbound() ) {
1107 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(reference
->getTargetName());
1108 if ( target
!= NULL
) {
1109 reference
->setTarget(*target
, reference
->getTargetOffset());
1110 fLiveAtoms
.insert(target
);
1111 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1112 // references, which is true for commons.
1113 if ( target
->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition
)
1114 fprintf(stderr
, "warning: ld64 internal error %s is not a tentative definition\n", target
->getDisplayName());
1117 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() ) {
1118 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(reference
->getFromTargetName());
1119 if ( target
!= NULL
) {
1120 reference
->setFromTarget(*target
);
1121 fLiveAtoms
.insert(target
);
1122 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1123 // references, which is true for commons.
1124 if ( target
->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition
)
1125 fprintf(stderr
, "warning: ld64 internal error %s is not a tentative definition\n", target
->getDisplayName());
1131 // now remove all non-live atoms from fAllAtoms
1132 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), NotLive(fLiveAtoms
)), fAllAtoms
.end());
1135 void Linker::sortAtoms()
1137 fStartSortTime
= mach_absolute_time();
1138 Section::assignIndexes();
1139 std::sort(fAllAtoms
.begin(), fAllAtoms
.end(), Linker::AtomSorter());
1140 //fprintf(stderr, "Sorted atoms:\n");
1141 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1142 // fprintf(stderr, "\t%s\n", (*it)->getDisplayName());
1147 // make sure given addresses are within reach of branches, etc
1148 void Linker::tweakLayout()
1153 void Linker::writeDotOutput()
1155 const char* dotOutFilePath
= fOptions
.dotOutputFile();
1156 if ( dotOutFilePath
!= NULL
) {
1157 FILE* out
= fopen(dotOutFilePath
, "w");
1158 if ( out
!= NULL
) {
1160 fprintf(out
, "digraph dg\n{\n");
1161 fprintf(out
, "\tconcentrate = true;\n");
1162 fprintf(out
, "\trankdir = LR;\n");
1164 // print each atom as a node
1165 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1166 ObjectFile::Atom
* atom
= *it
;
1167 if ( atom
->getFile() != fOutputFile
) {
1168 const char* name
= atom
->getDisplayName();
1169 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
1170 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1171 fprintf(out
, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom
, name
);
1173 else if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
1174 char cstring
[atom
->getSize()+2];
1175 atom
->copyRawContent((uint8_t*)cstring
);
1176 fprintf(out
, "\taddr%p [ label = \"string: '", atom
);
1177 for (const char* s
=cstring
; *s
!= '\0'; ++s
) {
1179 fprintf(out
, "\\\\n");
1183 fprintf(out
, "'\" ];\n");
1186 fprintf(out
, "\taddr%p [ label = \"%s\" ];\n", atom
, name
);
1192 // print each reference as an edge
1193 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1194 ObjectFile::Atom
* fromAtom
= *it
;
1195 if ( fromAtom
->getFile() != fOutputFile
) {
1196 std::vector
<ObjectFile::Reference
*>& references
= fromAtom
->getReferences();
1197 std::set
<ObjectFile::Atom
*> seenTargets
;
1198 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1199 ObjectFile::Reference
* reference
= *rit
;
1200 ObjectFile::Atom
* toAtom
= &(reference
->getTarget());
1201 if ( seenTargets
.count(toAtom
) == 0 ) {
1202 seenTargets
.insert(toAtom
);
1203 fprintf(out
, "\taddr%p -> addr%p;\n", fromAtom
, toAtom
);
1210 // push all imports to bottom of graph
1211 fprintf(out
, "{ rank = same; ");
1212 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1213 ObjectFile::Atom
* atom
= *it
;
1214 if ( atom
->getFile() != fOutputFile
)
1215 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
1216 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1217 fprintf(out
, "addr%p; ", atom
);
1220 fprintf(out
, "};\n ");
1223 fprintf(out
, "}\n");
1227 fprintf(stderr
, "ld64 warning: could not write dot output file: %s\n", dotOutFilePath
);
1232 ObjectFile::Atom
* Linker::entryPoint()
1234 // if main executable, find entry point atom
1235 ObjectFile::Atom
* entryPoint
= NULL
;
1236 switch ( fOptions
.outputKind() ) {
1237 case Options::kDynamicExecutable
:
1238 case Options::kStaticExecutable
:
1239 case Options::kDyld
:
1240 entryPoint
= fGlobalSymbolTable
.find(fOptions
.entryName());
1241 if ( entryPoint
== NULL
) {
1242 throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions
.entryName());
1245 case Options::kDynamicLibrary
:
1246 if ( fOptions
.initFunctionName() != NULL
) {
1247 entryPoint
= fGlobalSymbolTable
.find(fOptions
.initFunctionName());
1248 if ( entryPoint
== NULL
) {
1249 throwf("could not find -init function: \"%s\"", fOptions
.initFunctionName());
1253 case Options::kObjectFile
:
1254 case Options::kDynamicBundle
:
1261 ObjectFile::Atom
* Linker::dyldHelper()
1263 return fGlobalSymbolTable
.find("dyld_stub_binding_helper");
1266 const char* Linker::assureFullPath(const char* path
)
1268 if ( path
[0] == '/' )
1270 char cwdbuff
[MAXPATHLEN
];
1271 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
1273 asprintf(&result
, "%s/%s", cwdbuff
, path
);
1274 if ( result
!= NULL
)
1282 // The stab strings are of the form:
1283 // <name> ':' <type-code> <number-pari>
1284 // but the <name> contain a colon.
1285 // For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
1286 // For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
1288 const char* Linker::truncateStabString(const char* str
)
1290 enum { start
, inObjc
} state
= start
;
1291 for (const char* s
= str
; *s
!= 0; ++s
) {
1300 if ( s
[1] == ':' ) {
1305 // Duplicate strndup behavior here.
1306 int trunStrLen
= s
-str
+2;
1307 char* temp
= new char[trunStrLen
+1];
1308 memcpy(temp
, str
, trunStrLen
);
1309 temp
[trunStrLen
] = '\0';
1327 bool Linker::minimizeStab(ObjectFile::Reader::Stab
& stab
)
1334 // these all need truncated strings
1335 stab
.string
= truncateStabString(stab
.string
);
1341 // these are included in the minimal stabs, but they keep their full string
1349 struct HeaderRange
{
1350 std::vector
<ObjectFile::Reader::Stab
>::iterator begin
;
1351 std::vector
<ObjectFile::Reader::Stab
>::iterator end
;
1352 int parentRangeIndex
;
1354 bool sumPrecomputed
;
1356 bool cannotEXCL
; // because of SLINE, etc stabs
1360 typedef __gnu_cxx::hash_map
<const char*, std::vector
<uint32_t>, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToSums
;
1362 // hash table that maps header path to a vector of known checksums for that path
1363 static PathToSums sKnownBINCLs
;
1366 void Linker::collectStabs(ObjectFile::Reader
* reader
, std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
)
1369 bool minimal
= ( fOptions
.readerOptions().fDebugInfoStripping
== ObjectFile::ReaderOptions::kDebugInfoMinimal
);
1370 std::vector
<class ObjectFile::Reader::Stab
>* readerStabs
= reader
->getStabs();
1371 if ( readerStabs
== NULL
)
1374 if ( log
) fprintf(stderr
, "processesing %lu stabs for %s\n", readerStabs
->size(), reader
->getPath());
1375 std::vector
<HeaderRange
> ranges
;
1376 int curRangeIndex
= -1;
1378 ObjectFile::Atom
* atomWithLowestOrdinal
= NULL
;
1379 ObjectFile::Atom
* atomWithHighestOrdinal
= NULL
;
1380 uint32_t highestOrdinal
= 0;
1381 uint32_t lowestOrdinal
= UINT_MAX
;
1382 std::vector
<std::pair
<ObjectFile::Atom
*,ObjectFile::Atom
*> > soRanges
;
1383 // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums
1384 // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein
1385 for(std::vector
<class ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
1387 switch ( it
->type
) {
1392 range
.end
= readerStabs
->end();
1393 range
.parentRangeIndex
= curRangeIndex
;
1394 range
.sum
= it
->value
;
1395 range
.sumPrecomputed
= (range
.sum
!= 0);
1396 range
.useEXCL
= false;
1397 range
.cannotEXCL
= false;
1398 curRangeIndex
= ranges
.size();
1399 if ( log
) fprintf(stderr
, "[%d]BINCL %s\n", curRangeIndex
, it
->string
);
1400 ranges
.push_back(range
);
1404 if ( curRangeIndex
== -1 ) {
1405 fprintf(stderr
, "ld64 warning: EINCL missing BINCL in %s\n", reader
->getPath());
1408 ranges
[curRangeIndex
].end
= it
+1;
1409 if ( log
) fprintf(stderr
, "[%d->%d]EINCL %s\n", curRangeIndex
, ranges
[curRangeIndex
].parentRangeIndex
, it
->string
);
1410 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
1415 std::map
<const class ObjectFile::Atom
*, uint32_t>::iterator pos
= atomOrdinals
.find(it
->atom
);
1416 if ( pos
!= atomOrdinals
.end() ) {
1417 uint32_t ordinal
= pos
->second
;
1418 if ( ordinal
> highestOrdinal
) {
1419 highestOrdinal
= ordinal
;
1420 atomWithHighestOrdinal
= it
->atom
;
1422 if ( ordinal
< lowestOrdinal
) {
1423 lowestOrdinal
= ordinal
;
1424 atomWithLowestOrdinal
= it
->atom
;
1436 if ( curRangeIndex
!= -1 ) {
1437 ranges
[curRangeIndex
].cannotEXCL
= true;
1438 if ( fOptions
.warnStabs() )
1439 fprintf(stderr
, "ld64: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
1443 if ( (it
->string
!= NULL
) && (strlen(it
->string
) > 0) ) {
1444 // start SO, reset hi/low FUN tracking
1445 atomWithLowestOrdinal
= NULL
;
1446 atomWithHighestOrdinal
= NULL
;
1448 lowestOrdinal
= UINT_MAX
;
1451 // end SO, record hi/low atoms for this SO range
1452 soRanges
.push_back(std::make_pair
<ObjectFile::Atom
*,ObjectFile::Atom
*>(atomWithLowestOrdinal
, atomWithHighestOrdinal
));
1456 if ( curRangeIndex
!= -1 ) {
1457 if ( ! ranges
[curRangeIndex
].sumPrecomputed
) {
1459 const char* s
= it
->string
;
1461 while ( (c
= *s
++) != 0 ) {
1463 // don't checkusm first number (file index) after open paren in string
1469 ranges
[curRangeIndex
].sum
+= sum
;
1475 if ( log
) fprintf(stderr
, "processesed %d stabs for %s\n", count
, reader
->getPath());
1476 if ( curRangeIndex
!= -1 )
1477 fprintf(stderr
, "ld64 warning: BINCL (%s) missing EINCL in %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
1480 if ( ranges
.size() == 0 ) {
1482 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
1483 // copy minimal or all stabs
1484 ObjectFile::Reader::Stab stab
= *it
;
1485 if ( !minimal
|| minimizeStab(stab
) ) {
1486 if ( stab
.type
== N_SO
) {
1487 if ( (stab
.string
!= NULL
) && (strlen(stab
.string
) > 0) ) {
1488 // starting SO is associated with first atom
1489 stab
.atom
= soRanges
[soIndex
].first
;
1492 // ending SO is associated with last atom
1493 stab
.atom
= soRanges
[soIndex
].second
;
1497 fStabs
.push_back(stab
);
1503 //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
1504 //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
1505 // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
1508 // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
1509 for(std::vector
<HeaderRange
>::iterator it
=ranges
.begin(); it
!= ranges
.end(); ++it
) {
1510 if ( ! it
->cannotEXCL
) {
1511 const char* header
= it
->begin
->string
;
1512 uint32_t sum
= it
->sum
;
1513 PathToSums::iterator pos
= sKnownBINCLs
.find(header
);
1514 if ( pos
!= sKnownBINCLs
.end() ) {
1515 std::vector
<uint32_t>& sums
= pos
->second
;
1516 for(std::vector
<uint32_t>::iterator sit
=sums
.begin(); sit
!= sums
.end(); ++sit
) {
1518 //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
1523 if ( ! it
->useEXCL
) {
1524 // have seen this path, but not this checksum
1525 //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
1526 sums
.push_back(sum
);
1530 // have not seen this path, so add to known BINCLs
1531 std::vector
<uint32_t> empty
;
1532 sKnownBINCLs
[header
] = empty
;
1533 sKnownBINCLs
[header
].push_back(sum
);
1534 //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
1539 // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
1541 const int maxRangeIndex
= ranges
.size();
1543 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
1544 switch ( it
->type
) {
1546 for(int i
=curRangeIndex
+1; i
< maxRangeIndex
; ++i
) {
1547 if ( ranges
[i
].begin
== it
) {
1549 HeaderRange
& range
= ranges
[curRangeIndex
];
1550 ObjectFile::Reader::Stab stab
= *it
;
1551 stab
.value
= range
.sum
; // BINCL and EXCL have n_value set to checksum
1552 if ( range
.useEXCL
)
1553 stab
.type
= N_EXCL
; // transform BINCL into EXCL
1555 fStabs
.push_back(stab
);
1561 if ( curRangeIndex
!= -1 ) {
1562 if ( !ranges
[curRangeIndex
].useEXCL
&& !minimal
)
1563 fStabs
.push_back(*it
);
1564 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
1568 if ( (curRangeIndex
== -1) || !ranges
[curRangeIndex
].useEXCL
) {
1569 ObjectFile::Reader::Stab stab
= *it
;
1570 if ( !minimal
|| minimizeStab(stab
) ) {
1571 if ( stab
.type
== N_SO
) {
1572 if ( (stab
.string
!= NULL
) || (strlen(stab
.string
) > 0) ) {
1573 // starting SO is associated with first atom
1574 stab
.atom
= soRanges
[soIndex
].first
;
1577 // ending SO is associated with last atom
1578 stab
.atom
= soRanges
[soIndex
].second
;
1582 fStabs
.push_back(stab
);
1591 // used to prune out atoms that don't need debug notes generated
1592 class NoDebugNoteAtom
1595 NoDebugNoteAtom(const std::map
<class ObjectFile::Reader
*, uint32_t>& readersWithDwarfOrdinals
)
1596 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals
) {}
1598 bool operator()(const ObjectFile::Atom
* atom
) const {
1599 if ( atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
)
1601 if ( atom
->getName() == NULL
)
1603 if ( fReadersWithDwarfOrdinals
.find(atom
->getFile()) == fReadersWithDwarfOrdinals
.end() )
1609 const std::map
<class ObjectFile::Reader
*, uint32_t>& fReadersWithDwarfOrdinals
;
1612 // used to sort atoms with debug notes
1613 class ReadersWithDwarfSorter
1616 ReadersWithDwarfSorter(const std::map
<class ObjectFile::Reader
*, uint32_t>& readersWithDwarfOrdinals
,
1617 const std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
)
1618 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals
), fAtomOrdinals(atomOrdinals
) {}
1620 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
) const
1622 // first sort by reader
1623 unsigned int leftReaderIndex
= fReadersWithDwarfOrdinals
.find(left
->getFile())->second
;
1624 unsigned int rightReaderIndex
= fReadersWithDwarfOrdinals
.find(right
->getFile())->second
;
1625 if ( leftReaderIndex
!= rightReaderIndex
)
1626 return (leftReaderIndex
< rightReaderIndex
);
1628 // then sort by atom ordinal
1629 unsigned int leftAtomIndex
= fAtomOrdinals
.find(left
)->second
;
1630 unsigned int rightAtomIndex
= fAtomOrdinals
.find(right
)->second
;
1631 return leftAtomIndex
< rightAtomIndex
;
1635 const std::map
<class ObjectFile::Reader
*, uint32_t>& fReadersWithDwarfOrdinals
;
1636 const std::map
<const class ObjectFile::Atom
*, uint32_t>& fAtomOrdinals
;
1643 void Linker::synthesizeDebugNotes(std::vector
<class ObjectFile::Atom
*>& allAtomsByReader
)
1645 // synthesize "debug notes" and add them to master stabs vector
1646 const char* dirPath
= NULL
;
1647 const char* filename
= NULL
;
1648 bool wroteStartSO
= false;
1649 __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> seenFiles
;
1650 for (std::vector
<ObjectFile::Atom
*>::iterator it
=allAtomsByReader
.begin(); it
!= allAtomsByReader
.end(); it
++) {
1651 ObjectFile::Atom
* atom
= *it
;
1652 const char* newDirPath
;
1653 const char* newFilename
;
1654 //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
1655 if ( atom
->getTranslationUnitSource(&newDirPath
, &newFilename
) ) {
1656 // need SO's whenever the translation unit source file changes
1657 if ( newFilename
!= filename
) {
1658 // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
1659 if ( (newDirPath
!= NULL
) && (strlen(newDirPath
) > 1 ) && (newDirPath
[strlen(newDirPath
)-1] != '/') )
1660 asprintf((char**)&newDirPath
, "%s/", newDirPath
);
1661 if ( filename
!= NULL
) {
1662 // translation unit change, emit ending SO
1663 ObjectFile::Reader::Stab endFileStab
;
1664 endFileStab
.atom
= NULL
;
1665 endFileStab
.type
= N_SO
;
1666 endFileStab
.other
= 1;
1667 endFileStab
.desc
= 0;
1668 endFileStab
.value
= 0;
1669 endFileStab
.string
= "";
1670 fStabs
.push_back(endFileStab
);
1672 // new translation unit, emit start SO's
1673 ObjectFile::Reader::Stab dirPathStab
;
1674 dirPathStab
.atom
= NULL
;
1675 dirPathStab
.type
= N_SO
;
1676 dirPathStab
.other
= 0;
1677 dirPathStab
.desc
= 0;
1678 dirPathStab
.value
= 0;
1679 dirPathStab
.string
= newDirPath
;
1680 fStabs
.push_back(dirPathStab
);
1681 ObjectFile::Reader::Stab fileStab
;
1682 fileStab
.atom
= NULL
;
1683 fileStab
.type
= N_SO
;
1687 fileStab
.string
= newFilename
;
1688 fStabs
.push_back(fileStab
);
1689 // Synthesize OSO for start of file
1690 ObjectFile::Reader::Stab objStab
;
1691 objStab
.atom
= NULL
;
1692 objStab
.type
= N_OSO
;
1695 objStab
.value
= atom
->getFile()->getModificationTime();
1696 objStab
.string
= assureFullPath(atom
->getFile()->getPath());
1697 fStabs
.push_back(objStab
);
1698 wroteStartSO
= true;
1699 // add the source file path to seenFiles so it does not show up in SOLs
1700 seenFiles
.insert(newFilename
);
1702 filename
= newFilename
;
1703 dirPath
= newDirPath
;
1704 if ( atom
->getSegment().isContentExecutable() && (strncmp(atom
->getSectionName(), "__text", 6) == 0) ) {
1705 // Synthesize BNSYM and start FUN stabs
1706 ObjectFile::Reader::Stab beginSym
;
1707 beginSym
.atom
= atom
;
1708 beginSym
.type
= N_BNSYM
;
1712 beginSym
.string
= "";
1713 fStabs
.push_back(beginSym
);
1714 ObjectFile::Reader::Stab startFun
;
1715 startFun
.atom
= atom
;
1716 startFun
.type
= N_FUN
;
1720 startFun
.string
= atom
->getName();
1721 fStabs
.push_back(startFun
);
1722 // Synthesize any SOL stabs needed
1723 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
1724 if ( lineInfo
!= NULL
) {
1725 const char* curFile
= NULL
;
1726 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
1727 if ( it
->fileName
!= curFile
) {
1728 if ( seenFiles
.count(it
->fileName
) == 0 ) {
1729 seenFiles
.insert(it
->fileName
);
1730 ObjectFile::Reader::Stab sol
;
1736 sol
.string
= it
->fileName
;
1737 fStabs
.push_back(sol
);
1739 curFile
= it
->fileName
;
1743 // Synthesize end FUN and ENSYM stabs
1744 ObjectFile::Reader::Stab endFun
;
1746 endFun
.type
= N_FUN
;
1751 fStabs
.push_back(endFun
);
1752 ObjectFile::Reader::Stab endSym
;
1754 endSym
.type
= N_ENSYM
;
1759 fStabs
.push_back(endSym
);
1762 ObjectFile::Reader::Stab globalsStab
;
1763 if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
1764 // Synthesize STSYM stab for statics
1765 const char* name
= atom
->getName();
1766 if ( name
[0] == '_' ) {
1767 globalsStab
.atom
= atom
;
1768 globalsStab
.type
= N_STSYM
;
1769 globalsStab
.other
= 1;
1770 globalsStab
.desc
= 0;
1771 globalsStab
.value
= 0;
1772 globalsStab
.string
= name
;
1773 fStabs
.push_back(globalsStab
);
1777 // Synthesize GSYM stab for other globals (but not .eh exception frame symbols)
1778 const char* name
= atom
->getName();
1779 if ( (name
[0] == '_') && (strcmp(atom
->getSectionName(), "__eh_frame") != 0) ) {
1780 globalsStab
.atom
= atom
;
1781 globalsStab
.type
= N_GSYM
;
1782 globalsStab
.other
= 1;
1783 globalsStab
.desc
= 0;
1784 globalsStab
.value
= 0;
1785 globalsStab
.string
= name
;
1786 fStabs
.push_back(globalsStab
);
1793 if ( wroteStartSO
) {
1795 ObjectFile::Reader::Stab endFileStab
;
1796 endFileStab
.atom
= NULL
;
1797 endFileStab
.type
= N_SO
;
1798 endFileStab
.other
= 1;
1799 endFileStab
.desc
= 0;
1800 endFileStab
.value
= 0;
1801 endFileStab
.string
= "";
1802 fStabs
.push_back(endFileStab
);
1809 void Linker::collectDebugInfo()
1811 std::map
<const class ObjectFile::Atom
*, uint32_t> atomOrdinals
;
1812 fStartDebugTime
= mach_absolute_time();
1813 if ( fOptions
.readerOptions().fDebugInfoStripping
!= ObjectFile::ReaderOptions::kDebugInfoNone
) {
1815 // determine mixture of stabs and dwarf
1816 bool someStabs
= false;
1817 bool someDwarf
= false;
1818 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
1819 it
!= fReadersThatHaveSuppliedAtoms
.end();
1821 ObjectFile::Reader
* reader
= *it
;
1822 if ( reader
!= NULL
) {
1823 switch ( reader
->getDebugInfoKind() ) {
1824 case ObjectFile::Reader::kDebugInfoNone
:
1826 case ObjectFile::Reader::kDebugInfoStabs
:
1829 case ObjectFile::Reader::kDebugInfoDwarf
:
1833 case ObjectFile::Reader::kDebugInfoStabsUUID
:
1838 throw "Unhandled type of debug information";
1843 if ( someDwarf
|| someStabs
) {
1844 // try to minimize re-allocations
1845 fStabs
.reserve(1024);
1847 // make mapping from atoms to ordinal
1848 uint32_t ordinal
= 1;
1849 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1850 atomOrdinals
[*it
] = ordinal
++;
1854 // process all dwarf .o files as a batch
1856 // make mapping from readers with dwarf to ordinal
1857 std::map
<class ObjectFile::Reader
*, uint32_t> readersWithDwarfOrdinals
;
1858 uint32_t readerOrdinal
= 1;
1859 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
1860 it
!= fReadersThatHaveSuppliedAtoms
.end();
1862 ObjectFile::Reader
* reader
= *it
;
1863 if ( (reader
!= NULL
) && (reader
->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoDwarf
) ) {
1864 readersWithDwarfOrdinals
[reader
] = readerOrdinal
++;
1868 // make a vector of atoms
1869 std::vector
<class ObjectFile::Atom
*> allAtomsByReader(fAllAtoms
.begin(), fAllAtoms
.end());
1870 // remove those not from a reader that has dwarf
1871 allAtomsByReader
.erase(std::remove_if(allAtomsByReader
.begin(), allAtomsByReader
.end(),
1872 NoDebugNoteAtom(readersWithDwarfOrdinals
)), allAtomsByReader
.end());
1873 // sort by reader then atom ordinal
1874 std::sort(allAtomsByReader
.begin(), allAtomsByReader
.end(), ReadersWithDwarfSorter(readersWithDwarfOrdinals
, atomOrdinals
));
1875 // add debug notes for each atom
1876 this->synthesizeDebugNotes(allAtomsByReader
);
1879 // process all stabs .o files one by one
1881 // get stabs from each reader, in command line order
1882 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
1883 it
!= fReadersThatHaveSuppliedAtoms
.end();
1885 ObjectFile::Reader
* reader
= *it
;
1886 if ( reader
!= NULL
) {
1887 switch ( reader
->getDebugInfoKind() ) {
1888 case ObjectFile::Reader::kDebugInfoDwarf
:
1889 case ObjectFile::Reader::kDebugInfoNone
:
1892 case ObjectFile::Reader::kDebugInfoStabs
:
1893 case ObjectFile::Reader::kDebugInfoStabsUUID
:
1894 collectStabs(reader
, atomOrdinals
);
1897 throw "Unhandled type of debug information";
1901 // remove stabs associated with atoms that won't be in output
1902 std::set
<class ObjectFile::Atom
*> allAtomsSet
;
1903 allAtomsSet
.insert(fAllAtoms
.begin(), fAllAtoms
.end());
1904 fStabs
.erase(std::remove_if(fStabs
.begin(), fStabs
.end(), NotInSet(allAtomsSet
)), fStabs
.end());
1909 void Linker::writeOutput()
1911 fStartWriteTime
= mach_absolute_time();
1912 // tell writer about each segment's atoms
1913 fOutputFileSize
= fOutputFile
->write(fAllAtoms
, fStabs
, this->entryPoint(), this->dyldHelper(), (fCreateUUID
&& fOptions
.emitUUID()));
1916 ObjectFile::Reader
* Linker::createReader(const Options::FileInfo
& info
)
1918 // map in whole file
1919 uint64_t len
= info
.fileLen
;
1920 int fd
= ::open(info
.path
, O_RDONLY
, 0);
1922 throwf("can't open file, errno=%d", errno
);
1923 if ( info
.fileLen
< 20 )
1924 throw "file too small";
1926 uint8_t* p
= (uint8_t*)::mmap(NULL
, info
.fileLen
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1927 if ( p
== (uint8_t*)(-1) )
1928 throwf("can't map file, errno=%d", errno
);
1930 // if fat file, skip to architecture we want
1931 const fat_header
* fh
= (fat_header
*)p
;
1932 if ( fh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1933 // Fat header is always big-endian
1934 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1935 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1936 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)fArchitecture
) {
1937 uint32_t fileOffset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1938 len
= OSSwapBigToHostInt32(archs
[i
].size
);
1939 // if requested architecture is page aligned within fat file, then remap just that portion of file
1940 if ( (fileOffset
& 0x00000FFF) == 0 ) {
1942 munmap((caddr_t
)p
, info
.fileLen
);
1943 // re-map just part we need
1944 p
= (uint8_t*)::mmap(NULL
, len
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, fileOffset
);
1945 if ( p
== (uint8_t*)(-1) )
1946 throwf("can't re-map file, errno=%d", errno
);
1957 switch (fArchitecture
) {
1958 case CPU_TYPE_POWERPC
:
1959 if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
1960 return this->addObject(mach_o::relocatable::Reader
<ppc
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1961 else if ( mach_o::dylib::Reader
<ppc
>::validFile(p
, info
.options
.fBundleLoader
) )
1962 return this->addDylib(mach_o::dylib::Reader
<ppc
>::make(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions()), info
, len
);
1963 else if ( mach_o::archive::Reader
<ppc
>::validFile(p
, len
) )
1964 return this->addArchive(mach_o::archive::Reader
<ppc
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1966 case CPU_TYPE_POWERPC64
:
1967 if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
1968 return this->addObject(mach_o::relocatable::Reader
<ppc64
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1969 else if ( mach_o::dylib::Reader
<ppc64
>::validFile(p
, info
.options
.fBundleLoader
) )
1970 return this->addDylib(mach_o::dylib::Reader
<ppc64
>::make(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions()), info
, len
);
1971 else if ( mach_o::archive::Reader
<ppc64
>::validFile(p
, len
) )
1972 return this->addArchive(mach_o::archive::Reader
<ppc64
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1975 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
1976 return this->addObject(mach_o::relocatable::Reader
<x86
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1977 else if ( mach_o::dylib::Reader
<x86
>::validFile(p
, info
.options
.fBundleLoader
) )
1978 return this->addDylib(mach_o::dylib::Reader
<x86
>::make(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions()), info
, len
);
1979 else if ( mach_o::archive::Reader
<x86
>::validFile(p
, len
) )
1980 return this->addArchive(mach_o::archive::Reader
<x86
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1982 case CPU_TYPE_X86_64
:
1983 if ( mach_o::relocatable::Reader
<x86_64
>::validFile(p
) )
1984 return this->addObject(mach_o::relocatable::Reader
<x86_64
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1985 else if ( mach_o::dylib::Reader
<x86_64
>::validFile(p
, info
.options
.fBundleLoader
) )
1986 return this->addDylib(mach_o::dylib::Reader
<x86_64
>::make(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions()), info
, len
);
1987 else if ( mach_o::archive::Reader
<x86_64
>::validFile(p
, len
) )
1988 return this->addArchive(mach_o::archive::Reader
<x86_64
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1993 if ( ((fat_header
*)p
)->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1994 throwf("missing required architecture %s in file", fArchitectureName
);
1997 throw "file is not of required architecture";
2002 void Linker::createReaders()
2004 fStartCreateReadersTime
= mach_absolute_time();
2005 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
2006 const int count
= files
.size();
2008 throw "no object files specified";
2009 // add all direct object, archives, and dylibs
2010 for (int i
=0; i
< count
; ++i
) {
2011 Options::FileInfo
& entry
= files
[i
];
2012 // ignore /usr/lib/dyld on command line in crt.o build
2013 if ( strcmp(entry
.path
, "/usr/lib/dyld") != 0 ) {
2015 this->addInputFile(this->createReader(entry
));
2017 catch (const char* msg
) {
2018 if ( strstr(msg
, "architecture") != NULL
) {
2019 if ( fOptions
.ignoreOtherArchInputFiles() ) {
2020 // ignore, because this is about an architecture not in use
2023 fprintf(stderr
, "ld64 warning: in %s, %s\n", entry
.path
, msg
);
2027 throwf("in %s, %s", entry
.path
, msg
);
2033 // add first level of indirect dylibs
2034 fDirectLibrariesComplete
= true;
2035 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator it
=fDynamicLibraries
.begin(); it
!= fDynamicLibraries
.end(); it
++) {
2036 this->addIndirectLibraries(it
->reader
);
2039 // indirect handling depends on namespace
2040 switch ( fOptions
.nameSpace() ) {
2041 case Options::kFlatNameSpace
:
2042 case Options::kForceFlatNameSpace
:
2043 // with flat namespace, blindly load all indirect libraries
2044 // the indirect list will grow as indirect libraries are loaded
2045 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
2047 it
->reader
= this->createReader(fOptions
.findFile(it
->path
));
2048 it
->reader
->setSortOrder(fNextObjectFileOrder
++);
2050 catch (const char* msg
) {
2051 fprintf(stderr
, "ld64 warning: indirect library %s could not be loaded: %s\n", it
->path
, msg
);
2056 case Options::kTwoLevelNameSpace
:
2057 // with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
2059 bool indirectAdded
= true;
2060 while ( indirectAdded
) {
2061 indirectAdded
= false;
2062 // instantiate a reader for each indirect library and try to find parent that re-exports it
2063 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
2064 if ( it
->reader
== NULL
) {
2066 it
->reader
= this->createReader(fOptions
.findFile(it
->path
));
2067 it
->reader
->setSortOrder(fNextObjectFileOrder
++);
2068 indirectAdded
= true;
2070 catch (const char* msg
) {
2071 fprintf(stderr
, "ld64 warning: indirect library %s could not be loaded: %s\n", it
->path
, msg
);
2074 // if an indirect library does not have an assigned parent, look for one
2075 if ( (it
->reader
!= NULL
) && (it
->reExportedViaDirectLibrary
== NULL
) ) {
2076 it
->reExportedViaDirectLibrary
= this->findDirectLibraryWhichReExports(*it
);
2084 // add relevant indirect libraries to the end of fDynamicLibraries
2085 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
2086 if ( (it
->reader
!= NULL
) && (it
->reExportedViaDirectLibrary
!= NULL
) || (fOptions
.nameSpace() != Options::kTwoLevelNameSpace
) ) {
2087 ExecutableFile::DyLibUsed dylibInfo
;
2088 dylibInfo
.reader
= it
->reader
;
2089 dylibInfo
.options
.fWeakImport
= false;
2090 dylibInfo
.options
.fReExport
= false;
2091 dylibInfo
.options
.fInstallPathOverride
= NULL
;
2092 dylibInfo
.indirect
= true;
2093 dylibInfo
.directReader
= it
->reExportedViaDirectLibrary
;
2094 fDynamicLibraries
.push_back(dylibInfo
);
2095 if ( fOptions
.readerOptions().fTraceIndirectDylibs
) {
2096 const char* fullPath
= it
->reader
->getPath();
2097 char realName
[MAXPATHLEN
];
2098 if ( realpath(fullPath
, realName
) != NULL
)
2099 fullPath
= realName
;
2100 logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath
);
2107 ObjectFile::Reader
* Linker::findDirectLibraryWhichReExports(IndirectLibrary
& indirectLib
)
2109 // ask each parent if they re-export this dylib
2110 for (std::set
<ObjectFile::Reader
*>::iterator pit
=indirectLib
.parents
.begin(); pit
!= indirectLib
.parents
.end(); pit
++) {
2111 if ( (*pit
)->reExports(indirectLib
.reader
) ) {
2112 ObjectFile::Reader
* lib
= *pit
;
2113 // first check if we found a direct library, if so return it
2114 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator dit
=fDynamicLibraries
.begin(); dit
!= fDynamicLibraries
.end(); dit
++) {
2115 if ( dit
->reader
== lib
&& dit
->indirect
== false )
2118 // otherwise search indirects for parent and see how it is reexported
2119 for (std::list
<IndirectLibrary
>::iterator iit
=fIndirectDynamicLibraries
.begin(); iit
!= fIndirectDynamicLibraries
.end(); iit
++) {
2120 if ( iit
->reader
== lib
) {
2121 ObjectFile::Reader
* lib2
= this->findDirectLibraryWhichReExports(*iit
);
2133 ObjectFile::Reader
* Linker::addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
2135 if (fOptions
.readerOptions().fTraceArchives
) {
2136 const char* fullPath
= reader
->getPath();
2137 char realName
[MAXPATHLEN
];
2138 if ( realpath(fullPath
, realName
) != NULL
)
2139 fullPath
= realName
;
2140 logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath
);
2144 fTotalArchiveSize
+= mappedLen
;
2145 ++fTotalArchivesLoaded
;
2149 ObjectFile::Reader
* Linker::addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
2152 fTotalObjectSize
+= mappedLen
;
2153 ++fTotalObjectLoaded
;
2157 ObjectFile::Reader
* Linker::addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
2159 if ( (reader
->getInstallPath() == NULL
) && !info
.options
.fBundleLoader
) {
2160 // this is a "blank" stub
2161 // silently ignore it
2165 if ( fDirectLibrariesComplete
) {
2166 this->addIndirectLibraries(reader
);
2169 if ( fOptions
.readerOptions().fTraceDylibs
) {
2170 const char* fullPath
= reader
->getPath();
2171 char realName
[MAXPATHLEN
];
2172 if ( realpath(fullPath
, realName
) != NULL
)
2173 fullPath
= realName
;
2174 logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath
);
2176 ExecutableFile::DyLibUsed dylibInfo
;
2177 dylibInfo
.reader
= reader
;
2178 dylibInfo
.options
= info
.options
;
2179 dylibInfo
.indirect
= false;
2180 dylibInfo
.directReader
= NULL
;
2181 fDynamicLibraries
.push_back(dylibInfo
);
2184 // Verify that a client is allowed to link to this dylib. There are three cases.
2185 bool okToLink
= true;
2186 const char* outputFilePath
= fOptions
.installPath();
2187 const char* outputFilePathLastSlash
= strrchr(outputFilePath
, '/');
2188 if ( reader
->parentUmbrella() != NULL
) {
2189 // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
2190 okToLink
= ( (outputFilePathLastSlash
!= NULL
) && (strcmp(&outputFilePathLastSlash
[1], reader
->parentUmbrella()) == 0) );
2193 if ( !okToLink
&& (reader
->parentUmbrella() != NULL
) ) {
2194 // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
2195 okToLink
= ( (outputFilePathLastSlash
!= NULL
)
2196 && (fOptions
.umbrellaName() != NULL
)
2197 && (strcmp(fOptions
.umbrellaName(), reader
->parentUmbrella()) == 0) );
2200 std::vector
<const char*>* clients
= reader
->getAllowableClients();
2201 if ( !okToLink
&& (clients
!= NULL
) ) {
2202 // case 3) the dylib has a list of allowable clients, and we are creating one of them
2203 const char* clientName
= fOptions
.clientName();
2204 int clientNameLen
= 0;
2205 if ( clientName
!= NULL
) {
2206 // use client name as specified on command line
2207 clientNameLen
= strlen(clientName
);
2210 // infer client name from output path (e.g. xxx/libfoo.A.dylib --> foo, Bar.framework/Bar --> Bar)
2211 clientName
= outputFilePath
;
2212 // starts after last slash
2213 if ( outputFilePathLastSlash
!= NULL
)
2214 clientName
= &outputFilePathLastSlash
[1];
2215 if ( strncmp(clientName
, "lib", 3) == 0 )
2216 clientName
= &clientName
[3];
2218 const char* firstDot
= strchr(clientName
, '.');
2219 if ( firstDot
== NULL
)
2220 clientNameLen
= strlen(clientName
);
2222 clientNameLen
= firstDot
- clientName
;
2225 // Use clientName to check if this dylib is able to link against the allowable clients.
2226 for (std::vector
<const char*>::iterator it
= clients
->begin(); it
!= clients
->end(); it
++) {
2227 if ( strncmp(*it
, clientName
, clientNameLen
) == 0 )
2232 // error out if we are not allowed to link
2234 //throwf("'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
2235 fprintf(stderr
, "'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
2236 reader
->getPath(), reader
->parentUmbrella());
2240 ++fTotalDylibsLoaded
;
2246 void Linker::addIndirectLibraries(ObjectFile::Reader
* reader
)
2248 std::vector
<const char*>* dependentLibs
= reader
->getDependentLibraryPaths();
2249 if ( dependentLibs
!= NULL
) {
2250 for (std::vector
<const char*>::iterator it
=dependentLibs
->begin(); it
!= dependentLibs
->end(); it
++) {
2251 if ( this->haveDirectLibrary(*it
) ) {
2252 // do nothing, direct library already exists
2254 else if ( this->haveIndirectLibrary(*it
, reader
) ) {
2255 // side effect of haveIndirectLibrary() added reader to parent list
2258 // add to list of indirect libraries
2259 IndirectLibrary indirectLib
;
2260 indirectLib
.path
= *it
;
2261 indirectLib
.fileLen
= 0;
2262 indirectLib
.reader
= NULL
;
2263 indirectLib
.parents
.insert(reader
);
2264 indirectLib
.reExportedViaDirectLibrary
= NULL
;
2265 fIndirectDynamicLibraries
.push_back(indirectLib
);
2266 //fprintf(stderr, "add indirect library: %s\n", *it);
2272 bool Linker::haveIndirectLibrary(const char* path
, ObjectFile::Reader
* parentReader
)
2274 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
2275 if ( strcmp(path
, it
->path
) == 0 ) {
2276 it
->parents
.insert(parentReader
);
2279 if ( it
->reader
!= NULL
) {
2280 const char* installPath
= it
->reader
->getInstallPath();
2281 if ( (installPath
!= NULL
) && (strcmp(path
, installPath
) == 0) )
2288 bool Linker::haveDirectLibrary(const char* path
)
2290 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator it
=fDynamicLibraries
.begin(); it
!= fDynamicLibraries
.end(); it
++) {
2291 if ( strcmp(path
, it
->reader
->getPath()) == 0 )
2293 const char* installPath
= it
->reader
->getInstallPath();
2294 if ( (installPath
!= NULL
) && (strcmp(path
, installPath
) == 0) )
2300 void Linker::logTraceInfo (const char* format
, ...)
2302 static int trace_file
= -1;
2303 char trace_buffer
[MAXPATHLEN
* 2];
2306 ssize_t amount_written
;
2307 const char *trace_file_path
= fOptions
.readerOptions().fTraceOutputFile
;
2309 if(trace_file
== -1) {
2310 if(trace_file_path
!= NULL
) {
2311 trace_file
= open(trace_file_path
, O_WRONLY
| O_APPEND
| O_CREAT
, 0666);
2312 if(trace_file
== -1)
2313 throwf("Could not open or create trace file: %s\n", trace_file_path
);
2316 trace_file
= fileno(stderr
);
2321 va_start(ap
, format
);
2322 length
= vsnprintf(trace_buffer
, sizeof(trace_buffer
), format
, ap
);
2324 buffer_ptr
= trace_buffer
;
2327 amount_written
= write(trace_file
, buffer_ptr
, length
);
2328 if(amount_written
== -1)
2329 /* Failure to write shouldn't fail the build. */
2331 buffer_ptr
+= amount_written
;
2332 length
-= amount_written
;
2338 void Linker::createWriter()
2340 fStartCreateWriterTime
= mach_absolute_time();
2341 const char* path
= fOptions
.getOutputFilePath();
2342 switch ( fArchitecture
) {
2343 case CPU_TYPE_POWERPC
:
2344 this->setOutputFile(new mach_o::executable::Writer
<ppc
>(path
, fOptions
, fDynamicLibraries
));
2346 case CPU_TYPE_POWERPC64
:
2347 this->setOutputFile(new mach_o::executable::Writer
<ppc64
>(path
, fOptions
, fDynamicLibraries
));
2350 this->setOutputFile(new mach_o::executable::Writer
<x86
>(path
, fOptions
, fDynamicLibraries
));
2352 case CPU_TYPE_X86_64
:
2353 this->setOutputFile(new mach_o::executable::Writer
<x86_64
>(path
, fOptions
, fDynamicLibraries
));
2356 throw "unknown architecture";
2361 Linker::SymbolTable::SymbolTable(Linker
& owner
)
2362 : fOwner(owner
), fRequireCount(0)
2366 void Linker::SymbolTable::require(const char* name
)
2368 //fprintf(stderr, "require(%s)\n", name);
2369 Mapper::iterator pos
= fTable
.find(name
);
2370 if ( pos
== fTable
.end() ) {
2371 fTable
[name
] = NULL
;
2376 // convenience labels for 2-dimensional switch statement
2378 kRegAndReg
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2379 kRegAndWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2380 kRegAndTent
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2381 kRegAndExtern
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2382 kRegAndExternWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2383 kWeakAndReg
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2384 kWeakAndWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2385 kWeakAndTent
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2386 kWeakAndExtern
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2387 kWeakAndExternWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2388 kTentAndReg
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2389 kTentAndWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2390 kTentAndTent
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2391 kTentAndExtern
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2392 kTentAndExternWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2393 kExternAndReg
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2394 kExternAndWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2395 kExternAndTent
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2396 kExternAndExtern
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2397 kExternAndExternWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2398 kExternWeakAndReg
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2399 kExternWeakAndWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2400 kExternWeakAndTent
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2401 kExternWeakAndExtern
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2402 kExternWeakAndExternWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
2405 bool Linker::SymbolTable::add(ObjectFile::Atom
& newAtom
)
2408 const char* name
= newAtom
.getName();
2409 //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
2410 Mapper::iterator pos
= fTable
.find(name
);
2411 ObjectFile::Atom
* existingAtom
= NULL
;
2412 if ( pos
!= fTable
.end() )
2413 existingAtom
= pos
->second
;
2414 if ( existingAtom
!= NULL
) {
2415 // already have atom with same name in symbol table
2416 switch ( (existingAtom
->getDefinitionKind() << 3) | newAtom
.getDefinitionKind() ) {
2418 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2420 // ignore new weak atom, because we already have a non-weak one
2424 // ignore new tentative atom, because we already have a regular one
2428 // ignore external atom, because we already have a one
2431 case kRegAndExternWeak
:
2432 // ignore external atom, because we already have a one
2436 // replace existing weak atom with regular one
2439 // have another weak atom, use whichever has largest alignment requirement
2440 // because codegen of some client may require alignment
2441 useNew
= ( newAtom
.getAlignment().leadingZeros() > existingAtom
->getAlignment().leadingZeros() );
2444 // replace existing weak atom with tentative one ???
2446 case kWeakAndExtern
:
2447 // keep weak atom, at runtime external one may override
2450 case kWeakAndExternWeak
:
2451 // keep weak atom, at runtime external one may override
2455 // replace existing tentative atom with regular one
2458 // replace existing tentative atom with weak one ???
2462 if ( newAtom
.getSize() < existingAtom
->getSize() ) {
2465 if ( newAtom
.getAlignment().leadingZeros() < existingAtom
->getAlignment().leadingZeros() )
2466 fprintf(stderr
, "ld64 warning: alignment lost in merging tentative definition %s\n", newAtom
.getDisplayName());
2469 case kTentAndExtern
:
2470 case kTentAndExternWeak
:
2471 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2472 switch ( fOwner
.fOptions
.commonsMode() ) {
2473 case Options::kCommonsIgnoreDylibs
:
2474 if ( fOwner
.fOptions
.warnCommons() )
2475 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2476 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2479 case Options::kCommonsOverriddenByDylibs
:
2480 if ( fOwner
.fOptions
.warnCommons() )
2481 fprintf(stderr
, "ld64: replacing common symbol %s from %s with true definition from dylib %s\n",
2482 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2484 case Options::kCommonsConflictsDylibsError
:
2485 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2486 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2490 // replace external atom with regular one
2492 case kExternAndWeak
:
2493 // replace external atom with weak one
2495 case kExternAndTent
:
2496 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2497 switch ( fOwner
.fOptions
.commonsMode() ) {
2498 case Options::kCommonsIgnoreDylibs
:
2499 if ( fOwner
.fOptions
.warnCommons() )
2500 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2501 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2503 case Options::kCommonsOverriddenByDylibs
:
2504 if ( fOwner
.fOptions
.warnCommons() )
2505 fprintf(stderr
, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2506 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2509 case Options::kCommonsConflictsDylibsError
:
2510 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2511 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2514 case kExternAndExtern
:
2515 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2516 case kExternAndExternWeak
:
2517 // keep strong dylib atom, ignore weak one
2520 case kExternWeakAndReg
:
2521 // replace existing weak external with regular
2523 case kExternWeakAndWeak
:
2524 // replace existing weak external with weak (let dyld decide at runtime which to use)
2526 case kExternWeakAndTent
:
2527 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2528 switch ( fOwner
.fOptions
.commonsMode() ) {
2529 case Options::kCommonsIgnoreDylibs
:
2530 if ( fOwner
.fOptions
.warnCommons() )
2531 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2532 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2534 case Options::kCommonsOverriddenByDylibs
:
2535 if ( fOwner
.fOptions
.warnCommons() )
2536 fprintf(stderr
, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2537 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2540 case Options::kCommonsConflictsDylibsError
:
2541 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2542 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2545 case kExternWeakAndExtern
:
2546 // replace existing weak external with external
2548 case kExternWeakAndExternWeak
:
2549 // keep existing external weak
2555 fTable
[name
] = &newAtom
;
2556 if ( existingAtom
!= NULL
)
2557 fOwner
.fDeadAtoms
.insert(existingAtom
);
2560 fOwner
.fDeadAtoms
.insert(&newAtom
);
2567 ObjectFile::Atom
* Linker::SymbolTable::find(const char* name
)
2569 Mapper::iterator pos
= fTable
.find(name
);
2570 if ( pos
!= fTable
.end() ) {
2577 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
)
2579 for (Mapper::iterator it
=fTable
.begin(); it
!= fTable
.end(); it
++) {
2580 if ( (it
->second
== NULL
) || (andWeakDefintions
&& (it
->second
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
)) ) {
2581 undefines
.push_back(it
->first
);
2589 bool Linker::AtomSorter::operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
)
2591 // first sort by section order (which is already sorted by segment)
2592 unsigned int leftSectionIndex
= left
->getSection()->getIndex();
2593 unsigned int rightSectionIndex
= right
->getSection()->getIndex();
2594 if ( leftSectionIndex
!= rightSectionIndex
)
2595 return (leftSectionIndex
< rightSectionIndex
);
2597 // then sort by .o file order
2598 ObjectFile::Reader
* leftReader
= left
->getFile();
2599 ObjectFile::Reader
* rightReader
= right
->getFile();
2600 if ( leftReader
!= rightReader
)
2601 return leftReader
->getSortOrder() < rightReader
->getSortOrder();
2603 // lastly sort by atom within a .o file
2604 return left
->getSortOrder() < right
->getSortOrder();
2608 int main(int argc
, const char* argv
[])
2610 const char* archName
= NULL
;
2611 bool showArch
= false;
2612 bool archInferred
= false;
2614 // create linker object given command line arguments
2615 Linker
ld(argc
, argv
);
2617 // save error message prefix
2618 archName
= ld
.architectureName();
2619 archInferred
= ld
.isInferredArchitecture();
2620 showArch
= ld
.showArchitectureInErrors();
2622 // open all input files
2631 catch (const char* msg
) {
2632 extern const double ld64VersionNumber
;
2634 fprintf(stderr
, "ld64-%g failed: %s for inferred architecture %s\n", ld64VersionNumber
, msg
, archName
);
2635 else if ( showArch
)
2636 fprintf(stderr
, "ld64-%g failed: %s for architecture %s\n", ld64VersionNumber
, msg
, archName
);
2638 fprintf(stderr
, "ld64-%g failed: %s\n", ld64VersionNumber
, msg
);