1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
2 * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 // start temp HACK for cross builds
25 extern "C" double log2 ( double );
27 // end temp HACK for cross builds
31 #include <sys/types.h>
34 #include <sys/sysctl.h>
39 #include <mach/mach_time.h>
40 #include <mach/vm_statistics.h>
41 #include <mach/mach_init.h>
42 #include <mach/mach_host.h>
52 #include <ext/hash_map>
54 #include <AvailabilityMacros.h>
56 #include "configure.h"
59 #include "ObjectFile.h"
61 #include "MachOReaderRelocatable.hpp"
62 #include "ArchiveReader.hpp"
63 #include "MachOReaderDylib.hpp"
64 #include "MachOWriterExecutable.hpp"
68 #include "LTOReader.hpp"
72 #include "OpaqueSection.hpp"
78 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) < 0); }
84 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
87 class Section
: public ObjectFile::Section
90 static Section
* find(const char* sectionName
, const char* segmentName
, bool zeroFill
);
91 static void assignIndexes();
92 const char* getName() { return fSectionName
; }
94 Section(const char* sectionName
, const char* segmentName
, bool zeroFill
);
97 static int segmentOrdinal(const char* segName
);
98 bool operator()(Section
* left
, Section
* right
);
101 typedef __gnu_cxx::hash_map
<const char*, uint32_t, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToOrdinal
;
102 typedef __gnu_cxx::hash_map
<const char*, class Section
*, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToSection
;
103 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
105 const char* fSectionName
;
106 const char* fSegmentName
;
109 static NameToSection fgMapping
;
110 static std::vector
<Section
*> fgSections
;
111 static NameToOrdinal fgSegmentDiscoverOrder
;
114 Section::NameToSection
Section::fgMapping
;
115 std::vector
<Section
*> Section::fgSections
;
116 Section::NameToOrdinal
Section::fgSegmentDiscoverOrder
;
118 Section::Section(const char* sectionName
, const char* segmentName
, bool zeroFill
)
119 : fSectionName(sectionName
), fSegmentName(segmentName
), fZeroFill(zeroFill
)
121 this->fIndex
= fgSections
.size();
122 //fprintf(stderr, "new Section(%s, %s) => %p, %u\n", sectionName, segmentName, this, this->getIndex());
125 Section
* Section::find(const char* sectionName
, const char* segmentName
, bool zeroFill
)
127 NameToSection::iterator pos
= fgMapping
.find(sectionName
);
128 if ( pos
!= fgMapping
.end() ) {
129 if ( strcmp(pos
->second
->fSegmentName
, segmentName
) == 0 )
131 // otherwise same section name is used in different segments, look slow way
132 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++) {
133 if ( (strcmp((*it
)->fSectionName
, sectionName
) == 0) && (strcmp((*it
)->fSegmentName
, segmentName
) == 0) )
138 // does not exist, so make a new one
139 Section
* sect
= new Section(sectionName
, segmentName
, zeroFill
);
140 fgMapping
[sectionName
] = sect
;
141 fgSections
.push_back(sect
);
143 if ( (strcmp(sectionName
, "__text") == 0) && (strcmp(segmentName
, "__TEXT") == 0) ) {
144 // special case __textcoal_nt to be right after __text
145 find("__textcoal_nt", "__TEXT", false);
148 // remember segment discovery order
149 if ( fgSegmentDiscoverOrder
.find(segmentName
) == fgSegmentDiscoverOrder
.end() )
150 fgSegmentDiscoverOrder
[segmentName
] = fgSegmentDiscoverOrder
.size();
155 int Section::Sorter::segmentOrdinal(const char* segName
)
157 if ( strcmp(segName
, "__PAGEZERO") == 0 )
159 if ( strcmp(segName
, "__TEXT") == 0 )
161 if ( strcmp(segName
, "__DATA") == 0 )
163 if ( strcmp(segName
, "__OBJC") == 0 )
165 if ( strcmp(segName
, "__OBJC2") == 0 )
167 if ( strcmp(segName
, "__LINKEDIT") == 0 )
168 return INT_MAX
; // linkedit segment should always sort last
170 return fgSegmentDiscoverOrder
[segName
]+6;
174 bool Section::Sorter::operator()(Section
* left
, Section
* right
)
176 // Segment is primary sort key
177 int leftSegOrdinal
= segmentOrdinal(left
->fSegmentName
);
178 int rightSegOrdinal
= segmentOrdinal(right
->fSegmentName
);
179 if ( leftSegOrdinal
< rightSegOrdinal
)
181 if ( leftSegOrdinal
> rightSegOrdinal
)
184 // zerofill section sort to the end
185 if ( !left
->fZeroFill
&& right
->fZeroFill
)
187 if ( left
->fZeroFill
&& !right
->fZeroFill
)
190 // section discovery order is last sort key
191 return left
->fIndex
< right
->fIndex
;
194 void Section::assignIndexes()
196 //printf("unsorted sections:\n");
197 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
198 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
202 std::sort(fgSections
.begin(), fgSections
.end(), Section::Sorter());
204 // assign correct section ordering to each Section object
205 unsigned int newOrder
= 1;
206 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++)
207 (*it
)->fIndex
= newOrder
++;
209 //printf("sorted sections:\n");
210 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
211 // printf("section: index=%d, obj=%p, name=%s\n", (*it)->fIndex, (*it), (*it)->fSectionName);
215 class Linker
: public ObjectFile::Reader::DylibHander
{
217 Linker(int argc
, const char* argv
[]);
219 const char* getArchPrefix();
220 const char* architectureName();
221 bool showArchitectureInErrors();
222 bool isInferredArchitecture();
223 void createReaders();
225 void addInputFile(ObjectFile::Reader
* reader
, const Options::FileInfo
& );
226 void setOutputFile(ExecutableFile::Writer
* writer
);
230 // implemenation from ObjectFile::Reader::DylibHander
231 virtual ObjectFile::Reader
* findDylib(const char* installPath
, const char* fromPath
);
234 struct WhyLiveBackChain
236 WhyLiveBackChain
* previous
;
240 ObjectFile::Reader
* createReader(const Options::FileInfo
&);
241 void addAtom(ObjectFile::Atom
& atom
);
242 void addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
);
243 void buildAtomList();
244 void processDylibs();
245 void markDead(ObjectFile::Atom
* atom
);
246 void updateConstraints(ObjectFile::Reader
* reader
);
247 void loadAndResolve();
248 void processDTrace();
250 void loadUndefines();
251 void checkUndefines();
252 void addWeakAtomOverrides();
253 void resolveReferences();
254 void deadStripResolve();
255 void addLiveRoot(const char* name
);
256 ObjectFile::Atom
* findAtom(const Options::OrderedSymbol
& pair
);
257 void logArchive(ObjectFile::Reader
* reader
);
261 void writeDotOutput();
262 static bool minimizeStab(ObjectFile::Reader::Stab
& stab
);
263 static const char* truncateStabString(const char* str
);
264 void collectDebugInfo();
266 ObjectFile::Atom
* entryPoint(bool orInit
);
267 ObjectFile::Atom
* dyldHelper();
268 ObjectFile::Atom
* dyldLazyLibraryHelper();
269 const char* assureFullPath(const char* path
);
270 void markLive(ObjectFile::Atom
& atom
, Linker::WhyLiveBackChain
* previous
);
271 void collectStabs(ObjectFile::Reader
* reader
, std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
);
272 void synthesizeDebugNotes(std::vector
<class ObjectFile::Atom
*>& allAtomsByReader
);
273 void printStatistics();
274 void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
);
275 char* commatize(uint64_t in
, char* out
);
276 void getVMInfo(vm_statistics_data_t
& info
);
277 cpu_type_t
inferArchitecture();
278 void addDtraceProbe(ObjectFile::Atom
& atom
, uint32_t offsetInAtom
, const char* probeName
);
279 void checkDylibClientRestrictions(ObjectFile::Reader
* reader
);
280 void logDylib(ObjectFile::Reader
* reader
, bool indirect
);
282 void resolve(ObjectFile::Reference
* reference
);
283 void resolveFrom(ObjectFile::Reference
* reference
);
284 std::vector
<class ObjectFile::Atom
*>* addJustInTimeAtoms(const char* name
, bool dylibsOnly
=false);
285 void addJustInTimeAtomsAndMarkLive(const char* name
);
287 ObjectFile::Reader
* addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
288 ObjectFile::Reader
* addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
289 ObjectFile::Reader
* addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
291 void logTraceInfo(const char* format
, ...);
297 typedef __gnu_cxx::hash_map
<const char*, ObjectFile::Atom
*, __gnu_cxx::hash
<const char*>, CStringEquals
> Mapper
;
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
);
305 bool hasExternalTentativeDefinitions() { return fHasExternalTentativeDefinitions
; }
306 bool hasExternalWeakDefinitions() { return fHasExternalWeakDefinitions
; }
307 void setHasExternalWeakDefinitions() { fHasExternalWeakDefinitions
= true; }
308 Mapper::iterator
begin() { return fTable
.begin(); }
309 Mapper::iterator
end() { return fTable
.end(); }
314 unsigned int fRequireCount
;
315 bool fHasExternalTentativeDefinitions
;
316 bool fHasExternalWeakDefinitions
;
322 AtomSorter(std::map
<const ObjectFile::Atom
*, uint32_t>* map
) : fOverriddenOrdinalMap(map
) {}
323 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
);
325 std::map
<const ObjectFile::Atom
*, uint32_t>* fOverriddenOrdinalMap
;
328 typedef std::map
<const char*, uint32_t, CStringComparor
> SectionOrder
;
330 struct DTraceProbeInfo
{
331 DTraceProbeInfo(const ObjectFile::Atom
* a
, uint32_t o
, const char* n
) : atom(a
), offset(o
), probeName(n
) {}
332 const ObjectFile::Atom
* atom
;
334 const char* probeName
;
336 typedef __gnu_cxx::hash_map
<const char*, std::vector
<DTraceProbeInfo
>, __gnu_cxx::hash
<const char*>, CStringEquals
> ProviderToProbes
;
337 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> CStringSet
;
338 typedef __gnu_cxx::hash_map
<const char*, ObjectFile::Reader
*, __gnu_cxx::hash
<const char*>, CStringEquals
> InstallNameToReader
;
340 struct IndirectLibrary
{
343 ObjectFile::Reader
* reader
;
344 std::set
<ObjectFile::Reader
*> parents
;
345 ObjectFile::Reader
* reExportedViaDirectLibrary
;
348 ObjectFile::Reader
* findDirectLibraryWhichReExports(struct IndirectLibrary
& indirectLib
);
351 SymbolTable fGlobalSymbolTable
;
352 uint32_t fNextInputOrdinal
;
353 std::vector
<class ObjectFile::Reader
*> fInputFiles
;
354 ExecutableFile::Writer
* fOutputFile
;
355 InstallNameToReader fDylibMap
;
356 std::map
<ObjectFile::Reader
*,DynamicLibraryOptions
> fDylibOptionsMap
;
357 std::set
<ObjectFile::Reader
*> fDylibsProcessed
;
358 ObjectFile::Reader
* fBundleLoaderReader
;
359 std::vector
<class ObjectFile::Reader
*> fReadersThatHaveSuppliedAtoms
;
360 std::vector
<class ObjectFile::Atom
*> fAllAtoms
;
361 std::set
<class ObjectFile::Reader
*> fArchiveReaders
;
362 std::set
<class ObjectFile::Reader
*> fArchiveReadersLogged
;
363 std::set
<class ObjectFile::Atom
*> fDeadAtoms
;
364 std::set
<ObjectFile::Atom
*> fLiveAtoms
;
365 std::set
<ObjectFile::Atom
*> fLiveRootAtoms
;
366 std::vector
<class ObjectFile::Reader::Stab
> fStabs
;
367 std::vector
<class ObjectFile::Atom
*> fAtomsWithUnresolvedReferences
;
368 std::vector
<DTraceProbeInfo
> fDtraceProbes
;
369 std::vector
<DTraceProbeInfo
> fDtraceProbeSites
;
370 std::vector
<DTraceProbeInfo
> fDtraceIsEnabledSites
;
371 std::map
<const ObjectFile::Atom
*,CStringSet
> fDtraceAtomToTypes
;
374 SectionOrder fSectionOrder
;
375 cpu_type_t fArchitecture
;
376 const char* fArchitectureName
;
377 bool fArchitectureInferred
;
378 bool fDirectLibrariesComplete
;
379 bool fBiggerThanTwoGigOutput
;
380 uint64_t fOutputFileSize
;
381 uint64_t fTotalZeroFillSize
;
384 uint64_t fStartCreateReadersTime
;
385 uint64_t fStartCreateWriterTime
;
386 uint64_t fStartBuildAtomsTime
;
387 uint64_t fStartLoadAndResolveTime
;
388 uint64_t fStartSortTime
;
389 uint64_t fStartDebugTime
;
390 uint64_t fStartWriteTime
;
392 uint64_t fTotalObjectSize
;
393 uint64_t fTotalArchiveSize
;
394 uint32_t fTotalObjectLoaded
;
395 uint32_t fTotalArchivesLoaded
;
396 uint32_t fTotalDylibsLoaded
;
397 vm_statistics_data_t fStartVMInfo
;
398 ObjectFile::Reader::ObjcConstraint fCurrentObjCConstraint
;
399 ObjectFile::Reader::CpuConstraint fCurrentCpuConstraint
;
400 bool fObjcReplacmentClasses
;
401 bool fAllDirectDylibsLoaded
;
405 Linker::Linker(int argc
, const char* argv
[])
406 : fOptions(argc
, argv
), fGlobalSymbolTable(*this), fNextInputOrdinal(1), fOutputFile(NULL
), fBundleLoaderReader(NULL
),
407 fCreateUUID(fOptions
.outputKind() != Options::kObjectFile
), fCanScatter(true),
408 fArchitecture(0), fArchitectureInferred(false), fDirectLibrariesComplete(false), fBiggerThanTwoGigOutput(false),
409 fOutputFileSize(0), fTotalZeroFillSize(0), fTotalSize(0), fTotalObjectSize(0),
410 fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0),
411 fCurrentObjCConstraint(ObjectFile::Reader::kObjcNone
), fCurrentCpuConstraint(ObjectFile::Reader::kCpuAny
),
412 fObjcReplacmentClasses(false), fAllDirectDylibsLoaded(false)
414 fStartTime
= mach_absolute_time();
415 if ( fOptions
.printStatistics() )
416 getVMInfo(fStartVMInfo
);
418 fArchitecture
= fOptions
.architecture();
419 if ( fArchitecture
== 0 ) {
420 // -arch not specified, scan .o files to figure out what it should be
421 fArchitecture
= inferArchitecture();
422 fArchitectureInferred
= true;
424 switch (fArchitecture
) {
425 case CPU_TYPE_POWERPC
:
426 fArchitectureName
= "ppc";
428 case CPU_TYPE_POWERPC64
:
429 fArchitectureName
= "ppc64";
432 fArchitectureName
= "i386";
434 case CPU_TYPE_X86_64
:
435 fArchitectureName
= "x86_64";
438 fArchitectureName
= "arm";
441 fArchitectureName
= "unknown architecture";
446 const char* Linker::architectureName()
448 return fArchitectureName
;
451 bool Linker::showArchitectureInErrors()
453 return fOptions
.printArchPrefix();
456 bool Linker::isInferredArchitecture()
458 return fArchitectureInferred
;
461 cpu_type_t
Linker::inferArchitecture()
463 // scan all input files, looking for a thin .o file.
464 // the first one found is presumably the architecture to link
465 uint8_t buffer
[sizeof(mach_header_64
)];
466 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
467 for (std::vector
<Options::FileInfo
>::iterator it
= files
.begin(); it
!= files
.end(); ++it
) {
468 int fd
= ::open(it
->path
, O_RDONLY
, 0);
470 ssize_t amount
= read(fd
, buffer
, sizeof(buffer
));
472 if ( amount
>= (ssize_t
)sizeof(buffer
) ) {
473 if ( mach_o::relocatable::Reader
<ppc
>::validFile(buffer
) ) {
474 //warning("-arch not used, infering -arch ppc based on %s", it->path);
475 return CPU_TYPE_POWERPC
;
477 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(buffer
) ) {
478 //warning("-arch not used, infering -arch ppc64 based on %s", it->path);
479 return CPU_TYPE_POWERPC64
;
481 else if ( mach_o::relocatable::Reader
<x86
>::validFile(buffer
) ) {
482 //warning("-arch not used, infering -arch i386 based on %s", it->path);
483 return CPU_TYPE_I386
;
485 else if ( mach_o::relocatable::Reader
<x86_64
>::validFile(buffer
) ) {
486 //warning("-arch not used, infering -arch x86_64 based on %s", it->path);
487 return CPU_TYPE_X86_64
;
489 else if ( mach_o::relocatable::Reader
<arm
>::validFile(buffer
) ) {
490 //warning("-arch not used, infering -arch arm based on %s", it->path);
497 // no thin .o files found, so default to same architecture this was built as
498 warning("-arch not specified");
500 return CPU_TYPE_POWERPC
;
502 return CPU_TYPE_I386
;
504 return CPU_TYPE_POWERPC64
;
506 return CPU_TYPE_X86_64
;
510 #error unknown default architecture
515 void Linker::addInputFile(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
)
517 fInputFiles
.push_back(reader
);
518 fDylibOptionsMap
[reader
] = info
.options
;
521 void Linker::setOutputFile(ExecutableFile::Writer
* writer
)
523 fOutputFile
= writer
;
529 InSet(std::set
<ObjectFile::Atom
*>& deadAtoms
) : fDeadAtoms(deadAtoms
) {}
531 bool operator()(ObjectFile::Atom
*& atom
) const {
532 return ( fDeadAtoms
.count(atom
) != 0 );
536 std::set
<ObjectFile::Atom
*>& fDeadAtoms
;
539 void Linker::loadAndResolve()
541 fStartLoadAndResolveTime
= mach_absolute_time();
542 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
543 // without dead-code-stripping:
544 // find atoms to resolve all undefines
545 this->loadUndefines();
546 // verify nothing is missing
547 this->checkUndefines();
548 // once all undefines fulfill, then bind all references
549 this->resolveReferences();
550 // remove atoms weak atoms that have been overridden
551 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fDeadAtoms
)), fAllAtoms
.end());
554 // with dead code stripping:
555 // start binding references from roots,
556 this->deadStripResolve();
557 // verify nothing is missing
558 this->checkUndefines();
562 void Linker::optimize()
564 // give each reader a chance to do any optimizations
565 std::vector
<class ObjectFile::Atom
*> newAtoms
;
566 std::vector
<const char *> additionalUndefines
;
567 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
568 (*it
)->optimize(fAllAtoms
, newAtoms
, additionalUndefines
, fDeadAtoms
, fNextInputOrdinal
, fOutputFile
,
569 fOptions
.llvmOptions(),
570 fOptions
.allGlobalsAreDeadStripRoots(), (int)fOptions
.outputKind(), fOptions
.verbose(),
571 fOptions
.saveTempFiles(), fOptions
.getOutputFilePath(), fOptions
.positionIndependentExecutable(),
572 fOptions
.allowTextRelocs());
575 // add all newly created atoms to fAllAtoms and update symbol table
576 this->addAtoms(newAtoms
);
578 // Make sure all atoms have a section. Atoms that were not originally in a mach-o file could
579 // not have their section set until now.
580 for(std::vector
<class ObjectFile::Atom
*>::iterator itr
= fAllAtoms
.begin(); itr
!= fAllAtoms
.end(); ++itr
) {
581 ObjectFile::Atom
*atom
= *itr
;
582 if ( atom
->getSection() == NULL
)
583 atom
->setSection(Section::find(atom
->getSectionName(), atom
->getSegment().getName(), atom
->isZeroFill()));
586 // resolve new undefines
587 for(std::vector
<const char*>::iterator riter
= additionalUndefines
.begin(); riter
!= additionalUndefines
.end(); ++riter
) {
588 const char *targetName
= *riter
;
589 //fprintf(stderr, "LTO additional undefine: %s\n", targetName);
590 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
591 if ( target
== NULL
) {
592 // mark that this symbol is needed
593 fGlobalSymbolTable
.require(targetName
);
594 // try to find it in some library
595 this->addJustInTimeAtoms(targetName
);
599 if ( fOptions
.deadStrip() != Options::kDeadStripOff
) {
601 this->deadStripResolve();
604 this->checkUndefines();
605 this->resolveReferences();
611 this->buildAtomList();
612 this->loadAndResolve();
615 this->processDTrace();
617 this->sortSections();
619 this->writeDotOutput();
620 this->collectDebugInfo();
622 this->printStatistics();
624 if ( fOptions
.pauseAtEnd() )
628 void Linker::printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
)
630 static uint64_t sUnitsPerSecond
= 0;
631 if ( sUnitsPerSecond
== 0 ) {
632 struct mach_timebase_info timeBaseInfo
;
633 if ( mach_timebase_info(&timeBaseInfo
) == KERN_SUCCESS
) {
634 sUnitsPerSecond
= 1000000000ULL * timeBaseInfo
.denom
/ timeBaseInfo
.numer
;
635 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
638 if ( partTime
< sUnitsPerSecond
) {
639 uint32_t milliSecondsTimeTen
= (partTime
*10000)/sUnitsPerSecond
;
640 uint32_t milliSeconds
= milliSecondsTimeTen
/10;
641 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
642 uint32_t percent
= percentTimesTen
/10;
643 fprintf(stderr
, "%s: %u.%u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimeTen
-milliSeconds
*10, percent
, percentTimesTen
-percent
*10);
646 uint32_t secondsTimeTen
= (partTime
*10)/sUnitsPerSecond
;
647 uint32_t seconds
= secondsTimeTen
/10;
648 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
649 uint32_t percent
= percentTimesTen
/10;
650 fprintf(stderr
, "%s: %u.%u seconds (%u.%u%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10);
654 char* Linker::commatize(uint64_t in
, char* out
)
658 sprintf(rawNum
, "%llu", in
);
659 const int rawNumLen
= strlen(rawNum
);
660 for(int i
=0; i
< rawNumLen
-1; ++i
) {
662 if ( ((rawNumLen
-i
) % 3) == 1 )
665 *out
++ = rawNum
[rawNumLen
-1];
670 void Linker::getVMInfo(vm_statistics_data_t
& info
)
672 mach_msg_type_number_t count
= sizeof(vm_statistics_data_t
) / sizeof(natural_t
);
673 kern_return_t error
= host_statistics(mach_host_self(), HOST_VM_INFO
,
674 (host_info_t
)&info
, &count
);
675 if (error
!= KERN_SUCCESS
) {
676 bzero(&info
, sizeof(vm_statistics_data_t
));
680 void Linker::printStatistics()
682 fEndTime
= mach_absolute_time();
683 if ( fOptions
.printStatistics() ) {
684 vm_statistics_data_t endVMInfo
;
685 getVMInfo(endVMInfo
);
687 uint64_t totalTime
= fEndTime
- fStartTime
;
688 printTime("ld total time", totalTime
, totalTime
);
689 printTime(" option parsing time", fStartCreateReadersTime
- fStartTime
, totalTime
);
690 printTime(" object file processing",fStartCreateWriterTime
- fStartCreateReadersTime
, totalTime
);
691 printTime(" output file setup", fStartBuildAtomsTime
- fStartCreateWriterTime
, totalTime
);
692 printTime(" build atom list", fStartLoadAndResolveTime
- fStartBuildAtomsTime
, totalTime
);
693 printTime(" resolve references", fStartSortTime
- fStartLoadAndResolveTime
, totalTime
);
694 printTime(" sort output", fStartDebugTime
- fStartSortTime
, totalTime
);
695 printTime(" process debug info", fStartWriteTime
- fStartDebugTime
, totalTime
);
696 printTime(" write output", fEndTime
- fStartWriteTime
, totalTime
);
697 fprintf(stderr
, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo
.pageins
-fStartVMInfo
.pageins
,
698 endVMInfo
.pageouts
-fStartVMInfo
.pageouts
, endVMInfo
.faults
-fStartVMInfo
.faults
);
700 fprintf(stderr
, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded
, commatize(fTotalObjectSize
, temp
));
701 fprintf(stderr
, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded
, commatize(fTotalArchiveSize
, temp
));
702 fprintf(stderr
, "processed %3u dylib files\n", fTotalDylibsLoaded
);
703 fprintf(stderr
, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize
, temp
));
707 inline void Linker::addAtom(ObjectFile::Atom
& atom
)
709 // add to list of all atoms
710 fAllAtoms
.push_back(&atom
);
712 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
713 // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later
714 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
715 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
716 ObjectFile::Reference
* reference
= *it
;
717 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
)
718 fGlobalSymbolTable
.require(reference
->getTargetName());
719 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
)
720 fGlobalSymbolTable
.require(reference
->getFromTargetName());
721 if ( reference
->getTargetBinding() == ObjectFile::Reference::kDontBind
)
722 addDtraceProbe(atom
, reference
->getFixUpOffset(), reference
->getTargetName());
724 // update total size info (except for __ZEROPAGE atom)
725 if ( atom
.getSegment().isContentReadable() ) {
726 fTotalSize
+= atom
.getSize();
727 if ( atom
.isZeroFill() )
728 fTotalZeroFillSize
+= atom
.getSize();
732 if ( atom
.dontDeadStrip() )
733 fLiveRootAtoms
.insert(&atom
);
736 // if in global namespace, add atom itself to symbol table
737 ObjectFile::Atom::Scope scope
= atom
.getScope();
738 const char* name
= atom
.getName();
739 if ( (scope
!= ObjectFile::Atom::scopeTranslationUnit
) && (name
!= NULL
) ) {
740 // update scope based on export list
741 if ( fOptions
.hasExportRestrictList() ) {
742 if ( scope
== ObjectFile::Atom::scopeGlobal
) {
743 // check for globals that are downgraded to hidden
744 bool doExport
= fOptions
.shouldExport(name
);
746 atom
.setScope(ObjectFile::Atom::scopeLinkageUnit
);
749 else if ( scope
== ObjectFile::Atom::scopeLinkageUnit
) {
750 // check for hiddens that were requested to be exported
751 if ( fOptions
.hasExportMaskList() && fOptions
.shouldExport(name
) ) {
752 warning("cannot export hidden symbol %s from %s", name
, atom
.getFile()->getPath());
756 // add to symbol table
757 if ( fOptions
.outputKind() == Options::kObjectFile
) {
758 // in ld -r mode don't add .eh symbols to symbol table
759 // instead kGroupSubordinate references will keep them paired
760 // with their functions.
761 const char* sectionName
= atom
.getSectionName();
762 if ( (sectionName
!= NULL
) && (strcmp(sectionName
, "__eh_frame") != 0) )
763 fGlobalSymbolTable
.add(atom
);
766 fGlobalSymbolTable
.add(atom
);
770 // record section orders so output file can have same order
771 if (atom
.getSectionName())
772 atom
.setSection(Section::find(atom
.getSectionName(), atom
.getSegment().getName(), atom
.isZeroFill()));
776 void Linker::markDead(ObjectFile::Atom
* atom
)
778 fDeadAtoms
.insert(atom
);
780 // The kGroupSubordinate reference kind is used to model group comdat.
781 // The "signature" atom in the group has a kGroupSubordinate reference to
782 // all other members of the group. So, if the signature atom is
783 // coalesced away, all other atoms in the group should also be removed.
785 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
786 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
787 ObjectFile::Reference
* ref
= *rit
;
788 if ( ref
->getKind() == 2 /*kGroupSubordinate*/ ) { // FIX FIX
789 ObjectFile::Atom
* targetAtom
= &(ref
->getTarget());
790 if ( targetAtom
== NULL
) {
791 warning("%s has a group reference to %s but is not bound", atom
->getDisplayName(), ref
->getTargetName());
794 if ( targetAtom
->getScope() != ObjectFile::Atom::scopeTranslationUnit
) {
795 // ok for .eh symbols to be not static in -r mode
796 if ( (fOptions
.outputKind() != Options::kObjectFile
) || (strcmp(targetAtom
->getSectionName(), "__eh_frame") != 0) )
797 warning("%s is in a comdat group but its scope is not static", targetAtom
->getDisplayName());
799 this->markDead(targetAtom
);
805 void Linker::updateConstraints(ObjectFile::Reader
* reader
)
807 // check objc objects were compiled compatibly
808 ObjectFile::Reader::ObjcConstraint objcAddition
= reader
->getObjCConstraint();
809 if ( reader
->getInstallPath() == NULL
) {
811 switch ( objcAddition
) {
812 case ObjectFile::Reader::kObjcNone
:
814 case ObjectFile::Reader::kObjcRetainRelease
:
815 if ( fCurrentObjCConstraint
== ObjectFile::Reader::kObjcGC
)
816 throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", reader
->getPath());
817 fCurrentObjCConstraint
= ObjectFile::Reader::kObjcRetainRelease
;
819 case ObjectFile::Reader::kObjcRetainReleaseOrGC
:
820 if ( fCurrentObjCConstraint
== ObjectFile::Reader::kObjcNone
)
821 fCurrentObjCConstraint
= ObjectFile::Reader::kObjcRetainReleaseOrGC
;
823 case ObjectFile::Reader::kObjcGC
:
824 if ( fCurrentObjCConstraint
== ObjectFile::Reader::kObjcRetainRelease
)
825 throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", reader
->getPath());
826 fCurrentObjCConstraint
= ObjectFile::Reader::kObjcGC
;
830 if ( reader
->objcReplacementClasses() )
831 fObjcReplacmentClasses
= true;
833 // check cpu sub-types for stricter sub-type
834 fCurrentCpuConstraint
= (ObjectFile::Reader::CpuConstraint
)reader
->updateCpuConstraint(fCurrentCpuConstraint
);
837 inline void Linker::addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
)
839 bool scanAll
= fOptions
.readerOptions().fFullyLoadArchives
|| fOptions
.readerOptions().fLoadAllObjcObjectsFromArchives
;
841 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
.begin(); it
!= atoms
.end(); it
++) {
842 // usually we only need to get the first atom's reader, but
843 // with -all_load all atoms from all .o files come come back together
844 // so we need to scan all atoms
845 if ( first
|| scanAll
) {
846 // update fReadersThatHaveSuppliedAtoms
847 ObjectFile::Reader
* reader
= (*it
)->getFile();
848 if ( std::find(fReadersThatHaveSuppliedAtoms
.begin(), fReadersThatHaveSuppliedAtoms
.end(), reader
)
849 == fReadersThatHaveSuppliedAtoms
.end() ) {
850 fReadersThatHaveSuppliedAtoms
.push_back(reader
);
851 updateConstraints(reader
);
859 void Linker::logArchive(ObjectFile::Reader
* reader
)
861 if ( (fArchiveReaders
.count(reader
) != 0) && (fArchiveReadersLogged
.count(reader
) == 0) ) {
862 fArchiveReadersLogged
.insert(reader
);
863 const char* fullPath
= reader
->getPath();
864 char realName
[MAXPATHLEN
];
865 if ( realpath(fullPath
, realName
) != NULL
)
867 logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath
);
872 void Linker::buildAtomList()
874 fStartBuildAtomsTime
= mach_absolute_time();
875 // add initial undefines from -u option
876 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
877 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++) {
878 fGlobalSymbolTable
.require(*it
);
881 // writer can contribute atoms
882 this->addAtoms(fOutputFile
->getAtoms());
884 // each reader contributes atoms
885 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
886 ObjectFile::Reader
* reader
= *it
;
887 std::vector
<class ObjectFile::Atom
*>& atoms
= reader
->getAtoms();
888 this->addAtoms(atoms
);
889 if ( fOptions
.readerOptions().fTraceArchives
&& (atoms
.size() != 0) )
893 // extra command line section always at end
894 std::vector
<Options::ExtraSection
>& extraSections
= fOptions
.extraSections();
895 for( std::vector
<Options::ExtraSection
>::iterator it
=extraSections
.begin(); it
!= extraSections
.end(); ++it
) {
896 this->addAtoms((new opaque_section::Reader(it
->segmentName
, it
->sectionName
, it
->path
, it
->data
, it
->dataLen
, fNextInputOrdinal
))->getAtoms());
897 fNextInputOrdinal
+= it
->dataLen
;
901 static const char* pathLeafName(const char* path
)
903 const char* shortPath
= strrchr(path
, '/');
904 if ( shortPath
== NULL
)
907 return &shortPath
[1];
910 void Linker::loadUndefines()
912 // keep looping until no more undefines were added in last loop
913 unsigned int undefineCount
= 0xFFFFFFFF;
914 while ( undefineCount
!= fGlobalSymbolTable
.getRequireCount() ) {
915 undefineCount
= fGlobalSymbolTable
.getRequireCount();
916 std::vector
<const char*> undefineNames
;
917 fGlobalSymbolTable
.getNeededNames(false, undefineNames
);
918 for(std::vector
<const char*>::iterator it
= undefineNames
.begin(); it
!= undefineNames
.end(); ++it
) {
919 const char* name
= *it
;
920 ObjectFile::Atom
* possibleAtom
= fGlobalSymbolTable
.find(name
);
921 if ( (possibleAtom
== NULL
)
922 || ((possibleAtom
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
)
923 && (fOptions
.outputKind() != Options::kObjectFile
)
924 && (possibleAtom
->getScope() == ObjectFile::Atom::scopeGlobal
)) ) {
925 std::vector
<class ObjectFile::Atom
*>* atoms
= this->addJustInTimeAtoms(name
);
933 // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
934 class ExportedObjcClass
937 ExportedObjcClass(Options
& opt
) : fOptions(opt
) {}
939 bool operator()(const char* name
) const {
940 if ( fOptions
.shouldExport(name
) ) {
941 if ( strncmp(name
, ".objc_class_name_", 17) == 0 )
943 if ( strncmp(name
, "_OBJC_CLASS_$_", 14) == 0 )
945 if ( strncmp(name
, "_OBJC_METACLASS_$_", 18) == 0 )
948 //fprintf(stderr, "%s is not exported\n", name);
956 void Linker::checkUndefines()
958 // error out on any remaining undefines
961 switch ( fOptions
.undefinedTreatment() ) {
962 case Options::kUndefinedError
:
964 case Options::kUndefinedDynamicLookup
:
967 case Options::kUndefinedWarning
:
970 case Options::kUndefinedSuppress
:
975 std::vector
<const char*> unresolvableUndefines
;
976 fGlobalSymbolTable
.getNeededNames(false, unresolvableUndefines
);
978 // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
979 // ignore unresolved references to Objc class names that are listed in -exported_symbols_list
980 if ( fOptions
.hasExportRestrictList() )
981 unresolvableUndefines
.erase(std::remove_if(unresolvableUndefines
.begin(), unresolvableUndefines
.end(), ExportedObjcClass(fOptions
)), unresolvableUndefines
.end());
983 const int unresolvableCount
= unresolvableUndefines
.size();
984 int unresolvableExportsCount
= 0;
985 if ( unresolvableCount
!= 0 ) {
987 if ( fOptions
.printArchPrefix() )
988 fprintf(stderr
, "Undefined symbols for architecture %s:\n", fArchitectureName
);
990 fprintf(stderr
, "Undefined symbols:\n");
991 for (int i
=0; i
< unresolvableCount
; ++i
) {
992 const char* name
= unresolvableUndefines
[i
];
993 fprintf(stderr
, " \"%s\", referenced from:\n", name
);
994 // scan all atoms for references
995 bool foundAtomReference
= false;
996 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
997 ObjectFile::Atom
* atom
= *it
;
998 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
999 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1000 ObjectFile::Reference
* reference
= *rit
;
1001 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1002 if ( strcmp(reference
->getTargetName(), name
) == 0 ) {
1003 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
1004 foundAtomReference
= true;
1007 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1008 if ( strcmp(reference
->getFromTargetName(), name
) == 0 ) {
1009 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
1010 foundAtomReference
= true;
1015 // scan command line options
1016 if ( !foundAtomReference
&& fOptions
.hasExportRestrictList() && fOptions
.shouldExport(name
) ) {
1017 fprintf(stderr
, " -exported_symbols_list command line option\n");
1018 ++unresolvableExportsCount
;
1023 throw "symbol(s) not found";
1026 // for each tentative definition in symbol table look for dylib that exports same symbol name
1027 if ( fGlobalSymbolTable
.hasExternalTentativeDefinitions() ) {
1028 for (SymbolTable::Mapper::iterator it
=fGlobalSymbolTable
.begin(); it
!= fGlobalSymbolTable
.end(); ++it
) {
1029 ObjectFile::Atom
* atom
= it
->second
;
1030 if ( (atom
!= NULL
) && (atom
->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition
)
1031 && (atom
->getScope() == ObjectFile::Atom::scopeGlobal
) ) {
1032 // look for dylibs that export same name as used by global tentative definition
1033 addJustInTimeAtoms(atom
->getName(), true);
1038 // if we have no weak symbols, see if we override some weak symbol in some dylib
1039 if ( !fGlobalSymbolTable
.hasExternalWeakDefinitions() ) {
1041 for (SymbolTable::Mapper::iterator it
=fGlobalSymbolTable
.begin(); !done
&& (it
!= fGlobalSymbolTable
.end()); ++it
) {
1042 ObjectFile::Atom
* atom
= it
->second
;
1043 if ( (atom
!= NULL
) && (atom
->getDefinitionKind()==ObjectFile::Atom::kRegularDefinition
)
1044 && (atom
->getScope() == ObjectFile::Atom::scopeGlobal
) ) {
1045 const char* name
= atom
->getName();
1046 //fprintf(stderr, "looking for dylibs with a weak %s\n", name);
1047 // look for dylibs with weak exports of the same name
1048 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1049 ObjectFile::Reader
* reader
= it
->second
;
1050 if ( reader
->hasWeakExternals() ) {
1051 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
1052 if ( atoms
!= NULL
) {
1053 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1054 // if this is a weak definition in a dylib
1055 if ( (atoms
->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1056 fGlobalSymbolTable
.setHasExternalWeakDefinitions();
1071 std::vector
<class ObjectFile::Atom
*>* Linker::addJustInTimeAtoms(const char* name
, bool dylibsOnly
)
1073 // when creating final linked image, writer gets first chance
1074 if ( fOptions
.outputKind() != Options::kObjectFile
) {
1075 std::vector
<class ObjectFile::Atom
*>* atoms
= fOutputFile
->getJustInTimeAtomsFor(name
);
1076 if ( atoms
!= NULL
) {
1077 this->addAtoms(*atoms
);
1078 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
1079 return atoms
; // found a definition, no need to search anymore
1083 // give readers a chance
1084 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
1085 ObjectFile::Reader
* reader
= *it
;
1086 if ( reader
!= NULL
) {
1087 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
1088 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
1089 //fprintf(stderr, "addJustInTimeAtoms(%s), looking in reader %s\n", name, reader->getPath() );
1090 bool isDylibReader
= (reader
->getInstallPath() != NULL
);
1091 if ( !dylibsOnly
|| isDylibReader
) {
1092 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
1093 if ( atoms
!= NULL
) {
1094 this->addAtoms(*atoms
);
1095 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1096 if ( !isDylibReader
&& fOptions
.readerOptions().fTraceArchives
) {
1099 // if this is a weak definition in a dylib
1100 if ( isDylibReader
&& (atoms
->size() == 1) && (atoms
->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1101 // keep looking for a non-weak definition
1104 // found a definition, no need to search anymore
1112 // for two level namesapce, give all implicitly link dylibs a chance
1113 if ( fOptions
.nameSpace() == Options::kTwoLevelNameSpace
) {
1114 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1115 if ( it
->second
->implicitlyLinked() ) {
1116 //fprintf(stderr, "addJustInTimeAtoms(%s), looking in implicitly linked %s\n", name, it->second->getPath() );
1117 std::vector
<class ObjectFile::Atom
*>* atoms
= it
->second
->getJustInTimeAtomsFor(name
);
1118 if ( atoms
!= NULL
) {
1119 this->addAtoms(*atoms
);
1120 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1121 // if this is a weak definition in a dylib
1122 if ( (atoms
->size() == 1) && (atoms
->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1123 // keep looking for a non-weak definition
1126 // found a definition, no need to search anymore
1134 // for flat namespace, give indirect dylibs
1135 if ( fOptions
.nameSpace() != Options::kTwoLevelNameSpace
) {
1136 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1137 if ( ! it
->second
->explicitlyLinked() ) {
1138 std::vector
<class ObjectFile::Atom
*>* atoms
= it
->second
->getJustInTimeAtomsFor(name
);
1139 if ( atoms
!= NULL
) {
1140 this->addAtoms(*atoms
);
1141 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1142 return atoms
; // found a definition, no need to search anymore
1148 // writer creates a proxy in two cases:
1149 // 1) ld -r is being used to create a .o file
1150 // 2) -undefined dynamic_lookup is being used
1151 // 3) -U _foo is being used
1152 if ( (fOptions
.outputKind() == Options::kObjectFile
)
1153 || ((fOptions
.undefinedTreatment() != Options::kUndefinedError
) && !dylibsOnly
)
1154 || (fOptions
.someAllowedUndefines() && !dylibsOnly
) ) {
1155 ObjectFile::Atom
* atom
= fOutputFile
->getUndefinedProxyAtom(name
);
1156 if ( atom
!= NULL
) {
1157 this->addAtom(*atom
);
1161 //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
1165 void Linker::resolve(ObjectFile::Reference
* reference
)
1167 // look in global symbol table
1168 const char* targetName
= reference
->getTargetName();
1169 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1170 if ( target
== NULL
) {
1171 fprintf(stderr
, "Undefined symbol: %s\n", targetName
);
1173 reference
->setTarget(*target
, reference
->getTargetOffset());
1176 void Linker::resolveFrom(ObjectFile::Reference
* reference
)
1178 // handle references that have two (from and to) targets
1179 const char* fromTargetName
= reference
->getFromTargetName();
1180 ObjectFile::Atom
* fromTarget
= fGlobalSymbolTable
.find(fromTargetName
);
1181 if ( fromTarget
== NULL
) {
1182 fprintf(stderr
, "Undefined symbol: %s\n", fromTargetName
);
1184 reference
->setFromTarget(*fromTarget
);
1188 void Linker::resolveReferences()
1190 // note: the atom list may grow during this loop as libraries supply needed atoms
1191 for (unsigned int j
=0; j
< fAllAtoms
.size(); ++j
) {
1192 ObjectFile::Atom
* atom
= fAllAtoms
[j
];
1193 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
1194 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
1195 ObjectFile::Reference
* reference
= *it
;
1196 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
)
1197 this->resolve(reference
);
1198 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
)
1199 this->resolveFrom(reference
);
1205 // used to remove stabs associated with atoms that won't be in output file
1209 NotInSet(std::set
<ObjectFile::Atom
*>& theSet
) : fSet(theSet
) {}
1211 bool operator()(const ObjectFile::Reader::Stab
& stab
) const {
1212 if ( stab
.atom
== NULL
)
1213 return false; // leave stabs that are not associated with any atome
1215 return ( fSet
.count(stab
.atom
) == 0 );
1219 std::set
<ObjectFile::Atom
*>& fSet
;
1226 NotLive(std::set
<ObjectFile::Atom
*>& set
) : fLiveAtoms(set
) {}
1228 bool operator()(ObjectFile::Atom
*& atom
) const {
1229 //if ( fLiveAtoms.count(atom) == 0 )
1230 // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
1231 return ( fLiveAtoms
.count(atom
) == 0 );
1234 std::set
<ObjectFile::Atom
*>& fLiveAtoms
;
1238 void Linker::addJustInTimeAtomsAndMarkLive(const char* name
)
1240 std::vector
<class ObjectFile::Atom
*>* atoms
= this->addJustInTimeAtoms(name
);
1241 if ( atoms
!= NULL
) {
1242 if ( fOptions
.allGlobalsAreDeadStripRoots() ) {
1243 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
->begin(); it
!= atoms
->end(); it
++) {
1244 ObjectFile::Atom
* atom
= *it
;
1245 if ( atom
->getScope() == ObjectFile::Atom::scopeGlobal
) {
1246 WhyLiveBackChain rootChain
;
1247 rootChain
.previous
= NULL
;
1248 rootChain
.name
= atom
->getDisplayName();
1249 this->markLive(*atom
, &rootChain
);
1257 void Linker::markLive(ObjectFile::Atom
& atom
, struct Linker::WhyLiveBackChain
* previous
)
1259 if ( fLiveAtoms
.count(&atom
) == 0 ) {
1260 // if -whylive cares about this symbol, then dump chain
1261 if ( (previous
->name
!= NULL
) && fOptions
.printWhyLive(previous
->name
) ) {
1263 for(WhyLiveBackChain
* p
= previous
; p
!= NULL
; p
= p
->previous
, ++depth
) {
1264 for(int i
=depth
; i
> 0; --i
)
1265 fprintf(stderr
, " ");
1266 fprintf(stderr
, "%s\n", p
->name
);
1269 // set up next chain
1270 WhyLiveBackChain thisChain
;
1271 thisChain
.previous
= previous
;
1272 // this atom is live
1273 fLiveAtoms
.insert(&atom
);
1274 // update total size info (except for __ZEROPAGE atom)
1275 if ( atom
.getSegment().isContentReadable() ) {
1276 fTotalSize
+= atom
.getSize();
1277 if ( atom
.isZeroFill() )
1278 fTotalZeroFillSize
+= atom
.getSize();
1280 // and all atoms it references
1281 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
1282 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
1283 ObjectFile::Reference
* reference
= *it
;
1284 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1285 // look in global symbol table
1286 const char* targetName
= reference
->getTargetName();
1287 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1288 if ( target
== NULL
) {
1289 // load archives or dylibs
1290 this->addJustInTimeAtomsAndMarkLive(targetName
);
1293 target
= fGlobalSymbolTable
.find(targetName
);
1294 if ( target
!= NULL
) {
1295 reference
->setTarget(*target
, reference
->getTargetOffset());
1298 // mark as undefined, for later error processing
1299 fAtomsWithUnresolvedReferences
.push_back(&atom
);
1300 fGlobalSymbolTable
.require(targetName
);
1303 switch ( reference
->getTargetBinding() ) {
1304 case ObjectFile::Reference::kBoundDirectly
:
1305 case ObjectFile::Reference::kBoundByName
:
1306 thisChain
.name
= reference
->getTargetName();
1307 markLive(reference
->getTarget(), &thisChain
);
1309 case ObjectFile::Reference::kDontBind
:
1310 addDtraceProbe(atom
, reference
->getFixUpOffset(), reference
->getTargetName());
1312 case ObjectFile::Reference::kUnboundByName
:
1316 // do the same as above, for "from target"
1317 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1318 // look in global symbol table
1319 const char* targetName
= reference
->getFromTargetName();
1320 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1321 if ( target
== NULL
) {
1322 // load archives or dylibs
1323 this->addJustInTimeAtomsAndMarkLive(targetName
);
1326 target
= fGlobalSymbolTable
.find(targetName
);
1327 if ( target
!= NULL
) {
1328 reference
->setFromTarget(*target
);
1331 // mark as undefined, for later error processing
1332 fGlobalSymbolTable
.require(targetName
);
1335 switch ( reference
->getFromTargetBinding() ) {
1336 case ObjectFile::Reference::kBoundDirectly
:
1337 case ObjectFile::Reference::kBoundByName
:
1338 thisChain
.name
= reference
->getFromTargetName();
1339 markLive(reference
->getFromTarget(), &thisChain
);
1341 case ObjectFile::Reference::kUnboundByName
:
1342 case ObjectFile::Reference::kDontBind
:
1351 void Linker::addLiveRoot(const char* name
)
1353 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(name
);
1354 if ( target
== NULL
) {
1355 this->addJustInTimeAtomsAndMarkLive(name
);
1356 target
= fGlobalSymbolTable
.find(name
);
1358 if ( target
!= NULL
)
1359 fLiveRootAtoms
.insert(target
);
1363 void Linker::deadStripResolve()
1365 // add main() to live roots
1366 ObjectFile::Atom
* entryPoint
= this->entryPoint(false);
1367 if ( entryPoint
!= NULL
)
1368 fLiveRootAtoms
.insert(entryPoint
);
1370 // add dyld_stub_binding_helper() to live roots
1371 ObjectFile::Atom
* dyldHelper
= this->dyldHelper();
1372 if ( dyldHelper
!= NULL
)
1373 fLiveRootAtoms
.insert(dyldHelper
);
1375 // if using lazy dylib loading, add dyld_lazy_dylib_stub_binding_helper() to live roots
1376 if ( fOptions
.usingLazyDylibLinking() ) {
1377 ObjectFile::Atom
* dyldLazyDylibHelper
= this->dyldLazyLibraryHelper();
1378 if ( dyldLazyDylibHelper
!= NULL
)
1379 fLiveRootAtoms
.insert(dyldLazyDylibHelper
);
1382 // add -exported_symbols_list, -init, and -u entries to live roots
1383 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
1384 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++)
1387 // if -exported_symbols_list that has wildcards, we need to find all matches and make them the roots
1388 // <rdar://problem/5524973>
1389 if ( fOptions
.hasWildCardExportRestrictList() ) {
1390 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1391 ObjectFile::Atom
* atom
= *it
;
1392 if ( (atom
->getScope() == ObjectFile::Atom::scopeGlobal
)
1393 && (fDeadAtoms
.count(atom
) == 0)
1394 && fOptions
.shouldExport(atom
->getName()) )
1395 fLiveRootAtoms
.insert(atom
);
1399 // in some cases, every global scope atom in initial .o files is a root
1400 if ( fOptions
.allGlobalsAreDeadStripRoots() ) {
1401 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1402 ObjectFile::Atom
* atom
= *it
;
1403 if ( (atom
->getScope() == ObjectFile::Atom::scopeGlobal
) && (fDeadAtoms
.count(atom
) == 0) )
1404 fLiveRootAtoms
.insert(atom
);
1408 // mark all roots as live, and all atoms they reference
1409 for (std::set
<ObjectFile::Atom
*>::iterator it
=fLiveRootAtoms
.begin(); it
!= fLiveRootAtoms
.end(); it
++) {
1410 WhyLiveBackChain rootChain
;
1411 rootChain
.previous
= NULL
;
1412 rootChain
.name
= (*it
)->getDisplayName();
1413 markLive(**it
, &rootChain
);
1416 // it is possible that there are unresolved references that can be resolved now
1417 // this can happen if the first reference to a common symbol in an archive.
1418 // common symbols are not in the archive TOC, but the .o could have been pulled in later.
1419 // <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
1420 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAtomsWithUnresolvedReferences
.begin(); it
!= fAtomsWithUnresolvedReferences
.end(); it
++) {
1421 std::vector
<class ObjectFile::Reference
*>& references
= (*it
)->getReferences();
1422 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1423 ObjectFile::Reference
* reference
= *rit
;
1424 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1425 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(reference
->getTargetName());
1426 if ( target
!= NULL
) {
1427 reference
->setTarget(*target
, reference
->getTargetOffset());
1428 fLiveAtoms
.insert(target
);
1429 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1430 // references, which is true for commons.
1431 if ( target
->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition
)
1432 warning("internal error %s is not a tentative definition", target
->getDisplayName());
1435 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1436 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(reference
->getFromTargetName());
1437 if ( target
!= NULL
) {
1438 reference
->setFromTarget(*target
);
1439 fLiveAtoms
.insert(target
);
1440 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1441 // references, which is true for commons.
1442 if ( target
->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition
)
1443 warning("internal error %s is not a tentative definition", target
->getDisplayName());
1449 // now remove all non-live atoms from fAllAtoms
1450 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), NotLive(fLiveAtoms
)), fAllAtoms
.end());
1453 void Linker::checkObjC()
1456 switch ( fCurrentObjCConstraint
) {
1457 case ObjectFile::Reader::kObjcNone
:
1458 // can link against any dylib
1460 case ObjectFile::Reader::kObjcRetainRelease
:
1461 // cannot link against GC-only dylibs
1462 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1463 if ( it
->second
->explicitlyLinked() ) {
1464 if ( it
->second
->getObjCConstraint() == ObjectFile::Reader::kObjcGC
)
1465 throwf("this linkage unit uses Retain/Release. It cannot link against the GC-only dylib: %s", it
->second
->getPath());
1469 case ObjectFile::Reader::kObjcRetainReleaseOrGC
:
1470 // can link against GC or RR dylibs
1472 case ObjectFile::Reader::kObjcGC
:
1473 // cannot link against RR-only dylibs
1474 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1475 if ( it
->second
->explicitlyLinked() ) {
1476 if ( it
->second
->getObjCConstraint() == ObjectFile::Reader::kObjcRetainRelease
)
1477 throwf("this linkage unit requires GC. It cannot link against Retain/Release dylib: %s", it
->second
->getPath());
1483 // synthesize __OBJC __image_info atom if needed
1484 if ( fCurrentObjCConstraint
!= ObjectFile::Reader::kObjcNone
) {
1485 this->addAtom(fOutputFile
->makeObjcInfoAtom(fCurrentObjCConstraint
, fObjcReplacmentClasses
));
1489 void Linker::addDtraceProbe(ObjectFile::Atom
& atom
, uint32_t offsetInAtom
, const char* probeName
)
1491 if ( probeName
!= NULL
) {
1492 if ( strncmp(probeName
, "___dtrace_probe$", 16) == 0 )
1493 fDtraceProbeSites
.push_back(DTraceProbeInfo(&atom
, offsetInAtom
, probeName
));
1494 else if ( strncmp(probeName
, "___dtrace_isenabled$", 20) == 0 )
1495 fDtraceIsEnabledSites
.push_back(DTraceProbeInfo(&atom
, offsetInAtom
, probeName
));
1496 else if ( strncmp(probeName
, "___dtrace_", 10) == 0 )
1497 fDtraceAtomToTypes
[&atom
].insert(probeName
);
1498 else if ( fOptions
.dTrace() && (strncmp(probeName
, "__dtrace_probe$", 15) == 0) )
1499 fDtraceProbes
.push_back(DTraceProbeInfo(&atom
, offsetInAtom
, probeName
));
1503 static uint8_t pointerKind(cpu_type_t arch
)
1506 case CPU_TYPE_POWERPC
:
1507 return ppc::kPointer
;
1508 case CPU_TYPE_POWERPC64
:
1509 return ppc64::kPointer
;
1511 return x86::kPointer
;
1512 case CPU_TYPE_X86_64
:
1513 return x86_64::kPointer
;
1515 return arm::kPointer
;
1517 throw "uknown architecture";
1520 static uint8_t pcRelKind(cpu_type_t arch
)
1523 case CPU_TYPE_POWERPC
:
1524 return ppc::kPointerDiff32
;
1525 case CPU_TYPE_POWERPC64
:
1526 return ppc64::kPointerDiff32
;
1528 return x86::kPointerDiff
;
1529 case CPU_TYPE_X86_64
:
1530 return x86_64::kPointerDiff32
;
1532 return arm::kPointerDiff
;
1534 throw "uknown architecture";
1537 typedef uint8_t* (*oldcreatedof_func_t
) (const char*, cpu_type_t
, unsigned int, const char*[], const char*[], uint64_t offsetsInDOF
[], size_t* size
);
1538 typedef uint8_t* (*createdof_func_t
)(cpu_type_t
, unsigned int, const char*[], unsigned int, const char*[], const char*[], uint64_t offsetsInDOF
[], size_t* size
);
1541 void Linker::processDTrace()
1543 // handle dtrace 2.0 static probes
1544 if ( (fOptions
.outputKind() != Options::kObjectFile
) && ((fDtraceProbeSites
.size() != 0) || (fDtraceIsEnabledSites
.size() != 0)) ) {
1545 // partition probes by provider name
1546 // The symbol names looks like:
1547 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
1548 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
1549 ProviderToProbes providerToProbes
;
1550 std::vector
<DTraceProbeInfo
> emptyList
;
1551 for(std::vector
<DTraceProbeInfo
>::iterator it
= fDtraceProbeSites
.begin(); it
!= fDtraceProbeSites
.end(); ++it
) {
1552 // ignore probes in functions that were coalesed away rdar://problem/5628149
1553 if ( fDeadAtoms
.count((ObjectFile::Atom
*)(it
->atom
)) == 0 ) {
1554 const char* providerStart
= &it
->probeName
[16];
1555 const char* providerEnd
= strchr(providerStart
, '$');
1556 if ( providerEnd
!= NULL
) {
1557 char providerName
[providerEnd
-providerStart
+1];
1558 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
1559 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
1560 if ( pos
== providerToProbes
.end() ) {
1561 const char* dup
= strdup(providerName
);
1562 providerToProbes
[dup
] = emptyList
;
1564 providerToProbes
[providerName
].push_back(*it
);
1568 for(std::vector
<DTraceProbeInfo
>::iterator it
= fDtraceIsEnabledSites
.begin(); it
!= fDtraceIsEnabledSites
.end(); ++it
) {
1569 // ignore probes in functions that were coalesed away rdar://problem/5628149
1570 if ( fDeadAtoms
.count((ObjectFile::Atom
*)(it
->atom
)) == 0 ) {
1571 const char* providerStart
= &it
->probeName
[20];
1572 const char* providerEnd
= strchr(providerStart
, '$');
1573 if ( providerEnd
!= NULL
) {
1574 char providerName
[providerEnd
-providerStart
+1];
1575 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
1576 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
1577 if ( pos
== providerToProbes
.end() ) {
1578 const char* dup
= strdup(providerName
);
1579 providerToProbes
[dup
] = emptyList
;
1581 providerToProbes
[providerName
].push_back(*it
);
1586 // create a DOF section for each provider
1588 CStringSet sectionNamesUsed
;
1589 for(ProviderToProbes::iterator pit
= providerToProbes
.begin(); pit
!= providerToProbes
.end(); ++pit
, ++dofIndex
) {
1590 const char* providerName
= pit
->first
;
1591 const std::vector
<DTraceProbeInfo
>& probes
= pit
->second
;
1593 // open library and find dtrace_create_dof()
1594 void* handle
= dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY
);
1595 if ( handle
== NULL
)
1596 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
1597 createdof_func_t pCreateDOF
= (createdof_func_t
)dlsym(handle
, "dtrace_ld_create_dof");
1598 if ( pCreateDOF
== NULL
)
1599 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
1600 // build list of typedefs/stability infos for this provider
1602 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
1603 std::map
<const ObjectFile::Atom
*,CStringSet
>::iterator pos
= fDtraceAtomToTypes
.find(it
->atom
);
1604 if ( pos
!= fDtraceAtomToTypes
.end() ) {
1605 for(CStringSet::iterator sit
= pos
->second
.begin(); sit
!= pos
->second
.end(); ++sit
) {
1606 const char* providerStart
= strchr(*sit
, '$')+1;
1607 const char* providerEnd
= strchr(providerStart
, '$');
1608 if ( providerEnd
!= NULL
) {
1609 char aProviderName
[providerEnd
-providerStart
+1];
1610 strlcpy(aProviderName
, providerStart
, providerEnd
-providerStart
+1);
1611 if ( strcmp(aProviderName
, providerName
) == 0 )
1617 int typeCount
= types
.size();
1618 const char* typeNames
[typeCount
];
1619 //fprintf(stderr, "types for %s:\n", providerName);
1621 for(CStringSet::iterator it
= types
.begin(); it
!= types
.end(); ++it
) {
1622 typeNames
[index
] = *it
;
1623 //fprintf(stderr, "\t%s\n", *it);
1627 // build list of probe/isenabled sites
1628 const uint32_t probeCount
= probes
.size();
1629 const char* probeNames
[probeCount
];
1630 const char* funtionNames
[probeCount
];
1631 uint64_t offsetsInDOF
[probeCount
];
1633 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
1634 probeNames
[index
] = it
->probeName
;
1635 funtionNames
[index
] = it
->atom
->getName();
1636 offsetsInDOF
[index
] = 0;
1639 //fprintf(stderr, "calling libtrace to create DOF\n");
1640 //for(uint32_t i=0; i < probeCount; ++i)
1641 // fprintf(stderr, " [%u]\t %s\t%s\n", i, probeNames[i], funtionNames[i]);
1642 // call dtrace library to create DOF section
1643 size_t dofSectionSize
;
1644 uint8_t* p
= (*pCreateDOF
)(fArchitecture
, typeCount
, typeNames
, probeCount
, probeNames
, funtionNames
, offsetsInDOF
, &dofSectionSize
);
1646 char sectionName
[18];
1647 strcpy(sectionName
, "__dof_");
1648 strlcpy(§ionName
[6], providerName
, 10);
1649 // create unique section name so each DOF is in its own section
1650 if ( sectionNamesUsed
.count(sectionName
) != 0 ) {
1651 sectionName
[15] = '0';
1652 sectionName
[16] = '\0';
1653 while ( sectionNamesUsed
.count(sectionName
) != 0 )
1656 sectionNamesUsed
.insert(sectionName
);
1657 char symbolName
[strlen(providerName
)+64];
1658 sprintf(symbolName
, "__dtrace_dof_for_provider_%s", providerName
);
1659 opaque_section::Reader
* reader
= new opaque_section::Reader("__TEXT", sectionName
,
1660 "dtrace", p
, dofSectionSize
, fNextInputOrdinal
, symbolName
);
1661 fNextInputOrdinal
+= dofSectionSize
;
1663 for (uint32_t i
=0; i
< probeCount
; ++i
) {
1664 uint64_t offset
= offsetsInDOF
[i
];
1665 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
1666 if ( offset
> dofSectionSize
)
1667 throwf("offsetsInDOF[i]=%0llX > dofSectionSize=%0lX\n", i
, offset
, dofSectionSize
);
1668 reader
->addSectionReference(pcRelKind(fArchitecture
), offset
, probes
[i
].atom
, probes
[i
].offset
, reader
->getAtoms()[0], 0);
1670 this->addAtoms(reader
->getAtoms());
1673 throw "error creating dtrace DOF section";
1677 // create a __DATA __dof section iff -dtrace option was used and static probes were found in .o files
1678 else if ( fOptions
.dTrace() && (fDtraceProbes
.size() != 0) ) {
1679 const uint32_t probeCount
= fDtraceProbes
.size();
1680 const char* labels
[probeCount
];
1681 const char* funtionNames
[probeCount
];
1682 uint64_t offsetsInDOF
[probeCount
];
1684 // open libray and find dtrace_ld64_create_dof()
1685 void* handle
= dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY
);
1686 if ( handle
== NULL
)
1687 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s\n", dlerror());
1688 oldcreatedof_func_t pCreateDOF
= (oldcreatedof_func_t
)dlsym(handle
, "dtrace_ld64_create_dof");
1689 if ( pCreateDOF
== NULL
)
1690 throwf("couldn't find \"dtrace_ld64_create_dof\" in /usr/lib/libdtrace.dylib: %s\n", dlerror());
1692 // build argument list
1694 for(std::vector
<DTraceProbeInfo
>::iterator it
= fDtraceProbes
.begin(); it
!= fDtraceProbes
.end(); ++it
) {
1695 labels
[index
] = it
->probeName
;
1696 funtionNames
[index
] = it
->atom
->getName();
1697 offsetsInDOF
[index
] = 0;
1700 size_t dofSectionSize
;
1701 // call dtrace library to create DOF section
1702 uint8_t* p
= (*pCreateDOF
)(fOptions
.dTraceScriptName(), fArchitecture
, probeCount
, labels
, funtionNames
, offsetsInDOF
, &dofSectionSize
);
1704 opaque_section::Reader
* reader
= new opaque_section::Reader("__DATA", "__dof", "dtrace", p
, dofSectionSize
, fNextInputOrdinal
);
1705 fNextInputOrdinal
+= dofSectionSize
;
1707 for (uint32_t i
=0; i
< probeCount
; ++i
) {
1708 uint64_t offset
= offsetsInDOF
[i
];
1709 if ( offset
> dofSectionSize
)
1710 throwf("offsetsInDOF[i]=%0llX > dofSectionSize=%0lX", i
, offset
, dofSectionSize
);
1711 reader
->addSectionReference(pointerKind(fArchitecture
), offset
, fDtraceProbes
[i
].atom
, fDtraceProbes
[i
].offset
);
1713 this->addAtoms(reader
->getAtoms());
1716 throw "error created dtrace DOF section";
1722 static bool matchesObjectFile(ObjectFile::Atom
* atom
, const char* objectFileLeafName
)
1724 if ( objectFileLeafName
== NULL
)
1726 const char* atomFullPath
= atom
->getFile()->getPath();
1727 const char* lastSlash
= strrchr(atomFullPath
, '/');
1728 if ( lastSlash
!= NULL
) {
1729 if ( strcmp(&lastSlash
[1], objectFileLeafName
) == 0 )
1733 if ( strcmp(atomFullPath
, objectFileLeafName
) == 0 )
1740 static bool usesAnonymousNamespace(const char* symbol
)
1742 return ( (strncmp(symbol
, "__Z", 3) == 0) && (strstr(symbol
, "_GLOBAL__N_") != NULL
) );
1748 // __ZN20_GLOBAL__N__Z5main2v3barEv => _ZN-3barEv
1749 // __ZN37_GLOBAL__N_main.cxx_00000000_493A01A33barEv => _ZN-3barEv
1751 static void canonicalizeAnonymousName(const char* inSymbol
, char outSymbol
[])
1753 const char* globPtr
= strstr(inSymbol
, "_GLOBAL__N_");
1754 while ( isdigit(*(--globPtr
)) )
1757 unsigned long length
= strtoul(globPtr
+1, &endptr
, 10);
1758 const char* globEndPtr
= endptr
+ length
;
1759 int startLen
= globPtr
-inSymbol
+1;
1760 memcpy(outSymbol
, inSymbol
, startLen
);
1761 outSymbol
[startLen
] = '-';
1762 strcpy(&outSymbol
[startLen
+1], globEndPtr
);
1766 ObjectFile::Atom
* Linker::findAtom(const Options::OrderedSymbol
& orderedSymbol
)
1768 ObjectFile::Atom
* atom
= fGlobalSymbolTable
.find(orderedSymbol
.symbolName
);
1769 if ( atom
!= NULL
) {
1770 if ( matchesObjectFile(atom
, orderedSymbol
.objectFileName
) )
1774 // slow case. The requested symbol is not in symbol table, so might be static function
1775 static SymbolTable::Mapper hashTableOfTranslationUnitScopedSymbols
;
1776 static SymbolTable::Mapper hashTableOfSymbolsWithAnonymousNamespace
;
1777 static bool built
= false;
1778 // build a hash_map the first time
1780 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1782 const char* name
= atom
->getName();
1783 if ( name
!= NULL
) {
1784 if ( usesAnonymousNamespace(name
) ) {
1785 // symbol that uses anonymous namespace
1786 char canonicalName
[strlen(name
)+2];
1787 canonicalizeAnonymousName(name
, canonicalName
);
1788 const char* hashName
= strdup(canonicalName
);
1789 SymbolTable::Mapper::iterator pos
= hashTableOfSymbolsWithAnonymousNamespace
.find(hashName
);
1790 if ( pos
== hashTableOfSymbolsWithAnonymousNamespace
.end() )
1791 hashTableOfSymbolsWithAnonymousNamespace
[hashName
] = atom
;
1793 hashTableOfSymbolsWithAnonymousNamespace
[hashName
] = NULL
; // collision, denote with NULL
1795 else if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
1796 // static function or data
1797 SymbolTable::Mapper::iterator pos
= hashTableOfTranslationUnitScopedSymbols
.find(name
);
1798 if ( pos
== hashTableOfTranslationUnitScopedSymbols
.end() )
1799 hashTableOfTranslationUnitScopedSymbols
[name
] = atom
;
1801 hashTableOfTranslationUnitScopedSymbols
[name
] = NULL
; // collision, denote with NULL
1805 //fprintf(stderr, "built hash table of %lu static functions\n", hashTableOfTranslationUnitScopedSymbols.size());
1809 // look for name in hashTableOfTranslationUnitScopedSymbols
1810 SymbolTable::Mapper::iterator pos
= hashTableOfTranslationUnitScopedSymbols
.find(orderedSymbol
.symbolName
);
1811 if ( pos
!= hashTableOfTranslationUnitScopedSymbols
.end() ) {
1812 if ( (pos
->second
!= NULL
) && matchesObjectFile(pos
->second
, orderedSymbol
.objectFileName
) ) {
1813 //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName);
1816 if ( pos
->second
== NULL
)
1817 // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
1818 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1820 if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
1821 const char* name
= atom
->getName();
1822 if ( (name
!= NULL
) && (strcmp(name
, orderedSymbol
.symbolName
) == 0) ) {
1823 if ( matchesObjectFile(atom
, orderedSymbol
.objectFileName
) ) {
1824 if ( fOptions
.printOrderFileStatistics() )
1825 warning("%s specified in order_file but it exists in multiple .o files. "
1826 "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol
.symbolName
);
1834 // look for name in hashTableOfSymbolsWithAnonymousNamespace
1835 if ( usesAnonymousNamespace(orderedSymbol
.symbolName
) ) {
1836 // symbol that uses anonymous namespace
1837 char canonicalName
[strlen(orderedSymbol
.symbolName
)+2];
1838 canonicalizeAnonymousName(orderedSymbol
.symbolName
, canonicalName
);
1839 SymbolTable::Mapper::iterator pos
= hashTableOfSymbolsWithAnonymousNamespace
.find(canonicalName
);
1840 if ( pos
!= hashTableOfSymbolsWithAnonymousNamespace
.end() ) {
1841 if ( (pos
->second
!= NULL
) && matchesObjectFile(pos
->second
, orderedSymbol
.objectFileName
) ) {
1842 //fprintf(stderr, "found %s in anonymous namespace hash table\n", canonicalName);
1845 if ( pos
->second
== NULL
)
1846 // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
1847 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1849 const char* name
= atom
->getName();
1850 if ( (name
!= NULL
) && usesAnonymousNamespace(name
) ) {
1851 char canonicalAtomName
[strlen(name
)+2];
1852 canonicalizeAnonymousName(name
, canonicalAtomName
);
1853 if ( strcmp(canonicalAtomName
, canonicalName
) == 0 ) {
1854 if ( matchesObjectFile(atom
, orderedSymbol
.objectFileName
) ) {
1855 if ( fOptions
.printOrderFileStatistics() )
1856 warning("%s specified in order_file but it exists in multiple .o files. "
1857 "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol
.symbolName
);
1870 void Linker::sortSections()
1872 Section::assignIndexes();
1877 // Linker::sortAtoms()
1879 // The purpose of this method is to take the graph of all Atoms and produce an ordered
1880 // sequence of atoms. The constraints are that: 1) all Atoms of the same Segment must
1881 // be contiguous, 2) all Atoms of the same Section must be contigous, 3) Atoms specified
1882 // in an order_file are seqenced as in the order_file and before Atoms not specified,
1883 // 4) Atoms in the same section from the same .o file should be contiguous and sequenced
1884 // in the same order they were in the .o file, 5) Atoms in the same Section but which came
1885 // from different .o files should be sequenced in the same order that the .o files
1886 // were passed to the linker (i.e. command line order).
1888 // The way this is implemented is that the linker passes a "base ordinal" to each Reader
1889 // as it is constructed. The reader should construct it Atoms so that calling getOrdinal()
1890 // on its atoms returns a contiguous range of values starting at the base ordinal. Then
1891 // sorting is just sorting by section, then by ordinal.
1893 // If an order_file is specified, it gets more complicated. First, an override-ordinal map
1894 // is created. It causes the sort routine to ignore the value returned by getOrdinal() and
1895 // use the override value instead. Next some Atoms must be layed out consecutively
1896 // (e.g. hand written assembly that does not end with return, but rather falls into
1897 // the next label). This is modeled in Readers via a "kFollowOn" reference. The use of
1898 // kFollowOn refernces produces "clusters" of atoms that must stay together.
1899 // If an order_file tries to move one atom, it may need to move a whole cluster. The
1900 // algorithm to do this models clusters using two maps. The "starts" maps maps any
1901 // atom in a cluster to the first Atom in the cluster. The "nexts" maps an Atom in a
1902 // cluster to the next Atom in the cluster. With this in place, while processing an
1903 // order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is
1904 // given ordinal overrides.
1906 void Linker::sortAtoms()
1908 fStartSortTime
= mach_absolute_time();
1909 // if -order_file is used, build map of atom ordinal overrides
1910 std::map
<const ObjectFile::Atom
*, uint32_t>* ordinalOverrideMap
= NULL
;
1911 std::map
<const ObjectFile::Atom
*, uint32_t> theOrdinalOverrideMap
;
1912 const bool log
= false;
1913 if ( fOptions
.orderedSymbols().size() != 0 ) {
1914 // first make a pass to find all follow-on references and build start/next maps
1915 // which are a way to represent clusters of atoms that must layout together
1916 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*> followOnStarts
;
1917 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*> followOnNexts
;
1918 for (std::vector
<ObjectFile::Atom
*>::iterator ait
=fAllAtoms
.begin(); ait
!= fAllAtoms
.end(); ait
++) {
1919 ObjectFile::Atom
* atom
= *ait
;
1920 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
1921 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1922 ObjectFile::Reference
* ref
= *rit
;
1923 if ( ref
->getKind() == 1 ) { // FIX FIX
1924 ObjectFile::Atom
* targetAtom
= &ref
->getTarget();
1925 if ( log
) fprintf(stderr
, "ref %s -> %s", atom
->getDisplayName(), targetAtom
->getDisplayName());
1926 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator startFrom
= followOnStarts
.find(atom
);
1927 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator startTo
= followOnStarts
.find(targetAtom
);
1928 if ( (startFrom
== followOnStarts
.end()) && (startTo
== followOnStarts
.end()) ) {
1929 // this is first time we've seen either atom, make simple cluster of the two
1930 if ( log
) fprintf(stderr
, " new cluster\n");
1931 followOnStarts
[atom
] = atom
;
1932 followOnStarts
[targetAtom
] = atom
;
1933 followOnNexts
[atom
] = targetAtom
;
1934 followOnNexts
[targetAtom
] = NULL
;
1936 else if ( (startFrom
!= followOnStarts
.end()) && (startTo
== followOnStarts
.end()) && (followOnNexts
[atom
] == NULL
) ) {
1937 // atom is at end of an existing cluster, so append target to end of cluster
1938 if ( log
) fprintf(stderr
, " end of cluster starting with %s\n", followOnStarts
[atom
]->getDisplayName());
1939 followOnNexts
[atom
] = targetAtom
;
1940 followOnNexts
[targetAtom
] = NULL
;
1941 followOnStarts
[targetAtom
] = followOnStarts
[atom
];
1944 // gerneral case of inserting into an existing cluster
1945 if ( followOnNexts
[atom
] != NULL
) {
1946 // an atom with two follow-ons is illegal
1947 warning("can't order %s because both %s and %s must follow it",
1948 atom
->getDisplayName(), targetAtom
->getDisplayName(), followOnNexts
[atom
]->getDisplayName());
1951 // there already exists an atom that says target must be its follow-on
1952 const ObjectFile::Atom
* originalStart
= startTo
->second
;
1953 const ObjectFile::Atom
* originalPrevious
= originalStart
;
1954 while ( followOnNexts
[originalPrevious
] != targetAtom
)
1955 originalPrevious
= followOnNexts
[originalPrevious
];
1956 bool otherIsAlias
= (originalPrevious
->getSize() == 0);
1957 bool thisIsAlias
= (atom
->getSize() == 0);
1958 if ( !otherIsAlias
&& !thisIsAlias
) {
1959 warning("can't order %s because both %s and %s must preceed it",
1960 targetAtom
->getDisplayName(), originalPrevious
->getDisplayName(), atom
->getDisplayName());
1962 else if ( otherIsAlias
) {
1963 if ( originalPrevious
== originalStart
) {
1964 // other is alias at start of cluster, make this the new start of cluster
1965 if ( log
) fprintf(stderr
, " becomes new start of cluster previous starting with %s\n", originalStart
->getDisplayName());
1966 followOnNexts
[atom
] = originalPrevious
;
1967 for(const ObjectFile::Atom
* nextAtom
= atom
; nextAtom
!= NULL
; nextAtom
= followOnNexts
[nextAtom
])
1968 followOnStarts
[nextAtom
] = atom
;
1971 // other is alias in middle of cluster, insert new atom before it
1972 if ( log
) fprintf(stderr
, " insert into cluster starting with %s before alias %s\n", originalStart
->getDisplayName(), originalPrevious
->getDisplayName());
1973 followOnStarts
[atom
] = originalStart
;
1974 followOnNexts
[atom
] = originalPrevious
;
1975 for(const ObjectFile::Atom
* a
= originalStart
; a
!= NULL
; a
= followOnNexts
[a
]) {
1976 if ( followOnNexts
[a
] == originalPrevious
) {
1977 followOnNexts
[a
] = atom
;
1984 // this is alias, so it can go inbetween originalPrevious and targetAtom
1985 if ( log
) fprintf(stderr
, " insert into cluster starting with %s after %s\n", originalStart
->getDisplayName(), originalPrevious
->getDisplayName());
1986 followOnStarts
[atom
] = originalStart
;
1987 followOnNexts
[atom
] = followOnNexts
[originalPrevious
];
1988 followOnNexts
[originalPrevious
] = atom
;
1997 for(std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator it
= followOnStarts
.begin(); it
!= followOnStarts
.end(); ++it
)
1998 fprintf(stderr
, "start %s -> %s\n", it
->first
->getDisplayName(), it
->second
->getDisplayName());
2000 for(std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator it
= followOnNexts
.begin(); it
!= followOnNexts
.end(); ++it
)
2001 fprintf(stderr
, "next %s -> %s\n", it
->first
->getDisplayName(), (it
->second
!= NULL
) ? it
->second
->getDisplayName() : "null");
2004 // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals
2005 ordinalOverrideMap
= &theOrdinalOverrideMap
;
2007 uint32_t matchCount
= 0;
2008 std::vector
<Options::OrderedSymbol
>& orderedSymbols
= fOptions
.orderedSymbols();
2009 for(std::vector
<Options::OrderedSymbol
>::iterator it
= orderedSymbols
.begin(); it
!= orderedSymbols
.end(); ++it
) {
2010 ObjectFile::Atom
* atom
= this->findAtom(*it
);
2011 if ( atom
!= NULL
) {
2012 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator start
= followOnStarts
.find(atom
);
2013 if ( start
!= followOnStarts
.end() ) {
2014 // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together
2015 for(const ObjectFile::Atom
* nextAtom
= start
->second
; nextAtom
!= NULL
; nextAtom
= followOnNexts
[nextAtom
]) {
2016 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator pos
= theOrdinalOverrideMap
.find(nextAtom
);
2017 if ( pos
== theOrdinalOverrideMap
.end() ) {
2018 theOrdinalOverrideMap
[nextAtom
] = index
++;
2019 if (log
) fprintf(stderr
, "override ordinal %u assigned to %s in cluster from %s\n", index
, nextAtom
->getDisplayName(), nextAtom
->getFile()->getPath());
2022 if (log
) fprintf(stderr
, "could not order %s as %u because it was already laid out earlier by %s as %u\n",
2023 atom
->getDisplayName(), index
, followOnStarts
[atom
]->getDisplayName(), theOrdinalOverrideMap
[atom
] );
2028 theOrdinalOverrideMap
[atom
] = index
;
2029 if (log
) fprintf(stderr
, "override ordinal %u assigned to %s from %s\n", index
, atom
->getDisplayName(), atom
->getFile()->getPath());
2034 //fprintf(stderr, "can't find match for order_file entry %s/%s\n", it->objectFileName, it->symbolName);
2038 if ( fOptions
.printOrderFileStatistics() && (fOptions
.orderedSymbols().size() != matchCount
) ) {
2039 warning("only %u out of %lu order_file symbols were applicable", matchCount
, fOptions
.orderedSymbols().size() );
2044 std::sort(fAllAtoms
.begin(), fAllAtoms
.end(), Linker::AtomSorter(ordinalOverrideMap
));
2046 //fprintf(stderr, "Sorted atoms:\n");
2047 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
2048 // fprintf(stderr, "\t%p, %u %s\n", (*it)->getSection(), (*it)->getSection()->getIndex(), (*it)->getDisplayName());
2053 // make sure given addresses are within reach of branches, etc
2054 void Linker::tweakLayout()
2056 // > 2GB images need their large zero fill atoms sorted to the end to keep access with +/- 2GB
2057 if ( fTotalSize
> 0x7F000000 ) {
2058 fBiggerThanTwoGigOutput
= true;
2060 if ( (fTotalSize
-fTotalZeroFillSize
) > 0x7F000000 )
2061 throwf("total output size exceeds 2GB (%lldMB)", (fTotalSize
-fTotalZeroFillSize
)/(1024*1024));
2063 // move very large (>1MB) zero fill atoms to a new section at very end of __DATA segment
2064 Section
* hugeZeroFills
= Section::find("__huge", "__DATA", true);
2065 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2066 ObjectFile::Atom
* atom
= *it
;
2067 if ( atom
->isZeroFill() && (atom
->getSize() > 1024*1024) && (strcmp(atom
->getSegment().getName(), "__DATA") == 0) )
2068 atom
->setSection(hugeZeroFills
);
2074 void Linker::writeDotOutput()
2076 const char* dotOutFilePath
= fOptions
.dotOutputFile();
2077 if ( dotOutFilePath
!= NULL
) {
2078 FILE* out
= fopen(dotOutFilePath
, "w");
2079 if ( out
!= NULL
) {
2081 fprintf(out
, "digraph dg\n{\n");
2082 fprintf(out
, "\tconcentrate = true;\n");
2083 fprintf(out
, "\trankdir = LR;\n");
2085 // print each atom as a node
2086 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2087 ObjectFile::Atom
* atom
= *it
;
2088 if ( atom
->getFile() != fOutputFile
) {
2089 const char* name
= atom
->getDisplayName();
2090 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
2091 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
2092 fprintf(out
, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom
, name
);
2094 else if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
2095 char cstring
[atom
->getSize()+2];
2096 atom
->copyRawContent((uint8_t*)cstring
);
2097 fprintf(out
, "\taddr%p [ label = \"string: '", atom
);
2098 for (const char* s
=cstring
; *s
!= '\0'; ++s
) {
2100 fprintf(out
, "\\\\n");
2104 fprintf(out
, "'\" ];\n");
2107 fprintf(out
, "\taddr%p [ label = \"%s\" ];\n", atom
, name
);
2113 // print each reference as an edge
2114 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2115 ObjectFile::Atom
* fromAtom
= *it
;
2116 if ( fromAtom
->getFile() != fOutputFile
) {
2117 std::vector
<ObjectFile::Reference
*>& references
= fromAtom
->getReferences();
2118 std::set
<ObjectFile::Atom
*> seenTargets
;
2119 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
2120 ObjectFile::Reference
* reference
= *rit
;
2121 ObjectFile::Atom
* toAtom
= &(reference
->getTarget());
2122 if ( seenTargets
.count(toAtom
) == 0 ) {
2123 seenTargets
.insert(toAtom
);
2124 fprintf(out
, "\taddr%p -> addr%p;\n", fromAtom
, toAtom
);
2131 // push all imports to bottom of graph
2132 fprintf(out
, "{ rank = same; ");
2133 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2134 ObjectFile::Atom
* atom
= *it
;
2135 if ( atom
->getFile() != fOutputFile
)
2136 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
2137 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
2138 fprintf(out
, "addr%p; ", atom
);
2141 fprintf(out
, "};\n ");
2144 fprintf(out
, "}\n");
2148 warning("could not write dot output file: %s", dotOutFilePath
);
2153 ObjectFile::Atom
* Linker::entryPoint(bool orInit
)
2155 // if main executable, find entry point atom
2156 ObjectFile::Atom
* entryPoint
= NULL
;
2157 switch ( fOptions
.outputKind() ) {
2158 case Options::kDynamicExecutable
:
2159 case Options::kStaticExecutable
:
2160 case Options::kDyld
:
2161 entryPoint
= fGlobalSymbolTable
.find(fOptions
.entryName());
2162 if ( entryPoint
== NULL
) {
2163 throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions
.entryName());
2166 case Options::kDynamicLibrary
:
2167 if ( orInit
&& (fOptions
.initFunctionName() != NULL
) ) {
2168 entryPoint
= fGlobalSymbolTable
.find(fOptions
.initFunctionName());
2169 if ( entryPoint
== NULL
) {
2170 throwf("could not find -init function: \"%s\"", fOptions
.initFunctionName());
2174 case Options::kObjectFile
:
2175 case Options::kDynamicBundle
:
2182 ObjectFile::Atom
* Linker::dyldHelper()
2184 return fGlobalSymbolTable
.find("dyld_stub_binding_helper");
2187 ObjectFile::Atom
* Linker::dyldLazyLibraryHelper()
2189 return fGlobalSymbolTable
.find("dyld_lazy_dylib_stub_binding_helper");
2192 const char* Linker::assureFullPath(const char* path
)
2194 if ( path
[0] == '/' )
2196 char cwdbuff
[MAXPATHLEN
];
2197 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
2199 asprintf(&result
, "%s/%s", cwdbuff
, path
);
2200 if ( result
!= NULL
)
2208 // The stab strings are of the form:
2209 // <name> ':' <type-code> <number-pari>
2210 // but the <name> contain a colon.
2211 // For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
2212 // For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
2214 const char* Linker::truncateStabString(const char* str
)
2216 enum { start
, inObjc
} state
= start
;
2217 for (const char* s
= str
; *s
!= 0; ++s
) {
2226 if ( s
[1] == ':' ) {
2231 // Duplicate strndup behavior here.
2232 int trunStrLen
= s
-str
+2;
2233 char* temp
= new char[trunStrLen
+1];
2234 memcpy(temp
, str
, trunStrLen
);
2235 temp
[trunStrLen
] = '\0';
2253 bool Linker::minimizeStab(ObjectFile::Reader::Stab
& stab
)
2260 // these all need truncated strings
2261 stab
.string
= truncateStabString(stab
.string
);
2267 // these are included in the minimal stabs, but they keep their full string
2275 struct HeaderRange
{
2276 std::vector
<ObjectFile::Reader::Stab
>::iterator begin
;
2277 std::vector
<ObjectFile::Reader::Stab
>::iterator end
;
2278 int parentRangeIndex
;
2280 bool sumPrecomputed
;
2282 bool cannotEXCL
; // because of SLINE, etc stabs
2286 typedef __gnu_cxx::hash_map
<const char*, std::vector
<uint32_t>, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToSums
;
2288 // hash table that maps header path to a vector of known checksums for that path
2289 static PathToSums sKnownBINCLs
;
2292 void Linker::collectStabs(ObjectFile::Reader
* reader
, std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
)
2294 const bool log
= false;
2295 bool minimal
= ( fOptions
.readerOptions().fDebugInfoStripping
== ObjectFile::ReaderOptions::kDebugInfoMinimal
);
2296 std::vector
<class ObjectFile::Reader::Stab
>* readerStabs
= reader
->getStabs();
2297 if ( readerStabs
== NULL
)
2300 if ( log
) fprintf(stderr
, "processesing %lu stabs for %s\n", readerStabs
->size(), reader
->getPath());
2301 std::vector
<HeaderRange
> ranges
;
2302 int curRangeIndex
= -1;
2304 ObjectFile::Atom
* atomWithLowestOrdinal
= NULL
;
2305 ObjectFile::Atom
* atomWithHighestOrdinal
= NULL
;
2306 uint32_t highestOrdinal
= 0;
2307 uint32_t lowestOrdinal
= UINT_MAX
;
2308 std::vector
<std::pair
<ObjectFile::Atom
*,ObjectFile::Atom
*> > soRanges
;
2309 // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums
2310 // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein
2311 for(std::vector
<class ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
2313 switch ( it
->type
) {
2318 range
.end
= readerStabs
->end();
2319 range
.parentRangeIndex
= curRangeIndex
;
2320 range
.sum
= it
->value
;
2321 range
.sumPrecomputed
= (range
.sum
!= 0);
2322 range
.useEXCL
= false;
2323 range
.cannotEXCL
= false;
2324 curRangeIndex
= ranges
.size();
2325 if ( log
) fprintf(stderr
, "[%d]BINCL %s\n", curRangeIndex
, it
->string
);
2326 ranges
.push_back(range
);
2330 if ( curRangeIndex
== -1 ) {
2331 warning("EINCL missing BINCL in %s", reader
->getPath());
2334 ranges
[curRangeIndex
].end
= it
+1;
2335 if ( log
) fprintf(stderr
, "[%d->%d]EINCL %s\n", curRangeIndex
, ranges
[curRangeIndex
].parentRangeIndex
, it
->string
);
2336 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
2341 std::map
<const class ObjectFile::Atom
*, uint32_t>::iterator pos
= atomOrdinals
.find(it
->atom
);
2342 if ( pos
!= atomOrdinals
.end() ) {
2343 uint32_t ordinal
= pos
->second
;
2344 if ( ordinal
> highestOrdinal
) {
2345 highestOrdinal
= ordinal
;
2346 atomWithHighestOrdinal
= it
->atom
;
2348 if ( ordinal
< lowestOrdinal
) {
2349 lowestOrdinal
= ordinal
;
2350 atomWithLowestOrdinal
= it
->atom
;
2362 if ( curRangeIndex
!= -1 ) {
2363 ranges
[curRangeIndex
].cannotEXCL
= true;
2364 if ( fOptions
.warnStabs() )
2365 warning("cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
2369 if ( (it
->string
!= NULL
) && (strlen(it
->string
) > 0) ) {
2370 // start SO, reset hi/low FUN tracking
2371 atomWithLowestOrdinal
= NULL
;
2372 atomWithHighestOrdinal
= NULL
;
2374 lowestOrdinal
= UINT_MAX
;
2377 // end SO, record hi/low atoms for this SO range
2378 soRanges
.push_back(std::make_pair
<ObjectFile::Atom
*,ObjectFile::Atom
*>(atomWithLowestOrdinal
, atomWithHighestOrdinal
));
2382 if ( curRangeIndex
!= -1 ) {
2383 if ( ! ranges
[curRangeIndex
].sumPrecomputed
) {
2385 const char* s
= it
->string
;
2387 while ( (c
= *s
++) != 0 ) {
2389 // don't checkusm first number (file index) after open paren in string
2395 ranges
[curRangeIndex
].sum
+= sum
;
2401 if ( log
) fprintf(stderr
, "processesed %d stabs for %s\n", count
, reader
->getPath());
2402 if ( curRangeIndex
!= -1 )
2403 warning("BINCL (%s) missing EINCL in %s", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
2406 if ( ranges
.size() == 0 ) {
2407 unsigned int soIndex
= 0;
2408 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
2409 // copy minimal or all stabs
2410 ObjectFile::Reader::Stab stab
= *it
;
2411 if ( !minimal
|| minimizeStab(stab
) ) {
2412 if ( stab
.type
== N_SO
) {
2413 if ( soIndex
< soRanges
.size() ) {
2414 if ( (stab
.string
!= NULL
) && (strlen(stab
.string
) > 0) ) {
2415 // starting SO is associated with first atom
2416 stab
.atom
= soRanges
[soIndex
].first
;
2419 // ending SO is associated with last atom
2420 stab
.atom
= soRanges
[soIndex
].second
;
2425 fStabs
.push_back(stab
);
2431 //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
2432 //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
2433 // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
2436 // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
2437 for(std::vector
<HeaderRange
>::iterator it
=ranges
.begin(); it
!= ranges
.end(); ++it
) {
2438 if ( ! it
->cannotEXCL
) {
2439 const char* header
= it
->begin
->string
;
2440 uint32_t sum
= it
->sum
;
2441 PathToSums::iterator pos
= sKnownBINCLs
.find(header
);
2442 if ( pos
!= sKnownBINCLs
.end() ) {
2443 std::vector
<uint32_t>& sums
= pos
->second
;
2444 for(std::vector
<uint32_t>::iterator sit
=sums
.begin(); sit
!= sums
.end(); ++sit
) {
2446 //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
2451 if ( ! it
->useEXCL
) {
2452 // have seen this path, but not this checksum
2453 //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
2454 sums
.push_back(sum
);
2458 // have not seen this path, so add to known BINCLs
2459 std::vector
<uint32_t> empty
;
2460 sKnownBINCLs
[header
] = empty
;
2461 sKnownBINCLs
[header
].push_back(sum
);
2462 //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
2467 // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
2469 const int maxRangeIndex
= ranges
.size();
2471 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
2472 switch ( it
->type
) {
2474 for(int i
=curRangeIndex
+1; i
< maxRangeIndex
; ++i
) {
2475 if ( ranges
[i
].begin
== it
) {
2477 HeaderRange
& range
= ranges
[curRangeIndex
];
2478 ObjectFile::Reader::Stab stab
= *it
;
2479 stab
.value
= range
.sum
; // BINCL and EXCL have n_value set to checksum
2480 if ( range
.useEXCL
)
2481 stab
.type
= N_EXCL
; // transform BINCL into EXCL
2483 fStabs
.push_back(stab
);
2489 if ( curRangeIndex
!= -1 ) {
2490 if ( !ranges
[curRangeIndex
].useEXCL
&& !minimal
)
2491 fStabs
.push_back(*it
);
2492 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
2496 if ( (curRangeIndex
== -1) || !ranges
[curRangeIndex
].useEXCL
) {
2497 ObjectFile::Reader::Stab stab
= *it
;
2498 if ( !minimal
|| minimizeStab(stab
) ) {
2499 if ( stab
.type
== N_SO
) {
2500 if ( (stab
.string
!= NULL
) && (strlen(stab
.string
) > 0) ) {
2501 // starting SO is associated with first atom
2502 stab
.atom
= soRanges
[soIndex
].first
;
2505 // ending SO is associated with last atom
2506 stab
.atom
= soRanges
[soIndex
].second
;
2510 fStabs
.push_back(stab
);
2519 // used to prune out atoms that don't need debug notes generated
2520 class NoDebugNoteAtom
2523 NoDebugNoteAtom(const std::map
<class ObjectFile::Reader
*, uint32_t>& readersWithDwarfOrdinals
)
2524 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals
) {}
2526 bool operator()(const ObjectFile::Atom
* atom
) const {
2527 if ( atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
)
2529 if ( atom
->getName() == NULL
)
2531 if ( fReadersWithDwarfOrdinals
.find(atom
->getFile()) == fReadersWithDwarfOrdinals
.end() )
2537 const std::map
<class ObjectFile::Reader
*, uint32_t>& fReadersWithDwarfOrdinals
;
2540 // used to sort atoms with debug notes
2541 class ReadersWithDwarfSorter
2544 ReadersWithDwarfSorter(const std::map
<class ObjectFile::Reader
*, uint32_t>& readersWithDwarfOrdinals
,
2545 const std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
)
2546 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals
), fAtomOrdinals(atomOrdinals
) {}
2548 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
) const
2550 // first sort by reader
2551 unsigned int leftReaderIndex
= fReadersWithDwarfOrdinals
.find(left
->getFile())->second
;
2552 unsigned int rightReaderIndex
= fReadersWithDwarfOrdinals
.find(right
->getFile())->second
;
2553 if ( leftReaderIndex
!= rightReaderIndex
)
2554 return (leftReaderIndex
< rightReaderIndex
);
2556 // then sort by atom ordinal
2557 unsigned int leftAtomIndex
= fAtomOrdinals
.find(left
)->second
;
2558 unsigned int rightAtomIndex
= fAtomOrdinals
.find(right
)->second
;
2559 return leftAtomIndex
< rightAtomIndex
;
2563 const std::map
<class ObjectFile::Reader
*, uint32_t>& fReadersWithDwarfOrdinals
;
2564 const std::map
<const class ObjectFile::Atom
*, uint32_t>& fAtomOrdinals
;
2571 void Linker::synthesizeDebugNotes(std::vector
<class ObjectFile::Atom
*>& allAtomsByReader
)
2573 // synthesize "debug notes" and add them to master stabs vector
2574 const char* dirPath
= NULL
;
2575 const char* filename
= NULL
;
2576 bool wroteStartSO
= false;
2577 bool useZeroOSOModTime
= (getenv("RC_RELEASE") != NULL
);
2578 __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> seenFiles
;
2579 for (std::vector
<ObjectFile::Atom
*>::iterator it
=allAtomsByReader
.begin(); it
!= allAtomsByReader
.end(); it
++) {
2580 ObjectFile::Atom
* atom
= *it
;
2581 const char* newDirPath
;
2582 const char* newFilename
;
2583 //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
2584 if ( atom
->getTranslationUnitSource(&newDirPath
, &newFilename
) ) {
2585 // need SO's whenever the translation unit source file changes
2586 if ( newFilename
!= filename
) {
2587 // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
2588 if ( (newDirPath
!= NULL
) && (strlen(newDirPath
) > 1 ) && (newDirPath
[strlen(newDirPath
)-1] != '/') )
2589 asprintf((char**)&newDirPath
, "%s/", newDirPath
);
2590 if ( filename
!= NULL
) {
2591 // translation unit change, emit ending SO
2592 ObjectFile::Reader::Stab endFileStab
;
2593 endFileStab
.atom
= NULL
;
2594 endFileStab
.type
= N_SO
;
2595 endFileStab
.other
= 1;
2596 endFileStab
.desc
= 0;
2597 endFileStab
.value
= 0;
2598 endFileStab
.string
= "";
2599 fStabs
.push_back(endFileStab
);
2601 // new translation unit, emit start SO's
2602 ObjectFile::Reader::Stab dirPathStab
;
2603 dirPathStab
.atom
= NULL
;
2604 dirPathStab
.type
= N_SO
;
2605 dirPathStab
.other
= 0;
2606 dirPathStab
.desc
= 0;
2607 dirPathStab
.value
= 0;
2608 dirPathStab
.string
= newDirPath
;
2609 fStabs
.push_back(dirPathStab
);
2610 ObjectFile::Reader::Stab fileStab
;
2611 fileStab
.atom
= NULL
;
2612 fileStab
.type
= N_SO
;
2616 fileStab
.string
= newFilename
;
2617 fStabs
.push_back(fileStab
);
2618 // Synthesize OSO for start of file
2619 ObjectFile::Reader::Stab objStab
;
2620 objStab
.atom
= NULL
;
2621 objStab
.type
= N_OSO
;
2624 objStab
.value
= useZeroOSOModTime
? 0 : atom
->getFile()->getModificationTime();
2625 objStab
.string
= assureFullPath(atom
->getFile()->getPath());
2626 fStabs
.push_back(objStab
);
2627 wroteStartSO
= true;
2628 // add the source file path to seenFiles so it does not show up in SOLs
2629 seenFiles
.insert(newFilename
);
2631 filename
= newFilename
;
2632 dirPath
= newDirPath
;
2633 if ( atom
->getSegment().isContentExecutable() && (strncmp(atom
->getSectionName(), "__text", 6) == 0) ) {
2634 // Synthesize BNSYM and start FUN stabs
2635 ObjectFile::Reader::Stab beginSym
;
2636 beginSym
.atom
= atom
;
2637 beginSym
.type
= N_BNSYM
;
2641 beginSym
.string
= "";
2642 fStabs
.push_back(beginSym
);
2643 ObjectFile::Reader::Stab startFun
;
2644 startFun
.atom
= atom
;
2645 startFun
.type
= N_FUN
;
2649 startFun
.string
= atom
->getName();
2650 fStabs
.push_back(startFun
);
2651 // Synthesize any SOL stabs needed
2652 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
2653 if ( lineInfo
!= NULL
) {
2654 const char* curFile
= NULL
;
2655 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
2656 if ( it
->fileName
!= curFile
) {
2657 if ( seenFiles
.count(it
->fileName
) == 0 ) {
2658 seenFiles
.insert(it
->fileName
);
2659 ObjectFile::Reader::Stab sol
;
2665 sol
.string
= it
->fileName
;
2666 fStabs
.push_back(sol
);
2668 curFile
= it
->fileName
;
2672 // Synthesize end FUN and ENSYM stabs
2673 ObjectFile::Reader::Stab endFun
;
2675 endFun
.type
= N_FUN
;
2680 fStabs
.push_back(endFun
);
2681 ObjectFile::Reader::Stab endSym
;
2683 endSym
.type
= N_ENSYM
;
2688 fStabs
.push_back(endSym
);
2690 else if ( atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
) {
2691 // no stabs for atoms that would not be in the symbol table
2693 else if ( atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute
) {
2694 // no stabs for absolute symbols
2696 else if ( (strcmp(atom
->getSectionName(), "__eh_frame") == 0) ) {
2697 // no stabs for .eh atoms
2700 ObjectFile::Reader::Stab globalsStab
;
2701 const char* name
= atom
->getName();
2702 if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
2703 // Synthesize STSYM stab for statics
2704 globalsStab
.atom
= atom
;
2705 globalsStab
.type
= N_STSYM
;
2706 globalsStab
.other
= 1;
2707 globalsStab
.desc
= 0;
2708 globalsStab
.value
= 0;
2709 globalsStab
.string
= name
;
2710 fStabs
.push_back(globalsStab
);
2713 // Synthesize GSYM stab for other globals
2714 globalsStab
.atom
= atom
;
2715 globalsStab
.type
= N_GSYM
;
2716 globalsStab
.other
= 1;
2717 globalsStab
.desc
= 0;
2718 globalsStab
.value
= 0;
2719 globalsStab
.string
= name
;
2720 fStabs
.push_back(globalsStab
);
2726 if ( wroteStartSO
) {
2728 ObjectFile::Reader::Stab endFileStab
;
2729 endFileStab
.atom
= NULL
;
2730 endFileStab
.type
= N_SO
;
2731 endFileStab
.other
= 1;
2732 endFileStab
.desc
= 0;
2733 endFileStab
.value
= 0;
2734 endFileStab
.string
= "";
2735 fStabs
.push_back(endFileStab
);
2742 void Linker::collectDebugInfo()
2744 std::map
<const class ObjectFile::Atom
*, uint32_t> atomOrdinals
;
2745 fStartDebugTime
= mach_absolute_time();
2746 if ( fOptions
.readerOptions().fDebugInfoStripping
!= ObjectFile::ReaderOptions::kDebugInfoNone
) {
2748 // determine mixture of stabs and dwarf
2749 bool someStabs
= false;
2750 bool someDwarf
= false;
2751 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
2752 it
!= fReadersThatHaveSuppliedAtoms
.end();
2754 ObjectFile::Reader
* reader
= *it
;
2755 if ( reader
!= NULL
) {
2756 switch ( reader
->getDebugInfoKind() ) {
2757 case ObjectFile::Reader::kDebugInfoNone
:
2759 case ObjectFile::Reader::kDebugInfoStabs
:
2762 case ObjectFile::Reader::kDebugInfoDwarf
:
2766 case ObjectFile::Reader::kDebugInfoStabsUUID
:
2771 throw "Unhandled type of debug information";
2776 if ( someDwarf
|| someStabs
) {
2777 // try to minimize re-allocations
2778 fStabs
.reserve(1024);
2780 // make mapping from atoms to ordinal
2781 uint32_t ordinal
= 1;
2782 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2783 atomOrdinals
[*it
] = ordinal
++;
2787 // process all dwarf .o files as a batch
2789 // make mapping from readers with dwarf to ordinal
2790 std::map
<class ObjectFile::Reader
*, uint32_t> readersWithDwarfOrdinals
;
2791 uint32_t readerOrdinal
= 1;
2792 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
2793 it
!= fReadersThatHaveSuppliedAtoms
.end();
2795 ObjectFile::Reader
* reader
= *it
;
2796 if ( (reader
!= NULL
) && (reader
->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoDwarf
) ) {
2797 readersWithDwarfOrdinals
[reader
] = readerOrdinal
++;
2801 // make a vector of atoms
2802 std::vector
<class ObjectFile::Atom
*> allAtomsByReader(fAllAtoms
.begin(), fAllAtoms
.end());
2803 // remove those not from a reader that has dwarf
2804 allAtomsByReader
.erase(std::remove_if(allAtomsByReader
.begin(), allAtomsByReader
.end(),
2805 NoDebugNoteAtom(readersWithDwarfOrdinals
)), allAtomsByReader
.end());
2806 // sort by reader then atom ordinal
2807 std::sort(allAtomsByReader
.begin(), allAtomsByReader
.end(), ReadersWithDwarfSorter(readersWithDwarfOrdinals
, atomOrdinals
));
2808 // add debug notes for each atom
2809 this->synthesizeDebugNotes(allAtomsByReader
);
2812 // process all stabs .o files one by one
2814 // get stabs from each reader, in command line order
2815 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
2816 it
!= fReadersThatHaveSuppliedAtoms
.end();
2818 ObjectFile::Reader
* reader
= *it
;
2819 if ( reader
!= NULL
) {
2820 switch ( reader
->getDebugInfoKind() ) {
2821 case ObjectFile::Reader::kDebugInfoDwarf
:
2822 case ObjectFile::Reader::kDebugInfoNone
:
2825 case ObjectFile::Reader::kDebugInfoStabs
:
2826 case ObjectFile::Reader::kDebugInfoStabsUUID
:
2827 collectStabs(reader
, atomOrdinals
);
2830 throw "Unhandled type of debug information";
2834 // remove stabs associated with atoms that won't be in output
2835 std::set
<class ObjectFile::Atom
*> allAtomsSet
;
2836 allAtomsSet
.insert(fAllAtoms
.begin(), fAllAtoms
.end());
2837 fStabs
.erase(std::remove_if(fStabs
.begin(), fStabs
.end(), NotInSet(allAtomsSet
)), fStabs
.end());
2842 void Linker::writeOutput()
2844 if ( fOptions
.forceCpuSubtypeAll() )
2845 fCurrentCpuConstraint
= ObjectFile::Reader::kCpuAny
;
2847 fStartWriteTime
= mach_absolute_time();
2848 // tell writer about each segment's atoms
2849 fOutputFileSize
= fOutputFile
->write(fAllAtoms
, fStabs
, this->entryPoint(true),
2850 this->dyldHelper(), this->dyldLazyLibraryHelper(),
2851 fCreateUUID
, fCanScatter
,
2852 fCurrentCpuConstraint
, fBiggerThanTwoGigOutput
,
2853 fGlobalSymbolTable
.hasExternalWeakDefinitions());
2856 ObjectFile::Reader
* Linker::createReader(const Options::FileInfo
& info
)
2858 // map in whole file
2859 uint64_t len
= info
.fileLen
;
2860 int fd
= ::open(info
.path
, O_RDONLY
, 0);
2862 throwf("can't open file, errno=%d", errno
);
2863 if ( info
.fileLen
< 20 )
2864 throw "file too small";
2866 uint8_t* p
= (uint8_t*)::mmap(NULL
, info
.fileLen
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
2867 if ( p
== (uint8_t*)(-1) )
2868 throwf("can't map file, errno=%d", errno
);
2870 // if fat file, skip to architecture we want
2871 // Note: fat header is always big-endian
2872 const fat_header
* fh
= (fat_header
*)p
;
2873 if ( fh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2874 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
2875 uint32_t sliceToUse
;
2876 bool sliceFound
= false;
2877 if ( fOptions
.preferSubArchitecture() ) {
2878 // first try to find a slice that match cpu-type and cpu-sub-type
2879 for (uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2880 if ( (OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)fArchitecture
)
2881 && (OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == (uint32_t)fOptions
.subArchitecture()) ) {
2888 if ( !sliceFound
) {
2889 // look for any slice that matches just cpu-type
2890 for (uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2891 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)fArchitecture
) {
2899 uint32_t fileOffset
= OSSwapBigToHostInt32(archs
[sliceToUse
].offset
);
2900 len
= OSSwapBigToHostInt32(archs
[sliceToUse
].size
);
2901 // if requested architecture is page aligned within fat file, then remap just that portion of file
2902 if ( (fileOffset
& 0x00000FFF) == 0 ) {
2904 munmap((caddr_t
)p
, info
.fileLen
);
2905 // re-map just part we need
2906 p
= (uint8_t*)::mmap(NULL
, len
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, fileOffset
);
2907 if ( p
== (uint8_t*)(-1) )
2908 throwf("can't re-map file, errno=%d", errno
);
2917 switch (fArchitecture
) {
2918 case CPU_TYPE_POWERPC
:
2919 if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
2920 return this->addObject(new mach_o::relocatable::Reader
<ppc
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2921 else if ( mach_o::dylib::Reader
<ppc
>::validFile(p
, info
.options
.fBundleLoader
) )
2922 return this->addDylib(new mach_o::dylib::Reader
<ppc
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2923 else if ( archive::Reader
<ppc
>::validFile(p
, len
) )
2924 return this->addArchive(new archive::Reader
<ppc
>::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2926 case CPU_TYPE_POWERPC64
:
2927 if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
2928 return this->addObject(new mach_o::relocatable::Reader
<ppc64
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2929 else if ( mach_o::dylib::Reader
<ppc64
>::validFile(p
, info
.options
.fBundleLoader
) )
2930 return this->addDylib(new mach_o::dylib::Reader
<ppc64
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2931 else if ( archive::Reader
<ppc64
>::validFile(p
, len
) )
2932 return this->addArchive(new archive::Reader
<ppc64
>::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2935 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
2936 return this->addObject(new mach_o::relocatable::Reader
<x86
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2937 else if ( mach_o::dylib::Reader
<x86
>::validFile(p
, info
.options
.fBundleLoader
) )
2938 return this->addDylib(new mach_o::dylib::Reader
<x86
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2939 else if ( archive::Reader
<x86
>::validFile(p
, len
) )
2940 return this->addArchive(new archive::Reader
<x86
>::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2942 case CPU_TYPE_X86_64
:
2943 if ( mach_o::relocatable::Reader
<x86_64
>::validFile(p
) )
2944 return this->addObject(new mach_o::relocatable::Reader
<x86_64
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2945 else if ( mach_o::dylib::Reader
<x86_64
>::validFile(p
, info
.options
.fBundleLoader
) )
2946 return this->addDylib(new mach_o::dylib::Reader
<x86_64
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2947 else if ( archive::Reader
<x86_64
>::validFile(p
, len
) )
2948 return this->addArchive(new archive::Reader
<x86_64
>::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2950 if ( mach_o::relocatable::Reader
<arm
>::validFile(p
) )
2951 return this->addObject(new mach_o::relocatable::Reader
<arm
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2952 else if ( mach_o::dylib::Reader
<arm
>::validFile(p
, info
.options
.fBundleLoader
) )
2953 return this->addDylib(new mach_o::dylib::Reader
<arm
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2954 else if ( archive::Reader
<arm
>::validFile(p
, len
) )
2955 return this->addArchive(new archive::Reader
<arm
>::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2961 if ( lto::Reader::validFile(p
, len
, fArchitecture
) ) {
2962 return this->addObject(new lto::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fArchitecture
), info
, len
);
2964 else if ( !lto::Reader::loaded() && (p
[0] == 'B') && (p
[1] == 'C') ) {
2965 throw "could not process object file. Looks like an llvm bitcode object file, but libLTO.dylib could not be loaded";
2969 if ( ((fat_header
*)p
)->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2970 throwf("missing required architecture %s in file", fArchitectureName
);
2973 throw "file is not of required architecture";
2977 void Linker::logDylib(ObjectFile::Reader
* reader
, bool indirect
)
2979 if ( fOptions
.readerOptions().fTraceDylibs
) {
2980 const char* fullPath
= reader
->getPath();
2981 char realName
[MAXPATHLEN
];
2982 if ( realpath(fullPath
, realName
) != NULL
)
2983 fullPath
= realName
;
2985 logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath
);
2987 logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath
);
2993 ObjectFile::Reader
* Linker::findDylib(const char* installPath
, const char* fromPath
)
2995 //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
2996 InstallNameToReader::iterator pos
= fDylibMap
.find(installPath
);
2997 if ( pos
!= fDylibMap
.end() ) {
3001 // allow -dylib_path option to override indirect library to use
3002 for (std::vector
<Options::DylibOverride
>::iterator dit
= fOptions
.dylibOverrides().begin(); dit
!= fOptions
.dylibOverrides().end(); ++dit
) {
3003 if ( strcmp(dit
->installName
,installPath
) == 0 ) {\
3005 Options::FileInfo info
= fOptions
.findFile(dit
->useInstead
);
3006 ObjectFile::Reader
* reader
= this->createReader(info
);
3007 fDylibMap
[strdup(installPath
)] = reader
;
3008 this->logDylib(reader
, true);
3011 catch (const char* msg
) {
3012 warning("ignoring -dylib_file option, %s", msg
);
3016 char newPath
[MAXPATHLEN
];
3017 // handle @loader_path
3018 if ( strncmp(installPath
, "@loader_path/", 13) == 0 ) {
3019 strcpy(newPath
, fromPath
);
3020 char* addPoint
= strrchr(newPath
,'/');
3021 if ( addPoint
!= NULL
)
3022 strcpy(&addPoint
[1], &installPath
[13]);
3024 strcpy(newPath
, &installPath
[13]);
3025 installPath
= newPath
;
3027 // note: @executable_path case is handled inside findFileUsingPaths()
3028 // search for dylib using -F and -L paths
3029 Options::FileInfo info
= fOptions
.findFileUsingPaths(installPath
);
3031 ObjectFile::Reader
* reader
= this->createReader(info
);
3032 fDylibMap
[strdup(installPath
)] = reader
;
3033 this->logDylib(reader
, true);
3036 catch (const char* msg
) {
3037 throwf("in %s, %s", info
.path
, msg
);
3043 void Linker::processDylibs()
3045 fAllDirectDylibsLoaded
= true;
3047 // mark all dylibs initially specified as required and check if they can be used
3048 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
3049 it
->second
->setExplicitlyLinked();
3050 this->checkDylibClientRestrictions(it
->second
);
3053 // keep processing dylibs until no more dylibs are added
3054 unsigned long lastMapSize
= 0;
3055 while ( lastMapSize
!= fDylibMap
.size() ) {
3056 lastMapSize
= fDylibMap
.size();
3057 // can't iterator fDylibMap while modifying it, so use temp buffer
3058 std::vector
<ObjectFile::Reader
*> currentUnprocessedReaders
;
3059 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
3060 if ( fDylibsProcessed
.count(it
->second
) == 0 )
3061 currentUnprocessedReaders
.push_back(it
->second
);
3063 for (std::vector
<ObjectFile::Reader
*>::iterator it
=currentUnprocessedReaders
.begin(); it
!= currentUnprocessedReaders
.end(); it
++) {
3064 fDylibsProcessed
.insert(*it
);
3065 (*it
)->processIndirectLibraries(this);
3069 // go back over original dylibs and mark sub frameworks as re-exported
3070 if ( fOptions
.outputKind() == Options::kDynamicLibrary
) {
3071 const char* myLeaf
= strrchr(fOptions
.installPath(), '/');
3072 if ( myLeaf
!= NULL
) {
3073 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
3074 ObjectFile::Reader
* reader
= *it
;
3075 const char* childParent
= reader
->parentUmbrella();
3076 if ( childParent
!= NULL
) {
3077 if ( strcmp(childParent
, &myLeaf
[1]) == 0 ) {
3078 // set re-export bit of info
3079 std::map
<ObjectFile::Reader
*,DynamicLibraryOptions
>::iterator pos
= fDylibOptionsMap
.find(reader
);
3080 if ( pos
!= fDylibOptionsMap
.end() ) {
3081 pos
->second
.fReExport
= true;
3093 void Linker::createReaders()
3095 fStartCreateReadersTime
= mach_absolute_time();
3096 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
3097 const int count
= files
.size();
3099 throw "no object files specified";
3100 // add all direct object, archives, and dylibs
3101 for (int i
=0; i
< count
; ++i
) {
3102 Options::FileInfo
& entry
= files
[i
];
3103 // ignore /usr/lib/dyld on command line in crt.o build
3104 if ( strcmp(entry
.path
, "/usr/lib/dyld") != 0 ) {
3106 this->addInputFile(this->createReader(entry
), entry
);
3108 catch (const char* msg
) {
3109 if ( strstr(msg
, "architecture") != NULL
) {
3110 if ( fOptions
.ignoreOtherArchInputFiles() ) {
3111 // ignore, because this is about an architecture not in use
3114 warning("in %s, %s", entry
.path
, msg
);
3118 throwf("in %s, %s", entry
.path
, msg
);
3124 this->processDylibs();
3129 ObjectFile::Reader
* Linker::addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
3131 fNextInputOrdinal
+= mappedLen
;
3132 // remember which readers are archives because they are logged differently
3133 fArchiveReaders
.insert(reader
);
3136 fTotalArchiveSize
+= mappedLen
;
3137 ++fTotalArchivesLoaded
;
3141 ObjectFile::Reader
* Linker::addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
3143 fNextInputOrdinal
+= mappedLen
;
3144 // any .o files that don't have MH_SUBSECTIONS_VIA_SYMBOLS, that means a generated .o file can't
3145 if ( (fOptions
.outputKind() == Options::kObjectFile
) && !reader
->canScatterAtoms() )
3146 fCanScatter
= false;
3149 fTotalObjectSize
+= mappedLen
;
3150 ++fTotalObjectLoaded
;
3155 void Linker::checkDylibClientRestrictions(ObjectFile::Reader
* reader
)
3157 // Check for any restrictions on who can link with this dylib
3158 const char* readerParentName
= reader
->parentUmbrella() ;
3159 std::vector
<const char*>* clients
= reader
->getAllowableClients();
3160 if ( (readerParentName
!= NULL
) || (clients
!= NULL
) ) {
3161 // only dylibs that are in an umbrella or have a client list need verification
3162 const char* installName
= fOptions
.installPath();
3163 const char* installNameLastSlash
= strrchr(installName
, '/');
3164 bool isParent
= false;
3165 bool isSibling
= false;
3166 bool isAllowableClient
= false;
3167 // There are three cases:
3168 if ( (readerParentName
!= NULL
) && (installNameLastSlash
!= NULL
) ) {
3169 // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
3170 isParent
= ( strcmp(&installNameLastSlash
[1], readerParentName
) == 0 );
3172 // hack to support umbrella variants that encode the variant name in the install name
3173 // e.g. CoreServices_profile
3175 const char* underscore
= strchr(&installNameLastSlash
[1], '_');
3176 if ( underscore
!= NULL
) {
3177 isParent
= ( strncmp(&installNameLastSlash
[1], readerParentName
, underscore
-installNameLastSlash
-1) == 0 );
3181 // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
3182 isSibling
= ( (fOptions
.umbrellaName() != NULL
) && (strcmp(fOptions
.umbrellaName(), readerParentName
) == 0) );
3185 if ( !isParent
&& !isSibling
&& (clients
!= NULL
) ) {
3186 // case 3) the dylib has a list of allowable clients, and we are creating one of them
3187 const char* clientName
= fOptions
.clientName();
3188 int clientNameLen
= 0;
3189 if ( clientName
!= NULL
) {
3190 // use client name as specified on command line
3191 clientNameLen
= strlen(clientName
);
3194 // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar)
3195 clientName
= installName
;
3196 clientNameLen
= strlen(clientName
);
3197 // starts after last slash
3198 if ( installNameLastSlash
!= NULL
)
3199 clientName
= &installNameLastSlash
[1];
3200 if ( strncmp(clientName
, "lib", 3) == 0 )
3201 clientName
= &clientName
[3];
3203 const char* firstDot
= strchr(clientName
, '.');
3204 if ( firstDot
!= NULL
)
3205 clientNameLen
= firstDot
- clientName
;
3206 // up to first underscore
3207 const char* firstUnderscore
= strchr(clientName
, '_');
3208 if ( (firstUnderscore
!= NULL
) && ((firstUnderscore
- clientName
) < clientNameLen
) )
3209 clientNameLen
= firstUnderscore
- clientName
;
3212 // Use clientName to check if this dylib is able to link against the allowable clients.
3213 for (std::vector
<const char*>::iterator it
= clients
->begin(); it
!= clients
->end(); it
++) {
3214 if ( strncmp(*it
, clientName
, clientNameLen
) == 0 )
3215 isAllowableClient
= true;
3219 if ( !isParent
&& !isSibling
&& !isAllowableClient
) {
3220 if ( readerParentName
!= NULL
) {
3221 throwf("cannot link directly with %s. Link against the umbrella framework '%s.framework' instead.",
3222 reader
->getPath(), readerParentName
);
3225 throwf("cannot link directly with %s", reader
->getPath());
3233 ObjectFile::Reader
* Linker::addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
3235 fNextInputOrdinal
+= mappedLen
;
3236 if ( (reader
->getInstallPath() == NULL
) && !info
.options
.fBundleLoader
) {
3237 // this is a "blank" stub
3238 // silently ignore it
3241 // add to map of loaded dylibs
3242 const char* installPath
= reader
->getInstallPath();
3243 if ( installPath
!= NULL
) {
3244 InstallNameToReader::iterator pos
= fDylibMap
.find(installPath
);
3245 if ( pos
== fDylibMap
.end() ) {
3246 fDylibMap
[strdup(installPath
)] = reader
;
3249 InstallNameToReader::iterator pos2
= fDylibMap
.find(reader
->getPath());
3250 if ( pos2
== fDylibMap
.end() )
3251 fDylibMap
[strdup(reader
->getPath())] = reader
;
3253 warning("duplicate dylib %s", reader
->getPath());
3256 else if ( info
.options
.fBundleLoader
)
3257 fBundleLoaderReader
= reader
;
3259 // log direct readers
3260 if ( !fAllDirectDylibsLoaded
)
3261 this->logDylib(reader
, false);
3264 ++fTotalDylibsLoaded
;
3270 void Linker::logTraceInfo (const char* format
, ...)
3272 static int trace_file
= -1;
3273 char trace_buffer
[MAXPATHLEN
* 2];
3276 ssize_t amount_written
;
3277 const char *trace_file_path
= fOptions
.readerOptions().fTraceOutputFile
;
3279 if(trace_file
== -1) {
3280 if(trace_file_path
!= NULL
) {
3281 trace_file
= open(trace_file_path
, O_WRONLY
| O_APPEND
| O_CREAT
, 0666);
3282 if(trace_file
== -1)
3283 throwf("Could not open or create trace file: %s", trace_file_path
);
3286 trace_file
= fileno(stderr
);
3291 va_start(ap
, format
);
3292 length
= vsnprintf(trace_buffer
, sizeof(trace_buffer
), format
, ap
);
3294 buffer_ptr
= trace_buffer
;
3297 amount_written
= write(trace_file
, buffer_ptr
, length
);
3298 if(amount_written
== -1)
3299 /* Failure to write shouldn't fail the build. */
3301 buffer_ptr
+= amount_written
;
3302 length
-= amount_written
;
3308 void Linker::createWriter()
3310 fStartCreateWriterTime
= mach_absolute_time();
3312 // make a vector out of all required dylibs in fDylibMap
3313 std::vector
<ExecutableFile::DyLibUsed
> dynamicLibraries
;
3314 // need to preserve command line order
3315 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
3316 ObjectFile::Reader
* reader
= *it
;
3317 for (InstallNameToReader::iterator mit
=fDylibMap
.begin(); mit
!= fDylibMap
.end(); mit
++) {
3318 if ( reader
== mit
->second
) {
3319 ExecutableFile::DyLibUsed dylibInfo
;
3320 dylibInfo
.reader
= reader
;
3321 dylibInfo
.options
= fDylibOptionsMap
[reader
];
3322 dynamicLibraries
.push_back(dylibInfo
);
3327 // then add any other dylibs
3328 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
3329 if ( it
->second
->implicitlyLinked() ) {
3330 // if not already in dynamicLibraries
3331 bool alreadyInDynamicLibraries
= false;
3332 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator dit
=dynamicLibraries
.begin(); dit
!= dynamicLibraries
.end(); dit
++) {
3333 if ( dit
->reader
== it
->second
) {
3334 alreadyInDynamicLibraries
= true;
3338 if ( ! alreadyInDynamicLibraries
) {
3339 ExecutableFile::DyLibUsed dylibInfo
;
3340 dylibInfo
.reader
= it
->second
;
3341 std::map
<ObjectFile::Reader
*,DynamicLibraryOptions
>::iterator pos
= fDylibOptionsMap
.find(it
->second
);
3342 if ( pos
!= fDylibOptionsMap
.end() ) {
3343 dylibInfo
.options
= pos
->second
;
3346 dylibInfo
.options
.fWeakImport
= false; // FIX ME
3347 dylibInfo
.options
.fReExport
= false;
3348 dylibInfo
.options
.fBundleLoader
= false;
3350 dynamicLibraries
.push_back(dylibInfo
);
3354 if ( fBundleLoaderReader
!= NULL
) {
3355 ExecutableFile::DyLibUsed dylibInfo
;
3356 dylibInfo
.reader
= fBundleLoaderReader
;
3357 dylibInfo
.options
.fWeakImport
= false;
3358 dylibInfo
.options
.fReExport
= false;
3359 dylibInfo
.options
.fBundleLoader
= true;
3360 dynamicLibraries
.push_back(dylibInfo
);
3363 const char* path
= fOptions
.getOutputFilePath();
3364 switch ( fArchitecture
) {
3365 case CPU_TYPE_POWERPC
:
3366 this->setOutputFile(new mach_o::executable::Writer
<ppc
>(path
, fOptions
, dynamicLibraries
));
3368 case CPU_TYPE_POWERPC64
:
3369 this->setOutputFile(new mach_o::executable::Writer
<ppc64
>(path
, fOptions
, dynamicLibraries
));
3372 this->setOutputFile(new mach_o::executable::Writer
<x86
>(path
, fOptions
, dynamicLibraries
));
3374 case CPU_TYPE_X86_64
:
3375 this->setOutputFile(new mach_o::executable::Writer
<x86_64
>(path
, fOptions
, dynamicLibraries
));
3378 this->setOutputFile(new mach_o::executable::Writer
<arm
>(path
, fOptions
, dynamicLibraries
));
3381 throw "unknown architecture";
3386 Linker::SymbolTable::SymbolTable(Linker
& owner
)
3387 : fOwner(owner
), fRequireCount(0), fHasExternalTentativeDefinitions(false), fHasExternalWeakDefinitions(false)
3391 void Linker::SymbolTable::require(const char* name
)
3393 //fprintf(stderr, "require(%s)\n", name);
3394 Mapper::iterator pos
= fTable
.find(name
);
3395 if ( pos
== fTable
.end() ) {
3396 fTable
[name
] = NULL
;
3401 // convenience labels for 2-dimensional switch statement
3402 enum AllDefinitionCombinations
{
3403 kRegAndReg
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3404 kRegAndWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3405 kRegAndTent
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3406 kRegAndExtern
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3407 kRegAndExternWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3408 kRegAndAbsolute
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3409 kWeakAndReg
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3410 kWeakAndWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3411 kWeakAndTent
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3412 kWeakAndExtern
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3413 kWeakAndExternWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3414 kWeakAndAbsolute
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3415 kTentAndReg
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3416 kTentAndWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3417 kTentAndTent
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3418 kTentAndExtern
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3419 kTentAndExternWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3420 kTentAndAbsolute
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3421 kExternAndReg
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3422 kExternAndWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3423 kExternAndTent
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3424 kExternAndExtern
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3425 kExternAndExternWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3426 kExternAndAbsolute
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3427 kExternWeakAndReg
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3428 kExternWeakAndWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3429 kExternWeakAndTent
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3430 kExternWeakAndExtern
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3431 kExternWeakAndExternWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3432 kExternWeakAndAbsolute
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3433 kAbsoluteAndReg
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3434 kAbsoluteAndWeak
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3435 kAbsoluteAndTent
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3436 kAbsoluteAndExtern
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3437 kAbsoluteAndExternWeak
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3438 kAbsoluteAndAbsolute
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
3441 bool Linker::SymbolTable::add(ObjectFile::Atom
& newAtom
)
3444 bool checkVisibilityMismatch
= false;
3445 const char* name
= newAtom
.getName();
3446 if ( newAtom
.getScope() == ObjectFile::Atom::scopeGlobal
) {
3447 switch ( newAtom
.getDefinitionKind() ) {
3448 case ObjectFile::Atom::kTentativeDefinition
:
3449 fHasExternalTentativeDefinitions
= true;
3451 case ObjectFile::Atom::kWeakDefinition
:
3452 fHasExternalWeakDefinitions
= true;
3458 //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
3459 Mapper::iterator pos
= fTable
.find(name
);
3460 ObjectFile::Atom
* existingAtom
= NULL
;
3461 if ( pos
!= fTable
.end() )
3462 existingAtom
= pos
->second
;
3463 if ( existingAtom
!= NULL
) {
3464 // already have atom with same name in symbol table
3465 switch ( (AllDefinitionCombinations
)((existingAtom
->getDefinitionKind() << 3) | newAtom
.getDefinitionKind()) ) {
3467 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3469 // ignore new weak atom, because we already have a non-weak one
3473 // ignore new tentative atom, because we already have a regular one
3475 checkVisibilityMismatch
= true;
3476 if ( newAtom
.getSize() > existingAtom
->getSize() ) {
3477 warning("for symbol %s tentative definition of size %llu from %s is "
3478 "is smaller than the real definition of size %llu from %s",
3479 newAtom
.getDisplayName(), newAtom
.getSize(), newAtom
.getFile()->getPath(),
3480 existingAtom
->getSize(), existingAtom
->getFile()->getPath());
3484 // ignore external atom, because we already have a one
3487 case kRegAndExternWeak
:
3488 // ignore external atom, because we already have a one
3491 case kRegAndAbsolute
:
3492 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3495 // replace existing weak atom with regular one
3498 // have another weak atom, use whichever has largest alignment requirement
3499 // because codegen of some client may require alignment
3500 useNew
= ( newAtom
.getAlignment().trailingZeros() > existingAtom
->getAlignment().trailingZeros() );
3501 checkVisibilityMismatch
= true;
3504 // replace existing weak atom with tentative one ???
3506 case kWeakAndExtern
:
3507 // keep weak atom, at runtime external one may override
3510 case kWeakAndExternWeak
:
3511 // keep weak atom, at runtime external one may override
3514 case kWeakAndAbsolute
:
3515 // replace existing weak atom with absolute one
3518 // replace existing tentative atom with regular one
3519 checkVisibilityMismatch
= true;
3520 if ( newAtom
.getSize() < existingAtom
->getSize() ) {
3521 warning("for symbol %s tentative definition of size %llu from %s is "
3522 "being replaced by a real definition of size %llu from %s",
3523 newAtom
.getDisplayName(), existingAtom
->getSize(), existingAtom
->getFile()->getPath(),
3524 newAtom
.getSize(), newAtom
.getFile()->getPath());
3528 // replace existing tentative atom with weak one ???
3532 checkVisibilityMismatch
= true;
3533 if ( newAtom
.getSize() < existingAtom
->getSize() ) {
3537 if ( newAtom
.getAlignment().trailingZeros() < existingAtom
->getAlignment().trailingZeros() )
3538 warning("alignment lost in merging tentative definition %s", newAtom
.getDisplayName());
3541 case kTentAndExtern
:
3542 case kTentAndExternWeak
:
3543 // a tentative definition and a dylib definition, so commons-mode decides how to handle
3544 switch ( fOwner
.fOptions
.commonsMode() ) {
3545 case Options::kCommonsIgnoreDylibs
:
3546 if ( fOwner
.fOptions
.warnCommons() )
3547 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
3548 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3551 case Options::kCommonsOverriddenByDylibs
:
3552 if ( fOwner
.fOptions
.warnCommons() )
3553 warning("replacing common symbol %s from %s with true definition from dylib %s",
3554 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3556 case Options::kCommonsConflictsDylibsError
:
3557 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
3558 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3561 case kTentAndAbsolute
:
3562 // replace tentative with absolute (can't size check because absolutes have no size)
3565 // replace external atom with regular one
3567 case kExternAndWeak
:
3568 // replace external atom with weak one
3570 case kExternAndTent
:
3571 // a tentative definition and a dylib definition, so commons-mode decides how to handle
3572 switch ( fOwner
.fOptions
.commonsMode() ) {
3573 case Options::kCommonsIgnoreDylibs
:
3574 if ( fOwner
.fOptions
.warnCommons() )
3575 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
3576 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3578 case Options::kCommonsOverriddenByDylibs
:
3579 if ( fOwner
.fOptions
.warnCommons() )
3580 warning("replacing defintion of %s from dylib %s with common symbol from %s",
3581 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3584 case Options::kCommonsConflictsDylibsError
:
3585 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
3586 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3589 case kExternAndExtern
:
3590 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3591 case kExternAndExternWeak
:
3592 // keep strong dylib atom, ignore weak one
3595 case kExternAndAbsolute
:
3596 // replace external atom with absolute one
3598 case kExternWeakAndReg
:
3599 // replace existing weak external with regular
3601 case kExternWeakAndWeak
:
3602 // replace existing weak external with weak (let dyld decide at runtime which to use)
3604 case kExternWeakAndTent
:
3605 // a tentative definition and a dylib definition, so commons-mode decides how to handle
3606 switch ( fOwner
.fOptions
.commonsMode() ) {
3607 case Options::kCommonsIgnoreDylibs
:
3608 if ( fOwner
.fOptions
.warnCommons() )
3609 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
3610 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3612 case Options::kCommonsOverriddenByDylibs
:
3613 if ( fOwner
.fOptions
.warnCommons() )
3614 warning("replacing defintion of %s from dylib %s with common symbol from %s",
3615 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3618 case Options::kCommonsConflictsDylibsError
:
3619 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
3620 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3623 case kExternWeakAndExtern
:
3624 // replace existing weak external with external
3626 case kExternWeakAndExternWeak
:
3627 // keep existing external weak
3630 case kExternWeakAndAbsolute
:
3631 // replace existing weak external with absolute
3633 case kAbsoluteAndReg
:
3634 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3635 case kAbsoluteAndWeak
:
3636 // ignore new weak atom, because we already have a non-weak one
3639 case kAbsoluteAndTent
:
3640 // ignore new tentative atom, because we already have a regular one
3643 case kAbsoluteAndExtern
:
3644 // ignore external atom, because we already have a one
3647 case kAbsoluteAndExternWeak
:
3648 // ignore external atom, because we already have a one
3651 case kAbsoluteAndAbsolute
:
3652 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3656 if ( (existingAtom
!= NULL
) && checkVisibilityMismatch
&& (newAtom
.getScope() != existingAtom
->getScope()) ) {
3657 warning("%s has different visibility (%s) in %s and (%s) in %s",
3658 newAtom
.getDisplayName(), (newAtom
.getScope() == 1 ? "hidden" : "default"), newAtom
.getFile()->getPath(), (existingAtom
->getScope() == 1 ? "hidden" : "default"), existingAtom
->getFile()->getPath());
3661 fTable
[name
] = &newAtom
;
3662 if ( existingAtom
!= NULL
)
3663 fOwner
.markDead(existingAtom
);
3666 fOwner
.markDead(&newAtom
);
3673 ObjectFile::Atom
* Linker::SymbolTable::find(const char* name
)
3675 Mapper::iterator pos
= fTable
.find(name
);
3676 if ( pos
!= fTable
.end() ) {
3683 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
)
3685 for (Mapper::iterator it
=fTable
.begin(); it
!= fTable
.end(); it
++) {
3686 if ( (it
->second
== NULL
) || (andWeakDefintions
&& (it
->second
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
)) ) {
3687 undefines
.push_back(it
->first
);
3694 bool Linker::AtomSorter::operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
)
3696 if ( left
== right
)
3699 // first sort by section order (which is already sorted by segment)
3700 unsigned int leftSectionIndex
= left
->getSection()->getIndex();
3701 unsigned int rightSectionIndex
= right
->getSection()->getIndex();
3702 if ( leftSectionIndex
!= rightSectionIndex
)
3703 return (leftSectionIndex
< rightSectionIndex
);
3705 // if a -order_file is specified, then sorting is altered to sort those symbols first
3706 if ( fOverriddenOrdinalMap
!= NULL
) {
3707 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator leftPos
= fOverriddenOrdinalMap
->find(left
);
3708 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator rightPos
= fOverriddenOrdinalMap
->find(right
);
3709 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator end
= fOverriddenOrdinalMap
->end();
3710 if ( leftPos
!= end
) {
3711 if ( rightPos
!= end
) {
3712 // both left and right are overridden, so compare overridden ordinals
3713 return leftPos
->second
< rightPos
->second
;
3716 // left is overridden and right is not, so left < right
3721 if ( rightPos
!= end
) {
3722 // right is overridden and left is not, so right < left
3726 // neither are overridden, do default sort
3727 // fall into default sorting below
3732 // the __common section can have real or tentative definitions
3733 // we want the real ones to sort before tentative ones
3734 bool leftIsTent
= (left
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
);
3735 bool rightIsTent
= (right
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
);
3736 if ( leftIsTent
!= rightIsTent
)
3739 // lastly sort by atom ordinal. this is already sorted by .o order
3740 return left
->getOrdinal() < right
->getOrdinal();
3744 int main(int argc
, const char* argv
[])
3746 const char* archName
= NULL
;
3747 bool showArch
= false;
3748 bool archInferred
= false;
3750 // create linker object given command line arguments
3751 Linker
ld(argc
, argv
);
3753 // save error message prefix
3754 archName
= ld
.architectureName();
3755 archInferred
= ld
.isInferredArchitecture();
3756 showArch
= ld
.showArchitectureInErrors();
3758 // open all input files
3767 catch (const char* msg
) {
3769 fprintf(stderr
, "ld: %s for inferred architecture %s\n", msg
, archName
);
3770 else if ( showArch
)
3771 fprintf(stderr
, "ld: %s for architecture %s\n", msg
, archName
);
3773 fprintf(stderr
, "ld: %s\n", msg
);