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 #include <sys/types.h>
27 #include <sys/sysctl.h>
32 #include <mach/mach_time.h>
33 #include <mach/vm_statistics.h>
34 #include <mach/mach_init.h>
35 #include <mach/mach_host.h>
36 #include <mach-o/fat.h>
46 #include <ext/hash_map>
48 #include <AvailabilityMacros.h>
52 #include "ObjectFile.h"
54 #include "MachOReaderRelocatable.hpp"
55 #include "MachOReaderArchive.hpp"
56 #include "MachOReaderDylib.hpp"
57 #include "MachOWriterExecutable.hpp"
59 #define LLVM_SUPPORT 0
62 #include "LLVMReader.hpp"
65 #include "OpaqueSection.hpp"
71 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) < 0); }
77 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
80 class Section
: public ObjectFile::Section
83 static Section
* find(const char* sectionName
, const char* segmentName
, bool zeroFill
);
84 static void assignIndexes();
85 const char* getName() { return fSectionName
; }
87 Section(const char* sectionName
, const char* segmentName
, bool zeroFill
);
90 static int segmentOrdinal(const char* segName
);
91 bool operator()(Section
* left
, Section
* right
);
94 typedef __gnu_cxx::hash_map
<const char*, uint32_t, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToOrdinal
;
95 typedef __gnu_cxx::hash_map
<const char*, class Section
*, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToSection
;
96 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
98 const char* fSectionName
;
99 const char* fSegmentName
;
102 static NameToSection fgMapping
;
103 static std::vector
<Section
*> fgSections
;
104 static NameToOrdinal fgSegmentDiscoverOrder
;
107 Section::NameToSection
Section::fgMapping
;
108 std::vector
<Section
*> Section::fgSections
;
109 Section::NameToOrdinal
Section::fgSegmentDiscoverOrder
;
111 Section::Section(const char* sectionName
, const char* segmentName
, bool zeroFill
)
112 : fSectionName(sectionName
), fSegmentName(segmentName
), fZeroFill(zeroFill
)
114 this->fIndex
= fgSections
.size();
115 //fprintf(stderr, "new Section(%s, %s) => %p, %u\n", sectionName, segmentName, this, this->getIndex());
118 Section
* Section::find(const char* sectionName
, const char* segmentName
, bool zeroFill
)
120 NameToSection::iterator pos
= fgMapping
.find(sectionName
);
121 if ( pos
!= fgMapping
.end() ) {
122 if ( strcmp(pos
->second
->fSegmentName
, segmentName
) == 0 )
124 // otherwise same section name is used in different segments, look slow way
125 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++) {
126 if ( (strcmp((*it
)->fSectionName
, sectionName
) == 0) && (strcmp((*it
)->fSegmentName
, segmentName
) == 0) )
131 // does not exist, so make a new one
132 Section
* sect
= new Section(sectionName
, segmentName
, zeroFill
);
133 fgMapping
[sectionName
] = sect
;
134 fgSections
.push_back(sect
);
136 if ( (strcmp(sectionName
, "__text") == 0) && (strcmp(segmentName
, "__TEXT") == 0) ) {
137 // special case __textcoal_nt to be right after __text
138 find("__textcoal_nt", "__TEXT", false);
141 // remember segment discovery order
142 if ( fgSegmentDiscoverOrder
.find(segmentName
) == fgSegmentDiscoverOrder
.end() )
143 fgSegmentDiscoverOrder
[segmentName
] = fgSegmentDiscoverOrder
.size();
148 int Section::Sorter::segmentOrdinal(const char* segName
)
150 if ( strcmp(segName
, "__PAGEZERO") == 0 )
152 if ( strcmp(segName
, "__TEXT") == 0 )
154 if ( strcmp(segName
, "__DATA") == 0 )
156 if ( strcmp(segName
, "__OBJC") == 0 )
158 if ( strcmp(segName
, "__OBJC2") == 0 )
160 if ( strcmp(segName
, "__LINKEDIT") == 0 )
161 return INT_MAX
; // linkedit segment should always sort last
163 return fgSegmentDiscoverOrder
[segName
]+6;
167 bool Section::Sorter::operator()(Section
* left
, Section
* right
)
169 // Segment is primary sort key
170 int leftSegOrdinal
= segmentOrdinal(left
->fSegmentName
);
171 int rightSegOrdinal
= segmentOrdinal(right
->fSegmentName
);
172 if ( leftSegOrdinal
< rightSegOrdinal
)
174 if ( leftSegOrdinal
> rightSegOrdinal
)
177 // zerofill section sort to the end
178 if ( !left
->fZeroFill
&& right
->fZeroFill
)
180 if ( left
->fZeroFill
&& !right
->fZeroFill
)
183 // section discovery order is last sort key
184 return left
->fIndex
< right
->fIndex
;
187 void Section::assignIndexes()
189 //printf("unsorted sections:\n");
190 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
191 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
195 std::sort(fgSections
.begin(), fgSections
.end(), Section::Sorter());
197 // assign correct section ordering to each Section object
198 unsigned int newOrder
= 1;
199 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++)
200 (*it
)->fIndex
= newOrder
++;
202 //printf("sorted sections:\n");
203 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
204 // printf("section: index=%d, obj=%p, name=%s\n", (*it)->fIndex, (*it), (*it)->fSectionName);
208 class Linker
: public ObjectFile::Reader::DylibHander
{
210 Linker(int argc
, const char* argv
[]);
212 const char* getArchPrefix();
213 const char* architectureName();
214 bool showArchitectureInErrors();
215 bool isInferredArchitecture();
216 void createReaders();
218 void addInputFile(ObjectFile::Reader
* reader
, const Options::FileInfo
& );
219 void setOutputFile(ExecutableFile::Writer
* writer
);
223 // implemenation from ObjectFile::Reader::DylibHander
224 virtual ObjectFile::Reader
* findDylib(const char* installPath
, const char* fromPath
);
227 struct WhyLiveBackChain
229 WhyLiveBackChain
* previous
;
233 ObjectFile::Reader
* createReader(const Options::FileInfo
&);
234 void addAtom(ObjectFile::Atom
& atom
);
235 void addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
);
236 void buildAtomList();
237 void processDylibs();
238 void updateContraints(ObjectFile::Reader
* reader
);
239 void loadAndResolve();
240 void processDTrace();
242 void loadUndefines();
243 void checkUndefines();
244 void addWeakAtomOverrides();
245 void resolveReferences();
246 void deadStripResolve();
247 void addLiveRoot(const char* name
);
248 ObjectFile::Atom
* findAtom(const Options::OrderedSymbol
& pair
);
249 void logArchive(ObjectFile::Reader
* reader
);
253 void writeDotOutput();
254 static bool minimizeStab(ObjectFile::Reader::Stab
& stab
);
255 static const char* truncateStabString(const char* str
);
256 void collectDebugInfo();
258 ObjectFile::Atom
* entryPoint();
259 ObjectFile::Atom
* dyldHelper();
260 const char* assureFullPath(const char* path
);
261 void markLive(ObjectFile::Atom
& atom
, Linker::WhyLiveBackChain
* previous
);
262 void collectStabs(ObjectFile::Reader
* reader
, std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
);
263 void synthesizeDebugNotes(std::vector
<class ObjectFile::Atom
*>& allAtomsByReader
);
264 void printStatistics();
265 void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
);
266 char* commatize(uint64_t in
, char* out
);
267 void getVMInfo(vm_statistics_data_t
& info
);
268 cpu_type_t
inferArchitecture();
269 void addDtraceProbe(ObjectFile::Atom
& atom
, uint32_t offsetInAtom
, const char* probeName
);
270 void checkDylibClientRestrictions(ObjectFile::Reader
* reader
);
271 void logDylib(ObjectFile::Reader
* reader
, bool indirect
);
273 void resolve(ObjectFile::Reference
* reference
);
274 void resolveFrom(ObjectFile::Reference
* reference
);
275 std::vector
<class ObjectFile::Atom
*>* addJustInTimeAtoms(const char* name
);
276 void addJustInTimeAtomsAndMarkLive(const char* name
);
278 ObjectFile::Reader
* addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
279 ObjectFile::Reader
* addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
280 ObjectFile::Reader
* addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
282 void logTraceInfo(const char* format
, ...);
288 SymbolTable(Linker
&);
289 void require(const char* name
);
290 bool add(ObjectFile::Atom
& atom
);
291 ObjectFile::Atom
* find(const char* name
);
292 unsigned int getRequireCount() { return fRequireCount
; }
293 void getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
);
294 typedef __gnu_cxx::hash_map
<const char*, ObjectFile::Atom
*, __gnu_cxx::hash
<const char*>, CStringEquals
> Mapper
;
298 unsigned int fRequireCount
;
304 AtomSorter(std::map
<const ObjectFile::Atom
*, uint32_t>* map
) : fOverriddenOrdinalMap(map
) {}
305 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
);
307 std::map
<const ObjectFile::Atom
*, uint32_t>* fOverriddenOrdinalMap
;
310 typedef std::map
<const char*, uint32_t, CStringComparor
> SectionOrder
;
312 struct DTraceProbeInfo
{
313 DTraceProbeInfo(const ObjectFile::Atom
* a
, uint32_t o
, const char* n
) : atom(a
), offset(o
), probeName(n
) {}
314 const ObjectFile::Atom
* atom
;
316 const char* probeName
;
318 typedef __gnu_cxx::hash_map
<const char*, std::vector
<DTraceProbeInfo
>, __gnu_cxx::hash
<const char*>, CStringEquals
> ProviderToProbes
;
319 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> CStringSet
;
320 typedef __gnu_cxx::hash_map
<const char*, ObjectFile::Reader
*, __gnu_cxx::hash
<const char*>, CStringEquals
> InstallNameToReader
;
322 struct IndirectLibrary
{
325 ObjectFile::Reader
* reader
;
326 std::set
<ObjectFile::Reader
*> parents
;
327 ObjectFile::Reader
* reExportedViaDirectLibrary
;
330 ObjectFile::Reader
* findDirectLibraryWhichReExports(struct IndirectLibrary
& indirectLib
);
333 SymbolTable fGlobalSymbolTable
;
334 uint32_t fNextInputOrdinal
;
335 std::vector
<class ObjectFile::Reader
*> fInputFiles
;
336 ExecutableFile::Writer
* fOutputFile
;
337 InstallNameToReader fDylibMap
;
338 std::map
<ObjectFile::Reader
*,DynamicLibraryOptions
> fDylibOptionsMap
;
339 std::set
<ObjectFile::Reader
*> fDylibsProcessed
;
340 ObjectFile::Reader
* fBundleLoaderReader
;
341 std::vector
<class ObjectFile::Reader
*> fReadersThatHaveSuppliedAtoms
;
342 std::vector
<class ObjectFile::Atom
*> fAllAtoms
;
343 std::set
<class ObjectFile::Reader
*> fArchiveReaders
;
344 std::set
<class ObjectFile::Reader
*> fArchiveReadersLogged
;
345 std::set
<class ObjectFile::Atom
*> fDeadAtoms
;
346 std::set
<ObjectFile::Atom
*> fLiveAtoms
;
347 std::set
<ObjectFile::Atom
*> fLiveRootAtoms
;
348 std::vector
<class ObjectFile::Reader::Stab
> fStabs
;
349 std::vector
<class ObjectFile::Atom
*> fAtomsWithUnresolvedReferences
;
350 std::vector
<DTraceProbeInfo
> fDtraceProbes
;
351 std::vector
<DTraceProbeInfo
> fDtraceProbeSites
;
352 std::vector
<DTraceProbeInfo
> fDtraceIsEnabledSites
;
353 std::map
<const ObjectFile::Atom
*,CStringSet
> fDtraceAtomToTypes
;
356 SectionOrder fSectionOrder
;
357 cpu_type_t fArchitecture
;
358 const char* fArchitectureName
;
359 bool fArchitectureInferred
;
360 bool fDirectLibrariesComplete
;
361 bool fBiggerThanTwoGigOutput
;
362 uint64_t fOutputFileSize
;
363 uint64_t fTotalZeroFillSize
;
366 uint64_t fStartCreateReadersTime
;
367 uint64_t fStartCreateWriterTime
;
368 uint64_t fStartBuildAtomsTime
;
369 uint64_t fStartLoadAndResolveTime
;
370 uint64_t fStartSortTime
;
371 uint64_t fStartDebugTime
;
372 uint64_t fStartWriteTime
;
374 uint64_t fTotalObjectSize
;
375 uint64_t fTotalArchiveSize
;
376 uint32_t fTotalObjectLoaded
;
377 uint32_t fTotalArchivesLoaded
;
378 uint32_t fTotalDylibsLoaded
;
379 vm_statistics_data_t fStartVMInfo
;
380 ObjectFile::Reader::ObjcConstraint fCurrentObjCConstraint
;
381 ObjectFile::Reader::CpuConstraint fCurrentCpuConstraint
;
382 bool fObjcReplacmentClasses
;
383 bool fAllDirectDylibsLoaded
;
387 Linker::Linker(int argc
, const char* argv
[])
388 : fOptions(argc
, argv
), fGlobalSymbolTable(*this), fNextInputOrdinal(1), fOutputFile(NULL
), fBundleLoaderReader(NULL
),
389 fCreateUUID(false), fCanScatter(true),
390 fArchitecture(0), fArchitectureInferred(false), fDirectLibrariesComplete(false), fBiggerThanTwoGigOutput(false),
391 fOutputFileSize(0), fTotalZeroFillSize(0), fTotalSize(0), fTotalObjectSize(0),
392 fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0),
393 fCurrentObjCConstraint(ObjectFile::Reader::kObjcNone
), fCurrentCpuConstraint(ObjectFile::Reader::kCpuAny
),
394 fObjcReplacmentClasses(false), fAllDirectDylibsLoaded(false)
396 fStartTime
= mach_absolute_time();
397 if ( fOptions
.printStatistics() )
398 getVMInfo(fStartVMInfo
);
400 fArchitecture
= fOptions
.architecture();
401 if ( fArchitecture
== 0 ) {
402 // -arch not specified, scan .o files to figure out what it should be
403 fArchitecture
= inferArchitecture();
404 fArchitectureInferred
= true;
406 switch (fArchitecture
) {
407 case CPU_TYPE_POWERPC
:
408 fArchitectureName
= "ppc";
410 case CPU_TYPE_POWERPC64
:
411 fArchitectureName
= "ppc64";
414 fArchitectureName
= "i386";
416 case CPU_TYPE_X86_64
:
417 fArchitectureName
= "x86_64";
420 fArchitectureName
= "unknown architecture";
425 const char* Linker::architectureName()
427 return fArchitectureName
;
430 bool Linker::showArchitectureInErrors()
432 return fOptions
.printArchPrefix();
435 bool Linker::isInferredArchitecture()
437 return fArchitectureInferred
;
440 cpu_type_t
Linker::inferArchitecture()
442 // scan all input files, looking for a thin .o file.
443 // the first one found is presumably the architecture to link
444 uint8_t buffer
[sizeof(mach_header_64
)];
445 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
446 for (std::vector
<Options::FileInfo
>::iterator it
= files
.begin(); it
!= files
.end(); ++it
) {
447 int fd
= ::open(it
->path
, O_RDONLY
, 0);
449 ssize_t amount
= read(fd
, buffer
, sizeof(buffer
));
451 if ( amount
>= (ssize_t
)sizeof(buffer
) ) {
452 if ( mach_o::relocatable::Reader
<ppc
>::validFile(buffer
) ) {
453 //fprintf(stderr, "ld: warning -arch not used, infering -arch ppc based on %s\n", it->path);
454 return CPU_TYPE_POWERPC
;
456 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(buffer
) ) {
457 //fprintf(stderr, "ld: warning -arch not used, infering -arch ppc64 based on %s\n", it->path);
458 return CPU_TYPE_POWERPC64
;
460 else if ( mach_o::relocatable::Reader
<x86
>::validFile(buffer
) ) {
461 //fprintf(stderr, "ld: warning -arch not used, infering -arch i386 based on %s\n", it->path);
462 return CPU_TYPE_I386
;
464 else if ( mach_o::relocatable::Reader
<x86_64
>::validFile(buffer
) ) {
465 //fprintf(stderr, "ld: warning -arch not used, infering -arch x86_64 based on %s\n", it->path);
466 return CPU_TYPE_X86_64
;
472 // no thin .o files found, so default to same architecture this was built as
473 fprintf(stderr
, "ld: warning -arch not specified\n");
475 return CPU_TYPE_POWERPC
;
477 return CPU_TYPE_I386
;
479 return CPU_TYPE_POWERPC64
;
481 return CPU_TYPE_X86_64
;
483 #error unknown default architecture
488 void Linker::addInputFile(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
)
490 fInputFiles
.push_back(reader
);
491 fDylibOptionsMap
[reader
] = info
.options
;
494 void Linker::setOutputFile(ExecutableFile::Writer
* writer
)
496 fOutputFile
= writer
;
502 InSet(std::set
<ObjectFile::Atom
*>& deadAtoms
) : fDeadAtoms(deadAtoms
) {}
504 bool operator()(ObjectFile::Atom
*& atom
) const {
505 return ( fDeadAtoms
.count(atom
) != 0 );
509 std::set
<ObjectFile::Atom
*>& fDeadAtoms
;
512 void Linker::loadAndResolve()
514 fStartLoadAndResolveTime
= mach_absolute_time();
515 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
516 // without dead-code-stripping:
517 // find atoms to resolve all undefines
518 this->loadUndefines();
519 // verify nothing is missing
520 this->checkUndefines();
521 // once all undefines fulfill, then bind all references
522 this->resolveReferences();
523 // remove atoms weak atoms that have been overridden
524 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fDeadAtoms
)), fAllAtoms
.end());
527 // with dead code stripping:
528 // start binding references from roots,
529 this->deadStripResolve();
530 // verify nothing is missing
531 this->checkUndefines();
535 void Linker::optimize()
537 std::vector
<class ObjectFile::Atom
*> newAtoms
;
539 const int readerCount
= fInputFiles
.size();
540 for (int i
=0; i
< readerCount
; ++i
) {
541 fInputFiles
[i
]->optimize(fAllAtoms
, newAtoms
, fNextInputOrdinal
);
543 // note: When writer start generating stubs and non-lazy-pointers for all architecture, do not insert
544 // newAtoms into fGlobalSymbolTable. Instead directly insert them in fAllAtoms and set their order appropriately.
545 this->addAtoms(newAtoms
);
547 // Some of the optimized atoms may not have identified section properly, if they
548 // were created before optimizer produces corrosponding real atom. Here, input
549 // file readers are not able to patch it themselves because Section::find() is
551 for(std::vector
<class ObjectFile::Atom
*>::iterator itr
= fAllAtoms
.begin();
552 itr
!= fAllAtoms
.end(); ++itr
) {
554 ObjectFile::Atom
*atom
= *itr
;
555 if (atom
->getSectionName() && !atom
->getSection())
556 atom
->setSection(Section::find(atom
->getSectionName(), atom
->getSegment().getName(), atom
->isZeroFill()));
559 if ( fOptions
.deadStrip() != Options::kDeadStripOff
) {
569 this->buildAtomList();
570 this->loadAndResolve();
573 this->processDTrace();
575 this->sortSections();
577 this->writeDotOutput();
578 this->collectDebugInfo();
580 this->printStatistics();
582 if ( fOptions
.pauseAtEnd() )
586 void Linker::printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
)
588 static uint64_t sUnitsPerSecond
= 0;
589 if ( sUnitsPerSecond
== 0 ) {
590 struct mach_timebase_info timeBaseInfo
;
591 if ( mach_timebase_info(&timeBaseInfo
) == KERN_SUCCESS
) {
592 sUnitsPerSecond
= 1000000000ULL * timeBaseInfo
.denom
/ timeBaseInfo
.numer
;
593 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
596 if ( partTime
< sUnitsPerSecond
) {
597 uint32_t milliSecondsTimeTen
= (partTime
*10000)/sUnitsPerSecond
;
598 uint32_t milliSeconds
= milliSecondsTimeTen
/10;
599 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
600 uint32_t percent
= percentTimesTen
/10;
601 fprintf(stderr
, "%s: %u.%u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimeTen
-milliSeconds
*10, percent
, percentTimesTen
-percent
*10);
604 uint32_t secondsTimeTen
= (partTime
*10)/sUnitsPerSecond
;
605 uint32_t seconds
= secondsTimeTen
/10;
606 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
607 uint32_t percent
= percentTimesTen
/10;
608 fprintf(stderr
, "%s: %u.%u seconds (%u.%u%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10);
612 char* Linker::commatize(uint64_t in
, char* out
)
616 sprintf(rawNum
, "%llu", in
);
617 const int rawNumLen
= strlen(rawNum
);
618 for(int i
=0; i
< rawNumLen
-1; ++i
) {
620 if ( ((rawNumLen
-i
) % 3) == 1 )
623 *out
++ = rawNum
[rawNumLen
-1];
628 void Linker::getVMInfo(vm_statistics_data_t
& info
)
630 mach_msg_type_number_t count
= sizeof(vm_statistics_data_t
) / sizeof(natural_t
);
631 kern_return_t error
= host_statistics(mach_host_self(), HOST_VM_INFO
,
632 (host_info_t
)&info
, &count
);
633 if (error
!= KERN_SUCCESS
) {
634 bzero(&info
, sizeof(vm_statistics_data_t
));
638 void Linker::printStatistics()
640 fEndTime
= mach_absolute_time();
641 if ( fOptions
.printStatistics() ) {
642 vm_statistics_data_t endVMInfo
;
643 getVMInfo(endVMInfo
);
645 uint64_t totalTime
= fEndTime
- fStartTime
;
646 printTime("ld total time", totalTime
, totalTime
);
647 printTime(" option parsing time", fStartCreateReadersTime
- fStartTime
, totalTime
);
648 printTime(" object file processing",fStartCreateWriterTime
- fStartCreateReadersTime
, totalTime
);
649 printTime(" output file setup", fStartBuildAtomsTime
- fStartCreateWriterTime
, totalTime
);
650 printTime(" build atom list", fStartLoadAndResolveTime
- fStartBuildAtomsTime
, totalTime
);
651 printTime(" resolve references", fStartSortTime
- fStartLoadAndResolveTime
, totalTime
);
652 printTime(" sort output", fStartDebugTime
- fStartSortTime
, totalTime
);
653 printTime(" process debug info", fStartWriteTime
- fStartDebugTime
, totalTime
);
654 printTime(" write output", fEndTime
- fStartWriteTime
, totalTime
);
655 fprintf(stderr
, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo
.pageins
-fStartVMInfo
.pageins
,
656 endVMInfo
.pageouts
-fStartVMInfo
.pageouts
, endVMInfo
.faults
-fStartVMInfo
.faults
);
658 fprintf(stderr
, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded
, commatize(fTotalObjectSize
, temp
));
659 fprintf(stderr
, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded
, commatize(fTotalArchiveSize
, temp
));
660 fprintf(stderr
, "processed %3u dylib files\n", fTotalDylibsLoaded
);
661 fprintf(stderr
, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize
, temp
));
665 inline void Linker::addAtom(ObjectFile::Atom
& atom
)
667 // add to list of all atoms
668 fAllAtoms
.push_back(&atom
);
670 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
671 // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later
672 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
673 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
674 ObjectFile::Reference
* reference
= *it
;
675 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
)
676 fGlobalSymbolTable
.require(reference
->getTargetName());
677 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
)
678 fGlobalSymbolTable
.require(reference
->getFromTargetName());
679 if ( reference
->getTargetBinding() == ObjectFile::Reference::kDontBind
)
680 addDtraceProbe(atom
, reference
->getFixUpOffset(), reference
->getTargetName());
682 // update total size info (except for __ZEROPAGE atom)
683 if ( atom
.getSegment().isContentReadable() ) {
684 fTotalSize
+= atom
.getSize();
685 if ( atom
.isZeroFill() )
686 fTotalZeroFillSize
+= atom
.getSize();
690 if ( atom
.dontDeadStrip() )
691 fLiveRootAtoms
.insert(&atom
);
694 // if in global namespace, add atom itself to symbol table
695 ObjectFile::Atom::Scope scope
= atom
.getScope();
696 const char* name
= atom
.getName();
697 if ( (scope
!= ObjectFile::Atom::scopeTranslationUnit
) && (name
!= NULL
) ) {
698 // update scope based on export list (possible that globals are downgraded to private_extern)
699 if ( (scope
== ObjectFile::Atom::scopeGlobal
) && fOptions
.hasExportRestrictList() ) {
700 bool doExport
= fOptions
.shouldExport(name
);
702 atom
.setScope(ObjectFile::Atom::scopeLinkageUnit
);
705 // add to symbol table
706 fGlobalSymbolTable
.add(atom
);
709 // record section orders so output file can have same order
710 if (atom
.getSectionName())
711 atom
.setSection(Section::find(atom
.getSectionName(), atom
.getSegment().getName(), atom
.isZeroFill()));
714 void Linker::updateContraints(ObjectFile::Reader
* reader
)
716 // check objc objects were compiled compatibly
717 ObjectFile::Reader::ObjcConstraint objcAddition
= reader
->getObjCConstraint();
718 if ( reader
->getInstallPath() == NULL
) {
720 switch ( fCurrentObjCConstraint
) {
721 case ObjectFile::Reader::kObjcNone
:
722 fCurrentObjCConstraint
= objcAddition
;
724 case ObjectFile::Reader::kObjcRetainRelease
:
725 case ObjectFile::Reader::kObjcRetainReleaseOrGC
:
726 case ObjectFile::Reader::kObjcGC
:
727 if ( (fCurrentObjCConstraint
!= objcAddition
) && (objcAddition
!= ObjectFile::Reader::kObjcNone
) )
728 throwf("%s built with different Garbage Collection settings", reader
->getPath());
732 if ( reader
->objcReplacementClasses() )
733 fObjcReplacmentClasses
= true;
735 // check cpu sub-types
736 ObjectFile::Reader::CpuConstraint cpuAddition
= reader
->getCpuConstraint();
737 switch ( fCurrentCpuConstraint
) {
738 case ObjectFile::Reader::kCpuAny
:
739 fCurrentCpuConstraint
= cpuAddition
;
741 case ObjectFile::Reader::kCpuG3
:
742 switch ( cpuAddition
) {
743 case ObjectFile::Reader::kCpuAny
:
744 case ObjectFile::Reader::kCpuG3
:
746 case ObjectFile::Reader::kCpuG4
:
747 case ObjectFile::Reader::kCpuG5
:
748 // previous file for G3 this one is more contrained, use it
749 fCurrentCpuConstraint
= cpuAddition
;
753 case ObjectFile::Reader::kCpuG4
:
754 switch ( cpuAddition
) {
755 case ObjectFile::Reader::kCpuAny
:
756 case ObjectFile::Reader::kCpuG3
:
757 case ObjectFile::Reader::kCpuG4
:
759 case ObjectFile::Reader::kCpuG5
:
760 // previous file for G5 this one is more contrained, use it
761 fCurrentCpuConstraint
= cpuAddition
;
765 case ObjectFile::Reader::kCpuG5
:
766 // G5 can run everything
771 inline void Linker::addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
)
773 bool scanAll
= fOptions
.readerOptions().fFullyLoadArchives
|| fOptions
.readerOptions().fLoadAllObjcObjectsFromArchives
;
775 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
.begin(); it
!= atoms
.end(); it
++) {
776 // usually we only need to get the first atom's reader, but
777 // with -all_load all atoms from all .o files come come back together
778 // so we need to scan all atoms
779 if ( first
|| scanAll
) {
780 // update fReadersThatHaveSuppliedAtoms
781 ObjectFile::Reader
* reader
= (*it
)->getFile();
782 if ( std::find(fReadersThatHaveSuppliedAtoms
.begin(), fReadersThatHaveSuppliedAtoms
.end(), reader
)
783 == fReadersThatHaveSuppliedAtoms
.end() ) {
784 fReadersThatHaveSuppliedAtoms
.push_back(reader
);
785 updateContraints(reader
);
793 void Linker::logArchive(ObjectFile::Reader
* reader
)
795 if ( (fArchiveReaders
.count(reader
) != 0) && (fArchiveReadersLogged
.count(reader
) == 0) ) {
796 fArchiveReadersLogged
.insert(reader
);
797 const char* fullPath
= reader
->getPath();
798 char realName
[MAXPATHLEN
];
799 if ( realpath(fullPath
, realName
) != NULL
)
801 logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath
);
806 void Linker::buildAtomList()
808 fStartBuildAtomsTime
= mach_absolute_time();
809 // add initial undefines from -u option
810 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
811 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++) {
812 fGlobalSymbolTable
.require(*it
);
815 // writer can contribute atoms
816 this->addAtoms(fOutputFile
->getAtoms());
818 // each reader contributes atoms
819 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
820 ObjectFile::Reader
* reader
= *it
;
821 std::vector
<class ObjectFile::Atom
*>& atoms
= reader
->getAtoms();
822 this->addAtoms(atoms
);
823 if ( fOptions
.readerOptions().fTraceArchives
&& (atoms
.size() != 0) )
827 // extra command line section always at end
828 std::vector
<Options::ExtraSection
>& extraSections
= fOptions
.extraSections();
829 for( std::vector
<Options::ExtraSection
>::iterator it
=extraSections
.begin(); it
!= extraSections
.end(); ++it
) {
830 this->addAtoms((new opaque_section::Reader(it
->segmentName
, it
->sectionName
, it
->path
, it
->data
, it
->dataLen
, fNextInputOrdinal
))->getAtoms());
831 fNextInputOrdinal
+= it
->dataLen
;
835 static const char* pathLeafName(const char* path
)
837 const char* shortPath
= strrchr(path
, '/');
838 if ( shortPath
== NULL
)
841 return &shortPath
[1];
844 void Linker::loadUndefines()
846 // keep looping until no more undefines were added in last loop
847 unsigned int undefineCount
= 0xFFFFFFFF;
848 while ( undefineCount
!= fGlobalSymbolTable
.getRequireCount() ) {
849 undefineCount
= fGlobalSymbolTable
.getRequireCount();
850 std::vector
<const char*> undefineNames
;
851 fGlobalSymbolTable
.getNeededNames(false, undefineNames
);
852 for(std::vector
<const char*>::iterator it
= undefineNames
.begin(); it
!= undefineNames
.end(); ++it
) {
853 const char* name
= *it
;
854 ObjectFile::Atom
* possibleAtom
= fGlobalSymbolTable
.find(name
);
855 if ( (possibleAtom
== NULL
)
856 || ((possibleAtom
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
)
857 && (fOptions
.outputKind() != Options::kObjectFile
)
858 && (possibleAtom
->getScope() == ObjectFile::Atom::scopeGlobal
)) ) {
859 std::vector
<class ObjectFile::Atom
*>* atoms
= this->addJustInTimeAtoms(name
);
867 // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
868 class ExportedObjcClass
871 ExportedObjcClass(Options
& opt
) : fOptions(opt
) {}
873 bool operator()(const char* name
) const {
874 if ( fOptions
.shouldExport(name
) ) {
875 if ( strncmp(name
, ".objc_class_name_", 17) == 0 )
877 if ( strncmp(name
, "_OBJC_CLASS_$_", 14) == 0 )
879 if ( strncmp(name
, "_OBJC_METACLASS_$_", 18) == 0 )
882 //fprintf(stderr, "%s is not exported\n", name);
890 void Linker::checkUndefines()
892 // error out on any remaining undefines
895 switch ( fOptions
.undefinedTreatment() ) {
896 case Options::kUndefinedError
:
898 case Options::kUndefinedDynamicLookup
:
901 case Options::kUndefinedWarning
:
904 case Options::kUndefinedSuppress
:
909 std::vector
<const char*> unresolvableUndefines
;
910 fGlobalSymbolTable
.getNeededNames(false, unresolvableUndefines
);
912 // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
913 // ignore unresolved references to Objc class names that are listed in -exported_symbols_list
914 if ( fOptions
.hasExportRestrictList() )
915 unresolvableUndefines
.erase(std::remove_if(unresolvableUndefines
.begin(), unresolvableUndefines
.end(), ExportedObjcClass(fOptions
)), unresolvableUndefines
.end());
917 const int unresolvableCount
= unresolvableUndefines
.size();
918 int unresolvableExportsCount
= 0;
919 if ( unresolvableCount
!= 0 ) {
921 if ( fOptions
.printArchPrefix() )
922 fprintf(stderr
, "Undefined symbols for architecture %s:\n", fArchitectureName
);
924 fprintf(stderr
, "Undefined symbols:\n");
925 for (int i
=0; i
< unresolvableCount
; ++i
) {
926 const char* name
= unresolvableUndefines
[i
];
927 fprintf(stderr
, " \"%s\", referenced from:\n", name
);
928 // scan all atoms for references
929 bool foundAtomReference
= false;
930 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
931 ObjectFile::Atom
* atom
= *it
;
932 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
933 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
934 ObjectFile::Reference
* reference
= *rit
;
935 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
936 if ( strcmp(reference
->getTargetName(), name
) == 0 ) {
937 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
938 foundAtomReference
= true;
941 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
942 if ( strcmp(reference
->getFromTargetName(), name
) == 0 ) {
943 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
944 foundAtomReference
= true;
949 // scan command line options
950 if ( !foundAtomReference
&& fOptions
.hasExportRestrictList() && fOptions
.shouldExport(name
) ) {
951 fprintf(stderr
, " -exported_symbols_list command line option\n");
952 ++unresolvableExportsCount
;
957 throw "symbol(s) not found";
963 std::vector
<class ObjectFile::Atom
*>* Linker::addJustInTimeAtoms(const char* name
)
965 // when creating final linked image, writer gets first chance
966 if ( fOptions
.outputKind() != Options::kObjectFile
) {
967 std::vector
<class ObjectFile::Atom
*>* atoms
= fOutputFile
->getJustInTimeAtomsFor(name
);
968 if ( atoms
!= NULL
) {
969 this->addAtoms(*atoms
);
970 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
971 return atoms
; // found a definition, no need to search anymore
975 // give readers a chance
976 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
977 ObjectFile::Reader
* reader
= *it
;
978 if ( reader
!= NULL
) {
979 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
980 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
981 //fprintf(stderr, "addJustInTimeAtoms(%s), looking in reader %s\n", name, reader->getPath() );
982 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
983 if ( atoms
!= NULL
) {
984 this->addAtoms(*atoms
);
985 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
986 if ( fOptions
.readerOptions().fTraceArchives
) {
989 // if this is a weak definition in a dylib
990 if ( (atoms
->size() == 1) && (reader
->getInstallPath() != NULL
) && (atoms
->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
991 // keep looking for a non-weak definition
994 // found a definition, no need to search anymore
1001 // for two level namesapce, give all implicitly link dylibs a chance
1002 if ( fOptions
.nameSpace() == Options::kTwoLevelNameSpace
) {
1003 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1004 if ( it
->second
->implicitlyLinked() ) {
1005 //fprintf(stderr, "addJustInTimeAtoms(%s), looking in implicitly linked %s\n", name, it->second->getPath() );
1006 std::vector
<class ObjectFile::Atom
*>* atoms
= it
->second
->getJustInTimeAtomsFor(name
);
1007 if ( atoms
!= NULL
) {
1008 this->addAtoms(*atoms
);
1009 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1010 // if this is a weak definition in a dylib
1011 if ( (atoms
->size() == 1) && (atoms
->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1012 // keep looking for a non-weak definition
1015 // found a definition, no need to search anymore
1023 // for flat namespace, give indirect dylibs
1024 if ( fOptions
.nameSpace() != Options::kTwoLevelNameSpace
) {
1025 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1026 if ( ! it
->second
->explicitlyLinked() ) {
1027 std::vector
<class ObjectFile::Atom
*>* atoms
= it
->second
->getJustInTimeAtomsFor(name
);
1028 if ( atoms
!= NULL
) {
1029 this->addAtoms(*atoms
);
1030 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1031 return atoms
; // found a definition, no need to search anymore
1037 // when creating .o file, writer goes last (this is so any static archives will be searched above)
1038 if ( (fOptions
.outputKind() == Options::kObjectFile
)
1039 || (fOptions
.undefinedTreatment() != Options::kUndefinedError
)
1040 || fOptions
.someAllowedUndefines() ) {
1041 ObjectFile::Atom
* atom
= fOutputFile
->getUndefinedProxyAtom(name
);
1042 if ( atom
!= NULL
) {
1043 this->addAtom(*atom
);
1047 //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
1051 void Linker::resolve(ObjectFile::Reference
* reference
)
1053 // look in global symbol table
1054 const char* targetName
= reference
->getTargetName();
1055 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1056 if ( target
== NULL
) {
1057 fprintf(stderr
, "Undefined symbol: %s\n", targetName
);
1059 reference
->setTarget(*target
, reference
->getTargetOffset());
1062 void Linker::resolveFrom(ObjectFile::Reference
* reference
)
1064 // handle references that have two (from and to) targets
1065 const char* fromTargetName
= reference
->getFromTargetName();
1066 ObjectFile::Atom
* fromTarget
= fGlobalSymbolTable
.find(fromTargetName
);
1067 if ( fromTarget
== NULL
) {
1068 fprintf(stderr
, "Undefined symbol: %s\n", fromTargetName
);
1070 reference
->setFromTarget(*fromTarget
);
1074 void Linker::resolveReferences()
1076 // note: the atom list may grow during this loop as libraries supply needed atoms
1077 for (unsigned int j
=0; j
< fAllAtoms
.size(); ++j
) {
1078 ObjectFile::Atom
* atom
= fAllAtoms
[j
];
1079 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
1080 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
1081 ObjectFile::Reference
* reference
= *it
;
1082 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
)
1083 this->resolve(reference
);
1084 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
)
1085 this->resolveFrom(reference
);
1091 // used to remove stabs associated with atoms that won't be in output file
1095 NotInSet(std::set
<ObjectFile::Atom
*>& theSet
) : fSet(theSet
) {}
1097 bool operator()(const ObjectFile::Reader::Stab
& stab
) const {
1098 if ( stab
.atom
== NULL
)
1099 return false; // leave stabs that are not associated with any atome
1101 return ( fSet
.count(stab
.atom
) == 0 );
1105 std::set
<ObjectFile::Atom
*>& fSet
;
1112 NotLive(std::set
<ObjectFile::Atom
*>& set
) : fLiveAtoms(set
) {}
1114 bool operator()(ObjectFile::Atom
*& atom
) const {
1115 //if ( fLiveAtoms.count(atom) == 0 )
1116 // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
1117 return ( fLiveAtoms
.count(atom
) == 0 );
1120 std::set
<ObjectFile::Atom
*>& fLiveAtoms
;
1124 void Linker::addJustInTimeAtomsAndMarkLive(const char* name
)
1126 std::vector
<class ObjectFile::Atom
*>* atoms
= this->addJustInTimeAtoms(name
);
1127 if ( atoms
!= NULL
) {
1128 if ( fOptions
.allGlobalsAreDeadStripRoots() ) {
1129 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
->begin(); it
!= atoms
->end(); it
++) {
1130 ObjectFile::Atom
* atom
= *it
;
1131 if ( atom
->getScope() == ObjectFile::Atom::scopeGlobal
) {
1132 WhyLiveBackChain rootChain
;
1133 rootChain
.previous
= NULL
;
1134 rootChain
.name
= atom
->getDisplayName();
1135 this->markLive(*atom
, &rootChain
);
1143 void Linker::markLive(ObjectFile::Atom
& atom
, struct Linker::WhyLiveBackChain
* previous
)
1145 if ( fLiveAtoms
.count(&atom
) == 0 ) {
1146 // if -whylive cares about this symbol, then dump chain
1147 if ( (previous
->name
!= NULL
) && fOptions
.printWhyLive(previous
->name
) ) {
1149 for(WhyLiveBackChain
* p
= previous
; p
!= NULL
; p
= p
->previous
, ++depth
) {
1150 for(int i
=depth
; i
> 0; --i
)
1151 fprintf(stderr
, " ");
1152 fprintf(stderr
, "%s\n", p
->name
);
1155 // set up next chain
1156 WhyLiveBackChain thisChain
;
1157 thisChain
.previous
= previous
;
1158 // this atom is live
1159 fLiveAtoms
.insert(&atom
);
1160 // update total size info (except for __ZEROPAGE atom)
1161 if ( atom
.getSegment().isContentReadable() ) {
1162 fTotalSize
+= atom
.getSize();
1163 if ( atom
.isZeroFill() )
1164 fTotalZeroFillSize
+= atom
.getSize();
1166 // and all atoms it references
1167 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
1168 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
1169 ObjectFile::Reference
* reference
= *it
;
1170 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1171 // look in global symbol table
1172 const char* targetName
= reference
->getTargetName();
1173 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1174 if ( target
== NULL
) {
1175 // load archives or dylibs
1176 this->addJustInTimeAtomsAndMarkLive(targetName
);
1179 target
= fGlobalSymbolTable
.find(targetName
);
1180 if ( target
!= NULL
) {
1181 reference
->setTarget(*target
, reference
->getTargetOffset());
1184 // mark as undefined, for later error processing
1185 fAtomsWithUnresolvedReferences
.push_back(&atom
);
1186 fGlobalSymbolTable
.require(targetName
);
1189 switch ( reference
->getTargetBinding() ) {
1190 case ObjectFile::Reference::kBoundDirectly
:
1191 case ObjectFile::Reference::kBoundByName
:
1192 thisChain
.name
= reference
->getTargetName();
1193 markLive(reference
->getTarget(), &thisChain
);
1195 case ObjectFile::Reference::kDontBind
:
1196 addDtraceProbe(atom
, reference
->getFixUpOffset(), reference
->getTargetName());
1198 case ObjectFile::Reference::kUnboundByName
:
1202 // do the same as above, for "from target"
1203 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1204 // look in global symbol table
1205 const char* targetName
= reference
->getFromTargetName();
1206 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1207 if ( target
== NULL
) {
1208 // load archives or dylibs
1209 this->addJustInTimeAtomsAndMarkLive(targetName
);
1212 target
= fGlobalSymbolTable
.find(targetName
);
1213 if ( target
!= NULL
) {
1214 reference
->setFromTarget(*target
);
1217 // mark as undefined, for later error processing
1218 fGlobalSymbolTable
.require(targetName
);
1221 switch ( reference
->getFromTargetBinding() ) {
1222 case ObjectFile::Reference::kBoundDirectly
:
1223 case ObjectFile::Reference::kBoundByName
:
1224 thisChain
.name
= reference
->getFromTargetName();
1225 markLive(reference
->getFromTarget(), &thisChain
);
1227 case ObjectFile::Reference::kUnboundByName
:
1228 case ObjectFile::Reference::kDontBind
:
1237 void Linker::addLiveRoot(const char* name
)
1239 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(name
);
1240 if ( target
== NULL
) {
1241 this->addJustInTimeAtomsAndMarkLive(name
);
1242 target
= fGlobalSymbolTable
.find(name
);
1244 if ( target
!= NULL
)
1245 fLiveRootAtoms
.insert(target
);
1249 void Linker::deadStripResolve()
1251 // add main() to live roots
1252 ObjectFile::Atom
* entryPoint
= this->entryPoint();
1253 if ( entryPoint
!= NULL
)
1254 fLiveRootAtoms
.insert(entryPoint
);
1256 // add dyld_stub_binding_helper() to live roots
1257 ObjectFile::Atom
* dyldHelper
= this->dyldHelper();
1258 if ( dyldHelper
!= NULL
)
1259 fLiveRootAtoms
.insert(dyldHelper
);
1261 // add -exported_symbols_list, -init, and -u entries to live roots
1262 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
1263 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++)
1266 // in some cases, every global scope atom in initial .o files is a root
1267 if ( fOptions
.allGlobalsAreDeadStripRoots() ) {
1268 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1269 ObjectFile::Atom
* atom
= *it
;
1270 if ( (atom
->getScope() == ObjectFile::Atom::scopeGlobal
) && (fDeadAtoms
.count(atom
) == 0) )
1271 fLiveRootAtoms
.insert(atom
);
1275 // mark all roots as live, and all atoms they reference
1276 for (std::set
<ObjectFile::Atom
*>::iterator it
=fLiveRootAtoms
.begin(); it
!= fLiveRootAtoms
.end(); it
++) {
1277 WhyLiveBackChain rootChain
;
1278 rootChain
.previous
= NULL
;
1279 rootChain
.name
= (*it
)->getDisplayName();
1280 markLive(**it
, &rootChain
);
1283 // it is possible that there are unresolved references that can be resolved now
1284 // this can happen if the first reference to a common symbol in an archive.
1285 // common symbols are not in the archive TOC, but the .o could have been pulled in later.
1286 // <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
1287 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAtomsWithUnresolvedReferences
.begin(); it
!= fAtomsWithUnresolvedReferences
.end(); it
++) {
1288 std::vector
<class ObjectFile::Reference
*>& references
= (*it
)->getReferences();
1289 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1290 ObjectFile::Reference
* reference
= *rit
;
1291 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1292 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(reference
->getTargetName());
1293 if ( target
!= NULL
) {
1294 reference
->setTarget(*target
, reference
->getTargetOffset());
1295 fLiveAtoms
.insert(target
);
1296 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1297 // references, which is true for commons.
1298 if ( target
->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition
)
1299 fprintf(stderr
, "warning: ld64 internal error %s is not a tentative definition\n", target
->getDisplayName());
1302 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1303 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(reference
->getFromTargetName());
1304 if ( target
!= NULL
) {
1305 reference
->setFromTarget(*target
);
1306 fLiveAtoms
.insert(target
);
1307 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1308 // references, which is true for commons.
1309 if ( target
->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition
)
1310 fprintf(stderr
, "warning: ld64 internal error %s is not a tentative definition\n", target
->getDisplayName());
1316 // now remove all non-live atoms from fAllAtoms
1317 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), NotLive(fLiveAtoms
)), fAllAtoms
.end());
1320 void Linker::checkObjC()
1323 switch ( fCurrentObjCConstraint
) {
1324 case ObjectFile::Reader::kObjcNone
:
1325 // can link against any dylib
1327 case ObjectFile::Reader::kObjcRetainRelease
:
1328 // cannot link against GC-only dylibs
1329 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1330 if ( it
->second
->explicitlyLinked() ) {
1331 if ( it
->second
->getObjCConstraint() == ObjectFile::Reader::kObjcGC
)
1332 throwf("this linkage unit uses Retain/Release. It cannot link against the GC-only dylib: %s", it
->second
->getPath());
1336 case ObjectFile::Reader::kObjcRetainReleaseOrGC
:
1337 // can link against GC or RR dylibs
1339 case ObjectFile::Reader::kObjcGC
:
1340 // cannot link against RR-only dylibs
1341 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1342 if ( it
->second
->explicitlyLinked() ) {
1343 if ( it
->second
->getObjCConstraint() == ObjectFile::Reader::kObjcRetainRelease
)
1344 throwf("this linkage unit requires GC. It cannot link against Retain/Release dylib: %s", it
->second
->getPath());
1350 // synthesize __OBJC __image_info atom if needed
1351 if ( fCurrentObjCConstraint
!= ObjectFile::Reader::kObjcNone
) {
1352 this->addAtom(fOutputFile
->makeObjcInfoAtom(fCurrentObjCConstraint
, fObjcReplacmentClasses
));
1356 void Linker::addDtraceProbe(ObjectFile::Atom
& atom
, uint32_t offsetInAtom
, const char* probeName
)
1358 if ( probeName
!= NULL
) {
1359 if ( strncmp(probeName
, "___dtrace_probe$", 16) == 0 )
1360 fDtraceProbeSites
.push_back(DTraceProbeInfo(&atom
, offsetInAtom
, probeName
));
1361 else if ( strncmp(probeName
, "___dtrace_isenabled$", 20) == 0 )
1362 fDtraceIsEnabledSites
.push_back(DTraceProbeInfo(&atom
, offsetInAtom
, probeName
));
1363 else if ( strncmp(probeName
, "___dtrace_", 10) == 0 )
1364 fDtraceAtomToTypes
[&atom
].insert(probeName
);
1365 else if ( fOptions
.dTrace() && (strncmp(probeName
, "__dtrace_probe$", 15) == 0) )
1366 fDtraceProbes
.push_back(DTraceProbeInfo(&atom
, offsetInAtom
, probeName
));
1370 static uint8_t pointerKind(cpu_type_t arch
)
1373 case CPU_TYPE_POWERPC
:
1374 return ppc::kPointer
;
1375 case CPU_TYPE_POWERPC64
:
1376 return ppc64::kPointer
;
1378 return x86::kPointer
;
1379 case CPU_TYPE_X86_64
:
1380 return x86_64::kPointer
;
1382 throw "uknown architecture";
1385 static uint8_t pcRelKind(cpu_type_t arch
)
1388 case CPU_TYPE_POWERPC
:
1389 return ppc::kPointerDiff32
;
1390 case CPU_TYPE_POWERPC64
:
1391 return ppc64::kPointerDiff32
;
1393 return x86::kPointerDiff
;
1394 case CPU_TYPE_X86_64
:
1395 return x86_64::kPointerDiff32
;
1397 throw "uknown architecture";
1400 typedef uint8_t* (*oldcreatedof_func_t
) (const char*, cpu_type_t
, unsigned int, const char*[], const char*[], uint64_t offsetsInDOF
[], size_t* size
);
1401 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
);
1404 void Linker::processDTrace()
1406 // handle dtrace 2.0 static probes
1407 if ( (fOptions
.outputKind() != Options::kObjectFile
) && ((fDtraceProbeSites
.size() != 0) || (fDtraceIsEnabledSites
.size() != 0)) ) {
1408 // partition probes by provider name
1409 // The symbol names looks like:
1410 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
1411 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
1412 ProviderToProbes providerToProbes
;
1413 std::vector
<DTraceProbeInfo
> emptyList
;
1414 for(std::vector
<DTraceProbeInfo
>::iterator it
= fDtraceProbeSites
.begin(); it
!= fDtraceProbeSites
.end(); ++it
) {
1415 const char* providerStart
= &it
->probeName
[16];
1416 const char* providerEnd
= strchr(providerStart
, '$');
1417 if ( providerEnd
!= NULL
) {
1418 char providerName
[providerEnd
-providerStart
+1];
1419 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
1420 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
1421 if ( pos
== providerToProbes
.end() ) {
1422 const char* dup
= strdup(providerName
);
1423 providerToProbes
[dup
] = emptyList
;
1425 providerToProbes
[providerName
].push_back(*it
);
1428 for(std::vector
<DTraceProbeInfo
>::iterator it
= fDtraceIsEnabledSites
.begin(); it
!= fDtraceIsEnabledSites
.end(); ++it
) {
1429 const char* providerStart
= &it
->probeName
[20];
1430 const char* providerEnd
= strchr(providerStart
, '$');
1431 if ( providerEnd
!= NULL
) {
1432 char providerName
[providerEnd
-providerStart
+1];
1433 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
1434 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
1435 if ( pos
== providerToProbes
.end() ) {
1436 const char* dup
= strdup(providerName
);
1437 providerToProbes
[dup
] = emptyList
;
1439 providerToProbes
[providerName
].push_back(*it
);
1443 // create a DOF section for each provider
1445 CStringSet sectionNamesUsed
;
1446 for(ProviderToProbes::iterator pit
= providerToProbes
.begin(); pit
!= providerToProbes
.end(); ++pit
, ++dofIndex
) {
1447 const char* providerName
= pit
->first
;
1448 const std::vector
<DTraceProbeInfo
>& probes
= pit
->second
;
1450 // open library and find dtrace_create_dof()
1451 void* handle
= dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY
);
1452 if ( handle
== NULL
)
1453 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s\n", dlerror());
1454 createdof_func_t pCreateDOF
= (createdof_func_t
)dlsym(handle
, "dtrace_ld_create_dof");
1455 if ( pCreateDOF
== NULL
)
1456 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s\n", dlerror());
1457 // build list of typedefs/stability infos for this provider
1459 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
1460 std::map
<const ObjectFile::Atom
*,CStringSet
>::iterator pos
= fDtraceAtomToTypes
.find(it
->atom
);
1461 if ( pos
!= fDtraceAtomToTypes
.end() ) {
1462 for(CStringSet::iterator sit
= pos
->second
.begin(); sit
!= pos
->second
.end(); ++sit
) {
1463 const char* providerStart
= strchr(*sit
, '$')+1;
1464 const char* providerEnd
= strchr(providerStart
, '$');
1465 if ( providerEnd
!= NULL
) {
1466 char aProviderName
[providerEnd
-providerStart
+1];
1467 strlcpy(aProviderName
, providerStart
, providerEnd
-providerStart
+1);
1468 if ( strcmp(aProviderName
, providerName
) == 0 )
1474 int typeCount
= types
.size();
1475 const char* typeNames
[typeCount
];
1476 //fprintf(stderr, "types for %s:\n", providerName);
1478 for(CStringSet::iterator it
= types
.begin(); it
!= types
.end(); ++it
) {
1479 typeNames
[index
] = *it
;
1480 //fprintf(stderr, "\t%s\n", *it);
1484 // build list of probe/isenabled sites
1485 const uint32_t probeCount
= probes
.size();
1486 const char* probeNames
[probeCount
];
1487 const char* funtionNames
[probeCount
];
1488 uint64_t offsetsInDOF
[probeCount
];
1490 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
1491 probeNames
[index
] = it
->probeName
;
1492 funtionNames
[index
] = it
->atom
->getName();
1493 offsetsInDOF
[index
] = 0;
1496 // call dtrace library to create DOF section
1497 size_t dofSectionSize
;
1498 uint8_t* p
= (*pCreateDOF
)(fArchitecture
, typeCount
, typeNames
, probeCount
, probeNames
, funtionNames
, offsetsInDOF
, &dofSectionSize
);
1500 char sectionName
[18];
1501 strcpy(sectionName
, "__dof_");
1502 strlcpy(§ionName
[6], providerName
, 10);
1503 // create unique section name so each DOF is in its own section
1504 if ( sectionNamesUsed
.count(sectionName
) != 0 ) {
1505 sectionName
[15] = '0';
1506 sectionName
[16] = '\0';
1507 while ( sectionNamesUsed
.count(sectionName
) != 0 )
1510 sectionNamesUsed
.insert(sectionName
);
1511 char symbolName
[strlen(providerName
)+64];
1512 sprintf(symbolName
, "__dtrace_dof_for_provider_%s", providerName
);
1513 opaque_section::Reader
* reader
= new opaque_section::Reader("__TEXT", sectionName
,
1514 "dtrace", p
, dofSectionSize
, fNextInputOrdinal
, symbolName
);
1515 fNextInputOrdinal
+= dofSectionSize
;
1517 for (uint32_t i
=0; i
< probeCount
; ++i
) {
1518 uint64_t offset
= offsetsInDOF
[i
];
1519 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
1520 if ( offset
> dofSectionSize
)
1521 throwf("offsetsInDOF[i]=%0llX > dofSectionSize=%0lX\n", i
, offset
, dofSectionSize
);
1522 reader
->addSectionReference(pcRelKind(fArchitecture
), offset
, probes
[i
].atom
, probes
[i
].offset
, reader
->getAtoms()[0], 0);
1524 this->addAtoms(reader
->getAtoms());
1527 throw "error creating dtrace DOF section";
1531 // create a __DATA __dof section iff -dtrace option was used and static probes were found in .o files
1532 else if ( fOptions
.dTrace() && (fDtraceProbes
.size() != 0) ) {
1533 const uint32_t probeCount
= fDtraceProbes
.size();
1534 const char* labels
[probeCount
];
1535 const char* funtionNames
[probeCount
];
1536 uint64_t offsetsInDOF
[probeCount
];
1538 // open libray and find dtrace_ld64_create_dof()
1539 void* handle
= dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY
);
1540 if ( handle
== NULL
)
1541 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s\n", dlerror());
1542 oldcreatedof_func_t pCreateDOF
= (oldcreatedof_func_t
)dlsym(handle
, "dtrace_ld64_create_dof");
1543 if ( pCreateDOF
== NULL
)
1544 throwf("couldn't find \"dtrace_ld64_create_dof\" in /usr/lib/libdtrace.dylib: %s\n", dlerror());
1546 // build argument list
1548 for(std::vector
<DTraceProbeInfo
>::iterator it
= fDtraceProbes
.begin(); it
!= fDtraceProbes
.end(); ++it
) {
1549 labels
[index
] = it
->probeName
;
1550 funtionNames
[index
] = it
->atom
->getName();
1551 offsetsInDOF
[index
] = 0;
1554 size_t dofSectionSize
;
1555 // call dtrace library to create DOF section
1556 uint8_t* p
= (*pCreateDOF
)(fOptions
.dTraceScriptName(), fArchitecture
, probeCount
, labels
, funtionNames
, offsetsInDOF
, &dofSectionSize
);
1558 opaque_section::Reader
* reader
= new opaque_section::Reader("__DATA", "__dof", "dtrace", p
, dofSectionSize
, fNextInputOrdinal
);
1559 fNextInputOrdinal
+= dofSectionSize
;
1561 for (uint32_t i
=0; i
< probeCount
; ++i
) {
1562 uint64_t offset
= offsetsInDOF
[i
];
1563 if ( offset
> dofSectionSize
)
1564 throwf("offsetsInDOF[i]=%0llX > dofSectionSize=%0lX\n", i
, offset
, dofSectionSize
);
1565 reader
->addSectionReference(pointerKind(fArchitecture
), offset
, fDtraceProbes
[i
].atom
, fDtraceProbes
[i
].offset
);
1567 this->addAtoms(reader
->getAtoms());
1570 throw "error created dtrace DOF section";
1576 static bool matchesObjectFile(ObjectFile::Atom
* atom
, const char* objectFileLeafName
)
1578 if ( objectFileLeafName
== NULL
)
1580 const char* atomFullPath
= atom
->getFile()->getPath();
1581 const char* lastSlash
= strrchr(atomFullPath
, '/');
1582 if ( lastSlash
!= NULL
) {
1583 if ( strcmp(&lastSlash
[1], objectFileLeafName
) == 0 )
1587 if ( strcmp(atomFullPath
, objectFileLeafName
) == 0 )
1594 static bool usesAnonymousNamespace(const char* symbol
)
1596 return ( (strncmp(symbol
, "__Z", 3) == 0) && (strstr(symbol
, "_GLOBAL__N_") != NULL
) );
1602 // __ZN20_GLOBAL__N__Z5main2v3barEv => _ZN-3barEv
1603 // __ZN37_GLOBAL__N_main.cxx_00000000_493A01A33barEv => _ZN-3barEv
1605 static void canonicalizeAnonymousName(const char* inSymbol
, char outSymbol
[])
1607 const char* globPtr
= strstr(inSymbol
, "_GLOBAL__N_");
1608 while ( isdigit(*(--globPtr
)) )
1611 unsigned long length
= strtoul(globPtr
+1, &endptr
, 10);
1612 const char* globEndPtr
= endptr
+ length
;
1613 int startLen
= globPtr
-inSymbol
+1;
1614 memcpy(outSymbol
, inSymbol
, startLen
);
1615 outSymbol
[startLen
] = '-';
1616 strcpy(&outSymbol
[startLen
+1], globEndPtr
);
1620 ObjectFile::Atom
* Linker::findAtom(const Options::OrderedSymbol
& orderedSymbol
)
1622 ObjectFile::Atom
* atom
= fGlobalSymbolTable
.find(orderedSymbol
.symbolName
);
1623 if ( atom
!= NULL
) {
1624 if ( matchesObjectFile(atom
, orderedSymbol
.objectFileName
) )
1628 // slow case. The requested symbol is not in symbol table, so might be static function
1629 static SymbolTable::Mapper hashTableOfTranslationUnitScopedSymbols
;
1630 static SymbolTable::Mapper hashTableOfSymbolsWithAnonymousNamespace
;
1631 static bool built
= false;
1632 // build a hash_map the first time
1634 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1636 const char* name
= atom
->getName();
1637 if ( name
!= NULL
) {
1638 if ( usesAnonymousNamespace(name
) ) {
1639 // symbol that uses anonymous namespace
1640 char canonicalName
[strlen(name
)+2];
1641 canonicalizeAnonymousName(name
, canonicalName
);
1642 const char* hashName
= strdup(canonicalName
);
1643 SymbolTable::Mapper::iterator pos
= hashTableOfSymbolsWithAnonymousNamespace
.find(hashName
);
1644 if ( pos
== hashTableOfSymbolsWithAnonymousNamespace
.end() )
1645 hashTableOfSymbolsWithAnonymousNamespace
[hashName
] = atom
;
1647 hashTableOfSymbolsWithAnonymousNamespace
[hashName
] = NULL
; // collision, denote with NULL
1649 else if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
1650 // static function or data
1651 SymbolTable::Mapper::iterator pos
= hashTableOfTranslationUnitScopedSymbols
.find(name
);
1652 if ( pos
== hashTableOfTranslationUnitScopedSymbols
.end() )
1653 hashTableOfTranslationUnitScopedSymbols
[name
] = atom
;
1655 hashTableOfTranslationUnitScopedSymbols
[name
] = NULL
; // collision, denote with NULL
1659 //fprintf(stderr, "built hash table of %lu static functions\n", hashTableOfTranslationUnitScopedSymbols.size());
1663 // look for name in hashTableOfTranslationUnitScopedSymbols
1664 SymbolTable::Mapper::iterator pos
= hashTableOfTranslationUnitScopedSymbols
.find(orderedSymbol
.symbolName
);
1665 if ( pos
!= hashTableOfTranslationUnitScopedSymbols
.end() ) {
1666 if ( (pos
->second
!= NULL
) && matchesObjectFile(pos
->second
, orderedSymbol
.objectFileName
) ) {
1667 //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName);
1670 if ( pos
->second
== NULL
)
1671 // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
1672 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1674 if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
1675 const char* name
= atom
->getName();
1676 if ( (name
!= NULL
) && (strcmp(name
, orderedSymbol
.symbolName
) == 0) ) {
1677 if ( matchesObjectFile(atom
, orderedSymbol
.objectFileName
) ) {
1678 if ( fOptions
.printOrderFileStatistics() )
1679 fprintf(stderr
, "ld: warning %s specified in order_file but it exists in multiple .o files. "
1680 "Prefix symbol with .o filename in order_file to disambiguate\n", orderedSymbol
.symbolName
);
1688 // look for name in hashTableOfSymbolsWithAnonymousNamespace
1689 if ( usesAnonymousNamespace(orderedSymbol
.symbolName
) ) {
1690 // symbol that uses anonymous namespace
1691 char canonicalName
[strlen(orderedSymbol
.symbolName
)+2];
1692 canonicalizeAnonymousName(orderedSymbol
.symbolName
, canonicalName
);
1693 SymbolTable::Mapper::iterator pos
= hashTableOfSymbolsWithAnonymousNamespace
.find(canonicalName
);
1694 if ( pos
!= hashTableOfSymbolsWithAnonymousNamespace
.end() ) {
1695 if ( (pos
->second
!= NULL
) && matchesObjectFile(pos
->second
, orderedSymbol
.objectFileName
) ) {
1696 //fprintf(stderr, "found %s in anonymous namespace hash table\n", canonicalName);
1699 if ( pos
->second
== NULL
)
1700 // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
1701 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1703 const char* name
= atom
->getName();
1704 if ( (name
!= NULL
) && usesAnonymousNamespace(name
) ) {
1705 char canonicalAtomName
[strlen(name
)+2];
1706 canonicalizeAnonymousName(name
, canonicalAtomName
);
1707 if ( strcmp(canonicalAtomName
, canonicalName
) == 0 ) {
1708 if ( matchesObjectFile(atom
, orderedSymbol
.objectFileName
) ) {
1709 if ( fOptions
.printOrderFileStatistics() )
1710 fprintf(stderr
, "ld: warning %s specified in order_file but it exists in multiple .o files. "
1711 "Prefix symbol with .o filename in order_file to disambiguate\n", orderedSymbol
.symbolName
);
1724 void Linker::sortSections()
1726 Section::assignIndexes();
1731 // Linker::sortAtoms()
1733 // The purpose of this method is to take the graph of all Atoms and produce an ordered
1734 // sequence of atoms. The constraints are that: 1) all Atoms of the same Segment must
1735 // be contiguous, 2) all Atoms of the same Section must be contigous, 3) Atoms specified
1736 // in an order_file are seqenced as in the order_file and before Atoms not specified,
1737 // 4) Atoms in the same section from the same .o file should be contiguous and sequenced
1738 // in the same order they were in the .o file, 5) Atoms in the same Section but which came
1739 // from different .o files should be sequenced in the same order that the .o files
1740 // were passed to the linker (i.e. command line order).
1742 // The way this is implemented is that the linker passes a "base ordinal" to each Reader
1743 // as it is constructed. The reader should construct it Atoms so that calling getOrdinal()
1744 // on its atoms returns a contiguous range of values starting at the base ordinal. Then
1745 // sorting is just sorting by section, then by ordinal.
1747 // If an order_file is specified, it gets more complicated. First, an override-ordinal map
1748 // is created. It causes the sort routine to ignore the value returned by getOrdinal() and
1749 // use the override value instead. Next some Atoms must be layed out consecutively
1750 // (e.g. hand written assembly that does not end with return, but rather falls into
1751 // the next label). This is modeled in Readers via a "kFollowOn" reference. The use of
1752 // kFollowOn refernces produces "clusters" of atoms that must stay together.
1753 // If an order_file tries to move one atom, it may need to move a whole cluster. The
1754 // algorithm to do this models clusters using two maps. The "starts" maps maps any
1755 // atom in a cluster to the first Atom in the cluster. The "nexts" maps an Atom in a
1756 // cluster to the next Atom in the cluster. With this in place, while processing an
1757 // order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is
1758 // given ordinal overrides.
1760 void Linker::sortAtoms()
1762 fStartSortTime
= mach_absolute_time();
1763 // if -order_file is used, build map of atom ordinal overrides
1764 std::map
<const ObjectFile::Atom
*, uint32_t>* ordinalOverrideMap
= NULL
;
1765 std::map
<const ObjectFile::Atom
*, uint32_t> theOrdinalOverrideMap
;
1766 const bool log
= false;
1767 if ( fOptions
.orderedSymbols().size() != 0 ) {
1768 // first make a pass to find all follow-on references and build start/next maps
1769 // which are a way to represent clusters of atoms that must layout together
1770 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*> followOnStarts
;
1771 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*> followOnNexts
;
1772 for (std::vector
<ObjectFile::Atom
*>::iterator ait
=fAllAtoms
.begin(); ait
!= fAllAtoms
.end(); ait
++) {
1773 ObjectFile::Atom
* atom
= *ait
;
1774 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
1775 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1776 ObjectFile::Reference
* ref
= *rit
;
1777 if ( ref
->getKind() == 1 ) { // FIX FIX
1778 ObjectFile::Atom
* targetAtom
= &ref
->getTarget();
1779 if ( log
) fprintf(stderr
, "ref %s -> %s", atom
->getDisplayName(), targetAtom
->getDisplayName());
1780 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator startFrom
= followOnStarts
.find(atom
);
1781 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator startTo
= followOnStarts
.find(targetAtom
);
1782 if ( (startFrom
== followOnStarts
.end()) && (startTo
== followOnStarts
.end()) ) {
1783 // this is first time we've seen either atom, make simple cluster of the two
1784 if ( log
) fprintf(stderr
, " new cluster\n");
1785 followOnStarts
[atom
] = atom
;
1786 followOnStarts
[targetAtom
] = atom
;
1787 followOnNexts
[atom
] = targetAtom
;
1788 followOnNexts
[targetAtom
] = NULL
;
1790 else if ( (startFrom
!= followOnStarts
.end()) && (startTo
== followOnStarts
.end()) && (followOnNexts
[atom
] == NULL
) ) {
1791 // atom is at end of an existing cluster, so append target to end of cluster
1792 if ( log
) fprintf(stderr
, " end of cluster starting with %s\n", followOnStarts
[atom
]->getDisplayName());
1793 followOnNexts
[atom
] = targetAtom
;
1794 followOnNexts
[targetAtom
] = NULL
;
1795 followOnStarts
[targetAtom
] = followOnStarts
[atom
];
1798 // gerneral case of inserting into an existing cluster
1799 if ( followOnNexts
[atom
] != NULL
) {
1800 // an atom with two follow-ons is illegal
1801 fprintf(stderr
, "ld: warning can't order %s because both %s and %s must follow it\n",
1802 atom
->getDisplayName(), targetAtom
->getDisplayName(), followOnNexts
[atom
]->getDisplayName());
1805 // there already exists an atom that says target must be its follow-on
1806 const ObjectFile::Atom
* originalStart
= startTo
->second
;
1807 const ObjectFile::Atom
* originalPrevious
= originalStart
;
1808 while ( followOnNexts
[originalPrevious
] != targetAtom
)
1809 originalPrevious
= followOnNexts
[originalPrevious
];
1810 bool otherIsAlias
= (originalPrevious
->getSize() == 0);
1811 bool thisIsAlias
= (atom
->getSize() == 0);
1812 if ( !otherIsAlias
&& !thisIsAlias
) {
1813 fprintf(stderr
, "ld: warning can't order %s because both %s and %s must preceed it\n",
1814 targetAtom
->getDisplayName(), originalPrevious
->getDisplayName(), atom
->getDisplayName());
1816 else if ( otherIsAlias
) {
1817 if ( originalPrevious
== originalStart
) {
1818 // other is alias at start of cluster, make this the new start of cluster
1819 if ( log
) fprintf(stderr
, " becomes new start of cluster previous starting with %s\n", originalStart
->getDisplayName());
1820 followOnNexts
[atom
] = originalPrevious
;
1821 for(const ObjectFile::Atom
* nextAtom
= atom
; nextAtom
!= NULL
; nextAtom
= followOnNexts
[nextAtom
])
1822 followOnStarts
[nextAtom
] = atom
;
1825 // other is alias in middle of cluster, insert new atom before it
1826 if ( log
) fprintf(stderr
, " insert into cluster starting with %s before alias %s\n", originalStart
->getDisplayName(), originalPrevious
->getDisplayName());
1827 followOnStarts
[atom
] = originalStart
;
1828 followOnNexts
[atom
] = originalPrevious
;
1829 for(const ObjectFile::Atom
* a
= originalStart
; a
!= NULL
; a
= followOnNexts
[a
]) {
1830 if ( followOnNexts
[a
] == originalPrevious
) {
1831 followOnNexts
[a
] = atom
;
1838 // this is alias, so it can go inbetween originalPrevious and targetAtom
1839 if ( log
) fprintf(stderr
, " insert into cluster starting with %s after %s\n", originalStart
->getDisplayName(), originalPrevious
->getDisplayName());
1840 followOnStarts
[atom
] = originalStart
;
1841 followOnNexts
[atom
] = followOnNexts
[originalPrevious
];
1842 followOnNexts
[originalPrevious
] = atom
;
1851 for(std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator it
= followOnStarts
.begin(); it
!= followOnStarts
.end(); ++it
)
1852 fprintf(stderr
, "start %s -> %s\n", it
->first
->getDisplayName(), it
->second
->getDisplayName());
1854 for(std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator it
= followOnNexts
.begin(); it
!= followOnNexts
.end(); ++it
)
1855 fprintf(stderr
, "next %s -> %s\n", it
->first
->getDisplayName(), (it
->second
!= NULL
) ? it
->second
->getDisplayName() : "null");
1858 // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals
1859 ordinalOverrideMap
= &theOrdinalOverrideMap
;
1861 uint32_t matchCount
= 0;
1862 std::vector
<Options::OrderedSymbol
>& orderedSymbols
= fOptions
.orderedSymbols();
1863 for(std::vector
<Options::OrderedSymbol
>::iterator it
= orderedSymbols
.begin(); it
!= orderedSymbols
.end(); ++it
) {
1864 ObjectFile::Atom
* atom
= this->findAtom(*it
);
1865 if ( atom
!= NULL
) {
1866 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator start
= followOnStarts
.find(atom
);
1867 if ( start
!= followOnStarts
.end() ) {
1868 // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together
1869 for(const ObjectFile::Atom
* nextAtom
= start
->second
; nextAtom
!= NULL
; nextAtom
= followOnNexts
[nextAtom
]) {
1870 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator pos
= theOrdinalOverrideMap
.find(nextAtom
);
1871 if ( pos
== theOrdinalOverrideMap
.end() ) {
1872 theOrdinalOverrideMap
[nextAtom
] = index
++;
1873 if (log
) fprintf(stderr
, "override ordinal %u assigned to %s in cluster from %s\n", index
, nextAtom
->getDisplayName(), nextAtom
->getFile()->getPath());
1876 if (log
) fprintf(stderr
, "could not order %s as %u because it was already laid out earlier by %s as %u\n",
1877 atom
->getDisplayName(), index
, followOnStarts
[atom
]->getDisplayName(), theOrdinalOverrideMap
[atom
] );
1882 theOrdinalOverrideMap
[atom
] = index
;
1883 if (log
) fprintf(stderr
, "override ordinal %u assigned to %s from %s\n", index
, atom
->getDisplayName(), atom
->getFile()->getPath());
1888 //fprintf(stderr, "can't find match for order_file entry %s/%s\n", it->objectFileName, it->symbolName);
1892 if ( fOptions
.printOrderFileStatistics() && (fOptions
.orderedSymbols().size() != matchCount
) ) {
1893 fprintf(stderr
, "ld: warning only %u out of %lu order_file symbols were applicable\n", matchCount
, fOptions
.orderedSymbols().size() );
1898 std::sort(fAllAtoms
.begin(), fAllAtoms
.end(), Linker::AtomSorter(ordinalOverrideMap
));
1900 //fprintf(stderr, "Sorted atoms:\n");
1901 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1902 // fprintf(stderr, "\t%p, %u %s\n", (*it)->getSection(), (*it)->getSection()->getIndex(), (*it)->getDisplayName());
1907 // make sure given addresses are within reach of branches, etc
1908 void Linker::tweakLayout()
1910 // > 2GB images need their large zero fill atoms sorted to the end to keep access with +/- 2GB
1911 if ( fTotalSize
> 0x7F000000 ) {
1912 fBiggerThanTwoGigOutput
= true;
1914 if ( (fTotalSize
-fTotalZeroFillSize
) > 0x7F000000 )
1915 throwf("total output size exceeds 2GB (%lldMB)", (fTotalSize
-fTotalZeroFillSize
)/(1024*1024));
1917 // move very large (>1MB) zero fill atoms to a new section at very end
1918 Section
* hugeZeroFills
= Section::find("__huge", "__DATA", true);
1919 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1920 ObjectFile::Atom
* atom
= *it
;
1921 if ( atom
->isZeroFill() && (atom
->getSize() > 1024*1024) && atom
->getSegment().isContentReadable() )
1922 atom
->setSection(hugeZeroFills
);
1928 void Linker::writeDotOutput()
1930 const char* dotOutFilePath
= fOptions
.dotOutputFile();
1931 if ( dotOutFilePath
!= NULL
) {
1932 FILE* out
= fopen(dotOutFilePath
, "w");
1933 if ( out
!= NULL
) {
1935 fprintf(out
, "digraph dg\n{\n");
1936 fprintf(out
, "\tconcentrate = true;\n");
1937 fprintf(out
, "\trankdir = LR;\n");
1939 // print each atom as a node
1940 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1941 ObjectFile::Atom
* atom
= *it
;
1942 if ( atom
->getFile() != fOutputFile
) {
1943 const char* name
= atom
->getDisplayName();
1944 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
1945 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1946 fprintf(out
, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom
, name
);
1948 else if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
1949 char cstring
[atom
->getSize()+2];
1950 atom
->copyRawContent((uint8_t*)cstring
);
1951 fprintf(out
, "\taddr%p [ label = \"string: '", atom
);
1952 for (const char* s
=cstring
; *s
!= '\0'; ++s
) {
1954 fprintf(out
, "\\\\n");
1958 fprintf(out
, "'\" ];\n");
1961 fprintf(out
, "\taddr%p [ label = \"%s\" ];\n", atom
, name
);
1967 // print each reference as an edge
1968 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1969 ObjectFile::Atom
* fromAtom
= *it
;
1970 if ( fromAtom
->getFile() != fOutputFile
) {
1971 std::vector
<ObjectFile::Reference
*>& references
= fromAtom
->getReferences();
1972 std::set
<ObjectFile::Atom
*> seenTargets
;
1973 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1974 ObjectFile::Reference
* reference
= *rit
;
1975 ObjectFile::Atom
* toAtom
= &(reference
->getTarget());
1976 if ( seenTargets
.count(toAtom
) == 0 ) {
1977 seenTargets
.insert(toAtom
);
1978 fprintf(out
, "\taddr%p -> addr%p;\n", fromAtom
, toAtom
);
1985 // push all imports to bottom of graph
1986 fprintf(out
, "{ rank = same; ");
1987 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1988 ObjectFile::Atom
* atom
= *it
;
1989 if ( atom
->getFile() != fOutputFile
)
1990 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
1991 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1992 fprintf(out
, "addr%p; ", atom
);
1995 fprintf(out
, "};\n ");
1998 fprintf(out
, "}\n");
2002 fprintf(stderr
, "ld: warning could not write dot output file: %s\n", dotOutFilePath
);
2007 ObjectFile::Atom
* Linker::entryPoint()
2009 // if main executable, find entry point atom
2010 ObjectFile::Atom
* entryPoint
= NULL
;
2011 switch ( fOptions
.outputKind() ) {
2012 case Options::kDynamicExecutable
:
2013 case Options::kStaticExecutable
:
2014 case Options::kDyld
:
2015 entryPoint
= fGlobalSymbolTable
.find(fOptions
.entryName());
2016 if ( entryPoint
== NULL
) {
2017 throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions
.entryName());
2020 case Options::kDynamicLibrary
:
2021 if ( fOptions
.initFunctionName() != NULL
) {
2022 entryPoint
= fGlobalSymbolTable
.find(fOptions
.initFunctionName());
2023 if ( entryPoint
== NULL
) {
2024 throwf("could not find -init function: \"%s\"", fOptions
.initFunctionName());
2028 case Options::kObjectFile
:
2029 case Options::kDynamicBundle
:
2036 ObjectFile::Atom
* Linker::dyldHelper()
2038 return fGlobalSymbolTable
.find("dyld_stub_binding_helper");
2041 const char* Linker::assureFullPath(const char* path
)
2043 if ( path
[0] == '/' )
2045 char cwdbuff
[MAXPATHLEN
];
2046 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
2048 asprintf(&result
, "%s/%s", cwdbuff
, path
);
2049 if ( result
!= NULL
)
2057 // The stab strings are of the form:
2058 // <name> ':' <type-code> <number-pari>
2059 // but the <name> contain a colon.
2060 // For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
2061 // For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
2063 const char* Linker::truncateStabString(const char* str
)
2065 enum { start
, inObjc
} state
= start
;
2066 for (const char* s
= str
; *s
!= 0; ++s
) {
2075 if ( s
[1] == ':' ) {
2080 // Duplicate strndup behavior here.
2081 int trunStrLen
= s
-str
+2;
2082 char* temp
= new char[trunStrLen
+1];
2083 memcpy(temp
, str
, trunStrLen
);
2084 temp
[trunStrLen
] = '\0';
2102 bool Linker::minimizeStab(ObjectFile::Reader::Stab
& stab
)
2109 // these all need truncated strings
2110 stab
.string
= truncateStabString(stab
.string
);
2116 // these are included in the minimal stabs, but they keep their full string
2124 struct HeaderRange
{
2125 std::vector
<ObjectFile::Reader::Stab
>::iterator begin
;
2126 std::vector
<ObjectFile::Reader::Stab
>::iterator end
;
2127 int parentRangeIndex
;
2129 bool sumPrecomputed
;
2131 bool cannotEXCL
; // because of SLINE, etc stabs
2135 typedef __gnu_cxx::hash_map
<const char*, std::vector
<uint32_t>, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToSums
;
2137 // hash table that maps header path to a vector of known checksums for that path
2138 static PathToSums sKnownBINCLs
;
2141 void Linker::collectStabs(ObjectFile::Reader
* reader
, std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
)
2144 bool minimal
= ( fOptions
.readerOptions().fDebugInfoStripping
== ObjectFile::ReaderOptions::kDebugInfoMinimal
);
2145 std::vector
<class ObjectFile::Reader::Stab
>* readerStabs
= reader
->getStabs();
2146 if ( readerStabs
== NULL
)
2149 if ( log
) fprintf(stderr
, "processesing %lu stabs for %s\n", readerStabs
->size(), reader
->getPath());
2150 std::vector
<HeaderRange
> ranges
;
2151 int curRangeIndex
= -1;
2153 ObjectFile::Atom
* atomWithLowestOrdinal
= NULL
;
2154 ObjectFile::Atom
* atomWithHighestOrdinal
= NULL
;
2155 uint32_t highestOrdinal
= 0;
2156 uint32_t lowestOrdinal
= UINT_MAX
;
2157 std::vector
<std::pair
<ObjectFile::Atom
*,ObjectFile::Atom
*> > soRanges
;
2158 // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums
2159 // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein
2160 for(std::vector
<class ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
2162 switch ( it
->type
) {
2167 range
.end
= readerStabs
->end();
2168 range
.parentRangeIndex
= curRangeIndex
;
2169 range
.sum
= it
->value
;
2170 range
.sumPrecomputed
= (range
.sum
!= 0);
2171 range
.useEXCL
= false;
2172 range
.cannotEXCL
= false;
2173 curRangeIndex
= ranges
.size();
2174 if ( log
) fprintf(stderr
, "[%d]BINCL %s\n", curRangeIndex
, it
->string
);
2175 ranges
.push_back(range
);
2179 if ( curRangeIndex
== -1 ) {
2180 fprintf(stderr
, "ld: warning EINCL missing BINCL in %s\n", reader
->getPath());
2183 ranges
[curRangeIndex
].end
= it
+1;
2184 if ( log
) fprintf(stderr
, "[%d->%d]EINCL %s\n", curRangeIndex
, ranges
[curRangeIndex
].parentRangeIndex
, it
->string
);
2185 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
2190 std::map
<const class ObjectFile::Atom
*, uint32_t>::iterator pos
= atomOrdinals
.find(it
->atom
);
2191 if ( pos
!= atomOrdinals
.end() ) {
2192 uint32_t ordinal
= pos
->second
;
2193 if ( ordinal
> highestOrdinal
) {
2194 highestOrdinal
= ordinal
;
2195 atomWithHighestOrdinal
= it
->atom
;
2197 if ( ordinal
< lowestOrdinal
) {
2198 lowestOrdinal
= ordinal
;
2199 atomWithLowestOrdinal
= it
->atom
;
2211 if ( curRangeIndex
!= -1 ) {
2212 ranges
[curRangeIndex
].cannotEXCL
= true;
2213 if ( fOptions
.warnStabs() )
2214 fprintf(stderr
, "ld: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
2218 if ( (it
->string
!= NULL
) && (strlen(it
->string
) > 0) ) {
2219 // start SO, reset hi/low FUN tracking
2220 atomWithLowestOrdinal
= NULL
;
2221 atomWithHighestOrdinal
= NULL
;
2223 lowestOrdinal
= UINT_MAX
;
2226 // end SO, record hi/low atoms for this SO range
2227 soRanges
.push_back(std::make_pair
<ObjectFile::Atom
*,ObjectFile::Atom
*>(atomWithLowestOrdinal
, atomWithHighestOrdinal
));
2231 if ( curRangeIndex
!= -1 ) {
2232 if ( ! ranges
[curRangeIndex
].sumPrecomputed
) {
2234 const char* s
= it
->string
;
2236 while ( (c
= *s
++) != 0 ) {
2238 // don't checkusm first number (file index) after open paren in string
2244 ranges
[curRangeIndex
].sum
+= sum
;
2250 if ( log
) fprintf(stderr
, "processesed %d stabs for %s\n", count
, reader
->getPath());
2251 if ( curRangeIndex
!= -1 )
2252 fprintf(stderr
, "ld: warning BINCL (%s) missing EINCL in %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
2255 if ( ranges
.size() == 0 ) {
2257 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
2258 // copy minimal or all stabs
2259 ObjectFile::Reader::Stab stab
= *it
;
2260 if ( !minimal
|| minimizeStab(stab
) ) {
2261 if ( stab
.type
== N_SO
) {
2262 if ( (stab
.string
!= NULL
) && (strlen(stab
.string
) > 0) ) {
2263 // starting SO is associated with first atom
2264 stab
.atom
= soRanges
[soIndex
].first
;
2267 // ending SO is associated with last atom
2268 stab
.atom
= soRanges
[soIndex
].second
;
2272 fStabs
.push_back(stab
);
2278 //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
2279 //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
2280 // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
2283 // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
2284 for(std::vector
<HeaderRange
>::iterator it
=ranges
.begin(); it
!= ranges
.end(); ++it
) {
2285 if ( ! it
->cannotEXCL
) {
2286 const char* header
= it
->begin
->string
;
2287 uint32_t sum
= it
->sum
;
2288 PathToSums::iterator pos
= sKnownBINCLs
.find(header
);
2289 if ( pos
!= sKnownBINCLs
.end() ) {
2290 std::vector
<uint32_t>& sums
= pos
->second
;
2291 for(std::vector
<uint32_t>::iterator sit
=sums
.begin(); sit
!= sums
.end(); ++sit
) {
2293 //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
2298 if ( ! it
->useEXCL
) {
2299 // have seen this path, but not this checksum
2300 //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
2301 sums
.push_back(sum
);
2305 // have not seen this path, so add to known BINCLs
2306 std::vector
<uint32_t> empty
;
2307 sKnownBINCLs
[header
] = empty
;
2308 sKnownBINCLs
[header
].push_back(sum
);
2309 //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
2314 // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
2316 const int maxRangeIndex
= ranges
.size();
2318 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
2319 switch ( it
->type
) {
2321 for(int i
=curRangeIndex
+1; i
< maxRangeIndex
; ++i
) {
2322 if ( ranges
[i
].begin
== it
) {
2324 HeaderRange
& range
= ranges
[curRangeIndex
];
2325 ObjectFile::Reader::Stab stab
= *it
;
2326 stab
.value
= range
.sum
; // BINCL and EXCL have n_value set to checksum
2327 if ( range
.useEXCL
)
2328 stab
.type
= N_EXCL
; // transform BINCL into EXCL
2330 fStabs
.push_back(stab
);
2336 if ( curRangeIndex
!= -1 ) {
2337 if ( !ranges
[curRangeIndex
].useEXCL
&& !minimal
)
2338 fStabs
.push_back(*it
);
2339 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
2343 if ( (curRangeIndex
== -1) || !ranges
[curRangeIndex
].useEXCL
) {
2344 ObjectFile::Reader::Stab stab
= *it
;
2345 if ( !minimal
|| minimizeStab(stab
) ) {
2346 if ( stab
.type
== N_SO
) {
2347 if ( (stab
.string
!= NULL
) && (strlen(stab
.string
) > 0) ) {
2348 // starting SO is associated with first atom
2349 stab
.atom
= soRanges
[soIndex
].first
;
2352 // ending SO is associated with last atom
2353 stab
.atom
= soRanges
[soIndex
].second
;
2357 fStabs
.push_back(stab
);
2366 // used to prune out atoms that don't need debug notes generated
2367 class NoDebugNoteAtom
2370 NoDebugNoteAtom(const std::map
<class ObjectFile::Reader
*, uint32_t>& readersWithDwarfOrdinals
)
2371 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals
) {}
2373 bool operator()(const ObjectFile::Atom
* atom
) const {
2374 if ( atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
)
2376 if ( atom
->getName() == NULL
)
2378 if ( fReadersWithDwarfOrdinals
.find(atom
->getFile()) == fReadersWithDwarfOrdinals
.end() )
2384 const std::map
<class ObjectFile::Reader
*, uint32_t>& fReadersWithDwarfOrdinals
;
2387 // used to sort atoms with debug notes
2388 class ReadersWithDwarfSorter
2391 ReadersWithDwarfSorter(const std::map
<class ObjectFile::Reader
*, uint32_t>& readersWithDwarfOrdinals
,
2392 const std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
)
2393 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals
), fAtomOrdinals(atomOrdinals
) {}
2395 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
) const
2397 // first sort by reader
2398 unsigned int leftReaderIndex
= fReadersWithDwarfOrdinals
.find(left
->getFile())->second
;
2399 unsigned int rightReaderIndex
= fReadersWithDwarfOrdinals
.find(right
->getFile())->second
;
2400 if ( leftReaderIndex
!= rightReaderIndex
)
2401 return (leftReaderIndex
< rightReaderIndex
);
2403 // then sort by atom ordinal
2404 unsigned int leftAtomIndex
= fAtomOrdinals
.find(left
)->second
;
2405 unsigned int rightAtomIndex
= fAtomOrdinals
.find(right
)->second
;
2406 return leftAtomIndex
< rightAtomIndex
;
2410 const std::map
<class ObjectFile::Reader
*, uint32_t>& fReadersWithDwarfOrdinals
;
2411 const std::map
<const class ObjectFile::Atom
*, uint32_t>& fAtomOrdinals
;
2418 void Linker::synthesizeDebugNotes(std::vector
<class ObjectFile::Atom
*>& allAtomsByReader
)
2420 // synthesize "debug notes" and add them to master stabs vector
2421 const char* dirPath
= NULL
;
2422 const char* filename
= NULL
;
2423 bool wroteStartSO
= false;
2424 bool useZeroOSOModTime
= (getenv("RC_RELEASE") != NULL
);
2425 __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> seenFiles
;
2426 for (std::vector
<ObjectFile::Atom
*>::iterator it
=allAtomsByReader
.begin(); it
!= allAtomsByReader
.end(); it
++) {
2427 ObjectFile::Atom
* atom
= *it
;
2428 const char* newDirPath
;
2429 const char* newFilename
;
2430 //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
2431 if ( atom
->getTranslationUnitSource(&newDirPath
, &newFilename
) ) {
2432 // need SO's whenever the translation unit source file changes
2433 if ( newFilename
!= filename
) {
2434 // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
2435 if ( (newDirPath
!= NULL
) && (strlen(newDirPath
) > 1 ) && (newDirPath
[strlen(newDirPath
)-1] != '/') )
2436 asprintf((char**)&newDirPath
, "%s/", newDirPath
);
2437 if ( filename
!= NULL
) {
2438 // translation unit change, emit ending SO
2439 ObjectFile::Reader::Stab endFileStab
;
2440 endFileStab
.atom
= NULL
;
2441 endFileStab
.type
= N_SO
;
2442 endFileStab
.other
= 1;
2443 endFileStab
.desc
= 0;
2444 endFileStab
.value
= 0;
2445 endFileStab
.string
= "";
2446 fStabs
.push_back(endFileStab
);
2448 // new translation unit, emit start SO's
2449 ObjectFile::Reader::Stab dirPathStab
;
2450 dirPathStab
.atom
= NULL
;
2451 dirPathStab
.type
= N_SO
;
2452 dirPathStab
.other
= 0;
2453 dirPathStab
.desc
= 0;
2454 dirPathStab
.value
= 0;
2455 dirPathStab
.string
= newDirPath
;
2456 fStabs
.push_back(dirPathStab
);
2457 ObjectFile::Reader::Stab fileStab
;
2458 fileStab
.atom
= NULL
;
2459 fileStab
.type
= N_SO
;
2463 fileStab
.string
= newFilename
;
2464 fStabs
.push_back(fileStab
);
2465 // Synthesize OSO for start of file
2466 ObjectFile::Reader::Stab objStab
;
2467 objStab
.atom
= NULL
;
2468 objStab
.type
= N_OSO
;
2471 objStab
.value
= useZeroOSOModTime
? 0 : atom
->getFile()->getModificationTime();
2472 objStab
.string
= assureFullPath(atom
->getFile()->getPath());
2473 fStabs
.push_back(objStab
);
2474 wroteStartSO
= true;
2475 // add the source file path to seenFiles so it does not show up in SOLs
2476 seenFiles
.insert(newFilename
);
2478 filename
= newFilename
;
2479 dirPath
= newDirPath
;
2480 if ( atom
->getSegment().isContentExecutable() && (strncmp(atom
->getSectionName(), "__text", 6) == 0) ) {
2481 // Synthesize BNSYM and start FUN stabs
2482 ObjectFile::Reader::Stab beginSym
;
2483 beginSym
.atom
= atom
;
2484 beginSym
.type
= N_BNSYM
;
2488 beginSym
.string
= "";
2489 fStabs
.push_back(beginSym
);
2490 ObjectFile::Reader::Stab startFun
;
2491 startFun
.atom
= atom
;
2492 startFun
.type
= N_FUN
;
2496 startFun
.string
= atom
->getName();
2497 fStabs
.push_back(startFun
);
2498 // Synthesize any SOL stabs needed
2499 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
2500 if ( lineInfo
!= NULL
) {
2501 const char* curFile
= NULL
;
2502 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
2503 if ( it
->fileName
!= curFile
) {
2504 if ( seenFiles
.count(it
->fileName
) == 0 ) {
2505 seenFiles
.insert(it
->fileName
);
2506 ObjectFile::Reader::Stab sol
;
2512 sol
.string
= it
->fileName
;
2513 fStabs
.push_back(sol
);
2515 curFile
= it
->fileName
;
2519 // Synthesize end FUN and ENSYM stabs
2520 ObjectFile::Reader::Stab endFun
;
2522 endFun
.type
= N_FUN
;
2527 fStabs
.push_back(endFun
);
2528 ObjectFile::Reader::Stab endSym
;
2530 endSym
.type
= N_ENSYM
;
2535 fStabs
.push_back(endSym
);
2538 ObjectFile::Reader::Stab globalsStab
;
2539 if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
2540 // Synthesize STSYM stab for statics
2541 const char* name
= atom
->getName();
2542 if ( name
[0] == '_' ) {
2543 globalsStab
.atom
= atom
;
2544 globalsStab
.type
= N_STSYM
;
2545 globalsStab
.other
= 1;
2546 globalsStab
.desc
= 0;
2547 globalsStab
.value
= 0;
2548 globalsStab
.string
= name
;
2549 fStabs
.push_back(globalsStab
);
2553 // Synthesize GSYM stab for other globals (but not .eh exception frame symbols)
2554 const char* name
= atom
->getName();
2555 if ( (name
[0] == '_') && (strcmp(atom
->getSectionName(), "__eh_frame") != 0) ) {
2556 globalsStab
.atom
= atom
;
2557 globalsStab
.type
= N_GSYM
;
2558 globalsStab
.other
= 1;
2559 globalsStab
.desc
= 0;
2560 globalsStab
.value
= 0;
2561 globalsStab
.string
= name
;
2562 fStabs
.push_back(globalsStab
);
2569 if ( wroteStartSO
) {
2571 ObjectFile::Reader::Stab endFileStab
;
2572 endFileStab
.atom
= NULL
;
2573 endFileStab
.type
= N_SO
;
2574 endFileStab
.other
= 1;
2575 endFileStab
.desc
= 0;
2576 endFileStab
.value
= 0;
2577 endFileStab
.string
= "";
2578 fStabs
.push_back(endFileStab
);
2585 void Linker::collectDebugInfo()
2587 std::map
<const class ObjectFile::Atom
*, uint32_t> atomOrdinals
;
2588 fStartDebugTime
= mach_absolute_time();
2589 if ( fOptions
.readerOptions().fDebugInfoStripping
!= ObjectFile::ReaderOptions::kDebugInfoNone
) {
2591 // determine mixture of stabs and dwarf
2592 bool someStabs
= false;
2593 bool someDwarf
= false;
2594 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
2595 it
!= fReadersThatHaveSuppliedAtoms
.end();
2597 ObjectFile::Reader
* reader
= *it
;
2598 if ( reader
!= NULL
) {
2599 switch ( reader
->getDebugInfoKind() ) {
2600 case ObjectFile::Reader::kDebugInfoNone
:
2602 case ObjectFile::Reader::kDebugInfoStabs
:
2605 case ObjectFile::Reader::kDebugInfoDwarf
:
2609 case ObjectFile::Reader::kDebugInfoStabsUUID
:
2614 throw "Unhandled type of debug information";
2619 if ( someDwarf
|| someStabs
) {
2620 // try to minimize re-allocations
2621 fStabs
.reserve(1024);
2623 // make mapping from atoms to ordinal
2624 uint32_t ordinal
= 1;
2625 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2626 atomOrdinals
[*it
] = ordinal
++;
2630 // process all dwarf .o files as a batch
2632 // make mapping from readers with dwarf to ordinal
2633 std::map
<class ObjectFile::Reader
*, uint32_t> readersWithDwarfOrdinals
;
2634 uint32_t readerOrdinal
= 1;
2635 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
2636 it
!= fReadersThatHaveSuppliedAtoms
.end();
2638 ObjectFile::Reader
* reader
= *it
;
2639 if ( (reader
!= NULL
) && (reader
->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoDwarf
) ) {
2640 readersWithDwarfOrdinals
[reader
] = readerOrdinal
++;
2644 // make a vector of atoms
2645 std::vector
<class ObjectFile::Atom
*> allAtomsByReader(fAllAtoms
.begin(), fAllAtoms
.end());
2646 // remove those not from a reader that has dwarf
2647 allAtomsByReader
.erase(std::remove_if(allAtomsByReader
.begin(), allAtomsByReader
.end(),
2648 NoDebugNoteAtom(readersWithDwarfOrdinals
)), allAtomsByReader
.end());
2649 // sort by reader then atom ordinal
2650 std::sort(allAtomsByReader
.begin(), allAtomsByReader
.end(), ReadersWithDwarfSorter(readersWithDwarfOrdinals
, atomOrdinals
));
2651 // add debug notes for each atom
2652 this->synthesizeDebugNotes(allAtomsByReader
);
2655 // process all stabs .o files one by one
2657 // get stabs from each reader, in command line order
2658 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
2659 it
!= fReadersThatHaveSuppliedAtoms
.end();
2661 ObjectFile::Reader
* reader
= *it
;
2662 if ( reader
!= NULL
) {
2663 switch ( reader
->getDebugInfoKind() ) {
2664 case ObjectFile::Reader::kDebugInfoDwarf
:
2665 case ObjectFile::Reader::kDebugInfoNone
:
2668 case ObjectFile::Reader::kDebugInfoStabs
:
2669 case ObjectFile::Reader::kDebugInfoStabsUUID
:
2670 collectStabs(reader
, atomOrdinals
);
2673 throw "Unhandled type of debug information";
2677 // remove stabs associated with atoms that won't be in output
2678 std::set
<class ObjectFile::Atom
*> allAtomsSet
;
2679 allAtomsSet
.insert(fAllAtoms
.begin(), fAllAtoms
.end());
2680 fStabs
.erase(std::remove_if(fStabs
.begin(), fStabs
.end(), NotInSet(allAtomsSet
)), fStabs
.end());
2685 void Linker::writeOutput()
2687 if ( fOptions
.forceCpuSubtypeAll() )
2688 fCurrentCpuConstraint
= ObjectFile::Reader::kCpuAny
;
2690 fStartWriteTime
= mach_absolute_time();
2691 // tell writer about each segment's atoms
2692 fOutputFileSize
= fOutputFile
->write(fAllAtoms
, fStabs
, this->entryPoint(), this->dyldHelper(),
2693 fCreateUUID
, fCanScatter
,
2694 fCurrentCpuConstraint
, fBiggerThanTwoGigOutput
);
2697 ObjectFile::Reader
* Linker::createReader(const Options::FileInfo
& info
)
2699 // map in whole file
2700 uint64_t len
= info
.fileLen
;
2701 int fd
= ::open(info
.path
, O_RDONLY
, 0);
2703 throwf("can't open file, errno=%d", errno
);
2704 if ( info
.fileLen
< 20 )
2705 throw "file too small";
2707 uint8_t* p
= (uint8_t*)::mmap(NULL
, info
.fileLen
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
2708 if ( p
== (uint8_t*)(-1) )
2709 throwf("can't map file, errno=%d", errno
);
2711 // if fat file, skip to architecture we want
2712 const fat_header
* fh
= (fat_header
*)p
;
2713 if ( fh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2714 // Fat header is always big-endian
2715 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
2716 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2717 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)fArchitecture
) {
2718 uint32_t fileOffset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2719 len
= OSSwapBigToHostInt32(archs
[i
].size
);
2720 // if requested architecture is page aligned within fat file, then remap just that portion of file
2721 if ( (fileOffset
& 0x00000FFF) == 0 ) {
2723 munmap((caddr_t
)p
, info
.fileLen
);
2724 // re-map just part we need
2725 p
= (uint8_t*)::mmap(NULL
, len
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, fileOffset
);
2726 if ( p
== (uint8_t*)(-1) )
2727 throwf("can't re-map file, errno=%d", errno
);
2738 switch (fArchitecture
) {
2739 case CPU_TYPE_POWERPC
:
2740 if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
2741 return this->addObject(new mach_o::relocatable::Reader
<ppc
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2742 else if ( mach_o::dylib::Reader
<ppc
>::validFile(p
, info
.options
.fBundleLoader
) )
2743 return this->addDylib(new mach_o::dylib::Reader
<ppc
>::Reader(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2744 else if ( mach_o::archive::Reader
<ppc
>::validFile(p
, len
) )
2745 return this->addArchive(new mach_o::archive::Reader
<ppc
>::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2747 case CPU_TYPE_POWERPC64
:
2748 if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
2749 return this->addObject(new mach_o::relocatable::Reader
<ppc64
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2750 else if ( mach_o::dylib::Reader
<ppc64
>::validFile(p
, info
.options
.fBundleLoader
) )
2751 return this->addDylib(new mach_o::dylib::Reader
<ppc64
>::Reader(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2752 else if ( mach_o::archive::Reader
<ppc64
>::validFile(p
, len
) )
2753 return this->addArchive(new mach_o::archive::Reader
<ppc64
>::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2756 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
2757 return this->addObject(new mach_o::relocatable::Reader
<x86
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2758 else if ( mach_o::dylib::Reader
<x86
>::validFile(p
, info
.options
.fBundleLoader
) )
2759 return this->addDylib(new mach_o::dylib::Reader
<x86
>::Reader(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2760 else if ( mach_o::archive::Reader
<x86
>::validFile(p
, len
) )
2761 return this->addArchive(new mach_o::archive::Reader
<x86
>::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2763 case CPU_TYPE_X86_64
:
2764 if ( mach_o::relocatable::Reader
<x86_64
>::validFile(p
) )
2765 return this->addObject(new mach_o::relocatable::Reader
<x86_64
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2766 else if ( mach_o::dylib::Reader
<x86_64
>::validFile(p
, info
.options
.fBundleLoader
) )
2767 return this->addDylib(new mach_o::dylib::Reader
<x86_64
>::Reader(p
, len
, info
.path
, info
.options
.fBundleLoader
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2768 else if ( mach_o::archive::Reader
<x86_64
>::validFile(p
, len
) )
2769 return this->addArchive(new mach_o::archive::Reader
<x86_64
>::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
2774 if ( LLVMReader::validFile(p
, info
.path
, fArchitecture
, fOptions
) ) {
2775 return this->addObject(LLVMReader::make(p
, info
.path
, info
.modTime
, fOptions
), info
, len
);
2779 if ( ((fat_header
*)p
)->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2780 throwf("missing required architecture %s in file", fArchitectureName
);
2783 throw "file is not of required architecture";
2787 void Linker::logDylib(ObjectFile::Reader
* reader
, bool indirect
)
2789 if ( fOptions
.readerOptions().fTraceDylibs
) {
2790 const char* fullPath
= reader
->getPath();
2791 char realName
[MAXPATHLEN
];
2792 if ( realpath(fullPath
, realName
) != NULL
)
2793 fullPath
= realName
;
2795 logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath
);
2797 logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath
);
2803 ObjectFile::Reader
* Linker::findDylib(const char* installPath
, const char* fromPath
)
2805 //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
2806 InstallNameToReader::iterator pos
= fDylibMap
.find(installPath
);
2807 if ( pos
!= fDylibMap
.end() ) {
2811 // allow -dylib_path option to override indirect library to use
2812 for (std::vector
<Options::DylibOverride
>::iterator dit
= fOptions
.dylibOverrides().begin(); dit
!= fOptions
.dylibOverrides().end(); ++dit
) {
2813 if ( strcmp(dit
->installName
,installPath
) == 0 ) {\
2815 Options::FileInfo info
= fOptions
.findFile(dit
->useInstead
);
2816 ObjectFile::Reader
* reader
= this->createReader(info
);
2817 fDylibMap
[strdup(installPath
)] = reader
;
2818 this->logDylib(reader
, true);
2821 catch (const char* msg
) {
2822 fprintf(stderr
, "ld: warning ignoring -dylib_file option, %s\n", msg
);
2826 char newPath
[MAXPATHLEN
];
2827 // handle @loader_path
2828 if ( strncmp(installPath
, "@loader_path/", 13) == 0 ) {
2829 strcpy(newPath
, fromPath
);
2830 char* addPoint
= strrchr(newPath
,'/');
2831 if ( addPoint
!= NULL
)
2832 strcpy(&addPoint
[1], &installPath
[13]);
2834 strcpy(newPath
, &installPath
[13]);
2835 installPath
= newPath
;
2837 // note: @executable_path case is handled inside findFileUsingPaths()
2838 // search for dylib using -F and -L paths
2839 Options::FileInfo info
= fOptions
.findFileUsingPaths(installPath
);
2841 ObjectFile::Reader
* reader
= this->createReader(info
);
2842 fDylibMap
[strdup(installPath
)] = reader
;
2843 this->logDylib(reader
, true);
2846 catch (const char* msg
) {
2847 throwf("in %s, %s", info
.path
, msg
);
2853 void Linker::processDylibs()
2855 fAllDirectDylibsLoaded
= true;
2857 // mark all dylibs initially specified as required and check if they can be used
2858 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
2859 it
->second
->setExplicitlyLinked();
2860 this->checkDylibClientRestrictions(it
->second
);
2863 // keep processing dylibs until no more dylibs are added
2864 unsigned long lastMapSize
= 0;
2865 while ( lastMapSize
!= fDylibMap
.size() ) {
2866 lastMapSize
= fDylibMap
.size();
2867 // can't iterator fDylibMap while modifying it, so use temp buffer
2868 std::vector
<ObjectFile::Reader
*> currentUnprocessedReaders
;
2869 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
2870 if ( fDylibsProcessed
.count(it
->second
) == 0 )
2871 currentUnprocessedReaders
.push_back(it
->second
);
2873 for (std::vector
<ObjectFile::Reader
*>::iterator it
=currentUnprocessedReaders
.begin(); it
!= currentUnprocessedReaders
.end(); it
++) {
2874 fDylibsProcessed
.insert(*it
);
2875 (*it
)->processIndirectLibraries(this);
2879 // go back over original dylibs and mark sub frameworks as re-exported
2880 if ( fOptions
.outputKind() == Options::kDynamicLibrary
) {
2881 const char* myLeaf
= strrchr(fOptions
.installPath(), '/');
2882 if ( myLeaf
!= NULL
) {
2883 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
2884 ObjectFile::Reader
* reader
= *it
;
2885 const char* childParent
= reader
->parentUmbrella();
2886 if ( childParent
!= NULL
) {
2887 if ( strcmp(childParent
, &myLeaf
[1]) == 0 ) {
2888 // set re-export bit of info
2889 std::map
<ObjectFile::Reader
*,DynamicLibraryOptions
>::iterator pos
= fDylibOptionsMap
.find(reader
);
2890 if ( pos
!= fDylibOptionsMap
.end() ) {
2891 pos
->second
.fReExport
= true;
2903 void Linker::createReaders()
2905 fStartCreateReadersTime
= mach_absolute_time();
2906 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
2907 const int count
= files
.size();
2909 throw "no object files specified";
2910 // add all direct object, archives, and dylibs
2911 for (int i
=0; i
< count
; ++i
) {
2912 Options::FileInfo
& entry
= files
[i
];
2913 // ignore /usr/lib/dyld on command line in crt.o build
2914 if ( strcmp(entry
.path
, "/usr/lib/dyld") != 0 ) {
2916 this->addInputFile(this->createReader(entry
), entry
);
2918 catch (const char* msg
) {
2919 if ( strstr(msg
, "architecture") != NULL
) {
2920 if ( fOptions
.ignoreOtherArchInputFiles() ) {
2921 // ignore, because this is about an architecture not in use
2924 fprintf(stderr
, "ld: warning in %s, %s\n", entry
.path
, msg
);
2928 throwf("in %s, %s", entry
.path
, msg
);
2934 this->processDylibs();
2939 ObjectFile::Reader
* Linker::addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
2941 fNextInputOrdinal
+= mappedLen
;
2942 // remember which readers are archives because they are logged differently
2943 fArchiveReaders
.insert(reader
);
2946 fTotalArchiveSize
+= mappedLen
;
2947 ++fTotalArchivesLoaded
;
2951 ObjectFile::Reader
* Linker::addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
2953 fNextInputOrdinal
+= mappedLen
;
2954 // any .o files that don't have MH_SUBSECTIONS_VIA_SYMBOLS, that means a generated .o file can't
2955 if ( (fOptions
.outputKind() == Options::kObjectFile
) && !reader
->canScatterAtoms() )
2956 fCanScatter
= false;
2959 fTotalObjectSize
+= mappedLen
;
2960 ++fTotalObjectLoaded
;
2965 void Linker::checkDylibClientRestrictions(ObjectFile::Reader
* reader
)
2967 // Check for any restrictions on who can link with this dylib
2968 const char* readerParentName
= reader
->parentUmbrella() ;
2969 std::vector
<const char*>* clients
= reader
->getAllowableClients();
2970 if ( (readerParentName
!= NULL
) || (clients
!= NULL
) ) {
2971 // only dylibs that are in an umbrella or have a client list need verification
2972 const char* installName
= fOptions
.installPath();
2973 const char* installNameLastSlash
= strrchr(installName
, '/');
2974 bool isParent
= false;
2975 bool isSibling
= false;
2976 bool isAllowableClient
= false;
2977 // There are three cases:
2978 if ( (readerParentName
!= NULL
) && (installNameLastSlash
!= NULL
) ) {
2979 // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
2980 isParent
= ( strcmp(&installNameLastSlash
[1], readerParentName
) == 0 );
2982 // hack to support umbrella variants that encode the variant name in the install name
2983 // e.g. CoreServices_profile
2985 const char* underscore
= strchr(&installNameLastSlash
[1], '_');
2986 if ( underscore
!= NULL
) {
2987 isParent
= ( strncmp(&installNameLastSlash
[1], readerParentName
, underscore
-installNameLastSlash
-1) == 0 );
2991 // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
2992 isSibling
= ( (fOptions
.umbrellaName() != NULL
) && (strcmp(fOptions
.umbrellaName(), readerParentName
) == 0) );
2995 if ( !isParent
&& !isSibling
&& (clients
!= NULL
) ) {
2996 // case 3) the dylib has a list of allowable clients, and we are creating one of them
2997 const char* clientName
= fOptions
.clientName();
2998 int clientNameLen
= 0;
2999 if ( clientName
!= NULL
) {
3000 // use client name as specified on command line
3001 clientNameLen
= strlen(clientName
);
3004 // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar)
3005 clientName
= installName
;
3006 clientNameLen
= strlen(clientName
);
3007 // starts after last slash
3008 if ( installNameLastSlash
!= NULL
)
3009 clientName
= &installNameLastSlash
[1];
3010 if ( strncmp(clientName
, "lib", 3) == 0 )
3011 clientName
= &clientName
[3];
3013 const char* firstDot
= strchr(clientName
, '.');
3014 if ( firstDot
!= NULL
)
3015 clientNameLen
= firstDot
- clientName
;
3016 // up to first underscore
3017 const char* firstUnderscore
= strchr(clientName
, '_');
3018 if ( (firstUnderscore
!= NULL
) && ((firstUnderscore
- clientName
) < clientNameLen
) )
3019 clientNameLen
= firstUnderscore
- clientName
;
3022 // Use clientName to check if this dylib is able to link against the allowable clients.
3023 for (std::vector
<const char*>::iterator it
= clients
->begin(); it
!= clients
->end(); it
++) {
3024 if ( strncmp(*it
, clientName
, clientNameLen
) == 0 )
3025 isAllowableClient
= true;
3029 if ( !isParent
&& !isSibling
&& !isAllowableClient
) {
3030 if ( readerParentName
!= NULL
) {
3031 throwf("cannot link directly with %s. Link against the umbrella framework '%s.framework' instead.",
3032 reader
->getPath(), readerParentName
);
3035 throwf("cannot link directly with %s", reader
->getPath());
3043 ObjectFile::Reader
* Linker::addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
3045 fNextInputOrdinal
+= mappedLen
;
3046 if ( (reader
->getInstallPath() == NULL
) && !info
.options
.fBundleLoader
) {
3047 // this is a "blank" stub
3048 // silently ignore it
3051 // add to map of loaded dylibs
3052 const char* installPath
= reader
->getInstallPath();
3053 if ( installPath
!= NULL
) {
3054 InstallNameToReader::iterator pos
= fDylibMap
.find(installPath
);
3055 if ( pos
== fDylibMap
.end() ) {
3056 fDylibMap
[strdup(installPath
)] = reader
;
3059 InstallNameToReader::iterator pos2
= fDylibMap
.find(reader
->getPath());
3060 if ( pos2
== fDylibMap
.end() )
3061 fDylibMap
[strdup(reader
->getPath())] = reader
;
3063 fprintf(stderr
, "ld: warning, duplicate dylib %s\n", reader
->getPath());
3066 else if ( info
.options
.fBundleLoader
)
3067 fBundleLoaderReader
= reader
;
3069 // log direct readers
3070 if ( !fAllDirectDylibsLoaded
)
3071 this->logDylib(reader
, false);
3074 ++fTotalDylibsLoaded
;
3080 void Linker::logTraceInfo (const char* format
, ...)
3082 static int trace_file
= -1;
3083 char trace_buffer
[MAXPATHLEN
* 2];
3086 ssize_t amount_written
;
3087 const char *trace_file_path
= fOptions
.readerOptions().fTraceOutputFile
;
3089 if(trace_file
== -1) {
3090 if(trace_file_path
!= NULL
) {
3091 trace_file
= open(trace_file_path
, O_WRONLY
| O_APPEND
| O_CREAT
, 0666);
3092 if(trace_file
== -1)
3093 throwf("Could not open or create trace file: %s\n", trace_file_path
);
3096 trace_file
= fileno(stderr
);
3101 va_start(ap
, format
);
3102 length
= vsnprintf(trace_buffer
, sizeof(trace_buffer
), format
, ap
);
3104 buffer_ptr
= trace_buffer
;
3107 amount_written
= write(trace_file
, buffer_ptr
, length
);
3108 if(amount_written
== -1)
3109 /* Failure to write shouldn't fail the build. */
3111 buffer_ptr
+= amount_written
;
3112 length
-= amount_written
;
3118 void Linker::createWriter()
3120 fStartCreateWriterTime
= mach_absolute_time();
3122 // make a vector out of all required dylibs in fDylibMap
3123 std::vector
<ExecutableFile::DyLibUsed
> dynamicLibraries
;
3124 // need to preserve command line order
3125 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
3126 ObjectFile::Reader
* reader
= *it
;
3127 for (InstallNameToReader::iterator mit
=fDylibMap
.begin(); mit
!= fDylibMap
.end(); mit
++) {
3128 if ( reader
== mit
->second
) {
3129 ExecutableFile::DyLibUsed dylibInfo
;
3130 dylibInfo
.reader
= reader
;
3131 dylibInfo
.options
= fDylibOptionsMap
[reader
];
3132 dynamicLibraries
.push_back(dylibInfo
);
3137 // then add any other dylibs
3138 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
3139 if ( it
->second
->implicitlyLinked() ) {
3140 // if not already in dynamicLibraries
3141 bool alreadyInDynamicLibraries
= false;
3142 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator dit
=dynamicLibraries
.begin(); dit
!= dynamicLibraries
.end(); dit
++) {
3143 if ( dit
->reader
== it
->second
) {
3144 alreadyInDynamicLibraries
= true;
3148 if ( ! alreadyInDynamicLibraries
) {
3149 ExecutableFile::DyLibUsed dylibInfo
;
3150 dylibInfo
.reader
= it
->second
;
3151 std::map
<ObjectFile::Reader
*,DynamicLibraryOptions
>::iterator pos
= fDylibOptionsMap
.find(it
->second
);
3152 if ( pos
!= fDylibOptionsMap
.end() ) {
3153 dylibInfo
.options
= pos
->second
;
3156 dylibInfo
.options
.fWeakImport
= false; // FIX ME
3157 dylibInfo
.options
.fReExport
= false;
3158 dylibInfo
.options
.fBundleLoader
= false;
3160 dynamicLibraries
.push_back(dylibInfo
);
3164 if ( fBundleLoaderReader
!= NULL
) {
3165 ExecutableFile::DyLibUsed dylibInfo
;
3166 dylibInfo
.reader
= fBundleLoaderReader
;
3167 dylibInfo
.options
.fWeakImport
= false;
3168 dylibInfo
.options
.fReExport
= false;
3169 dylibInfo
.options
.fBundleLoader
= true;
3170 dynamicLibraries
.push_back(dylibInfo
);
3173 const char* path
= fOptions
.getOutputFilePath();
3174 switch ( fArchitecture
) {
3175 case CPU_TYPE_POWERPC
:
3176 this->setOutputFile(new mach_o::executable::Writer
<ppc
>(path
, fOptions
, dynamicLibraries
));
3178 case CPU_TYPE_POWERPC64
:
3179 this->setOutputFile(new mach_o::executable::Writer
<ppc64
>(path
, fOptions
, dynamicLibraries
));
3182 this->setOutputFile(new mach_o::executable::Writer
<x86
>(path
, fOptions
, dynamicLibraries
));
3184 case CPU_TYPE_X86_64
:
3185 this->setOutputFile(new mach_o::executable::Writer
<x86_64
>(path
, fOptions
, dynamicLibraries
));
3188 throw "unknown architecture";
3193 Linker::SymbolTable::SymbolTable(Linker
& owner
)
3194 : fOwner(owner
), fRequireCount(0)
3198 void Linker::SymbolTable::require(const char* name
)
3200 //fprintf(stderr, "require(%s)\n", name);
3201 Mapper::iterator pos
= fTable
.find(name
);
3202 if ( pos
== fTable
.end() ) {
3203 fTable
[name
] = NULL
;
3208 // convenience labels for 2-dimensional switch statement
3209 enum AllDefinitionCombinations
{
3210 kRegAndReg
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3211 kRegAndWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3212 kRegAndTent
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3213 kRegAndExtern
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3214 kRegAndExternWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3215 kRegAndAbsolute
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3216 kWeakAndReg
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3217 kWeakAndWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3218 kWeakAndTent
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3219 kWeakAndExtern
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3220 kWeakAndExternWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3221 kWeakAndAbsolute
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3222 kTentAndReg
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3223 kTentAndWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3224 kTentAndTent
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3225 kTentAndExtern
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3226 kTentAndExternWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3227 kTentAndAbsolute
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3228 kExternAndReg
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3229 kExternAndWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3230 kExternAndTent
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3231 kExternAndExtern
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3232 kExternAndExternWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3233 kExternAndAbsolute
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3234 kExternWeakAndReg
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3235 kExternWeakAndWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3236 kExternWeakAndTent
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3237 kExternWeakAndExtern
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3238 kExternWeakAndExternWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3239 kExternWeakAndAbsolute
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3240 kAbsoluteAndReg
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3241 kAbsoluteAndWeak
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3242 kAbsoluteAndTent
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3243 kAbsoluteAndExtern
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3244 kAbsoluteAndExternWeak
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3245 kAbsoluteAndAbsolute
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
3248 bool Linker::SymbolTable::add(ObjectFile::Atom
& newAtom
)
3251 const char* name
= newAtom
.getName();
3252 //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
3253 Mapper::iterator pos
= fTable
.find(name
);
3254 ObjectFile::Atom
* existingAtom
= NULL
;
3255 if ( pos
!= fTable
.end() )
3256 existingAtom
= pos
->second
;
3257 if ( existingAtom
!= NULL
) {
3258 // already have atom with same name in symbol table
3259 switch ( (AllDefinitionCombinations
)((existingAtom
->getDefinitionKind() << 3) | newAtom
.getDefinitionKind()) ) {
3261 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3263 // ignore new weak atom, because we already have a non-weak one
3267 // ignore new tentative atom, because we already have a regular one
3269 if ( newAtom
.getSize() > existingAtom
->getSize() ) {
3270 fprintf(stderr
, "ld: warning for symbol %s tentative definition of size %llu from %s is "
3271 "is smaller than the real definition of size %llu from %s\n",
3272 newAtom
.getDisplayName(), newAtom
.getSize(), newAtom
.getFile()->getPath(),
3273 existingAtom
->getSize(), existingAtom
->getFile()->getPath());
3277 // ignore external atom, because we already have a one
3280 case kRegAndExternWeak
:
3281 // ignore external atom, because we already have a one
3284 case kRegAndAbsolute
:
3285 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3288 // replace existing weak atom with regular one
3291 // have another weak atom, use whichever has largest alignment requirement
3292 // because codegen of some client may require alignment
3293 useNew
= ( newAtom
.getAlignment().trailingZeros() > existingAtom
->getAlignment().trailingZeros() );
3296 // replace existing weak atom with tentative one ???
3298 case kWeakAndExtern
:
3299 // keep weak atom, at runtime external one may override
3302 case kWeakAndExternWeak
:
3303 // keep weak atom, at runtime external one may override
3306 case kWeakAndAbsolute
:
3307 // replace existing weak atom with absolute one
3310 // replace existing tentative atom with regular one
3311 if ( newAtom
.getSize() < existingAtom
->getSize() ) {
3312 fprintf(stderr
, "ld: warning for symbol %s tentative definition of size %llu from %s is "
3313 "being replaced by a real definition of size %llu from %s\n",
3314 newAtom
.getDisplayName(), existingAtom
->getSize(), existingAtom
->getFile()->getPath(),
3315 newAtom
.getSize(), newAtom
.getFile()->getPath());
3319 // replace existing tentative atom with weak one ???
3323 if ( newAtom
.getSize() < existingAtom
->getSize() ) {
3327 if ( newAtom
.getAlignment().trailingZeros() < existingAtom
->getAlignment().trailingZeros() )
3328 fprintf(stderr
, "ld: warning alignment lost in merging tentative definition %s\n", newAtom
.getDisplayName());
3331 case kTentAndExtern
:
3332 case kTentAndExternWeak
:
3333 // a tentative definition and a dylib definition, so commons-mode decides how to handle
3334 switch ( fOwner
.fOptions
.commonsMode() ) {
3335 case Options::kCommonsIgnoreDylibs
:
3336 if ( fOwner
.fOptions
.warnCommons() )
3337 fprintf(stderr
, "ld: using common symbol %s from %s and ignoring defintion from dylib %s\n",
3338 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3341 case Options::kCommonsOverriddenByDylibs
:
3342 if ( fOwner
.fOptions
.warnCommons() )
3343 fprintf(stderr
, "ld: replacing common symbol %s from %s with true definition from dylib %s\n",
3344 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3346 case Options::kCommonsConflictsDylibsError
:
3347 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
3348 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3351 case kTentAndAbsolute
:
3352 // replace tentative with absolute (can't size check because absolutes have no size)
3355 // replace external atom with regular one
3357 case kExternAndWeak
:
3358 // replace external atom with weak one
3360 case kExternAndTent
:
3361 // a tentative definition and a dylib definition, so commons-mode decides how to handle
3362 switch ( fOwner
.fOptions
.commonsMode() ) {
3363 case Options::kCommonsIgnoreDylibs
:
3364 if ( fOwner
.fOptions
.warnCommons() )
3365 fprintf(stderr
, "ld: using common symbol %s from %s and ignoring defintion from dylib %s\n",
3366 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3368 case Options::kCommonsOverriddenByDylibs
:
3369 if ( fOwner
.fOptions
.warnCommons() )
3370 fprintf(stderr
, "ld: replacing defintion of %s from dylib %s with common symbol from %s\n",
3371 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3374 case Options::kCommonsConflictsDylibsError
:
3375 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
3376 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3379 case kExternAndExtern
:
3380 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3381 case kExternAndExternWeak
:
3382 // keep strong dylib atom, ignore weak one
3385 case kExternAndAbsolute
:
3386 // replace external atom with absolute one
3388 case kExternWeakAndReg
:
3389 // replace existing weak external with regular
3391 case kExternWeakAndWeak
:
3392 // replace existing weak external with weak (let dyld decide at runtime which to use)
3394 case kExternWeakAndTent
:
3395 // a tentative definition and a dylib definition, so commons-mode decides how to handle
3396 switch ( fOwner
.fOptions
.commonsMode() ) {
3397 case Options::kCommonsIgnoreDylibs
:
3398 if ( fOwner
.fOptions
.warnCommons() )
3399 fprintf(stderr
, "ld: using common symbol %s from %s and ignoring defintion from dylib %s\n",
3400 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3402 case Options::kCommonsOverriddenByDylibs
:
3403 if ( fOwner
.fOptions
.warnCommons() )
3404 fprintf(stderr
, "ld: replacing defintion of %s from dylib %s with common symbol from %s\n",
3405 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
3408 case Options::kCommonsConflictsDylibsError
:
3409 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
3410 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3413 case kExternWeakAndExtern
:
3414 // replace existing weak external with external
3416 case kExternWeakAndExternWeak
:
3417 // keep existing external weak
3420 case kExternWeakAndAbsolute
:
3421 // replace existing weak external with absolute
3423 case kAbsoluteAndReg
:
3424 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3425 case kAbsoluteAndWeak
:
3426 // ignore new weak atom, because we already have a non-weak one
3429 case kAbsoluteAndTent
:
3430 // ignore new tentative atom, because we already have a regular one
3433 case kAbsoluteAndExtern
:
3434 // ignore external atom, because we already have a one
3437 case kAbsoluteAndExternWeak
:
3438 // ignore external atom, because we already have a one
3441 case kAbsoluteAndAbsolute
:
3442 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3446 if ( (existingAtom
!= NULL
) && (newAtom
.getScope() != existingAtom
->getScope()) ) {
3447 fprintf(stderr
, "ld: warning %s has different visibility (%d) in %s and (%d) in %s\n",
3448 newAtom
.getDisplayName(), newAtom
.getScope(), newAtom
.getFile()->getPath(), existingAtom
->getScope(), existingAtom
->getFile()->getPath());
3451 fTable
[name
] = &newAtom
;
3452 if ( existingAtom
!= NULL
)
3453 fOwner
.fDeadAtoms
.insert(existingAtom
);
3456 fOwner
.fDeadAtoms
.insert(&newAtom
);
3463 ObjectFile::Atom
* Linker::SymbolTable::find(const char* name
)
3465 Mapper::iterator pos
= fTable
.find(name
);
3466 if ( pos
!= fTable
.end() ) {
3473 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
)
3475 for (Mapper::iterator it
=fTable
.begin(); it
!= fTable
.end(); it
++) {
3476 if ( (it
->second
== NULL
) || (andWeakDefintions
&& (it
->second
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
)) ) {
3477 undefines
.push_back(it
->first
);
3485 bool Linker::AtomSorter::operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
)
3487 if ( left
== right
)
3490 // first sort by section order (which is already sorted by segment)
3491 unsigned int leftSectionIndex
= left
->getSection()->getIndex();
3492 unsigned int rightSectionIndex
= right
->getSection()->getIndex();
3493 if ( leftSectionIndex
!= rightSectionIndex
)
3494 return (leftSectionIndex
< rightSectionIndex
);
3496 // if a -order_file is specified, then sorting is altered to sort those symbols first
3497 if ( fOverriddenOrdinalMap
!= NULL
) {
3498 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator leftPos
= fOverriddenOrdinalMap
->find(left
);
3499 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator rightPos
= fOverriddenOrdinalMap
->find(right
);
3500 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator end
= fOverriddenOrdinalMap
->end();
3501 if ( leftPos
!= end
) {
3502 if ( rightPos
!= end
) {
3503 // both left and right are overridden, so compare overridden ordinals
3504 return leftPos
->second
< rightPos
->second
;
3507 // left is overridden and right is not, so left < right
3512 if ( rightPos
!= end
) {
3513 // right is overridden and left is not, so right < left
3517 // neither are overridden, do default sort
3518 // fall into default sorting below
3523 // the __common section can have real or tentative definitions
3524 // we want the real ones to sort before tentative ones
3525 bool leftIsTent
= (left
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
);
3526 bool rightIsTent
= (right
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
);
3527 if ( leftIsTent
!= rightIsTent
)
3530 // lastly sort by atom ordinal. this is already sorted by .o order
3531 return left
->getOrdinal() < right
->getOrdinal();
3535 int main(int argc
, const char* argv
[])
3537 const char* archName
= NULL
;
3538 bool showArch
= false;
3539 bool archInferred
= false;
3541 // create linker object given command line arguments
3542 Linker
ld(argc
, argv
);
3544 // save error message prefix
3545 archName
= ld
.architectureName();
3546 archInferred
= ld
.isInferredArchitecture();
3547 showArch
= ld
.showArchitectureInErrors();
3549 // open all input files
3558 catch (const char* msg
) {
3560 fprintf(stderr
, "ld: %s for inferred architecture %s\n", msg
, archName
);
3561 else if ( showArch
)
3562 fprintf(stderr
, "ld: %s for architecture %s\n", msg
, archName
);
3564 fprintf(stderr
, "ld: %s\n", msg
);