1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
2 * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 // start temp HACK for cross builds
25 extern "C" double log2 ( double );
27 // end temp HACK for cross builds
31 #include <sys/types.h>
34 #include <sys/sysctl.h>
39 #include <mach/mach_time.h>
40 #include <mach/vm_statistics.h>
41 #include <mach/mach_init.h>
42 #include <mach/mach_host.h>
52 #include <ext/hash_map>
54 #include <AvailabilityMacros.h>
56 #include "configure.h"
59 #include "ObjectFile.h"
61 #include "MachOReaderRelocatable.hpp"
62 #include "ArchiveReader.hpp"
63 #include "MachOReaderDylib.hpp"
64 #include "MachOWriterExecutable.hpp"
68 #include "LTOReader.hpp"
71 #include "OpaqueSection.hpp"
77 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) < 0); }
83 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
86 class Section
: public ObjectFile::Section
89 static Section
* find(const char* sectionName
, const char* segmentName
, bool zeroFill
, bool untrustedZeroFill
, bool createIfNeeded
=true);
90 static void assignIndexes(bool objfile
);
91 const char* getName() { return fSectionName
; }
93 Section(const char* sectionName
, const char* segmentName
, bool zeroFill
, bool untrustedZeroFill
);
96 static int segmentOrdinal(const char* segName
);
97 bool operator()(Section
* left
, Section
* right
);
100 typedef __gnu_cxx::hash_map
<const char*, uint32_t, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToOrdinal
;
101 typedef __gnu_cxx::hash_map
<const char*, class Section
*, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToSection
;
102 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
104 char fSectionName
[18];
105 char fSegmentName
[18];
107 bool fUntrustedZeroFill
;
109 static NameToSection fgMapping
;
110 static std::vector
<Section
*> fgSections
;
111 static NameToOrdinal fgSegmentDiscoverOrder
;
112 static bool fgMakingObjectFile
;
115 Section::NameToSection
Section::fgMapping
;
116 std::vector
<Section
*> Section::fgSections
;
117 Section::NameToOrdinal
Section::fgSegmentDiscoverOrder
;
118 bool Section::fgMakingObjectFile
;
120 Section::Section(const char* sectionName
, const char* segmentName
, bool zeroFill
, bool untrustedZeroFill
)
121 : fZeroFill(zeroFill
), fUntrustedZeroFill(untrustedZeroFill
)
123 strlcpy(fSectionName
, sectionName
, sizeof(fSectionName
));
124 strlcpy(fSegmentName
, segmentName
, sizeof(fSegmentName
));
126 this->fIndex
= fgSections
.size() + 20; // room for 20 standard sections
127 // special placement of some sections
128 if ( strcmp(segmentName
, "__TEXT") == 0 ) {
129 // sort mach header and load commands to start of TEXT
130 if ( strcmp(sectionName
, "._mach_header") == 0 )
132 else if ( strcmp(sectionName
, "._load_commands") == 0 )
134 else if ( strcmp(sectionName
, "._load_cmds_pad") == 0 )
136 // sort __text after load commands
137 else if ( strcmp(sectionName
, "__text") == 0 )
139 // sort arm/ppc stubs after text to make branch islands feasible
140 else if ( strcmp(sectionName
, "__picsymbolstub4") == 0 )
142 else if ( strcmp(sectionName
, "__symbol_stub4") == 0 )
144 else if ( strcmp(sectionName
, "__picsymbolstub1") == 0 )
146 else if ( strcmp(sectionName
, "__symbol_stub1") == 0 )
148 // sort fast arm stubs to end of __TEXT to be close to lazy pointers
149 else if ( strcmp(sectionName
, "__symbolstub1") == 0 )
150 this->fIndex
= INT_MAX
;
151 // sort unwind info to end of segment
152 else if ( strcmp(sectionName
, "__eh_frame") == 0 )
153 this->fIndex
= INT_MAX
-1;
154 else if ( strcmp(sectionName
, "__unwind_info") == 0 )
155 this->fIndex
= INT_MAX
-2;
156 else if ( strcmp(sectionName
, "__gcc_except_tab") == 0 )
157 this->fIndex
= INT_MAX
-3;
159 else if ( strcmp(segmentName
, "__DATA") == 0 ) {
160 // sort arm lazy symbol pointers that must be at start of __DATA
161 if ( strcmp(sectionName
, "__lazy_symbol") == 0 )
163 // sort sections dyld will touch to start of segment
164 else if ( strcmp(sectionName
, "__dyld") == 0 )
166 else if ( strcmp(sectionName
, "__program_vars") == 0 )
168 else if ( strcmp(sectionName
, "__mod_init_func") == 0 )
170 else if ( strcmp(sectionName
, "__nl_symbol_ptr") == 0 )
172 else if ( strcmp(sectionName
, "__la_symbol_ptr") == 0 )
174 else if ( strcmp(sectionName
, "__const") == 0 )
176 else if ( strcmp(sectionName
, "__cfstring") == 0 )
178 else if ( strcmp(sectionName
, "__gcc_except_tab") == 0 )
180 else if ( strcmp(sectionName
, "__objc_data") == 0 )
182 else if ( strcmp(sectionName
, "__objc_msgrefs") == 0 )
184 else if ( strcmp(sectionName
, "__objc_protorefs") == 0 )
186 else if ( strcmp(sectionName
, "__objc_selrefs") == 0 )
188 else if ( strcmp(sectionName
, "__objc_classrefs") == 0 )
190 else if ( strcmp(sectionName
, "__objc_superrefs") == 0 )
192 else if ( strcmp(sectionName
, "__objc_const") == 0 )
194 else if ( strcmp(sectionName
, "__objc_classlist") == 0 )
196 else if ( strcmp(sectionName
, "__objc_nlclslist") == 0 )
198 else if ( strcmp(sectionName
, "__objc_catlist") == 0 )
200 else if ( strcmp(sectionName
, "__objc_protolist") == 0 )
202 else if ( strcmp(sectionName
, "__objc_imageinfo") == 0 )
204 else if ( strcmp(sectionName
, "__huge") == 0 )
205 this->fIndex
= INT_MAX
;
209 //fprintf(stderr, "new Section(%s, %s) => %p, %u\n", sectionName, segmentName, this, this->getIndex());
212 Section
* Section::find(const char* sectionName
, const char* segmentName
, bool zeroFill
, bool untrustedZeroFill
, bool createIfNeeded
)
214 NameToSection::iterator pos
= fgMapping
.find(sectionName
);
215 if ( pos
!= fgMapping
.end() ) {
216 if ( strcmp(pos
->second
->fSegmentName
, segmentName
) == 0 ) {
217 if ( !untrustedZeroFill
&& pos
->second
->fUntrustedZeroFill
) {
218 pos
->second
->fZeroFill
= zeroFill
;
219 pos
->second
->fUntrustedZeroFill
= false;
223 // otherwise same section name is used in different segments, look slow way
224 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++) {
225 if ( (strcmp((*it
)->fSectionName
, sectionName
) == 0) && (strcmp((*it
)->fSegmentName
, segmentName
) == 0) )
230 if ( !createIfNeeded
)
233 // does not exist, so make a new one
234 Section
* sect
= new Section(sectionName
, segmentName
, zeroFill
, untrustedZeroFill
);
235 fgMapping
[sectionName
] = sect
;
236 fgSections
.push_back(sect
);
238 if ( (strcmp(sectionName
, "__text") == 0) && (strcmp(segmentName
, "__TEXT") == 0) ) {
239 // special case __StaticInit to be right after __text
240 find("__StaticInit", "__TEXT", false, true);
243 // remember segment discovery order
244 if ( fgSegmentDiscoverOrder
.find(segmentName
) == fgSegmentDiscoverOrder
.end() )
245 fgSegmentDiscoverOrder
[segmentName
] = fgSegmentDiscoverOrder
.size();
250 int Section::Sorter::segmentOrdinal(const char* segName
)
252 if ( strcmp(segName
, "__HEADER") == 0 )
254 if ( strcmp(segName
, "__PAGEZERO") == 0 )
256 if ( strcmp(segName
, "__TEXT") == 0 )
258 if ( strcmp(segName
, "__DATA") == 0 )
259 return (fgMakingObjectFile
? 6 : 3); // __DATA is last in .o files and here in FLI
260 if ( strcmp(segName
, "__OBJC") == 0 )
262 if ( strcmp(segName
, "__IMPORT") == 0 )
264 if ( strcmp(segName
, "__LINKEDIT") == 0 )
265 return INT_MAX
; // linkedit segment should always sort last
267 return fgSegmentDiscoverOrder
[segName
]+6;
271 bool Section::Sorter::operator()(Section
* left
, Section
* right
)
273 // Segment is primary sort key
274 int leftSegOrdinal
= segmentOrdinal(left
->fSegmentName
);
275 int rightSegOrdinal
= segmentOrdinal(right
->fSegmentName
);
276 if ( leftSegOrdinal
< rightSegOrdinal
)
278 if ( leftSegOrdinal
> rightSegOrdinal
)
281 // zerofill section sort to the end
282 if ( !left
->fZeroFill
&& right
->fZeroFill
)
284 if ( left
->fZeroFill
&& !right
->fZeroFill
)
287 // section discovery order is last sort key
288 return left
->fIndex
< right
->fIndex
;
291 void Section::assignIndexes(bool objfile
)
293 //printf("unsorted sections:\n");
294 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
295 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
299 Section::fgMakingObjectFile
= objfile
;
300 std::sort(fgSections
.begin(), fgSections
.end(), Section::Sorter());
302 // assign correct section ordering to each Section object
303 unsigned int newOrder
= 1;
304 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++)
305 (*it
)->fIndex
= newOrder
++;
307 //printf("sorted sections:\n");
308 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
309 // printf("section: index=%d, obj=%p, name=%s\n", (*it)->fIndex, (*it), (*it)->fSectionName);
313 class Linker
: public ObjectFile::Reader::DylibHander
{
315 Linker(int argc
, const char* argv
[]);
317 const char* getArchPrefix();
318 const char* architectureName();
319 bool showArchitectureInErrors();
320 bool isInferredArchitecture();
321 void createReaders();
323 void addInputFile(ObjectFile::Reader
* reader
, const Options::FileInfo
& );
324 void setOutputFile(ExecutableFile::Writer
* writer
);
328 // implemenation from ObjectFile::Reader::DylibHander
329 virtual ObjectFile::Reader
* findDylib(const char* installPath
, const char* fromPath
);
332 struct WhyLiveBackChain
334 WhyLiveBackChain
* previous
;
335 ObjectFile::Atom
* referer
;
338 ObjectFile::Reader
* createReader(const Options::FileInfo
&);
339 const char* fileArch(const void* p
);
340 void addAtom(ObjectFile::Atom
& atom
);
341 void addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
);
342 void buildAtomList();
344 void processDylibs();
345 void markDead(ObjectFile::Atom
* atom
);
346 void updateConstraints(ObjectFile::Reader
* reader
);
347 void loadAndResolve();
348 void processDTrace();
350 void addSynthesizedAtoms();
351 void loadUndefines();
352 void checkUndefines();
353 void resolveReferences();
354 void deadStripResolve();
355 void addLiveRoot(const char* name
);
356 void moveToFrontOfSection(ObjectFile::Atom
* atom
);
357 ObjectFile::Atom
* findAtom(const Options::OrderedSymbol
& pair
);
358 void logArchive(ObjectFile::Reader
* reader
);
362 void writeDotOutput();
363 static bool minimizeStab(ObjectFile::Reader::Stab
& stab
);
364 static const char* truncateStabString(const char* str
);
365 void collectDebugInfo();
367 ObjectFile::Atom
* entryPoint(bool orInit
, bool searchArchives
=false);
368 ObjectFile::Atom
* dyldClassicHelper();
369 ObjectFile::Atom
* dyldCompressedHelper();
370 ObjectFile::Atom
* dyldLazyLibraryHelper();
371 const char* assureFullPath(const char* path
);
372 void markLive(ObjectFile::Atom
& atom
, Linker::WhyLiveBackChain
* previous
);
373 void collectStabs(ObjectFile::Reader
* reader
, std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
);
374 void synthesizeDebugNotes(std::vector
<class ObjectFile::Atom
*>& allAtomsByReader
);
375 void printStatistics();
376 void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
);
377 char* commatize(uint64_t in
, char* out
);
378 void getVMInfo(vm_statistics_data_t
& info
);
379 cpu_type_t
inferArchitecture();
380 void checkDylibClientRestrictions(ObjectFile::Reader
* reader
);
381 void logDylib(ObjectFile::Reader
* reader
, bool indirect
);
383 void resolve(ObjectFile::Reference
* reference
);
384 void resolveFrom(ObjectFile::Reference
* reference
);
385 std::vector
<class ObjectFile::Atom
*>* addJustInTimeAtoms(const char* name
, bool searchDylibs
, bool searchArchives
, bool okToMakeProxy
);
386 void addJustInTimeAtomsAndMarkLive(const char* name
);
388 ObjectFile::Reader
* addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
389 ObjectFile::Reader
* addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
390 ObjectFile::Reader
* addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
392 void logTraceInfo(const char* format
, ...);
398 typedef __gnu_cxx::hash_map
<const char*, ObjectFile::Atom
*, __gnu_cxx::hash
<const char*>, CStringEquals
> Mapper
;
400 SymbolTable(Linker
&);
401 void require(const char* name
);
402 bool add(ObjectFile::Atom
& atom
);
403 ObjectFile::Atom
* find(const char* name
);
404 void erase(const char* name
);
405 unsigned int getRequireCount() { return fRequireCount
; }
406 void getUndefinesNames(std::vector
<const char*>& undefines
);
407 void getTentativesNames(std::vector
<const char*>& tents
);
408 bool hasExternalTentativeDefinitions() { return fHasExternalTentativeDefinitions
; }
409 bool hasExternalWeakDefinitions() { return fHasExternalWeakDefinitions
; }
410 void setHasExternalWeakDefinitions(bool value
) { fHasExternalWeakDefinitions
= value
; }
411 uint32_t dylibSymbolCount() { return fDylibSymbolCount
; }
412 Mapper::iterator
begin() { return fTable
.begin(); }
413 Mapper::iterator
end() { return fTable
.end(); }
418 unsigned int fRequireCount
;
419 bool fHasExternalTentativeDefinitions
;
420 bool fHasExternalWeakDefinitions
;
421 uint32_t fDylibSymbolCount
;
427 AtomSorter(std::map
<const ObjectFile::Atom
*, uint32_t>* map
, std::set
<const ObjectFile::Atom
*>& inits
,
428 std::set
<const ObjectFile::Atom
*>& terms
) :
429 fOverriddenOrdinalMap(map
), fInitializerSet(inits
), fTerminatorSet(terms
) {}
430 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
);
432 std::map
<const ObjectFile::Atom
*, uint32_t>* fOverriddenOrdinalMap
;
433 std::set
<const ObjectFile::Atom
*>& fInitializerSet
;
434 std::set
<const ObjectFile::Atom
*>& fTerminatorSet
;
437 typedef std::map
<const char*, uint32_t, CStringComparor
> SectionOrder
;
439 struct DTraceProbeInfo
{
440 DTraceProbeInfo(const ObjectFile::Atom
* a
, uint32_t o
, const char* n
) : atom(a
), offset(o
), probeName(n
) {}
441 const ObjectFile::Atom
* atom
;
443 const char* probeName
;
445 typedef __gnu_cxx::hash_map
<const char*, std::vector
<DTraceProbeInfo
>, __gnu_cxx::hash
<const char*>, CStringEquals
> ProviderToProbes
;
446 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> CStringSet
;
447 typedef __gnu_cxx::hash_map
<const char*, ObjectFile::Reader
*, __gnu_cxx::hash
<const char*>, CStringEquals
> InstallNameToReader
;
449 struct IndirectLibrary
{
452 ObjectFile::Reader
* reader
;
453 std::set
<ObjectFile::Reader
*> parents
;
454 ObjectFile::Reader
* reExportedViaDirectLibrary
;
457 ObjectFile::Reader
* findDirectLibraryWhichReExports(struct IndirectLibrary
& indirectLib
);
460 SymbolTable fGlobalSymbolTable
;
461 uint32_t fNextInputOrdinal
;
462 std::vector
<class ObjectFile::Reader
*> fInputFiles
;
463 ExecutableFile::Writer
* fOutputFile
;
464 InstallNameToReader fDylibMap
;
465 std::map
<ObjectFile::Reader
*,LibraryOptions
> fDylibOptionsMap
;
466 std::set
<ObjectFile::Reader
*> fDylibsProcessed
;
467 ObjectFile::Reader
* fBundleLoaderReader
;
468 std::vector
<class ObjectFile::Reader
*> fReadersThatHaveSuppliedAtoms
;
469 std::vector
<class ObjectFile::Atom
*> fAllAtoms
;
470 std::set
<class ObjectFile::Reader
*> fArchiveReaders
;
471 std::set
<class ObjectFile::Reader
*> fArchiveReadersLogged
;
472 std::set
<class ObjectFile::Atom
*> fDeadAtoms
;
473 std::set
<ObjectFile::Atom
*> fLiveAtoms
;
474 std::set
<ObjectFile::Atom
*> fLiveRootAtoms
;
475 std::set
<const ObjectFile::Atom
*> fInitializerAtoms
;
476 std::set
<const ObjectFile::Atom
*> fTerminatorAtoms
;
477 std::set
<const ObjectFile::Atom
*> fRegularDefAtomsThatOverrideADylibsWeakDef
;
478 std::vector
<class ObjectFile::Reader::Stab
> fStabs
;
479 std::vector
<class ObjectFile::Atom
*> fAtomsWithUnresolvedReferences
;
480 std::set
<class ObjectFile::Atom
*> fAtomsOverriddenByLateLoads
;
481 bool fInitialLoadsDone
;
484 SectionOrder fSectionOrder
;
485 cpu_type_t fArchitecture
;
486 const char* fArchitectureName
;
487 bool fArchitectureInferred
;
488 bool fDirectLibrariesComplete
;
489 bool fBiggerThanTwoGigOutput
;
490 uint64_t fOutputFileSize
;
491 uint64_t fTotalZeroFillSize
;
494 uint64_t fStartCreateReadersTime
;
495 uint64_t fStartCreateWriterTime
;
496 uint64_t fStartBuildAtomsTime
;
497 uint64_t fStartLoadAndResolveTime
;
498 uint64_t fStartSortTime
;
499 uint64_t fStartDebugTime
;
500 uint64_t fStartWriteTime
;
502 uint64_t fTotalObjectSize
;
503 uint64_t fTotalArchiveSize
;
504 uint32_t fTotalObjectLoaded
;
505 uint32_t fTotalArchivesLoaded
;
506 uint32_t fTotalDylibsLoaded
;
507 vm_statistics_data_t fStartVMInfo
;
508 ObjectFile::Reader::ObjcConstraint fCurrentObjCConstraint
;
509 ObjectFile::Reader::CpuConstraint fCurrentCpuConstraint
;
510 bool fObjcReplacmentClasses
;
511 bool fAllDirectDylibsLoaded
;
515 Linker::Linker(int argc
, const char* argv
[])
516 : fOptions(argc
, argv
), fGlobalSymbolTable(*this), fNextInputOrdinal(1), fOutputFile(NULL
), fBundleLoaderReader(NULL
),
517 fInitialLoadsDone(false), fCreateUUID(fOptions
.outputKind() != Options::kObjectFile
), fCanScatter(true),
518 fArchitecture(0), fArchitectureInferred(false), fDirectLibrariesComplete(false), fBiggerThanTwoGigOutput(false),
519 fOutputFileSize(0), fTotalZeroFillSize(0), fTotalSize(0), fTotalObjectSize(0),
520 fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0),
521 fCurrentObjCConstraint(ObjectFile::Reader::kObjcNone
), fCurrentCpuConstraint(ObjectFile::Reader::kCpuAny
),
522 fObjcReplacmentClasses(false), fAllDirectDylibsLoaded(false)
524 fStartTime
= mach_absolute_time();
525 if ( fOptions
.printStatistics() )
526 getVMInfo(fStartVMInfo
);
528 fArchitecture
= fOptions
.architecture();
529 if ( fArchitecture
== 0 ) {
530 // -arch not specified, scan .o files to figure out what it should be
531 fArchitecture
= inferArchitecture();
532 fArchitectureInferred
= true;
534 switch (fArchitecture
) {
535 case CPU_TYPE_POWERPC
:
536 fArchitectureName
= "ppc";
538 case CPU_TYPE_POWERPC64
:
539 fArchitectureName
= "ppc64";
542 fArchitectureName
= "i386";
544 case CPU_TYPE_X86_64
:
545 fArchitectureName
= "x86_64";
548 fArchitectureName
= "arm";
549 if ( fOptions
.preferSubArchitecture() ) {
550 switch ( fOptions
.subArchitecture() ) {
551 case CPU_SUBTYPE_ARM_V4T
:
552 fArchitectureName
= "armv4t";
554 case CPU_SUBTYPE_ARM_V5TEJ
:
555 fArchitectureName
= "armv5";
557 case CPU_SUBTYPE_ARM_V6
:
558 fArchitectureName
= "armv6";
560 case CPU_SUBTYPE_ARM_V7
:
561 fArchitectureName
= "armv7";
567 fArchitectureName
= "unknown architecture";
572 const char* Linker::architectureName()
574 return fArchitectureName
;
577 bool Linker::showArchitectureInErrors()
579 return fOptions
.printArchPrefix();
582 bool Linker::isInferredArchitecture()
584 return fArchitectureInferred
;
587 cpu_type_t
Linker::inferArchitecture()
589 // scan all input files, looking for a thin .o file.
590 // the first one found is presumably the architecture to link
591 uint8_t buffer
[sizeof(mach_header_64
)];
592 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
593 for (std::vector
<Options::FileInfo
>::iterator it
= files
.begin(); it
!= files
.end(); ++it
) {
594 int fd
= ::open(it
->path
, O_RDONLY
, 0);
596 ssize_t amount
= read(fd
, buffer
, sizeof(buffer
));
598 if ( amount
>= (ssize_t
)sizeof(buffer
) ) {
599 if ( mach_o::relocatable::Reader
<ppc
>::validFile(buffer
) ) {
600 //warning("-arch not used, infering -arch ppc based on %s", it->path);
601 return CPU_TYPE_POWERPC
;
603 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(buffer
) ) {
604 //warning("-arch not used, infering -arch ppc64 based on %s", it->path);
605 return CPU_TYPE_POWERPC64
;
607 else if ( mach_o::relocatable::Reader
<x86
>::validFile(buffer
) ) {
608 //warning("-arch not used, infering -arch i386 based on %s", it->path);
609 return CPU_TYPE_I386
;
611 else if ( mach_o::relocatable::Reader
<x86_64
>::validFile(buffer
) ) {
612 //warning("-arch not used, infering -arch x86_64 based on %s", it->path);
613 return CPU_TYPE_X86_64
;
615 else if ( mach_o::relocatable::Reader
<arm
>::validFile(buffer
) ) {
616 //warning("-arch not used, infering -arch arm based on %s", it->path);
623 // no thin .o files found, so default to same architecture this was built as
624 warning("-arch not specified");
626 return CPU_TYPE_POWERPC
;
628 return CPU_TYPE_I386
;
630 return CPU_TYPE_POWERPC64
;
632 return CPU_TYPE_X86_64
;
636 #error unknown default architecture
641 void Linker::addInputFile(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
)
643 fInputFiles
.push_back(reader
);
644 fDylibOptionsMap
[reader
] = info
.options
;
647 void Linker::setOutputFile(ExecutableFile::Writer
* writer
)
649 fOutputFile
= writer
;
655 InSet(std::set
<ObjectFile::Atom
*>& deadAtoms
) : fDeadAtoms(deadAtoms
) {}
657 bool operator()(ObjectFile::Atom
*& atom
) const {
658 return ( fDeadAtoms
.count(atom
) != 0 );
662 std::set
<ObjectFile::Atom
*>& fDeadAtoms
;
665 void Linker::loadAndResolve()
667 fStartLoadAndResolveTime
= mach_absolute_time();
668 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
669 // without dead-code-stripping:
670 // find atoms to resolve all undefines
671 this->loadUndefines();
672 // verify nothing is missing
673 this->checkUndefines();
674 // once all undefines fulfill, then bind all references
675 this->resolveReferences();
676 // remove atoms weak atoms that have been overridden
677 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fDeadAtoms
)), fAllAtoms
.end());
680 // with dead code stripping:
681 // start binding references from roots,
682 this->deadStripResolve();
683 // verify nothing is missing
684 this->checkUndefines();
688 void Linker::addSynthesizedAtoms()
690 // give write a chance to synthesize stub, GOT, and lazy pointer atoms
691 std::vector
<class ObjectFile::Atom
*> newAtoms
;
692 fOutputFile
->addSynthesizedAtoms(fAllAtoms
, this->dyldClassicHelper(),
693 this->dyldCompressedHelper(), this->dyldLazyLibraryHelper(),
694 fBiggerThanTwoGigOutput
,
695 fGlobalSymbolTable
.dylibSymbolCount(),
698 // add all newly created atoms to fAllAtoms and update symbol table
699 this->addAtoms(newAtoms
);
702 void Linker::optimize()
704 // give each reader a chance to do any optimizations
705 bool didSomething
= false;
706 std::vector
<class ObjectFile::Atom
*> newAtoms
;
707 std::vector
<const char *> additionalUndefines
;
708 std::vector
<class ObjectFile::Atom
*> newlyDeadAtoms
;
709 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
710 didSomething
|= (*it
)->optimize(fAllAtoms
, newAtoms
, additionalUndefines
, fDeadAtoms
, newlyDeadAtoms
, fNextInputOrdinal
,
711 fOutputFile
, entryPoint(true), fOptions
.llvmOptions(),
712 fOptions
.allGlobalsAreDeadStripRoots(), (int)fOptions
.outputKind(), fOptions
.verbose(),
713 fOptions
.saveTempFiles(), fOptions
.getOutputFilePath(), fOptions
.positionIndependentExecutable(),
714 fOptions
.allowTextRelocs());
717 // only do next steps if some optimization was actually done
718 if ( didSomething
) {
720 if ( fOptions
.deadStrip() != Options::kDeadStripOff
) {
721 for(std::vector
<class ObjectFile::Atom
*>::iterator itr
= newAtoms
.begin(); itr
!= newAtoms
.end(); ++itr
) {
722 ObjectFile::Atom
* atom
= *itr
;
723 const char* name
= atom
->getName();
724 if ( name
!= NULL
) {
725 ObjectFile::Atom
* existingAtom
= fGlobalSymbolTable
.find(name
);
726 if ( (existingAtom
!= NULL
) && fLiveAtoms
.count(existingAtom
) == 0 ) {
727 // While dead code stripping, the atoms were not removed from fGlobalSymbolTable
728 // for performance reasons. Normally, libLTO will never recreate an atom
729 // that was previously dead stripped away, but if it does remove
730 // the remnents of the previous so the new one can be added
731 fGlobalSymbolTable
.erase(name
);
737 // add all newly created atoms to fAllAtoms and update symbol table
738 this->addAtoms(newAtoms
);
740 // add dead atoms to dead list and remove from fAllAtoms
741 for(std::vector
<class ObjectFile::Atom
*>::iterator itr
= newlyDeadAtoms
.begin(); itr
!= newlyDeadAtoms
.end(); ++itr
)
743 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fDeadAtoms
)), fAllAtoms
.end());
745 // Make sure all atoms have a section. Atoms that were not originally in a mach-o file could
746 // not have their section set until now.
747 for(std::vector
<class ObjectFile::Atom
*>::iterator itr
= fAllAtoms
.begin(); itr
!= fAllAtoms
.end(); ++itr
) {
748 ObjectFile::Atom
*atom
= *itr
;
749 if ( atom
->getSection() == NULL
)
750 atom
->setSection(Section::find(atom
->getSectionName(), atom
->getSegment().getName(), atom
->isZeroFill(), true));
753 // resolve new undefines
754 for(std::vector
<const char*>::iterator riter
= additionalUndefines
.begin(); riter
!= additionalUndefines
.end(); ++riter
) {
755 const char *targetName
= *riter
;
756 //fprintf(stderr, "LTO additional undefine: %s\n", targetName);
757 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
758 if ( target
== NULL
) {
759 // mark that this symbol is needed
760 fGlobalSymbolTable
.require(targetName
);
761 // try to find it in some library
762 this->addJustInTimeAtoms(targetName
, true, true, true);
766 if ( fOptions
.deadStrip() != Options::kDeadStripOff
) {
767 // LTO may optimize away some atoms, so dead stripping must be redone
769 this->deadStripResolve();
770 this->checkUndefines();
773 // LTO may require new library symbols to be loaded, so redo
774 this->checkUndefines();
775 this->resolveReferences();
781 void Linker::adjustScope()
783 // if -exported_symbols_list is used, demoted to hidden, symbols that are not in it
784 if ( fOptions
.hasExportRestrictList() ) {
785 // The use of an -export file means the previous computation of fHasExternalWeakDefinitions could change
786 fGlobalSymbolTable
.setHasExternalWeakDefinitions(false);
787 for(std::vector
<class ObjectFile::Atom
*>::iterator itr
= fAllAtoms
.begin(); itr
!= fAllAtoms
.end(); ++itr
) {
788 ObjectFile::Atom
*atom
= *itr
;
789 ObjectFile::Atom::Scope scope
= atom
->getScope();
790 const char* name
= atom
->getName();
791 if ( name
!= NULL
) {
792 if ( scope
== ObjectFile::Atom::scopeGlobal
) {
793 // check for globals that are downgraded to hidden
794 if ( !fOptions
.shouldExport(name
) ) {
795 atom
->setScope(ObjectFile::Atom::scopeLinkageUnit
);
796 //fprintf(stderr, "demote %s to hidden\n", name);
798 else if ( atom
->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition
) {
799 if ( atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn
) {
800 // we do have an exported weak symbol, turn WEAK_DEFINES back on
801 fGlobalSymbolTable
.setHasExternalWeakDefinitions(true);
805 else if ( scope
== ObjectFile::Atom::scopeLinkageUnit
) {
806 // check for hiddens that were requested to be exported
807 if ( fOptions
.hasExportMaskList() && fOptions
.shouldExport(name
) ) {
808 warning("cannot export hidden symbol %s from %s", name
, atom
->getFile()->getPath());
815 // linking is done, so demote hidden symbols to static
816 if ( (fOptions
.outputKind() == Options::kObjectFile
) && fOptions
.keepPrivateExterns() ) {
817 // ld -r -keep_private_externs does not move hidden symbols to static
820 for(std::vector
<class ObjectFile::Atom
*>::iterator itr
= fAllAtoms
.begin(); itr
!= fAllAtoms
.end(); ++itr
) {
821 ObjectFile::Atom
*atom
= *itr
;
822 // <rdar://problem/4637139> hidden common symbols cannot be demoted to static
823 if ( (atom
->getScope() == ObjectFile::Atom::scopeLinkageUnit
) && (atom
->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition
) ) {
824 atom
->setScope(ObjectFile::Atom::scopeTranslationUnit
);
825 //fprintf(stderr, "demote %s to static\n", atom->getDisplayName());
833 this->buildAtomList();
834 this->loadAndResolve();
838 this->processDTrace();
840 this->addSynthesizedAtoms();
841 this->sortSections();
843 this->writeDotOutput();
844 this->collectDebugInfo();
846 this->printStatistics();
848 if ( fOptions
.pauseAtEnd() )
852 void Linker::printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
)
854 static uint64_t sUnitsPerSecond
= 0;
855 if ( sUnitsPerSecond
== 0 ) {
856 struct mach_timebase_info timeBaseInfo
;
857 if ( mach_timebase_info(&timeBaseInfo
) == KERN_SUCCESS
) {
858 sUnitsPerSecond
= 1000000000ULL * timeBaseInfo
.denom
/ timeBaseInfo
.numer
;
859 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
862 if ( partTime
< sUnitsPerSecond
) {
863 uint32_t milliSecondsTimeTen
= (partTime
*10000)/sUnitsPerSecond
;
864 uint32_t milliSeconds
= milliSecondsTimeTen
/10;
865 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
866 uint32_t percent
= percentTimesTen
/10;
867 fprintf(stderr
, "%s: %u.%u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimeTen
-milliSeconds
*10, percent
, percentTimesTen
-percent
*10);
870 uint32_t secondsTimeTen
= (partTime
*10)/sUnitsPerSecond
;
871 uint32_t seconds
= secondsTimeTen
/10;
872 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
873 uint32_t percent
= percentTimesTen
/10;
874 fprintf(stderr
, "%s: %u.%u seconds (%u.%u%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10);
878 char* Linker::commatize(uint64_t in
, char* out
)
882 sprintf(rawNum
, "%llu", in
);
883 const int rawNumLen
= strlen(rawNum
);
884 for(int i
=0; i
< rawNumLen
-1; ++i
) {
886 if ( ((rawNumLen
-i
) % 3) == 1 )
889 *out
++ = rawNum
[rawNumLen
-1];
894 void Linker::getVMInfo(vm_statistics_data_t
& info
)
896 mach_msg_type_number_t count
= sizeof(vm_statistics_data_t
) / sizeof(natural_t
);
897 kern_return_t error
= host_statistics(mach_host_self(), HOST_VM_INFO
,
898 (host_info_t
)&info
, &count
);
899 if (error
!= KERN_SUCCESS
) {
900 bzero(&info
, sizeof(vm_statistics_data_t
));
904 void Linker::printStatistics()
906 fEndTime
= mach_absolute_time();
907 if ( fOptions
.printStatistics() ) {
908 vm_statistics_data_t endVMInfo
;
909 getVMInfo(endVMInfo
);
911 uint64_t totalTime
= fEndTime
- fStartTime
;
912 printTime("ld total time", totalTime
, totalTime
);
913 printTime(" option parsing time", fStartCreateReadersTime
- fStartTime
, totalTime
);
914 printTime(" object file processing",fStartCreateWriterTime
- fStartCreateReadersTime
, totalTime
);
915 printTime(" output file setup", fStartBuildAtomsTime
- fStartCreateWriterTime
, totalTime
);
916 printTime(" build atom list", fStartLoadAndResolveTime
- fStartBuildAtomsTime
, totalTime
);
917 printTime(" resolve references", fStartSortTime
- fStartLoadAndResolveTime
, totalTime
);
918 printTime(" sort output", fStartDebugTime
- fStartSortTime
, totalTime
);
919 printTime(" process debug info", fStartWriteTime
- fStartDebugTime
, totalTime
);
920 printTime(" write output", fEndTime
- fStartWriteTime
, totalTime
);
921 fprintf(stderr
, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo
.pageins
-fStartVMInfo
.pageins
,
922 endVMInfo
.pageouts
-fStartVMInfo
.pageouts
, endVMInfo
.faults
-fStartVMInfo
.faults
);
924 fprintf(stderr
, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded
, commatize(fTotalObjectSize
, temp
));
925 fprintf(stderr
, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded
, commatize(fTotalArchiveSize
, temp
));
926 fprintf(stderr
, "processed %3u dylib files\n", fTotalDylibsLoaded
);
927 fprintf(stderr
, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize
, temp
));
931 inline void Linker::addAtom(ObjectFile::Atom
& atom
)
933 // add to list of all atoms
934 fAllAtoms
.push_back(&atom
);
936 if ( fOptions
.deadStrip() == Options::kDeadStripOff
) {
937 // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later
938 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
939 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
940 ObjectFile::Reference
* reference
= *it
;
941 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
)
942 fGlobalSymbolTable
.require(reference
->getTargetName());
943 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
)
944 fGlobalSymbolTable
.require(reference
->getFromTargetName());
946 // update total size info (except for __ZEROPAGE atom)
947 if ( atom
.getSegment().isContentReadable() ) {
948 fTotalSize
+= atom
.getSize();
949 if ( atom
.isZeroFill() )
950 fTotalZeroFillSize
+= atom
.getSize();
954 if ( atom
.dontDeadStrip() )
955 fLiveRootAtoms
.insert(&atom
);
958 // if in global namespace, add atom itself to symbol table
959 ObjectFile::Atom::Scope scope
= atom
.getScope();
960 const char* name
= atom
.getName();
961 if ( (scope
!= ObjectFile::Atom::scopeTranslationUnit
) && (name
!= NULL
) ) {
962 // add to symbol table
963 fGlobalSymbolTable
.add(atom
);
966 // record section orders so output file can have same order
967 if (atom
.getSectionName()) {
968 bool untrusted
= false;
969 switch ( atom
.getContentType() ) {
970 case ObjectFile::Atom::kSectionStart
:
971 case ObjectFile::Atom::kSectionEnd
:
976 atom
.setSection(Section::find(atom
.getSectionName(), atom
.getSegment().getName(), atom
.isZeroFill(), untrusted
));
981 void Linker::markDead(ObjectFile::Atom
* atom
)
983 //fprintf(stderr, "markDead(%p) %s from %s\n", atom, atom->getDisplayName(), atom->getFile()->getPath());
984 fDeadAtoms
.insert(atom
);
986 // <rdar://problem/6578360> -dead_strip inhibits weak coalescing in no_dead_strip section
987 if ( fLiveRootAtoms
.count(atom
) != 0 ) {
988 fLiveRootAtoms
.erase(atom
);
992 // The kGroupSubordinate reference kind is used to model group comdat.
993 // The "signature" atom in the group has a kGroupSubordinate reference to
994 // all other members of the group. So, if the signature atom is
995 // coalesced away, all other atoms in the group should also be removed.
997 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
998 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
999 ObjectFile::Reference
* ref
= *rit
;
1000 if ( ref
->getKind() == 2 /*kGroupSubordinate*/ ) { // FIX FIX
1001 ObjectFile::Atom
* targetAtom
= &(ref
->getTarget());
1002 //fprintf(stderr, " markDead(%p) subordinate %s\n", targetAtom, targetAtom->getDisplayName());
1003 if ( targetAtom
== NULL
) {
1004 warning("%s has a group reference to %s but is not bound", atom
->getDisplayName(), ref
->getTargetName());
1007 if ( targetAtom
->getScope() != ObjectFile::Atom::scopeTranslationUnit
) {
1008 // ok for .eh symbols to be not static in -r mode
1009 if ( (fOptions
.outputKind() != Options::kObjectFile
) || (strcmp(targetAtom
->getSectionName(), "__eh_frame") != 0) )
1010 warning("%s is in a comdat group but its scope is not static", targetAtom
->getDisplayName());
1012 this->markDead(targetAtom
);
1018 void Linker::updateConstraints(ObjectFile::Reader
* reader
)
1020 // check objc objects were compiled compatibly
1021 ObjectFile::Reader::ObjcConstraint objcAddition
= reader
->getObjCConstraint();
1022 if ( reader
->getInstallPath() == NULL
) {
1024 switch ( objcAddition
) {
1025 case ObjectFile::Reader::kObjcNone
:
1027 case ObjectFile::Reader::kObjcRetainRelease
:
1028 if ( fCurrentObjCConstraint
== ObjectFile::Reader::kObjcGC
)
1029 throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", reader
->getPath());
1030 fCurrentObjCConstraint
= ObjectFile::Reader::kObjcRetainRelease
;
1032 case ObjectFile::Reader::kObjcRetainReleaseOrGC
:
1033 if ( fCurrentObjCConstraint
== ObjectFile::Reader::kObjcNone
)
1034 fCurrentObjCConstraint
= ObjectFile::Reader::kObjcRetainReleaseOrGC
;
1036 case ObjectFile::Reader::kObjcGC
:
1037 if ( fCurrentObjCConstraint
== ObjectFile::Reader::kObjcRetainRelease
)
1038 throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", reader
->getPath());
1039 fCurrentObjCConstraint
= ObjectFile::Reader::kObjcGC
;
1043 if ( reader
->objcReplacementClasses() )
1044 fObjcReplacmentClasses
= true;
1046 // check cpu sub-types for stricter sub-type
1047 fCurrentCpuConstraint
= (ObjectFile::Reader::CpuConstraint
)reader
->updateCpuConstraint(fCurrentCpuConstraint
);
1050 inline void Linker::addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
)
1052 bool scanAll
= fOptions
.readerOptions().fFullyLoadArchives
|| fOptions
.readerOptions().fLoadAllObjcObjectsFromArchives
;
1054 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
.begin(); it
!= atoms
.end(); it
++) {
1055 // usually we only need to get the first atom's reader, but
1056 // with -all_load all atoms from all .o files come come back together
1057 // so we need to scan all atoms
1058 if ( first
|| scanAll
) {
1059 // update fReadersThatHaveSuppliedAtoms
1060 ObjectFile::Reader
* reader
= (*it
)->getFile();
1061 if ( std::find(fReadersThatHaveSuppliedAtoms
.begin(), fReadersThatHaveSuppliedAtoms
.end(), reader
)
1062 == fReadersThatHaveSuppliedAtoms
.end() ) {
1063 fReadersThatHaveSuppliedAtoms
.push_back(reader
);
1064 updateConstraints(reader
);
1067 this->addAtom(**it
);
1072 void Linker::logArchive(ObjectFile::Reader
* reader
)
1074 if ( (fArchiveReaders
.count(reader
) != 0) && (fArchiveReadersLogged
.count(reader
) == 0) ) {
1075 fArchiveReadersLogged
.insert(reader
);
1076 const char* fullPath
= reader
->getPath();
1077 char realName
[MAXPATHLEN
];
1078 if ( realpath(fullPath
, realName
) != NULL
)
1079 fullPath
= realName
;
1080 logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath
);
1085 void Linker::buildAtomList()
1087 fStartBuildAtomsTime
= mach_absolute_time();
1088 // add initial undefines from -u option
1089 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
1090 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++) {
1091 fGlobalSymbolTable
.require(*it
);
1094 // writer can contribute atoms
1095 this->addAtoms(fOutputFile
->getAtoms());
1097 // each reader contributes atoms
1098 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
1099 ObjectFile::Reader
* reader
= *it
;
1100 std::vector
<class ObjectFile::Atom
*>& atoms
= reader
->getAtoms();
1101 this->addAtoms(atoms
);
1102 if ( fOptions
.readerOptions().fTraceArchives
&& (atoms
.size() != 0) )
1106 // extra command line section always at end
1107 std::vector
<Options::ExtraSection
>& extraSections
= fOptions
.extraSections();
1108 for( std::vector
<Options::ExtraSection
>::iterator it
=extraSections
.begin(); it
!= extraSections
.end(); ++it
) {
1109 this->addAtoms((new opaque_section::Reader(it
->segmentName
, it
->sectionName
, it
->path
, it
->data
, it
->dataLen
, fNextInputOrdinal
))->getAtoms());
1110 fNextInputOrdinal
+= it
->dataLen
;
1113 // done with all .o files on command line
1114 // everything loaded from now on is a just-in-time atom
1115 fInitialLoadsDone
= true;
1118 static const char* pathLeafName(const char* path
)
1120 const char* shortPath
= strrchr(path
, '/');
1121 if ( shortPath
== NULL
)
1124 return &shortPath
[1];
1128 void Linker::loadUndefines()
1130 // keep looping until no more undefines were added in last loop
1131 unsigned int undefineCount
= 0xFFFFFFFF;
1132 while ( undefineCount
!= fGlobalSymbolTable
.getRequireCount() ) {
1133 undefineCount
= fGlobalSymbolTable
.getRequireCount();
1134 std::vector
<const char*> undefineNames
;
1135 fGlobalSymbolTable
.getUndefinesNames(undefineNames
);
1136 for(std::vector
<const char*>::iterator it
= undefineNames
.begin(); it
!= undefineNames
.end(); ++it
) {
1137 // load for previous undefine may also have loaded this undefine, so check again
1138 if ( fGlobalSymbolTable
.find(*it
) == NULL
) {
1139 std::vector
<class ObjectFile::Atom
*>* atoms
= this->addJustInTimeAtoms(*it
, true, true, true);
1140 if ( atoms
!= NULL
)
1144 // <rdar://problem/5894163> need to search archives for overrides of common symbols
1145 if ( fGlobalSymbolTable
.hasExternalTentativeDefinitions() ) {
1146 bool searchDylibs
= (fOptions
.commonsMode() == Options::kCommonsOverriddenByDylibs
);
1147 std::vector
<const char*> tentativeDefinitionNames
;
1148 fGlobalSymbolTable
.getTentativesNames(tentativeDefinitionNames
);
1149 for(std::vector
<const char*>::iterator it
= tentativeDefinitionNames
.begin(); it
!= tentativeDefinitionNames
.end(); ++it
) {
1150 // load for previous tentative may also have overridden this tentative, so check again
1151 ObjectFile::Atom
* tent
= fGlobalSymbolTable
.find(*it
);
1152 if ( (tent
!= NULL
) && (tent
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
) ) {
1153 std::vector
<class ObjectFile::Atom
*>* atoms
= this->addJustInTimeAtoms(*it
, searchDylibs
, true, false);
1154 if ( atoms
!= NULL
)
1162 // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
1163 class ExportedObjcClass
1166 ExportedObjcClass(Options
& opt
) : fOptions(opt
) {}
1168 bool operator()(const char* name
) const {
1169 if ( fOptions
.shouldExport(name
) ) {
1170 if ( strncmp(name
, ".objc_class_name_", 17) == 0 )
1172 if ( strncmp(name
, "_OBJC_CLASS_$_", 14) == 0 )
1174 if ( strncmp(name
, "_OBJC_METACLASS_$_", 18) == 0 )
1177 //fprintf(stderr, "%s is not exported\n", name);
1185 void Linker::checkUndefines()
1187 // error out on any remaining undefines
1188 bool doPrint
= true;
1189 bool doError
= true;
1190 switch ( fOptions
.undefinedTreatment() ) {
1191 case Options::kUndefinedError
:
1193 case Options::kUndefinedDynamicLookup
:
1196 case Options::kUndefinedWarning
:
1199 case Options::kUndefinedSuppress
:
1204 std::vector
<const char*> unresolvableUndefines
;
1205 fGlobalSymbolTable
.getUndefinesNames(unresolvableUndefines
);
1207 // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
1208 // ignore unresolved references to Objc class names that are listed in -exported_symbols_list
1209 if ( fOptions
.hasExportRestrictList() )
1210 unresolvableUndefines
.erase(std::remove_if(unresolvableUndefines
.begin(), unresolvableUndefines
.end(), ExportedObjcClass(fOptions
)), unresolvableUndefines
.end());
1212 const int unresolvableCount
= unresolvableUndefines
.size();
1213 int unresolvableExportsCount
= 0;
1214 if ( unresolvableCount
!= 0 ) {
1216 if ( fOptions
.printArchPrefix() )
1217 fprintf(stderr
, "Undefined symbols for architecture %s:\n", fArchitectureName
);
1219 fprintf(stderr
, "Undefined symbols:\n");
1220 for (int i
=0; i
< unresolvableCount
; ++i
) {
1221 const char* name
= unresolvableUndefines
[i
];
1222 fprintf(stderr
, " \"%s\", referenced from:\n", name
);
1223 // scan all atoms for references
1224 bool foundAtomReference
= false;
1225 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1226 ObjectFile::Atom
* atom
= *it
;
1227 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
1228 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1229 ObjectFile::Reference
* reference
= *rit
;
1230 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1231 if ( strcmp(reference
->getTargetName(), name
) == 0 ) {
1232 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
1233 foundAtomReference
= true;
1236 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1237 if ( strcmp(reference
->getFromTargetName(), name
) == 0 ) {
1238 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
1239 foundAtomReference
= true;
1244 // scan command line options
1245 if ( !foundAtomReference
) {
1246 // might be from -init command line option
1247 if ( (fOptions
.initFunctionName() != NULL
) && (strcmp(name
, fOptions
.initFunctionName()) == 0) ) {
1248 fprintf(stderr
, " -init command line option\n");
1250 // or might be from exported symbol option
1251 else if ( fOptions
.hasExportMaskList() && fOptions
.shouldExport(name
) ) {
1252 fprintf(stderr
, " -exported_symbol[s_list] command line option\n");
1255 bool isInitialUndefine
= false;
1256 std::vector
<const char*>& clundefs
= fOptions
.initialUndefines();
1257 for (std::vector
<const char*>::iterator uit
= clundefs
.begin(); uit
!= clundefs
.end(); ++uit
) {
1258 if ( strcmp(*uit
, name
) == 0 ) {
1259 isInitialUndefine
= true;
1263 if ( isInitialUndefine
)
1264 fprintf(stderr
, " -u command line option\n");
1266 ++unresolvableExportsCount
;
1268 // be helpful and check for typos
1269 bool printedStart
= false;
1270 for (SymbolTable::Mapper::iterator sit
=fGlobalSymbolTable
.begin(); sit
!= fGlobalSymbolTable
.end(); ++sit
) {
1271 if ( (sit
->second
!= NULL
) && (strstr(sit
->first
, name
) != NULL
) ) {
1272 if ( ! printedStart
) {
1273 fprintf(stderr
, " (maybe you meant: %s", sit
->first
);
1274 printedStart
= true;
1277 fprintf(stderr
, ", %s ", sit
->first
);
1282 fprintf(stderr
, ")\n");
1286 throw "symbol(s) not found";
1289 // for each tentative definition in symbol table look for dylib that exports same symbol name
1290 if ( fGlobalSymbolTable
.hasExternalTentativeDefinitions() ) {
1291 for (SymbolTable::Mapper::iterator it
=fGlobalSymbolTable
.begin(); it
!= fGlobalSymbolTable
.end(); ++it
) {
1292 ObjectFile::Atom
* atom
= it
->second
;
1293 if ( (atom
!= NULL
) && (atom
->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition
)
1294 && (atom
->getScope() == ObjectFile::Atom::scopeGlobal
) ) {
1295 // look for dylibs that export same name as used by global tentative definition
1296 addJustInTimeAtoms(atom
->getName(), true, false, false);
1302 // record any overrides of weak symbols any linked dylib
1303 for (SymbolTable::Mapper::iterator it
=fGlobalSymbolTable
.begin(); it
!= fGlobalSymbolTable
.end(); ++it
) {
1304 ObjectFile::Atom
* atom
= it
->second
;
1305 if ( (atom
!= NULL
) && (atom
->getDefinitionKind()==ObjectFile::Atom::kRegularDefinition
)
1306 && (atom
->getScope() == ObjectFile::Atom::scopeGlobal
) ) {
1307 const char* name
= atom
->getName();
1308 //fprintf(stderr, "looking for dylibs with a weak %s\n", name);
1309 // look for dylibs with weak exports of the same name
1310 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1311 ObjectFile::Reader
* reader
= it
->second
;
1312 if ( reader
->hasWeakExternals() ) {
1313 std::vector
<class ObjectFile::Atom
*>* dylibAtoms
= reader
->getJustInTimeAtomsFor(name
);
1314 if ( dylibAtoms
!= NULL
) {
1315 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1316 // if this is a weak definition in a dylib
1317 if ( (dylibAtoms
->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1318 fRegularDefAtomsThatOverrideADylibsWeakDef
.insert(atom
);
1330 std::vector
<class ObjectFile::Atom
*>* Linker::addJustInTimeAtoms(const char* name
, bool searchDylibs
, bool searchArchives
, bool okToMakeProxy
)
1332 //fprintf(stderr, "addJustInTimeAtoms(%s, searchDylibs=%d, searchArchives=%d)\n", name, searchDylibs, searchArchives );
1333 // when creating final linked image, writer gets first chance
1334 if ( fOptions
.outputKind() != Options::kObjectFile
) {
1335 std::vector
<class ObjectFile::Atom
*>* atoms
= fOutputFile
->getJustInTimeAtomsFor(name
);
1336 if ( atoms
!= NULL
) {
1337 this->addAtoms(*atoms
);
1338 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
1339 return atoms
; // found a definition, no need to search anymore
1343 // give readers a chance
1344 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
1345 ObjectFile::Reader
* reader
= *it
;
1346 if ( reader
!= NULL
) {
1347 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
1348 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
1349 //fprintf(stderr, "addJustInTimeAtoms(%s), looking in reader %s\n", name, reader->getPath() );
1350 bool isDylibReader
= (reader
->getInstallPath() != NULL
);
1351 if ( isDylibReader
? searchDylibs
: searchArchives
) {
1352 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
1353 if ( atoms
!= NULL
) {
1354 this->addAtoms(*atoms
);
1355 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1356 if ( !isDylibReader
&& fOptions
.readerOptions().fTraceArchives
) {
1359 // if this is a weak definition in a dylib
1360 if ( isDylibReader
&& (atoms
->size() == 1) && (atoms
->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1361 // keep looking for a non-weak definition
1364 // found a definition, no need to search anymore
1372 // for two level namesapce, give all implicitly link dylibs a chance
1373 if ( fOptions
.nameSpace() == Options::kTwoLevelNameSpace
) {
1374 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1375 if ( it
->second
->implicitlyLinked() ) {
1376 //fprintf(stderr, "addJustInTimeAtoms(%s), looking in implicitly linked %s\n", name, it->second->getPath() );
1377 std::vector
<class ObjectFile::Atom
*>* atoms
= it
->second
->getJustInTimeAtomsFor(name
);
1378 if ( atoms
!= NULL
) {
1379 this->addAtoms(*atoms
);
1380 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1381 // if this is a weak definition in a dylib
1382 if ( (atoms
->size() == 1) && (atoms
->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1383 // keep looking for a non-weak definition
1386 // found a definition, no need to search anymore
1394 // for flat namespace, give indirect dylibs
1395 if ( fOptions
.nameSpace() != Options::kTwoLevelNameSpace
) {
1396 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1397 if ( ! it
->second
->explicitlyLinked() ) {
1398 std::vector
<class ObjectFile::Atom
*>* atoms
= it
->second
->getJustInTimeAtomsFor(name
);
1399 if ( atoms
!= NULL
) {
1400 this->addAtoms(*atoms
);
1401 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1402 return atoms
; // found a definition, no need to search anymore
1408 // writer creates a proxy in two cases:
1409 // 1) ld -r is being used to create a .o file
1410 // 2) -undefined dynamic_lookup is being used
1411 // 3) -U _foo is being used
1412 // 4) x86_64 kext bundle is being created
1413 if ( (fOptions
.outputKind() == Options::kObjectFile
)
1414 || ((fOptions
.undefinedTreatment() != Options::kUndefinedError
) && okToMakeProxy
)
1415 || (fOptions
.someAllowedUndefines() && okToMakeProxy
)
1416 || (fOptions
.outputKind() == Options::kKextBundle
) ) {
1417 ObjectFile::Atom
* atom
= fOutputFile
->getUndefinedProxyAtom(name
);
1418 if ( atom
!= NULL
) {
1419 this->addAtom(*atom
);
1423 //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
1427 void Linker::resolve(ObjectFile::Reference
* reference
)
1429 // look in global symbol table
1430 const char* targetName
= reference
->getTargetName();
1431 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1432 if ( target
== NULL
) {
1433 throwf("unexpected undefined symbol: %s", targetName
);
1435 reference
->setTarget(*target
, reference
->getTargetOffset());
1438 void Linker::resolveFrom(ObjectFile::Reference
* reference
)
1440 // handle references that have two (from and to) targets
1441 const char* fromTargetName
= reference
->getFromTargetName();
1442 ObjectFile::Atom
* fromTarget
= fGlobalSymbolTable
.find(fromTargetName
);
1443 if ( fromTarget
== NULL
) {
1444 throwf("unexpected undefined symbol: %s", fromTargetName
);
1446 reference
->setFromTarget(*fromTarget
);
1450 void Linker::resolveReferences()
1452 // note: the atom list may grow during this loop as libraries supply needed atoms
1453 for (unsigned int j
=0; j
< fAllAtoms
.size(); ++j
) {
1454 ObjectFile::Atom
* atom
= fAllAtoms
[j
];
1455 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
1456 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
1457 ObjectFile::Reference
* reference
= *it
;
1458 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
)
1459 this->resolve(reference
);
1460 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
)
1461 this->resolveFrom(reference
);
1467 // used to remove stabs associated with atoms that won't be in output file
1471 NotInSet(std::set
<ObjectFile::Atom
*>& theSet
) : fSet(theSet
) {}
1473 bool operator()(const ObjectFile::Reader::Stab
& stab
) const {
1474 if ( stab
.atom
== NULL
)
1475 return false; // leave stabs that are not associated with any atome
1477 return ( fSet
.count(stab
.atom
) == 0 );
1481 std::set
<ObjectFile::Atom
*>& fSet
;
1488 NotLive(std::set
<ObjectFile::Atom
*>& set
) : fLiveAtoms(set
) {}
1490 bool operator()(ObjectFile::Atom
*& atom
) const {
1491 //if ( fLiveAtoms.count(atom) == 0 )
1492 // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
1493 return ( fLiveAtoms
.count(atom
) == 0 );
1496 std::set
<ObjectFile::Atom
*>& fLiveAtoms
;
1500 void Linker::addJustInTimeAtomsAndMarkLive(const char* name
)
1502 //fprintf(stderr, "addJustInTimeAtomsAndMarkLive(%s)\n", name);
1503 std::vector
<class ObjectFile::Atom
*>* atoms
= this->addJustInTimeAtoms(name
, true, true, true);
1504 if ( atoms
!= NULL
) {
1505 if ( fOptions
.allGlobalsAreDeadStripRoots() ) {
1506 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
->begin(); it
!= atoms
->end(); it
++) {
1507 ObjectFile::Atom
* atom
= *it
;
1508 if ( atom
->getScope() == ObjectFile::Atom::scopeGlobal
) {
1509 WhyLiveBackChain rootChain
;
1510 rootChain
.previous
= NULL
;
1511 rootChain
.referer
= atom
;
1512 this->markLive(*atom
, &rootChain
);
1520 void Linker::markLive(ObjectFile::Atom
& atom
, struct Linker::WhyLiveBackChain
* previous
)
1522 //fprintf(stderr, "markLive(%p)\n", &atom);
1523 if ( fLiveAtoms
.count(&atom
) == 0 ) {
1524 // if -why_live cares about this symbol, then dump chain
1525 if ( (previous
->referer
!= NULL
) && fOptions
.printWhyLive(previous
->referer
->getDisplayName()) ) {
1527 for(WhyLiveBackChain
* p
= previous
; p
!= NULL
; p
= p
->previous
, ++depth
) {
1528 for(int i
=depth
; i
> 0; --i
)
1529 fprintf(stderr
, " ");
1530 fprintf(stderr
, "%p %s from %s\n", p
->referer
, p
->referer
->getDisplayName(), p
->referer
->getFile()->getPath());
1533 // set up next chain
1534 WhyLiveBackChain thisChain
;
1535 thisChain
.previous
= previous
;
1536 // this atom is live
1537 fLiveAtoms
.insert(&atom
);
1538 // update total size info (except for __ZEROPAGE atom)
1539 if ( atom
.getSegment().isContentReadable() ) {
1540 fTotalSize
+= atom
.getSize();
1541 if ( atom
.isZeroFill() )
1542 fTotalZeroFillSize
+= atom
.getSize();
1544 // and all atoms it references
1545 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
1546 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
1547 ObjectFile::Reference
* reference
= *it
;
1548 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1549 // look in global symbol table
1550 const char* targetName
= reference
->getTargetName();
1551 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1552 if ( (target
== NULL
) || (target
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
) ) {
1553 // load archives or dylibs
1554 this->addJustInTimeAtomsAndMarkLive(targetName
);
1557 target
= fGlobalSymbolTable
.find(targetName
);
1558 if ( target
!= NULL
) {
1559 reference
->setTarget(*target
, reference
->getTargetOffset());
1562 // mark as undefined, for later error processing
1563 fAtomsWithUnresolvedReferences
.push_back(&atom
);
1564 fGlobalSymbolTable
.require(targetName
);
1567 switch ( reference
->getTargetBinding() ) {
1568 case ObjectFile::Reference::kBoundDirectly
:
1569 case ObjectFile::Reference::kBoundByName
:
1570 thisChain
.referer
= &reference
->getTarget();
1571 markLive(reference
->getTarget(), &thisChain
);
1573 case ObjectFile::Reference::kDontBind
:
1574 case ObjectFile::Reference::kUnboundByName
:
1578 // do the same as above, for "from target"
1579 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1580 // look in global symbol table
1581 const char* targetName
= reference
->getFromTargetName();
1582 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
1583 if ( (target
== NULL
) || (target
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
) ) {
1584 // load archives or dylibs
1585 this->addJustInTimeAtomsAndMarkLive(targetName
);
1588 target
= fGlobalSymbolTable
.find(targetName
);
1589 if ( target
!= NULL
) {
1590 reference
->setFromTarget(*target
);
1593 // mark as undefined, for later error processing
1594 fGlobalSymbolTable
.require(targetName
);
1597 switch ( reference
->getFromTargetBinding() ) {
1598 case ObjectFile::Reference::kBoundDirectly
:
1599 case ObjectFile::Reference::kBoundByName
:
1600 thisChain
.referer
= &reference
->getFromTarget();
1601 markLive(reference
->getFromTarget(), &thisChain
);
1603 case ObjectFile::Reference::kUnboundByName
:
1604 case ObjectFile::Reference::kDontBind
:
1613 void Linker::addLiveRoot(const char* name
)
1615 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(name
);
1616 if ( target
== NULL
) {
1617 this->addJustInTimeAtomsAndMarkLive(name
);
1618 target
= fGlobalSymbolTable
.find(name
);
1620 if ( target
!= NULL
)
1621 fLiveRootAtoms
.insert(target
);
1624 void Linker::moveToFrontOfSection(ObjectFile::Atom
* atom
)
1626 // check if already moved to front
1627 if ( fInitializerAtoms
.find(atom
) == fInitializerAtoms
.end() ) {
1628 // don't re-order initializers from .o files without MH_SUBSECTIONS_VIA_SYMBOLS
1629 // since that could make all atoms in the file look like initializers
1630 if ( atom
->getFile()->canScatterAtoms() ) {
1631 //fprintf(stdout, "marking as initializer: %s\n", atom->getDisplayName());
1632 fInitializerAtoms
.insert(atom
);
1633 // mark all functions that this function references
1634 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
1635 for (std::vector
<ObjectFile::Reference
*>::const_iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1636 ObjectFile::Atom
* childAtom
= &((*rit
)->getTarget());
1637 if ( childAtom
!= NULL
) {
1638 if ( (*rit
)->isBranch() ) {
1639 this->moveToFrontOfSection(childAtom
);
1641 else if ( (childAtom
->getName() != NULL
) && (strncmp(childAtom
->getName(), "___tcf_", 7) == 0) ) {
1642 //fprintf(stdout, "marking as terminator: %s\n", childAtom->getDisplayName());
1643 fTerminatorAtoms
.insert(childAtom
);
1651 void Linker::deadStripResolve()
1653 // add main() to live roots
1654 ObjectFile::Atom
* entryPoint
= this->entryPoint(false, true);
1655 if ( entryPoint
!= NULL
)
1656 fLiveRootAtoms
.insert(entryPoint
);
1658 // add dyld_stub_binding_helper/dyld_stub_binder to live roots
1659 ObjectFile::Atom
* dyldHelper
= this->dyldClassicHelper();
1660 if ( dyldHelper
!= NULL
)
1661 fLiveRootAtoms
.insert(dyldHelper
);
1662 dyldHelper
= this->dyldCompressedHelper();
1663 if ( dyldHelper
!= NULL
)
1664 fLiveRootAtoms
.insert(dyldHelper
);
1666 // if using lazy dylib loading, add dyld_lazy_dylib_stub_binding_helper() to live roots
1667 if ( fOptions
.usingLazyDylibLinking() ) {
1668 ObjectFile::Atom
* dyldLazyDylibHelper
= this->dyldLazyLibraryHelper();
1669 if ( dyldLazyDylibHelper
!= NULL
)
1670 fLiveRootAtoms
.insert(dyldLazyDylibHelper
);
1673 // add -exported_symbols_list, -init, and -u entries to live roots
1674 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
1675 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++)
1678 // if -exported_symbols_list that has wildcards, we need to find all matches and make them the roots
1679 // <rdar://problem/5524973>
1680 if ( fOptions
.hasWildCardExportRestrictList() ) {
1681 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1682 ObjectFile::Atom
* atom
= *it
;
1683 if ( (atom
->getScope() == ObjectFile::Atom::scopeGlobal
)
1684 && (fDeadAtoms
.count(atom
) == 0)
1685 && fOptions
.shouldExport(atom
->getName()) )
1686 fLiveRootAtoms
.insert(atom
);
1690 // in some cases, every global scope atom in initial .o files is a root
1691 if ( fOptions
.allGlobalsAreDeadStripRoots() ) {
1692 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1693 ObjectFile::Atom
* atom
= *it
;
1694 if ( (atom
->getScope() == ObjectFile::Atom::scopeGlobal
) && (fDeadAtoms
.count(atom
) == 0) )
1695 fLiveRootAtoms
.insert(atom
);
1699 // mark all roots as live, and all atoms they reference
1700 for (std::set
<ObjectFile::Atom
*>::iterator it
=fLiveRootAtoms
.begin(); it
!= fLiveRootAtoms
.end(); it
++) {
1701 WhyLiveBackChain rootChain
;
1702 rootChain
.previous
= NULL
;
1703 rootChain
.referer
= *it
;
1704 markLive(**it
, &rootChain
);
1707 // it is possible that there are unresolved references that can be resolved now
1708 // this can happen if the first reference to a common symbol in an archive.
1709 // common symbols are not in the archive TOC, but the .o could have been pulled in later.
1710 // <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
1711 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAtomsWithUnresolvedReferences
.begin(); it
!= fAtomsWithUnresolvedReferences
.end(); it
++) {
1712 std::vector
<class ObjectFile::Reference
*>& references
= (*it
)->getReferences();
1713 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1714 ObjectFile::Reference
* reference
= *rit
;
1715 if ( reference
->getTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1716 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(reference
->getTargetName());
1717 if ( target
!= NULL
) {
1718 reference
->setTarget(*target
, reference
->getTargetOffset());
1719 fLiveAtoms
.insert(target
);
1720 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1721 // references, which is true for commons.
1722 if ( target
->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition
)
1723 warning("internal error %s is not a tentative definition", target
->getDisplayName());
1726 if ( reference
->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName
) {
1727 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(reference
->getFromTargetName());
1728 if ( target
!= NULL
) {
1729 reference
->setFromTarget(*target
);
1730 fLiveAtoms
.insert(target
);
1731 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1732 // references, which is true for commons.
1733 if ( target
->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition
)
1734 warning("internal error %s is not a tentative definition", target
->getDisplayName());
1740 // It is possible that some weak symbols were overridden by lazily load objects from archives
1741 // and we have some atoms that still refer to the overridden ones.
1742 // In that case we need to go back and rebind
1743 if ( fAtomsOverriddenByLateLoads
.size() > 0 ) {
1744 for (std::set
<ObjectFile::Atom
*>::iterator it
=fLiveAtoms
.begin(); it
!= fLiveAtoms
.end(); ++it
) {
1745 ObjectFile::Atom
* atom
= *it
;
1746 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
1747 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); ++rit
) {
1748 ObjectFile::Reference
* reference
= *rit
;
1749 ObjectFile::Atom
* toTarget
= &reference
->getTarget();
1750 if ( fAtomsOverriddenByLateLoads
.count(toTarget
) ) {
1751 //fprintf(stderr, "change reference in %p from %p to %p\n", atom, toTarget, fGlobalSymbolTable.find(toTarget->getName()));
1752 reference
->setTarget(*fGlobalSymbolTable
.find(toTarget
->getName()), reference
->getTargetOffset());
1754 ObjectFile::Atom
* fromTarget
= &reference
->getFromTarget();
1755 if ( (fromTarget
!= NULL
) && fAtomsOverriddenByLateLoads
.count(fromTarget
) ) {
1756 //fprintf(stderr, "change from reference in %p from %p to %p\n", atom, fromTarget, fGlobalSymbolTable.find(fromTarget->getName()));
1757 reference
->setTarget(*fGlobalSymbolTable
.find(fromTarget
->getName()), reference
->getFromTargetOffset());
1762 // make sure overriders are live if the atom they overrid was live
1763 for (std::set
<ObjectFile::Atom
*>::iterator it
=fAtomsOverriddenByLateLoads
.begin(); it
!= fAtomsOverriddenByLateLoads
.end(); ++it
) {
1764 ObjectFile::Atom
* overriderAtom
= *it
;
1765 if ( fLiveAtoms
.count(overriderAtom
) ) {
1766 WhyLiveBackChain rootChain
;
1767 rootChain
.previous
= NULL
;
1768 rootChain
.referer
= *it
;
1769 markLive(*fGlobalSymbolTable
.find(overriderAtom
->getName()), &rootChain
);
1773 // remove overridden atoms from fLiveAtoms
1774 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fAtomsOverriddenByLateLoads
)), fAllAtoms
.end());
1775 fAtomsOverriddenByLateLoads
.clear();
1776 // remove dead atoms from fLiveAtoms
1777 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fDeadAtoms
)), fAllAtoms
.end());
1780 // now remove all non-live atoms from fAllAtoms
1781 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), NotLive(fLiveAtoms
)), fAllAtoms
.end());
1784 void Linker::checkObjC()
1787 switch ( fCurrentObjCConstraint
) {
1788 case ObjectFile::Reader::kObjcNone
:
1789 // can link against any dylib
1791 case ObjectFile::Reader::kObjcRetainRelease
:
1792 // cannot link against GC-only dylibs
1793 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1794 if ( it
->second
->explicitlyLinked() ) {
1795 if ( it
->second
->getObjCConstraint() == ObjectFile::Reader::kObjcGC
)
1796 throwf("this linkage unit uses Retain/Release. It cannot link against the GC-only dylib: %s", it
->second
->getPath());
1800 case ObjectFile::Reader::kObjcRetainReleaseOrGC
:
1801 // can link against GC or RR dylibs
1803 case ObjectFile::Reader::kObjcGC
:
1804 // cannot link against RR-only dylibs
1805 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
1806 if ( it
->second
->explicitlyLinked() ) {
1807 if ( it
->second
->getObjCConstraint() == ObjectFile::Reader::kObjcRetainRelease
)
1808 throwf("this linkage unit requires GC. It cannot link against Retain/Release dylib: %s", it
->second
->getPath());
1814 // synthesize __OBJC __image_info atom if needed
1815 if ( fCurrentObjCConstraint
!= ObjectFile::Reader::kObjcNone
) {
1816 this->addAtom(fOutputFile
->makeObjcInfoAtom(fCurrentObjCConstraint
, fObjcReplacmentClasses
));
1821 static uint8_t pcRelKind(cpu_type_t arch
)
1824 case CPU_TYPE_POWERPC
:
1825 return ppc::kPointerDiff32
;
1826 case CPU_TYPE_POWERPC64
:
1827 return ppc64::kPointerDiff32
;
1829 return x86::kPointerDiff
;
1830 case CPU_TYPE_X86_64
:
1831 return x86_64::kPointerDiff32
;
1833 return arm::kPointerDiff
;
1835 throw "uknown architecture";
1838 typedef uint8_t* (*oldcreatedof_func_t
) (const char*, cpu_type_t
, unsigned int, const char*[], const char*[], uint64_t offsetsInDOF
[], size_t* size
);
1839 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
);
1842 void Linker::processDTrace()
1844 // only make __dof section in final linked images
1845 if ( fOptions
.outputKind() == Options::kObjectFile
)
1848 // scan all atoms looking for dtrace probes
1849 std::vector
<DTraceProbeInfo
> probeSites
;
1850 std::vector
<DTraceProbeInfo
> isEnabledSites
;
1851 std::map
<const ObjectFile::Atom
*,CStringSet
> atomToDtraceTypes
;
1852 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); ++it
) {
1853 ObjectFile::Atom
* atom
= *it
;
1854 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
1855 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); ++rit
) {
1856 ObjectFile::Reference
* ref
= *rit
;
1857 if ( ref
->getTargetBinding() == ObjectFile::Reference::kDontBind
) {
1858 const char* probeName
= ref
->getTargetName();
1859 if ( probeName
!= NULL
) {
1860 uint32_t offsetInAtom
= ref
->getFixUpOffset();
1861 if ( strncmp(probeName
, "___dtrace_probe$", 16) == 0 )
1862 probeSites
.push_back(DTraceProbeInfo(atom
, offsetInAtom
, probeName
));
1863 else if ( strncmp(probeName
, "___dtrace_isenabled$", 20) == 0 )
1864 isEnabledSites
.push_back(DTraceProbeInfo(atom
, offsetInAtom
, probeName
));
1865 else if ( strncmp(probeName
, "___dtrace_", 10) == 0 )
1866 atomToDtraceTypes
[atom
].insert(probeName
);
1872 // if no probes, we're done
1873 if ( (probeSites
.size() == 0) && (isEnabledSites
.size() == 0) )
1876 // partition probes by provider name
1877 // The symbol names looks like:
1878 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
1879 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
1880 ProviderToProbes providerToProbes
;
1881 std::vector
<DTraceProbeInfo
> emptyList
;
1882 for(std::vector
<DTraceProbeInfo
>::iterator it
= probeSites
.begin(); it
!= probeSites
.end(); ++it
) {
1883 // ignore probes in functions that were coalesed away rdar://problem/5628149
1884 if ( fDeadAtoms
.count((ObjectFile::Atom
*)(it
->atom
)) == 0 ) {
1885 const char* providerStart
= &it
->probeName
[16];
1886 const char* providerEnd
= strchr(providerStart
, '$');
1887 if ( providerEnd
!= NULL
) {
1888 char providerName
[providerEnd
-providerStart
+1];
1889 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
1890 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
1891 if ( pos
== providerToProbes
.end() ) {
1892 const char* dup
= strdup(providerName
);
1893 providerToProbes
[dup
] = emptyList
;
1895 providerToProbes
[providerName
].push_back(*it
);
1899 for(std::vector
<DTraceProbeInfo
>::iterator it
= isEnabledSites
.begin(); it
!= isEnabledSites
.end(); ++it
) {
1900 // ignore probes in functions that were coalesed away rdar://problem/5628149
1901 if ( fDeadAtoms
.count((ObjectFile::Atom
*)(it
->atom
)) == 0 ) {
1902 const char* providerStart
= &it
->probeName
[20];
1903 const char* providerEnd
= strchr(providerStart
, '$');
1904 if ( providerEnd
!= NULL
) {
1905 char providerName
[providerEnd
-providerStart
+1];
1906 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
1907 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
1908 if ( pos
== providerToProbes
.end() ) {
1909 const char* dup
= strdup(providerName
);
1910 providerToProbes
[dup
] = emptyList
;
1912 providerToProbes
[providerName
].push_back(*it
);
1917 // create a DOF section for each provider
1919 CStringSet sectionNamesUsed
;
1920 for(ProviderToProbes::iterator pit
= providerToProbes
.begin(); pit
!= providerToProbes
.end(); ++pit
, ++dofIndex
) {
1921 const char* providerName
= pit
->first
;
1922 const std::vector
<DTraceProbeInfo
>& probes
= pit
->second
;
1924 // open library and find dtrace_create_dof()
1925 void* handle
= dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY
);
1926 if ( handle
== NULL
)
1927 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
1928 createdof_func_t pCreateDOF
= (createdof_func_t
)dlsym(handle
, "dtrace_ld_create_dof");
1929 if ( pCreateDOF
== NULL
)
1930 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
1931 // build list of typedefs/stability infos for this provider
1933 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
1934 std::map
<const ObjectFile::Atom
*,CStringSet
>::iterator pos
= atomToDtraceTypes
.find(it
->atom
);
1935 if ( pos
!= atomToDtraceTypes
.end() ) {
1936 for(CStringSet::iterator sit
= pos
->second
.begin(); sit
!= pos
->second
.end(); ++sit
) {
1937 const char* providerStart
= strchr(*sit
, '$')+1;
1938 const char* providerEnd
= strchr(providerStart
, '$');
1939 if ( providerEnd
!= NULL
) {
1940 char aProviderName
[providerEnd
-providerStart
+1];
1941 strlcpy(aProviderName
, providerStart
, providerEnd
-providerStart
+1);
1942 if ( strcmp(aProviderName
, providerName
) == 0 )
1948 int typeCount
= types
.size();
1949 const char* typeNames
[typeCount
];
1950 //fprintf(stderr, "types for %s:\n", providerName);
1952 for(CStringSet::iterator it
= types
.begin(); it
!= types
.end(); ++it
) {
1953 typeNames
[index
] = *it
;
1954 //fprintf(stderr, "\t%s\n", *it);
1958 // build list of probe/isenabled sites
1959 const uint32_t probeCount
= probes
.size();
1960 const char* probeNames
[probeCount
];
1961 const char* funtionNames
[probeCount
];
1962 uint64_t offsetsInDOF
[probeCount
];
1964 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
1965 probeNames
[index
] = it
->probeName
;
1966 funtionNames
[index
] = it
->atom
->getName();
1967 offsetsInDOF
[index
] = 0;
1970 //fprintf(stderr, "calling libtrace to create DOF\n");
1971 //for(uint32_t i=0; i < probeCount; ++i)
1972 // fprintf(stderr, " [%u]\t %s\t%s\n", i, probeNames[i], funtionNames[i]);
1973 // call dtrace library to create DOF section
1974 size_t dofSectionSize
;
1975 uint8_t* p
= (*pCreateDOF
)(fArchitecture
, typeCount
, typeNames
, probeCount
, probeNames
, funtionNames
, offsetsInDOF
, &dofSectionSize
);
1977 char sectionName
[18];
1978 strcpy(sectionName
, "__dof_");
1979 strlcpy(§ionName
[6], providerName
, 10);
1980 // create unique section name so each DOF is in its own section
1981 if ( sectionNamesUsed
.count(sectionName
) != 0 ) {
1982 sectionName
[15] = '0';
1983 sectionName
[16] = '\0';
1984 while ( sectionNamesUsed
.count(sectionName
) != 0 )
1987 sectionNamesUsed
.insert(sectionName
);
1988 char symbolName
[strlen(providerName
)+64];
1989 sprintf(symbolName
, "__dtrace_dof_for_provider_%s", providerName
);
1990 opaque_section::Reader
* reader
= new opaque_section::Reader("__TEXT", sectionName
,
1991 "dtrace", p
, dofSectionSize
, fNextInputOrdinal
, symbolName
);
1992 fNextInputOrdinal
+= dofSectionSize
;
1994 for (uint32_t i
=0; i
< probeCount
; ++i
) {
1995 uint64_t offset
= offsetsInDOF
[i
];
1996 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
1997 if ( offset
> dofSectionSize
)
1998 throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i
, offset
, dofSectionSize
);
1999 reader
->addSectionReference(pcRelKind(fArchitecture
), offset
, probes
[i
].atom
, probes
[i
].offset
, reader
->getAtoms()[0], 0);
2001 this->addAtoms(reader
->getAtoms());
2004 throw "error creating dtrace DOF section";
2010 static bool matchesObjectFile(ObjectFile::Atom
* atom
, const char* objectFileLeafName
)
2012 if ( objectFileLeafName
== NULL
)
2014 const char* atomFullPath
= atom
->getFile()->getPath();
2015 const char* lastSlash
= strrchr(atomFullPath
, '/');
2016 if ( lastSlash
!= NULL
) {
2017 if ( strcmp(&lastSlash
[1], objectFileLeafName
) == 0 )
2021 if ( strcmp(atomFullPath
, objectFileLeafName
) == 0 )
2028 static bool usesAnonymousNamespace(const char* symbol
)
2030 return ( (strncmp(symbol
, "__Z", 3) == 0) && (strstr(symbol
, "_GLOBAL__N_") != NULL
) );
2036 // __ZN20_GLOBAL__N__Z5main2v3barEv => _ZN-3barEv
2037 // __ZN37_GLOBAL__N_main.cxx_00000000_493A01A33barEv => _ZN-3barEv
2039 static void canonicalizeAnonymousName(const char* inSymbol
, char outSymbol
[])
2041 const char* globPtr
= strstr(inSymbol
, "_GLOBAL__N_");
2042 while ( isdigit(*(--globPtr
)) )
2045 unsigned long length
= strtoul(globPtr
+1, &endptr
, 10);
2046 const char* globEndPtr
= endptr
+ length
;
2047 int startLen
= globPtr
-inSymbol
+1;
2048 memcpy(outSymbol
, inSymbol
, startLen
);
2049 outSymbol
[startLen
] = '-';
2050 strcpy(&outSymbol
[startLen
+1], globEndPtr
);
2054 ObjectFile::Atom
* Linker::findAtom(const Options::OrderedSymbol
& orderedSymbol
)
2056 ObjectFile::Atom
* atom
= fGlobalSymbolTable
.find(orderedSymbol
.symbolName
);
2057 if ( atom
!= NULL
) {
2058 if ( matchesObjectFile(atom
, orderedSymbol
.objectFileName
) )
2062 // slow case. The requested symbol is not in symbol table, so might be static function
2063 static SymbolTable::Mapper hashTableOfTranslationUnitScopedSymbols
;
2064 static SymbolTable::Mapper hashTableOfSymbolsWithAnonymousNamespace
;
2065 static bool built
= false;
2066 // build a hash_map the first time
2068 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2070 const char* name
= atom
->getName();
2071 if ( name
!= NULL
) {
2072 if ( usesAnonymousNamespace(name
) ) {
2073 // symbol that uses anonymous namespace
2074 char canonicalName
[strlen(name
)+2];
2075 canonicalizeAnonymousName(name
, canonicalName
);
2076 const char* hashName
= strdup(canonicalName
);
2077 SymbolTable::Mapper::iterator pos
= hashTableOfSymbolsWithAnonymousNamespace
.find(hashName
);
2078 if ( pos
== hashTableOfSymbolsWithAnonymousNamespace
.end() )
2079 hashTableOfSymbolsWithAnonymousNamespace
[hashName
] = atom
;
2081 hashTableOfSymbolsWithAnonymousNamespace
[hashName
] = NULL
; // collision, denote with NULL
2083 else if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
2084 // static function or data
2085 SymbolTable::Mapper::iterator pos
= hashTableOfTranslationUnitScopedSymbols
.find(name
);
2086 if ( pos
== hashTableOfTranslationUnitScopedSymbols
.end() )
2087 hashTableOfTranslationUnitScopedSymbols
[name
] = atom
;
2089 hashTableOfTranslationUnitScopedSymbols
[name
] = NULL
; // collision, denote with NULL
2093 //fprintf(stderr, "built hash table of %lu static functions\n", hashTableOfTranslationUnitScopedSymbols.size());
2097 // look for name in hashTableOfTranslationUnitScopedSymbols
2098 SymbolTable::Mapper::iterator pos
= hashTableOfTranslationUnitScopedSymbols
.find(orderedSymbol
.symbolName
);
2099 if ( pos
!= hashTableOfTranslationUnitScopedSymbols
.end() ) {
2100 if ( (pos
->second
!= NULL
) && matchesObjectFile(pos
->second
, orderedSymbol
.objectFileName
) ) {
2101 //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName);
2104 if ( pos
->second
== NULL
)
2105 // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
2106 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2108 if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
2109 const char* name
= atom
->getName();
2110 if ( (name
!= NULL
) && (strcmp(name
, orderedSymbol
.symbolName
) == 0) ) {
2111 if ( matchesObjectFile(atom
, orderedSymbol
.objectFileName
) ) {
2112 if ( fOptions
.printOrderFileStatistics() )
2113 warning("%s specified in order_file but it exists in multiple .o files. "
2114 "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol
.symbolName
);
2122 // look for name in hashTableOfSymbolsWithAnonymousNamespace
2123 if ( usesAnonymousNamespace(orderedSymbol
.symbolName
) ) {
2124 // symbol that uses anonymous namespace
2125 char canonicalName
[strlen(orderedSymbol
.symbolName
)+2];
2126 canonicalizeAnonymousName(orderedSymbol
.symbolName
, canonicalName
);
2127 SymbolTable::Mapper::iterator pos
= hashTableOfSymbolsWithAnonymousNamespace
.find(canonicalName
);
2128 if ( pos
!= hashTableOfSymbolsWithAnonymousNamespace
.end() ) {
2129 if ( (pos
->second
!= NULL
) && matchesObjectFile(pos
->second
, orderedSymbol
.objectFileName
) ) {
2130 //fprintf(stderr, "found %s in anonymous namespace hash table\n", canonicalName);
2133 if ( pos
->second
== NULL
)
2134 // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
2135 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2137 const char* name
= atom
->getName();
2138 if ( (name
!= NULL
) && usesAnonymousNamespace(name
) ) {
2139 char canonicalAtomName
[strlen(name
)+2];
2140 canonicalizeAnonymousName(name
, canonicalAtomName
);
2141 if ( strcmp(canonicalAtomName
, canonicalName
) == 0 ) {
2142 if ( matchesObjectFile(atom
, orderedSymbol
.objectFileName
) ) {
2143 if ( fOptions
.printOrderFileStatistics() )
2144 warning("%s specified in order_file but it exists in multiple .o files. "
2145 "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol
.symbolName
);
2158 void Linker::sortSections()
2160 Section::assignIndexes(fOptions
.outputKind() == Options::kObjectFile
);
2165 // Linker::sortAtoms()
2167 // The purpose of this method is to take the graph of all Atoms and produce an ordered
2168 // sequence of atoms. The constraints are that: 1) all Atoms of the same Segment must
2169 // be contiguous, 2) all Atoms of the same Section must be contigous, 3) Atoms specified
2170 // in an order_file are seqenced as in the order_file and before Atoms not specified,
2171 // 4) Atoms in the same section from the same .o file should be contiguous and sequenced
2172 // in the same order they were in the .o file, 5) Atoms in the same Section but which came
2173 // from different .o files should be sequenced in the same order that the .o files
2174 // were passed to the linker (i.e. command line order).
2176 // The way this is implemented is that the linker passes a "base ordinal" to each Reader
2177 // as it is constructed. The reader should construct it Atoms so that calling getOrdinal()
2178 // on its atoms returns a contiguous range of values starting at the base ordinal. Then
2179 // sorting is just sorting by section, then by ordinal.
2181 // If an order_file is specified, it gets more complicated. First, an override-ordinal map
2182 // is created. It causes the sort routine to ignore the value returned by getOrdinal() and
2183 // use the override value instead. Next some Atoms must be layed out consecutively
2184 // (e.g. hand written assembly that does not end with return, but rather falls into
2185 // the next label). This is modeled in Readers via a "kFollowOn" reference. The use of
2186 // kFollowOn refernces produces "clusters" of atoms that must stay together.
2187 // If an order_file tries to move one atom, it may need to move a whole cluster. The
2188 // algorithm to do this models clusters using two maps. The "starts" maps maps any
2189 // atom in a cluster to the first Atom in the cluster. The "nexts" maps an Atom in a
2190 // cluster to the next Atom in the cluster. With this in place, while processing an
2191 // order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is
2192 // given ordinal overrides.
2194 void Linker::sortAtoms()
2196 fStartSortTime
= mach_absolute_time();
2197 // if -order_file is used, build map of atom ordinal overrides
2198 std::map
<const ObjectFile::Atom
*, uint32_t>* ordinalOverrideMap
= NULL
;
2199 std::map
<const ObjectFile::Atom
*, uint32_t> theOrdinalOverrideMap
;
2200 const bool log
= false;
2201 if ( fOptions
.orderedSymbols().size() != 0 ) {
2202 // first make a pass to find all follow-on references and build start/next maps
2203 // which are a way to represent clusters of atoms that must layout together
2204 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*> followOnStarts
;
2205 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*> followOnNexts
;
2206 for (std::vector
<ObjectFile::Atom
*>::iterator ait
=fAllAtoms
.begin(); ait
!= fAllAtoms
.end(); ait
++) {
2207 ObjectFile::Atom
* atom
= *ait
;
2208 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
2209 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
2210 ObjectFile::Reference
* ref
= *rit
;
2211 if ( ref
->getKind() == 1 ) { // FIX FIX
2212 ObjectFile::Atom
* targetAtom
= &ref
->getTarget();
2213 if ( log
) fprintf(stderr
, "ref %s -> %s", atom
->getDisplayName(), targetAtom
->getDisplayName());
2214 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator startFrom
= followOnStarts
.find(atom
);
2215 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator startTo
= followOnStarts
.find(targetAtom
);
2216 if ( (startFrom
== followOnStarts
.end()) && (startTo
== followOnStarts
.end()) ) {
2217 // this is first time we've seen either atom, make simple cluster of the two
2218 if ( log
) fprintf(stderr
, " new cluster\n");
2219 followOnStarts
[atom
] = atom
;
2220 followOnStarts
[targetAtom
] = atom
;
2221 followOnNexts
[atom
] = targetAtom
;
2222 followOnNexts
[targetAtom
] = NULL
;
2224 else if ( (startFrom
!= followOnStarts
.end()) && (startTo
== followOnStarts
.end()) && (followOnNexts
[atom
] == NULL
) ) {
2225 // atom is at end of an existing cluster, so append target to end of cluster
2226 if ( log
) fprintf(stderr
, " end of cluster starting with %s\n", followOnStarts
[atom
]->getDisplayName());
2227 followOnNexts
[atom
] = targetAtom
;
2228 followOnNexts
[targetAtom
] = NULL
;
2229 followOnStarts
[targetAtom
] = followOnStarts
[atom
];
2232 // gerneral case of inserting into an existing cluster
2233 if ( followOnNexts
[atom
] != NULL
) {
2234 // an atom with two follow-ons is illegal
2235 warning("can't order %s because both %s and %s must follow it",
2236 atom
->getDisplayName(), targetAtom
->getDisplayName(), followOnNexts
[atom
]->getDisplayName());
2239 // there already exists an atom that says target must be its follow-on
2240 const ObjectFile::Atom
* originalStart
= startTo
->second
;
2241 const ObjectFile::Atom
* originalPrevious
= originalStart
;
2242 while ( followOnNexts
[originalPrevious
] != targetAtom
)
2243 originalPrevious
= followOnNexts
[originalPrevious
];
2244 bool otherIsAlias
= (originalPrevious
->getSize() == 0);
2245 bool thisIsAlias
= (atom
->getSize() == 0);
2246 if ( !otherIsAlias
&& !thisIsAlias
) {
2247 warning("can't order %s because both %s and %s must preceed it",
2248 targetAtom
->getDisplayName(), originalPrevious
->getDisplayName(), atom
->getDisplayName());
2250 else if ( otherIsAlias
) {
2251 if ( originalPrevious
== originalStart
) {
2252 // other is alias at start of cluster, make this the new start of cluster
2253 if ( log
) fprintf(stderr
, " becomes new start of cluster previous starting with %s\n", originalStart
->getDisplayName());
2254 followOnNexts
[atom
] = originalPrevious
;
2255 for(const ObjectFile::Atom
* nextAtom
= atom
; nextAtom
!= NULL
; nextAtom
= followOnNexts
[nextAtom
])
2256 followOnStarts
[nextAtom
] = atom
;
2259 // other is alias in middle of cluster, insert new atom before it
2260 if ( log
) fprintf(stderr
, " insert into cluster starting with %s before alias %s\n", originalStart
->getDisplayName(), originalPrevious
->getDisplayName());
2261 followOnStarts
[atom
] = originalStart
;
2262 followOnNexts
[atom
] = originalPrevious
;
2263 for(const ObjectFile::Atom
* a
= originalStart
; a
!= NULL
; a
= followOnNexts
[a
]) {
2264 if ( followOnNexts
[a
] == originalPrevious
) {
2265 followOnNexts
[a
] = atom
;
2272 // this is alias, so it can go inbetween originalPrevious and targetAtom
2273 if ( log
) fprintf(stderr
, " insert into cluster starting with %s after %s\n", originalStart
->getDisplayName(), originalPrevious
->getDisplayName());
2274 followOnStarts
[atom
] = originalStart
;
2275 followOnNexts
[atom
] = followOnNexts
[originalPrevious
];
2276 followOnNexts
[originalPrevious
] = atom
;
2285 for(std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator it
= followOnStarts
.begin(); it
!= followOnStarts
.end(); ++it
)
2286 fprintf(stderr
, "start %s -> %s\n", it
->first
->getDisplayName(), it
->second
->getDisplayName());
2288 for(std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator it
= followOnNexts
.begin(); it
!= followOnNexts
.end(); ++it
)
2289 fprintf(stderr
, "next %s -> %s\n", it
->first
->getDisplayName(), (it
->second
!= NULL
) ? it
->second
->getDisplayName() : "null");
2292 // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals
2293 ordinalOverrideMap
= &theOrdinalOverrideMap
;
2295 uint32_t matchCount
= 0;
2296 std::vector
<Options::OrderedSymbol
>& orderedSymbols
= fOptions
.orderedSymbols();
2297 for(std::vector
<Options::OrderedSymbol
>::iterator it
= orderedSymbols
.begin(); it
!= orderedSymbols
.end(); ++it
) {
2298 ObjectFile::Atom
* atom
= this->findAtom(*it
);
2299 if ( atom
!= NULL
) {
2300 std::map
<const ObjectFile::Atom
*, const ObjectFile::Atom
*>::iterator start
= followOnStarts
.find(atom
);
2301 if ( start
!= followOnStarts
.end() ) {
2302 // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together
2303 for(const ObjectFile::Atom
* nextAtom
= start
->second
; nextAtom
!= NULL
; nextAtom
= followOnNexts
[nextAtom
]) {
2304 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator pos
= theOrdinalOverrideMap
.find(nextAtom
);
2305 if ( pos
== theOrdinalOverrideMap
.end() ) {
2306 theOrdinalOverrideMap
[nextAtom
] = index
++;
2307 if (log
) fprintf(stderr
, "override ordinal %u assigned to %s in cluster from %s\n", index
, nextAtom
->getDisplayName(), nextAtom
->getFile()->getPath());
2310 if (log
) fprintf(stderr
, "could not order %s as %u because it was already laid out earlier by %s as %u\n",
2311 atom
->getDisplayName(), index
, followOnStarts
[atom
]->getDisplayName(), theOrdinalOverrideMap
[atom
] );
2316 theOrdinalOverrideMap
[atom
] = index
;
2317 if (log
) fprintf(stderr
, "override ordinal %u assigned to %s from %s\n", index
, atom
->getDisplayName(), atom
->getFile()->getPath());
2322 if ( fOptions
.printOrderFileStatistics() ) {
2323 if ( it
->objectFileName
== NULL
)
2324 warning("can't find match for order_file entry: %s", it
->symbolName
);
2326 warning("can't find match for order_file entry: %s/%s", it
->objectFileName
, it
->symbolName
);
2331 if ( fOptions
.printOrderFileStatistics() && (fOptions
.orderedSymbols().size() != matchCount
) ) {
2332 warning("only %u out of %lu order_file symbols were applicable", matchCount
, fOptions
.orderedSymbols().size() );
2337 std::sort(fAllAtoms
.begin(), fAllAtoms
.end(), Linker::AtomSorter(ordinalOverrideMap
, fInitializerAtoms
, fTerminatorAtoms
));
2339 //fprintf(stderr, "Sorted atoms:\n");
2340 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
2341 // fprintf(stderr, "\t%s, %u %s\t%s\n", (*it)->getSectionName(), (*it)->getSection()->getIndex(), (*it)->getDisplayName(), (*it)->getFile()->getPath());
2346 // make sure given addresses are within reach of branches, etc
2347 void Linker::tweakLayout()
2349 // > 2GB images need their large zero fill atoms sorted to the end to keep access with +/- 2GB
2350 if ( fTotalSize
> 0x7F000000 ) {
2351 fBiggerThanTwoGigOutput
= true;
2353 if ( (fTotalSize
-fTotalZeroFillSize
) > 0x7F000000 )
2354 throwf("total output size exceeds 2GB (%lldMB)", (fTotalSize
-fTotalZeroFillSize
)/(1024*1024));
2356 // move very large (>1MB) zero fill atoms to a new section at very end of __DATA segment
2357 Section
* hugeZeroFills
= Section::find("__huge", "__DATA", true, true);
2358 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2359 ObjectFile::Atom
* atom
= *it
;
2360 if ( atom
->isZeroFill() && (atom
->getSize() > 1024*1024) && (strcmp(atom
->getSegment().getName(), "__DATA") == 0) )
2361 atom
->setSection(hugeZeroFills
);
2365 // move all initializers to start of __text section
2366 if ( fOptions
.readerOptions().fAutoOrderInitializers
) {
2367 // move -init function to front of __text
2368 if ( fOptions
.initFunctionName() != NULL
) {
2369 ObjectFile::Atom
* initAtom
= fGlobalSymbolTable
.find(fOptions
.initFunctionName());
2370 if ( initAtom
== NULL
)
2371 throwf("could not find -init function: \"%s\"", fOptions
.initFunctionName());
2372 moveToFrontOfSection(initAtom
);
2375 // move all functions pointed to by __mod_init_func section to front of __text
2376 Section
* initSection
= Section::find("__mod_init_func", "__DATA", false, true, false);
2377 if ( initSection
!= NULL
) {
2378 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); ++it
) {
2379 if ( (*it
)->getSection() == initSection
) {
2380 std::vector
<class ObjectFile::Reference
*>& references
= (*it
)->getReferences();
2381 if ( references
.size() == 1 )
2382 moveToFrontOfSection(&(references
[0]->getTarget()));
2388 // move atoms with relocations to start of __DATA,__data section
2389 // <rdar://problem/6061558> linker should order __DATA segment to reduce dyld dirtied pages
2390 if ( fOptions
.orderData() ) {
2391 bool slideable
= false;
2392 switch ( fOptions
.outputKind() ) {
2393 case Options::kDynamicExecutable
:
2394 case Options::kStaticExecutable
:
2395 case Options::kDyld
:
2396 case Options::kPreload
:
2397 case Options::kObjectFile
:
2398 case Options::kKextBundle
:
2401 case Options::kDynamicLibrary
:
2402 case Options::kDynamicBundle
:
2406 const bool hasPreferredLoadAddress
= (fOptions
.baseAddress() != 0);
2407 Section
* dataSection
= Section::find("__data", "__DATA", false, true, false);
2408 if ( dataSection
!= NULL
) {
2409 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); ++it
) {
2410 ObjectFile::Atom
* dataAtom
= *it
;
2411 if ( dataAtom
->getSection() == dataSection
) {
2412 std::vector
<class ObjectFile::Reference
*>& references
= dataAtom
->getReferences();
2413 if ( references
.size() > 0 ) {
2414 if ( slideable
&& !hasPreferredLoadAddress
) {
2415 // in a slidable image dyld will need to rebase and bind so any references will need runtime fixups
2416 // if image has preferred base address, assume it will load there and not rebase
2417 moveToFrontOfSection(dataAtom
);
2420 // in a non-slideable image, dyld will only do binding, so only references to
2421 // symbols in another dylib will need runtime fixups
2422 //fprintf(stderr, "reference from atom %s\n", dataAtom->getDisplayName());
2423 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
2424 ObjectFile::Reference
* reference
= *rit
;
2425 //fprintf(stderr, "\t%d %s\n", reference->getTarget().getDefinitionKind(), reference->getTarget().getDisplayName());
2426 if ( (reference
->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
2427 || (reference
->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
2428 moveToFrontOfSection(dataAtom
);
2442 void Linker::writeDotOutput()
2444 const char* dotOutFilePath
= fOptions
.dotOutputFile();
2445 if ( dotOutFilePath
!= NULL
) {
2446 FILE* out
= fopen(dotOutFilePath
, "w");
2447 if ( out
!= NULL
) {
2449 fprintf(out
, "digraph dg\n{\n");
2450 fprintf(out
, "\tconcentrate = true;\n");
2451 fprintf(out
, "\trankdir = LR;\n");
2453 // print each atom as a node
2454 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2455 ObjectFile::Atom
* atom
= *it
;
2456 if ( atom
->getFile() != fOutputFile
) {
2457 const char* name
= atom
->getDisplayName();
2458 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
2459 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
2460 fprintf(out
, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom
, name
);
2462 else if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
2463 char cstring
[atom
->getSize()+2];
2464 atom
->copyRawContent((uint8_t*)cstring
);
2465 fprintf(out
, "\taddr%p [ label = \"string: '", atom
);
2466 for (const char* s
=cstring
; *s
!= '\0'; ++s
) {
2468 fprintf(out
, "\\\\n");
2472 fprintf(out
, "'\" ];\n");
2475 fprintf(out
, "\taddr%p [ label = \"%s\" ];\n", atom
, name
);
2481 // print each reference as an edge
2482 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2483 ObjectFile::Atom
* fromAtom
= *it
;
2484 if ( fromAtom
->getFile() != fOutputFile
) {
2485 std::vector
<ObjectFile::Reference
*>& references
= fromAtom
->getReferences();
2486 std::set
<ObjectFile::Atom
*> seenTargets
;
2487 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
2488 ObjectFile::Reference
* reference
= *rit
;
2489 ObjectFile::Atom
* toAtom
= &(reference
->getTarget());
2490 if ( seenTargets
.count(toAtom
) == 0 ) {
2491 seenTargets
.insert(toAtom
);
2492 fprintf(out
, "\taddr%p -> addr%p;\n", fromAtom
, toAtom
);
2499 // push all imports to bottom of graph
2500 fprintf(out
, "{ rank = same; ");
2501 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
2502 ObjectFile::Atom
* atom
= *it
;
2503 if ( atom
->getFile() != fOutputFile
)
2504 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
2505 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
2506 fprintf(out
, "addr%p; ", atom
);
2509 fprintf(out
, "};\n ");
2512 fprintf(out
, "}\n");
2516 warning("could not write dot output file: %s", dotOutFilePath
);
2521 ObjectFile::Atom
* Linker::entryPoint(bool orInit
, bool searchArchives
)
2523 // if main executable, find entry point atom
2524 ObjectFile::Atom
* entryPoint
= NULL
;
2525 switch ( fOptions
.outputKind() ) {
2526 case Options::kDynamicExecutable
:
2527 case Options::kStaticExecutable
:
2528 case Options::kDyld
:
2529 case Options::kPreload
:
2530 entryPoint
= fGlobalSymbolTable
.find(fOptions
.entryName());
2531 if ( (entryPoint
== NULL
) && searchArchives
) {
2532 // <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
2533 this->addJustInTimeAtoms(fOptions
.entryName(), false, true, false);
2534 entryPoint
= fGlobalSymbolTable
.find(fOptions
.entryName());
2536 if ( entryPoint
== NULL
) {
2537 throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions
.entryName());
2540 case Options::kDynamicLibrary
:
2541 if ( orInit
&& (fOptions
.initFunctionName() != NULL
) ) {
2542 entryPoint
= fGlobalSymbolTable
.find(fOptions
.initFunctionName());
2543 if ( entryPoint
== NULL
) {
2544 throwf("could not find -init function: \"%s\"", fOptions
.initFunctionName());
2548 case Options::kObjectFile
:
2549 case Options::kDynamicBundle
:
2550 case Options::kKextBundle
:
2557 ObjectFile::Atom
* Linker::dyldClassicHelper()
2559 if ( fOptions
.makeClassicDyldInfo() )
2560 return fGlobalSymbolTable
.find("dyld_stub_binding_helper");
2565 ObjectFile::Atom
* Linker::dyldCompressedHelper()
2567 if ( fOptions
.makeCompressedDyldInfo() ) {
2568 // dyld_stub_binder is in libSystem.B.dylib
2569 ObjectFile::Atom
* atom
= fGlobalSymbolTable
.find("dyld_stub_binder");
2570 if ( atom
== NULL
) {
2571 this->addJustInTimeAtoms("dyld_stub_binder", true, false, true);
2573 atom
= fGlobalSymbolTable
.find("dyld_stub_binder");
2580 ObjectFile::Atom
* Linker::dyldLazyLibraryHelper()
2582 return fGlobalSymbolTable
.find("dyld_lazy_dylib_stub_binding_helper");
2585 const char* Linker::assureFullPath(const char* path
)
2587 if ( path
[0] == '/' )
2589 char cwdbuff
[MAXPATHLEN
];
2590 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
2592 asprintf(&result
, "%s/%s", cwdbuff
, path
);
2593 if ( result
!= NULL
)
2601 // The stab strings are of the form:
2602 // <name> ':' <type-code> <number-pari>
2603 // but the <name> contain a colon.
2604 // For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
2605 // For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
2607 const char* Linker::truncateStabString(const char* str
)
2609 enum { start
, inObjc
} state
= start
;
2610 for (const char* s
= str
; *s
!= 0; ++s
) {
2619 if ( s
[1] == ':' ) {
2624 // Duplicate strndup behavior here.
2625 int trunStrLen
= s
-str
+2;
2626 char* temp
= new char[trunStrLen
+1];
2627 memcpy(temp
, str
, trunStrLen
);
2628 temp
[trunStrLen
] = '\0';
2646 bool Linker::minimizeStab(ObjectFile::Reader::Stab
& stab
)
2653 // these all need truncated strings
2654 stab
.string
= truncateStabString(stab
.string
);
2660 // these are included in the minimal stabs, but they keep their full string
2668 struct HeaderRange
{
2669 std::vector
<ObjectFile::Reader::Stab
>::iterator begin
;
2670 std::vector
<ObjectFile::Reader::Stab
>::iterator end
;
2671 int parentRangeIndex
;
2673 bool sumPrecomputed
;
2675 bool cannotEXCL
; // because of SLINE, etc stabs
2679 typedef __gnu_cxx::hash_map
<const char*, std::vector
<uint32_t>, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToSums
;
2681 // hash table that maps header path to a vector of known checksums for that path
2682 static PathToSums sKnownBINCLs
;
2685 void Linker::collectStabs(ObjectFile::Reader
* reader
, std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
)
2687 const bool log
= false;
2688 bool minimal
= ( fOptions
.readerOptions().fDebugInfoStripping
== ObjectFile::ReaderOptions::kDebugInfoMinimal
);
2689 std::vector
<class ObjectFile::Reader::Stab
>* readerStabs
= reader
->getStabs();
2690 if ( readerStabs
== NULL
)
2693 if ( log
) fprintf(stderr
, "processesing %lu stabs for %s\n", readerStabs
->size(), reader
->getPath());
2694 std::vector
<HeaderRange
> ranges
;
2695 int curRangeIndex
= -1;
2697 ObjectFile::Atom
* atomWithLowestOrdinal
= NULL
;
2698 ObjectFile::Atom
* atomWithHighestOrdinal
= NULL
;
2699 uint32_t highestOrdinal
= 0;
2700 uint32_t lowestOrdinal
= UINT_MAX
;
2701 std::vector
<std::pair
<ObjectFile::Atom
*,ObjectFile::Atom
*> > soRanges
;
2702 // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums
2703 // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein
2704 for(std::vector
<class ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
2706 switch ( it
->type
) {
2711 range
.end
= readerStabs
->end();
2712 range
.parentRangeIndex
= curRangeIndex
;
2713 range
.sum
= it
->value
;
2714 range
.sumPrecomputed
= (range
.sum
!= 0);
2715 range
.useEXCL
= false;
2716 range
.cannotEXCL
= false;
2717 curRangeIndex
= ranges
.size();
2718 if ( log
) fprintf(stderr
, "[%d]BINCL %s\n", curRangeIndex
, it
->string
);
2719 ranges
.push_back(range
);
2723 if ( curRangeIndex
== -1 ) {
2724 warning("EINCL missing BINCL in %s", reader
->getPath());
2727 ranges
[curRangeIndex
].end
= it
+1;
2728 if ( log
) fprintf(stderr
, "[%d->%d]EINCL %s\n", curRangeIndex
, ranges
[curRangeIndex
].parentRangeIndex
, it
->string
);
2729 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
2734 std::map
<const class ObjectFile::Atom
*, uint32_t>::iterator pos
= atomOrdinals
.find(it
->atom
);
2735 if ( pos
!= atomOrdinals
.end() ) {
2736 uint32_t ordinal
= pos
->second
;
2737 if ( ordinal
> highestOrdinal
) {
2738 highestOrdinal
= ordinal
;
2739 atomWithHighestOrdinal
= it
->atom
;
2741 if ( ordinal
< lowestOrdinal
) {
2742 lowestOrdinal
= ordinal
;
2743 atomWithLowestOrdinal
= it
->atom
;
2755 if ( curRangeIndex
!= -1 ) {
2756 ranges
[curRangeIndex
].cannotEXCL
= true;
2757 if ( fOptions
.warnStabs() )
2758 warning("cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
2762 if ( (it
->string
!= NULL
) && (strlen(it
->string
) > 0) ) {
2763 // start SO, reset hi/low FUN tracking
2764 atomWithLowestOrdinal
= NULL
;
2765 atomWithHighestOrdinal
= NULL
;
2767 lowestOrdinal
= UINT_MAX
;
2770 // end SO, record hi/low atoms for this SO range
2771 soRanges
.push_back(std::make_pair
<ObjectFile::Atom
*,ObjectFile::Atom
*>(atomWithLowestOrdinal
, atomWithHighestOrdinal
));
2775 if ( curRangeIndex
!= -1 ) {
2776 if ( ! ranges
[curRangeIndex
].sumPrecomputed
) {
2778 const char* s
= it
->string
;
2780 while ( (c
= *s
++) != 0 ) {
2782 // don't checkusm first number (file index) after open paren in string
2788 ranges
[curRangeIndex
].sum
+= sum
;
2794 if ( log
) fprintf(stderr
, "processesed %d stabs for %s\n", count
, reader
->getPath());
2795 if ( curRangeIndex
!= -1 )
2796 warning("BINCL (%s) missing EINCL in %s", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
2799 if ( ranges
.size() == 0 ) {
2800 unsigned int soIndex
= 0;
2801 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
2802 // copy minimal or all stabs
2803 ObjectFile::Reader::Stab stab
= *it
;
2804 if ( !minimal
|| minimizeStab(stab
) ) {
2805 if ( stab
.type
== N_SO
) {
2806 if ( soIndex
< soRanges
.size() ) {
2807 if ( (stab
.string
!= NULL
) && (strlen(stab
.string
) > 0) ) {
2808 // starting SO is associated with first atom
2809 stab
.atom
= soRanges
[soIndex
].first
;
2812 // ending SO is associated with last atom
2813 stab
.atom
= soRanges
[soIndex
].second
;
2818 fStabs
.push_back(stab
);
2824 //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
2825 //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
2826 // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
2829 // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
2830 for(std::vector
<HeaderRange
>::iterator it
=ranges
.begin(); it
!= ranges
.end(); ++it
) {
2831 if ( ! it
->cannotEXCL
) {
2832 const char* header
= it
->begin
->string
;
2833 uint32_t sum
= it
->sum
;
2834 PathToSums::iterator pos
= sKnownBINCLs
.find(header
);
2835 if ( pos
!= sKnownBINCLs
.end() ) {
2836 std::vector
<uint32_t>& sums
= pos
->second
;
2837 for(std::vector
<uint32_t>::iterator sit
=sums
.begin(); sit
!= sums
.end(); ++sit
) {
2839 //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
2844 if ( ! it
->useEXCL
) {
2845 // have seen this path, but not this checksum
2846 //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
2847 sums
.push_back(sum
);
2851 // have not seen this path, so add to known BINCLs
2852 std::vector
<uint32_t> empty
;
2853 sKnownBINCLs
[header
] = empty
;
2854 sKnownBINCLs
[header
].push_back(sum
);
2855 //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
2860 // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
2862 const int maxRangeIndex
= ranges
.size();
2864 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
2865 switch ( it
->type
) {
2867 for(int i
=curRangeIndex
+1; i
< maxRangeIndex
; ++i
) {
2868 if ( ranges
[i
].begin
== it
) {
2870 HeaderRange
& range
= ranges
[curRangeIndex
];
2871 ObjectFile::Reader::Stab stab
= *it
;
2872 stab
.value
= range
.sum
; // BINCL and EXCL have n_value set to checksum
2873 if ( range
.useEXCL
)
2874 stab
.type
= N_EXCL
; // transform BINCL into EXCL
2876 fStabs
.push_back(stab
);
2882 if ( curRangeIndex
!= -1 ) {
2883 if ( !ranges
[curRangeIndex
].useEXCL
&& !minimal
)
2884 fStabs
.push_back(*it
);
2885 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
2889 if ( (curRangeIndex
== -1) || !ranges
[curRangeIndex
].useEXCL
) {
2890 ObjectFile::Reader::Stab stab
= *it
;
2891 if ( !minimal
|| minimizeStab(stab
) ) {
2892 if ( stab
.type
== N_SO
) {
2893 if ( (stab
.string
!= NULL
) && (strlen(stab
.string
) > 0) ) {
2894 // starting SO is associated with first atom
2895 stab
.atom
= soRanges
[soIndex
].first
;
2898 // ending SO is associated with last atom
2899 stab
.atom
= soRanges
[soIndex
].second
;
2903 fStabs
.push_back(stab
);
2912 // used to prune out atoms that don't need debug notes generated
2913 class NoDebugNoteAtom
2916 NoDebugNoteAtom(const std::map
<class ObjectFile::Reader
*, uint32_t>& readersWithDwarfOrdinals
)
2917 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals
) {}
2919 bool operator()(const ObjectFile::Atom
* atom
) const {
2920 if ( atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
)
2922 if ( atom
->getName() == NULL
)
2924 if ( fReadersWithDwarfOrdinals
.find(atom
->getFile()) == fReadersWithDwarfOrdinals
.end() )
2930 const std::map
<class ObjectFile::Reader
*, uint32_t>& fReadersWithDwarfOrdinals
;
2933 // used to sort atoms with debug notes
2934 class ReadersWithDwarfSorter
2937 ReadersWithDwarfSorter(const std::map
<class ObjectFile::Reader
*, uint32_t>& readersWithDwarfOrdinals
,
2938 const std::map
<const class ObjectFile::Atom
*, uint32_t>& atomOrdinals
)
2939 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals
), fAtomOrdinals(atomOrdinals
) {}
2941 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
) const
2943 // first sort by reader
2944 unsigned int leftReaderIndex
= fReadersWithDwarfOrdinals
.find(left
->getFile())->second
;
2945 unsigned int rightReaderIndex
= fReadersWithDwarfOrdinals
.find(right
->getFile())->second
;
2946 if ( leftReaderIndex
!= rightReaderIndex
)
2947 return (leftReaderIndex
< rightReaderIndex
);
2949 // then sort by atom ordinal
2950 unsigned int leftAtomIndex
= fAtomOrdinals
.find(left
)->second
;
2951 unsigned int rightAtomIndex
= fAtomOrdinals
.find(right
)->second
;
2952 return leftAtomIndex
< rightAtomIndex
;
2956 const std::map
<class ObjectFile::Reader
*, uint32_t>& fReadersWithDwarfOrdinals
;
2957 const std::map
<const class ObjectFile::Atom
*, uint32_t>& fAtomOrdinals
;
2964 void Linker::synthesizeDebugNotes(std::vector
<class ObjectFile::Atom
*>& allAtomsByReader
)
2966 // synthesize "debug notes" and add them to master stabs vector
2967 const char* dirPath
= NULL
;
2968 const char* filename
= NULL
;
2969 bool wroteStartSO
= false;
2970 bool useZeroOSOModTime
= (getenv("RC_RELEASE") != NULL
);
2971 __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> seenFiles
;
2972 for (std::vector
<ObjectFile::Atom
*>::iterator it
=allAtomsByReader
.begin(); it
!= allAtomsByReader
.end(); it
++) {
2973 ObjectFile::Atom
* atom
= *it
;
2974 const char* newDirPath
;
2975 const char* newFilename
;
2976 //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
2977 if ( atom
->getTranslationUnitSource(&newDirPath
, &newFilename
) ) {
2978 // need SO's whenever the translation unit source file changes
2979 if ( newFilename
!= filename
) {
2980 // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
2981 if ( (newDirPath
!= NULL
) && (strlen(newDirPath
) > 1 ) && (newDirPath
[strlen(newDirPath
)-1] != '/') )
2982 asprintf((char**)&newDirPath
, "%s/", newDirPath
);
2983 if ( filename
!= NULL
) {
2984 // translation unit change, emit ending SO
2985 ObjectFile::Reader::Stab endFileStab
;
2986 endFileStab
.atom
= NULL
;
2987 endFileStab
.type
= N_SO
;
2988 endFileStab
.other
= 1;
2989 endFileStab
.desc
= 0;
2990 endFileStab
.value
= 0;
2991 endFileStab
.string
= "";
2992 fStabs
.push_back(endFileStab
);
2994 // new translation unit, emit start SO's
2995 ObjectFile::Reader::Stab dirPathStab
;
2996 dirPathStab
.atom
= NULL
;
2997 dirPathStab
.type
= N_SO
;
2998 dirPathStab
.other
= 0;
2999 dirPathStab
.desc
= 0;
3000 dirPathStab
.value
= 0;
3001 dirPathStab
.string
= newDirPath
;
3002 fStabs
.push_back(dirPathStab
);
3003 ObjectFile::Reader::Stab fileStab
;
3004 fileStab
.atom
= NULL
;
3005 fileStab
.type
= N_SO
;
3009 fileStab
.string
= newFilename
;
3010 fStabs
.push_back(fileStab
);
3011 // Synthesize OSO for start of file
3012 ObjectFile::Reader::Stab objStab
;
3013 objStab
.atom
= NULL
;
3014 objStab
.type
= N_OSO
;
3015 // <rdar://problem/6337329> linker should put cpusubtype in n_sect field of nlist entry for N_OSO debug note entries
3016 objStab
.other
= atom
->getFile()->updateCpuConstraint(0);
3018 objStab
.value
= useZeroOSOModTime
? 0 : atom
->getFile()->getModificationTime();
3019 objStab
.string
= assureFullPath(atom
->getFile()->getPath());
3020 fStabs
.push_back(objStab
);
3021 wroteStartSO
= true;
3022 // add the source file path to seenFiles so it does not show up in SOLs
3023 seenFiles
.insert(newFilename
);
3025 filename
= newFilename
;
3026 dirPath
= newDirPath
;
3027 if ( atom
->getSegment().isContentExecutable() && (strncmp(atom
->getSectionName(), "__text", 6) == 0) ) {
3028 // Synthesize BNSYM and start FUN stabs
3029 ObjectFile::Reader::Stab beginSym
;
3030 beginSym
.atom
= atom
;
3031 beginSym
.type
= N_BNSYM
;
3035 beginSym
.string
= "";
3036 fStabs
.push_back(beginSym
);
3037 ObjectFile::Reader::Stab startFun
;
3038 startFun
.atom
= atom
;
3039 startFun
.type
= N_FUN
;
3043 startFun
.string
= atom
->getName();
3044 fStabs
.push_back(startFun
);
3045 // Synthesize any SOL stabs needed
3046 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
3047 if ( lineInfo
!= NULL
) {
3048 const char* curFile
= NULL
;
3049 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
3050 if ( it
->fileName
!= curFile
) {
3051 if ( seenFiles
.count(it
->fileName
) == 0 ) {
3052 seenFiles
.insert(it
->fileName
);
3053 ObjectFile::Reader::Stab sol
;
3059 sol
.string
= it
->fileName
;
3060 fStabs
.push_back(sol
);
3062 curFile
= it
->fileName
;
3066 // Synthesize end FUN and ENSYM stabs
3067 ObjectFile::Reader::Stab endFun
;
3069 endFun
.type
= N_FUN
;
3074 fStabs
.push_back(endFun
);
3075 ObjectFile::Reader::Stab endSym
;
3077 endSym
.type
= N_ENSYM
;
3082 fStabs
.push_back(endSym
);
3084 else if ( atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
) {
3085 // no stabs for atoms that would not be in the symbol table
3087 else if ( atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute
) {
3088 // no stabs for absolute symbols
3090 else if ( (strcmp(atom
->getSectionName(), "__eh_frame") == 0) ) {
3091 // no stabs for .eh atoms
3093 else if ( (strncmp(atom
->getName(), "__dtrace_probe$", 15) == 0) ) {
3094 // no stabs for old style dtrace probes
3097 ObjectFile::Reader::Stab globalsStab
;
3098 const char* name
= atom
->getName();
3099 if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
3100 // Synthesize STSYM stab for statics
3101 globalsStab
.atom
= atom
;
3102 globalsStab
.type
= N_STSYM
;
3103 globalsStab
.other
= 1;
3104 globalsStab
.desc
= 0;
3105 globalsStab
.value
= 0;
3106 globalsStab
.string
= name
;
3107 fStabs
.push_back(globalsStab
);
3110 // Synthesize GSYM stab for other globals
3111 globalsStab
.atom
= atom
;
3112 globalsStab
.type
= N_GSYM
;
3113 globalsStab
.other
= 1;
3114 globalsStab
.desc
= 0;
3115 globalsStab
.value
= 0;
3116 globalsStab
.string
= name
;
3117 fStabs
.push_back(globalsStab
);
3123 if ( wroteStartSO
) {
3125 ObjectFile::Reader::Stab endFileStab
;
3126 endFileStab
.atom
= NULL
;
3127 endFileStab
.type
= N_SO
;
3128 endFileStab
.other
= 1;
3129 endFileStab
.desc
= 0;
3130 endFileStab
.value
= 0;
3131 endFileStab
.string
= "";
3132 fStabs
.push_back(endFileStab
);
3139 void Linker::collectDebugInfo()
3141 std::map
<const class ObjectFile::Atom
*, uint32_t> atomOrdinals
;
3142 fStartDebugTime
= mach_absolute_time();
3143 if ( fOptions
.readerOptions().fDebugInfoStripping
!= ObjectFile::ReaderOptions::kDebugInfoNone
) {
3145 // determine mixture of stabs and dwarf
3146 bool someStabs
= false;
3147 bool someDwarf
= false;
3148 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
3149 it
!= fReadersThatHaveSuppliedAtoms
.end();
3151 ObjectFile::Reader
* reader
= *it
;
3152 if ( reader
!= NULL
) {
3153 switch ( reader
->getDebugInfoKind() ) {
3154 case ObjectFile::Reader::kDebugInfoNone
:
3156 case ObjectFile::Reader::kDebugInfoStabs
:
3159 case ObjectFile::Reader::kDebugInfoDwarf
:
3163 case ObjectFile::Reader::kDebugInfoStabsUUID
:
3168 throw "Unhandled type of debug information";
3173 if ( someDwarf
|| someStabs
) {
3174 // try to minimize re-allocations
3175 fStabs
.reserve(1024);
3177 // make mapping from atoms to ordinal
3178 uint32_t ordinal
= 1;
3179 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
3180 atomOrdinals
[*it
] = ordinal
++;
3184 // process all dwarf .o files as a batch
3186 // make mapping from readers with dwarf to ordinal
3187 std::map
<class ObjectFile::Reader
*, uint32_t> readersWithDwarfOrdinals
;
3188 uint32_t readerOrdinal
= 1;
3189 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
3190 it
!= fReadersThatHaveSuppliedAtoms
.end();
3192 ObjectFile::Reader
* reader
= *it
;
3193 if ( (reader
!= NULL
) && (reader
->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoDwarf
) ) {
3194 readersWithDwarfOrdinals
[reader
] = readerOrdinal
++;
3198 // make a vector of atoms
3199 std::vector
<class ObjectFile::Atom
*> allAtomsByReader(fAllAtoms
.begin(), fAllAtoms
.end());
3200 // remove those not from a reader that has dwarf
3201 allAtomsByReader
.erase(std::remove_if(allAtomsByReader
.begin(), allAtomsByReader
.end(),
3202 NoDebugNoteAtom(readersWithDwarfOrdinals
)), allAtomsByReader
.end());
3203 // sort by reader then atom ordinal
3204 std::sort(allAtomsByReader
.begin(), allAtomsByReader
.end(), ReadersWithDwarfSorter(readersWithDwarfOrdinals
, atomOrdinals
));
3205 // add debug notes for each atom
3206 this->synthesizeDebugNotes(allAtomsByReader
);
3209 // process all stabs .o files one by one
3211 // get stabs from each reader, in command line order
3212 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
3213 it
!= fReadersThatHaveSuppliedAtoms
.end();
3215 ObjectFile::Reader
* reader
= *it
;
3216 if ( reader
!= NULL
) {
3217 switch ( reader
->getDebugInfoKind() ) {
3218 case ObjectFile::Reader::kDebugInfoDwarf
:
3219 case ObjectFile::Reader::kDebugInfoNone
:
3222 case ObjectFile::Reader::kDebugInfoStabs
:
3223 case ObjectFile::Reader::kDebugInfoStabsUUID
:
3224 collectStabs(reader
, atomOrdinals
);
3227 throw "Unhandled type of debug information";
3231 // remove stabs associated with atoms that won't be in output
3232 std::set
<class ObjectFile::Atom
*> allAtomsSet
;
3233 allAtomsSet
.insert(fAllAtoms
.begin(), fAllAtoms
.end());
3234 fStabs
.erase(std::remove_if(fStabs
.begin(), fStabs
.end(), NotInSet(allAtomsSet
)), fStabs
.end());
3239 void Linker::writeOutput()
3241 // <rdar://problem/6933931> ld -r of empty .o file should preserve sub-type
3242 // <rdar://problem/7049478> empty dylib should have subtype from command line
3243 if ( fOptions
.preferSubArchitecture() && (fOptions
.architecture() == CPU_TYPE_ARM
) ) {
3244 fCurrentCpuConstraint
= (ObjectFile::Reader::CpuConstraint
)fOptions
.subArchitecture();
3247 if ( fOptions
.forceCpuSubtypeAll() )
3248 fCurrentCpuConstraint
= ObjectFile::Reader::kCpuAny
;
3250 fStartWriteTime
= mach_absolute_time();
3251 // tell writer about each segment's atoms
3252 fOutputFileSize
= fOutputFile
->write(fAllAtoms
, fStabs
, this->entryPoint(true),
3253 fCreateUUID
, fCanScatter
,
3254 fCurrentCpuConstraint
,
3255 fRegularDefAtomsThatOverrideADylibsWeakDef
,
3256 fGlobalSymbolTable
.hasExternalWeakDefinitions());
3259 const char* Linker::fileArch(const void* p
)
3261 const uint8_t* bytes
= (uint8_t*)p
;
3263 result
= mach_o::relocatable::Reader
<ppc
>::fileKind(bytes
);
3264 if ( result
!= NULL
)
3266 result
= mach_o::relocatable::Reader
<ppc64
>::fileKind(bytes
);
3267 if ( result
!= NULL
)
3269 result
= mach_o::relocatable::Reader
<x86
>::fileKind(bytes
);
3270 if ( result
!= NULL
)
3272 result
= mach_o::relocatable::Reader
<x86_64
>::fileKind(bytes
);
3273 if ( result
!= NULL
)
3275 result
= mach_o::relocatable::Reader
<arm
>::fileKind(bytes
);
3276 if ( result
!= NULL
)
3279 result
= lto::Reader::fileKind(bytes
);
3280 if ( result
!= NULL
)
3283 return "unsupported file format";
3286 ObjectFile::Reader
* Linker::createReader(const Options::FileInfo
& info
)
3288 // map in whole file
3289 uint64_t len
= info
.fileLen
;
3290 int fd
= ::open(info
.path
, O_RDONLY
, 0);
3292 throwf("can't open file, errno=%d", errno
);
3293 if ( info
.fileLen
< 20 )
3294 throw "file too small";
3296 uint8_t* p
= (uint8_t*)::mmap(NULL
, info
.fileLen
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
3297 if ( p
== (uint8_t*)(-1) )
3298 throwf("can't map file, errno=%d", errno
);
3300 // if fat file, skip to architecture we want
3301 // Note: fat header is always big-endian
3302 bool isFatFile
= false;
3303 const fat_header
* fh
= (fat_header
*)p
;
3304 if ( fh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
3306 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
3307 uint32_t sliceToUse
;
3308 bool sliceFound
= false;
3309 if ( fOptions
.preferSubArchitecture() ) {
3310 // first try to find a slice that match cpu-type and cpu-sub-type
3311 for (uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
3312 if ( (OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)fArchitecture
)
3313 && (OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == (uint32_t)fOptions
.subArchitecture()) ) {
3320 if ( !sliceFound
) {
3321 // look for any slice that matches just cpu-type
3322 for (uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
3323 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)fArchitecture
) {
3331 uint32_t fileOffset
= OSSwapBigToHostInt32(archs
[sliceToUse
].offset
);
3332 len
= OSSwapBigToHostInt32(archs
[sliceToUse
].size
);
3333 // if requested architecture is page aligned within fat file, then remap just that portion of file
3334 if ( (fileOffset
& 0x00000FFF) == 0 ) {
3336 munmap((caddr_t
)p
, info
.fileLen
);
3337 // re-map just part we need
3338 p
= (uint8_t*)::mmap(NULL
, len
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, fileOffset
);
3339 if ( p
== (uint8_t*)(-1) )
3340 throwf("can't re-map file, errno=%d", errno
);
3349 bool objSubtypeMustMatch
= (fOptions
.preferSubArchitecture() && !fOptions
.allowSubArchitectureMismatches());
3350 switch (fArchitecture
) {
3351 case CPU_TYPE_POWERPC
:
3352 if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
3353 return this->addObject(new mach_o::relocatable::Reader
<ppc
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3354 else if ( mach_o::dylib::Reader
<ppc
>::validFile(p
, info
.options
.fBundleLoader
) )
3355 return this->addDylib(new mach_o::dylib::Reader
<ppc
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3356 else if ( archive::Reader
<ppc
>::validFile(p
, len
) )
3357 return this->addArchive(new archive::Reader
<ppc
>::Reader(p
, len
, info
.path
, info
.modTime
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3359 case CPU_TYPE_POWERPC64
:
3360 if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
3361 return this->addObject(new mach_o::relocatable::Reader
<ppc64
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3362 else if ( mach_o::dylib::Reader
<ppc64
>::validFile(p
, info
.options
.fBundleLoader
) )
3363 return this->addDylib(new mach_o::dylib::Reader
<ppc64
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3364 else if ( archive::Reader
<ppc64
>::validFile(p
, len
) )
3365 return this->addArchive(new archive::Reader
<ppc64
>::Reader(p
, len
, info
.path
, info
.modTime
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3368 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
3369 return this->addObject(new mach_o::relocatable::Reader
<x86
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3370 else if ( mach_o::dylib::Reader
<x86
>::validFile(p
, info
.options
.fBundleLoader
) )
3371 return this->addDylib(new mach_o::dylib::Reader
<x86
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3372 else if ( archive::Reader
<x86
>::validFile(p
, len
) )
3373 return this->addArchive(new archive::Reader
<x86
>::Reader(p
, len
, info
.path
, info
.modTime
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3375 case CPU_TYPE_X86_64
:
3376 if ( mach_o::relocatable::Reader
<x86_64
>::validFile(p
) )
3377 return this->addObject(new mach_o::relocatable::Reader
<x86_64
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3378 else if ( mach_o::dylib::Reader
<x86_64
>::validFile(p
, info
.options
.fBundleLoader
) )
3379 return this->addDylib(new mach_o::dylib::Reader
<x86_64
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3380 else if ( archive::Reader
<x86_64
>::validFile(p
, len
) )
3381 return this->addArchive(new archive::Reader
<x86_64
>::Reader(p
, len
, info
.path
, info
.modTime
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3383 if ( mach_o::relocatable::Reader
<arm
>::validFile(p
, objSubtypeMustMatch
, fOptions
.subArchitecture()) )
3384 return this->addObject(new mach_o::relocatable::Reader
<arm
>::Reader(p
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3385 else if ( mach_o::dylib::Reader
<arm
>::validFile(p
, info
.options
.fBundleLoader
) )
3386 return this->addDylib(new mach_o::dylib::Reader
<arm
>::Reader(p
, len
, info
.path
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3387 else if ( archive::Reader
<arm
>::validFile(p
, len
) )
3388 return this->addArchive(new archive::Reader
<arm
>::Reader(p
, len
, info
.path
, info
.modTime
, info
.options
, fOptions
.readerOptions(), fNextInputOrdinal
), info
, len
);
3393 if ( lto::Reader::validFile(p
, len
, fArchitecture
) ) {
3394 return this->addObject(new lto::Reader(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions(), fArchitecture
), info
, len
);
3396 else if ( lto::Reader::fileKind((uint8_t*)p
) != NULL
) {
3397 if ( lto::Reader::loaded() ) {
3398 throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p
), fArchitectureName
);
3401 const char* libLTO
= "libLTO.dylib";
3402 char ldPath
[PATH_MAX
];
3403 char tmpPath
[PATH_MAX
];
3404 char libLTOPath
[PATH_MAX
];
3405 uint32_t bufSize
= PATH_MAX
;
3406 if ( _NSGetExecutablePath(ldPath
, &bufSize
) != -1 ) {
3407 if ( realpath(ldPath
, tmpPath
) != NULL
) {
3408 char* lastSlash
= strrchr(tmpPath
, '/');
3409 if ( lastSlash
!= NULL
)
3410 strcpy(lastSlash
, "/../lib/libLTO.dylib");
3412 if ( realpath(tmpPath
, libLTOPath
) != NULL
)
3413 libLTO
= libLTOPath
;
3416 throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO
);
3421 if ( ((fat_header
*)p
)->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
3422 throwf("missing required architecture %s in file", fArchitectureName
);
3426 throwf("file is universal but does not contain a(n) %s slice", fArchitectureName
);
3428 throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p
), fArchitectureName
);
3432 void Linker::logDylib(ObjectFile::Reader
* reader
, bool indirect
)
3434 if ( fOptions
.readerOptions().fTraceDylibs
) {
3435 const char* fullPath
= reader
->getPath();
3436 char realName
[MAXPATHLEN
];
3437 if ( realpath(fullPath
, realName
) != NULL
)
3438 fullPath
= realName
;
3440 logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath
);
3442 logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath
);
3448 ObjectFile::Reader
* Linker::findDylib(const char* installPath
, const char* fromPath
)
3450 //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
3451 InstallNameToReader::iterator pos
= fDylibMap
.find(installPath
);
3452 if ( pos
!= fDylibMap
.end() ) {
3456 // allow -dylib_path option to override indirect library to use
3457 for (std::vector
<Options::DylibOverride
>::iterator dit
= fOptions
.dylibOverrides().begin(); dit
!= fOptions
.dylibOverrides().end(); ++dit
) {
3458 if ( strcmp(dit
->installName
,installPath
) == 0 ) {\
3460 Options::FileInfo info
= fOptions
.findFile(dit
->useInstead
);
3461 ObjectFile::Reader
* reader
= this->createReader(info
);
3462 fDylibMap
[strdup(installPath
)] = reader
;
3463 this->logDylib(reader
, true);
3466 catch (const char* msg
) {
3467 warning("ignoring -dylib_file option, %s", msg
);
3471 char newPath
[MAXPATHLEN
];
3472 // handle @loader_path
3473 if ( strncmp(installPath
, "@loader_path/", 13) == 0 ) {
3474 strcpy(newPath
, fromPath
);
3475 char* addPoint
= strrchr(newPath
,'/');
3476 if ( addPoint
!= NULL
)
3477 strcpy(&addPoint
[1], &installPath
[13]);
3479 strcpy(newPath
, &installPath
[13]);
3480 installPath
= newPath
;
3482 // note: @executable_path case is handled inside findFileUsingPaths()
3483 // search for dylib using -F and -L paths
3484 Options::FileInfo info
= fOptions
.findFileUsingPaths(installPath
);
3486 ObjectFile::Reader
* reader
= this->createReader(info
);
3487 fDylibMap
[strdup(installPath
)] = reader
;
3488 this->logDylib(reader
, true);
3491 catch (const char* msg
) {
3492 throwf("in %s, %s", info
.path
, msg
);
3498 void Linker::processDylibs()
3500 fAllDirectDylibsLoaded
= true;
3502 // mark all dylibs initially specified as required and check if they can be used
3503 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
3504 it
->second
->setExplicitlyLinked();
3505 this->checkDylibClientRestrictions(it
->second
);
3508 // keep processing dylibs until no more dylibs are added
3509 unsigned long lastMapSize
= 0;
3510 while ( lastMapSize
!= fDylibMap
.size() ) {
3511 lastMapSize
= fDylibMap
.size();
3512 // can't iterator fDylibMap while modifying it, so use temp buffer
3513 std::vector
<ObjectFile::Reader
*> currentUnprocessedReaders
;
3514 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
3515 if ( fDylibsProcessed
.count(it
->second
) == 0 )
3516 currentUnprocessedReaders
.push_back(it
->second
);
3518 for (std::vector
<ObjectFile::Reader
*>::iterator it
=currentUnprocessedReaders
.begin(); it
!= currentUnprocessedReaders
.end(); it
++) {
3519 fDylibsProcessed
.insert(*it
);
3520 (*it
)->processIndirectLibraries(this);
3524 // go back over original dylibs and mark sub frameworks as re-exported
3525 if ( fOptions
.outputKind() == Options::kDynamicLibrary
) {
3526 const char* myLeaf
= strrchr(fOptions
.installPath(), '/');
3527 if ( myLeaf
!= NULL
) {
3528 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
3529 ObjectFile::Reader
* reader
= *it
;
3530 const char* childParent
= reader
->parentUmbrella();
3531 if ( childParent
!= NULL
) {
3532 if ( strcmp(childParent
, &myLeaf
[1]) == 0 ) {
3533 // set re-export bit of info
3534 std::map
<ObjectFile::Reader
*,LibraryOptions
>::iterator pos
= fDylibOptionsMap
.find(reader
);
3535 if ( pos
!= fDylibOptionsMap
.end() ) {
3536 pos
->second
.fReExport
= true;
3548 void Linker::createReaders()
3550 fStartCreateReadersTime
= mach_absolute_time();
3551 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
3552 const int count
= files
.size();
3554 throw "no object files specified";
3555 // add all direct object, archives, and dylibs
3556 for (int i
=0; i
< count
; ++i
) {
3557 Options::FileInfo
& entry
= files
[i
];
3558 // ignore /usr/lib/dyld on command line in crt.o build
3559 if ( strcmp(entry
.path
, "/usr/lib/dyld") != 0 ) {
3561 this->addInputFile(this->createReader(entry
), entry
);
3563 catch (const char* msg
) {
3564 if ( (strstr(msg
, "architecture") != NULL
) && !fOptions
.errorOnOtherArchFiles() ) {
3565 if ( fOptions
.ignoreOtherArchInputFiles() ) {
3566 // ignore, because this is about an architecture not in use
3569 warning("in %s, %s", entry
.path
, msg
);
3573 throwf("in %s, %s", entry
.path
, msg
);
3579 this->processDylibs();
3584 ObjectFile::Reader
* Linker::addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
3586 fNextInputOrdinal
+= mappedLen
;
3587 // remember which readers are archives because they are logged differently
3588 fArchiveReaders
.insert(reader
);
3591 fTotalArchiveSize
+= mappedLen
;
3592 ++fTotalArchivesLoaded
;
3596 ObjectFile::Reader
* Linker::addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
3598 fNextInputOrdinal
+= mappedLen
;
3599 // any .o files that don't have MH_SUBSECTIONS_VIA_SYMBOLS, that means a generated .o file can't
3600 if ( (fOptions
.outputKind() == Options::kObjectFile
) && !reader
->canScatterAtoms() )
3601 fCanScatter
= false;
3604 fTotalObjectSize
+= mappedLen
;
3605 ++fTotalObjectLoaded
;
3610 void Linker::checkDylibClientRestrictions(ObjectFile::Reader
* reader
)
3612 // Check for any restrictions on who can link with this dylib
3613 const char* readerParentName
= reader
->parentUmbrella() ;
3614 std::vector
<const char*>* clients
= reader
->getAllowableClients();
3615 if ( (readerParentName
!= NULL
) || (clients
!= NULL
) ) {
3616 // only dylibs that are in an umbrella or have a client list need verification
3617 const char* installName
= fOptions
.installPath();
3618 const char* installNameLastSlash
= strrchr(installName
, '/');
3619 bool isParent
= false;
3620 bool isSibling
= false;
3621 bool isAllowableClient
= false;
3622 // There are three cases:
3623 if ( (readerParentName
!= NULL
) && (installNameLastSlash
!= NULL
) ) {
3624 // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
3625 isParent
= ( strcmp(&installNameLastSlash
[1], readerParentName
) == 0 );
3627 // hack to support umbrella variants that encode the variant name in the install name
3628 // e.g. CoreServices_profile
3630 const char* underscore
= strchr(&installNameLastSlash
[1], '_');
3631 if ( underscore
!= NULL
) {
3632 isParent
= ( strncmp(&installNameLastSlash
[1], readerParentName
, underscore
-installNameLastSlash
-1) == 0 );
3636 // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
3637 isSibling
= ( (fOptions
.umbrellaName() != NULL
) && (strcmp(fOptions
.umbrellaName(), readerParentName
) == 0) );
3640 if ( !isParent
&& !isSibling
&& (clients
!= NULL
) ) {
3641 // case 3) the dylib has a list of allowable clients, and we are creating one of them
3642 const char* clientName
= fOptions
.clientName();
3643 int clientNameLen
= 0;
3644 if ( clientName
!= NULL
) {
3645 // use client name as specified on command line
3646 clientNameLen
= strlen(clientName
);
3649 // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar)
3650 clientName
= installName
;
3651 clientNameLen
= strlen(clientName
);
3652 // starts after last slash
3653 if ( installNameLastSlash
!= NULL
)
3654 clientName
= &installNameLastSlash
[1];
3655 if ( strncmp(clientName
, "lib", 3) == 0 )
3656 clientName
= &clientName
[3];
3658 const char* firstDot
= strchr(clientName
, '.');
3659 if ( firstDot
!= NULL
)
3660 clientNameLen
= firstDot
- clientName
;
3661 // up to first underscore
3662 const char* firstUnderscore
= strchr(clientName
, '_');
3663 if ( (firstUnderscore
!= NULL
) && ((firstUnderscore
- clientName
) < clientNameLen
) )
3664 clientNameLen
= firstUnderscore
- clientName
;
3667 // Use clientName to check if this dylib is able to link against the allowable clients.
3668 for (std::vector
<const char*>::iterator it
= clients
->begin(); it
!= clients
->end(); it
++) {
3669 if ( strncmp(*it
, clientName
, clientNameLen
) == 0 )
3670 isAllowableClient
= true;
3674 if ( !isParent
&& !isSibling
&& !isAllowableClient
) {
3675 if ( readerParentName
!= NULL
) {
3676 throwf("cannot link directly with %s. Link against the umbrella framework '%s.framework' instead.",
3677 reader
->getPath(), readerParentName
);
3680 throwf("cannot link directly with %s", reader
->getPath());
3687 ObjectFile::Reader
* Linker::addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
3689 switch ( fOptions
.outputKind() ) {
3690 case Options::kDynamicExecutable
:
3691 case Options::kDynamicLibrary
:
3692 case Options::kDynamicBundle
:
3694 case Options::kStaticExecutable
:
3695 case Options::kDyld
:
3696 case Options::kPreload
:
3697 case Options::kObjectFile
:
3698 case Options::kKextBundle
:
3699 warning("unexpected dylib (%s) on link line", reader
->getPath());
3703 fNextInputOrdinal
+= mappedLen
;
3704 if ( (reader
->getInstallPath() == NULL
) && !info
.options
.fBundleLoader
) {
3705 // this is a "blank" stub
3706 // silently ignore it
3709 // add to map of loaded dylibs
3710 const char* installPath
= reader
->getInstallPath();
3711 if ( installPath
!= NULL
) {
3712 InstallNameToReader::iterator pos
= fDylibMap
.find(installPath
);
3713 if ( pos
== fDylibMap
.end() ) {
3714 fDylibMap
[strdup(installPath
)] = reader
;
3717 InstallNameToReader::iterator pos2
= fDylibMap
.find(reader
->getPath());
3718 if ( pos2
== fDylibMap
.end() )
3719 fDylibMap
[strdup(reader
->getPath())] = reader
;
3721 warning("duplicate dylib %s", reader
->getPath());
3724 else if ( info
.options
.fBundleLoader
)
3725 fBundleLoaderReader
= reader
;
3727 // log direct readers
3728 if ( !fAllDirectDylibsLoaded
)
3729 this->logDylib(reader
, false);
3732 ++fTotalDylibsLoaded
;
3738 void Linker::logTraceInfo (const char* format
, ...)
3740 static int trace_file
= -1;
3741 char trace_buffer
[MAXPATHLEN
* 2];
3744 ssize_t amount_written
;
3745 const char *trace_file_path
= fOptions
.readerOptions().fTraceOutputFile
;
3747 if(trace_file
== -1) {
3748 if(trace_file_path
!= NULL
) {
3749 trace_file
= open(trace_file_path
, O_WRONLY
| O_APPEND
| O_CREAT
, 0666);
3750 if(trace_file
== -1)
3751 throwf("Could not open or create trace file: %s", trace_file_path
);
3754 trace_file
= fileno(stderr
);
3759 va_start(ap
, format
);
3760 length
= vsnprintf(trace_buffer
, sizeof(trace_buffer
), format
, ap
);
3762 buffer_ptr
= trace_buffer
;
3765 amount_written
= write(trace_file
, buffer_ptr
, length
);
3766 if(amount_written
== -1)
3767 /* Failure to write shouldn't fail the build. */
3769 buffer_ptr
+= amount_written
;
3770 length
-= amount_written
;
3776 void Linker::createWriter()
3778 fStartCreateWriterTime
= mach_absolute_time();
3780 // make a vector out of all required dylibs in fDylibMap
3781 std::vector
<ExecutableFile::DyLibUsed
> dynamicLibraries
;
3782 // need to preserve command line order
3783 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
3784 ObjectFile::Reader
* reader
= *it
;
3785 for (InstallNameToReader::iterator mit
=fDylibMap
.begin(); mit
!= fDylibMap
.end(); mit
++) {
3786 if ( reader
== mit
->second
) {
3787 ExecutableFile::DyLibUsed dylibInfo
;
3788 dylibInfo
.reader
= reader
;
3789 dylibInfo
.options
= fDylibOptionsMap
[reader
];
3790 dynamicLibraries
.push_back(dylibInfo
);
3795 // then add any other dylibs
3796 for (InstallNameToReader::iterator it
=fDylibMap
.begin(); it
!= fDylibMap
.end(); it
++) {
3797 if ( it
->second
->implicitlyLinked() ) {
3798 // if not already in dynamicLibraries
3799 bool alreadyInDynamicLibraries
= false;
3800 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator dit
=dynamicLibraries
.begin(); dit
!= dynamicLibraries
.end(); dit
++) {
3801 if ( dit
->reader
== it
->second
) {
3802 alreadyInDynamicLibraries
= true;
3806 if ( ! alreadyInDynamicLibraries
) {
3807 ExecutableFile::DyLibUsed dylibInfo
;
3808 dylibInfo
.reader
= it
->second
;
3809 std::map
<ObjectFile::Reader
*,LibraryOptions
>::iterator pos
= fDylibOptionsMap
.find(it
->second
);
3810 if ( pos
!= fDylibOptionsMap
.end() ) {
3811 dylibInfo
.options
= pos
->second
;
3814 dylibInfo
.options
.fWeakImport
= false; // FIX ME
3815 dylibInfo
.options
.fReExport
= false;
3816 dylibInfo
.options
.fBundleLoader
= false;
3818 dynamicLibraries
.push_back(dylibInfo
);
3822 if ( fBundleLoaderReader
!= NULL
) {
3823 ExecutableFile::DyLibUsed dylibInfo
;
3824 dylibInfo
.reader
= fBundleLoaderReader
;
3825 dylibInfo
.options
.fWeakImport
= false;
3826 dylibInfo
.options
.fReExport
= false;
3827 dylibInfo
.options
.fBundleLoader
= true;
3828 dynamicLibraries
.push_back(dylibInfo
);
3831 const char* path
= fOptions
.getOutputFilePath();
3832 switch ( fArchitecture
) {
3833 case CPU_TYPE_POWERPC
:
3834 this->setOutputFile(new mach_o::executable::Writer
<ppc
>(path
, fOptions
, dynamicLibraries
));
3836 case CPU_TYPE_POWERPC64
:
3837 this->setOutputFile(new mach_o::executable::Writer
<ppc64
>(path
, fOptions
, dynamicLibraries
));
3840 this->setOutputFile(new mach_o::executable::Writer
<x86
>(path
, fOptions
, dynamicLibraries
));
3842 case CPU_TYPE_X86_64
:
3843 this->setOutputFile(new mach_o::executable::Writer
<x86_64
>(path
, fOptions
, dynamicLibraries
));
3846 this->setOutputFile(new mach_o::executable::Writer
<arm
>(path
, fOptions
, dynamicLibraries
));
3849 throw "unknown architecture";
3854 Linker::SymbolTable::SymbolTable(Linker
& owner
)
3855 : fOwner(owner
), fRequireCount(0), fHasExternalTentativeDefinitions(false), fHasExternalWeakDefinitions(false)
3859 void Linker::SymbolTable::require(const char* name
)
3861 //fprintf(stderr, "require(%s)\n", name);
3862 Mapper::iterator pos
= fTable
.find(name
);
3863 if ( pos
== fTable
.end() ) {
3864 fTable
[name
] = NULL
;
3869 // convenience labels for 2-dimensional switch statement
3870 enum AllDefinitionCombinations
{
3871 kRegAndReg
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3872 kRegAndWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3873 kRegAndTent
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3874 kRegAndExtern
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3875 kRegAndExternWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3876 kRegAndAbsolute
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3877 kWeakAndReg
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3878 kWeakAndWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3879 kWeakAndTent
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3880 kWeakAndExtern
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3881 kWeakAndExternWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3882 kWeakAndAbsolute
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3883 kTentAndReg
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3884 kTentAndWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3885 kTentAndTent
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3886 kTentAndExtern
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3887 kTentAndExternWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3888 kTentAndAbsolute
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3889 kExternAndReg
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3890 kExternAndWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3891 kExternAndTent
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3892 kExternAndExtern
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3893 kExternAndExternWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3894 kExternAndAbsolute
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3895 kExternWeakAndReg
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3896 kExternWeakAndWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3897 kExternWeakAndTent
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3898 kExternWeakAndExtern
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3899 kExternWeakAndExternWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3900 kExternWeakAndAbsolute
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
,
3901 kAbsoluteAndReg
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kRegularDefinition
,
3902 kAbsoluteAndWeak
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kWeakDefinition
,
3903 kAbsoluteAndTent
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
3904 kAbsoluteAndExtern
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kExternalDefinition
,
3905 kAbsoluteAndExternWeak
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
3906 kAbsoluteAndAbsolute
= (ObjectFile::Atom::kAbsoluteSymbol
<< 3) | ObjectFile::Atom::kAbsoluteSymbol
3909 bool Linker::SymbolTable::add(ObjectFile::Atom
& newAtom
)
3912 bool checkVisibilityMismatch
= false;
3913 const char* name
= newAtom
.getName();
3914 //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
3915 Mapper::iterator pos
= fTable
.find(name
);
3916 ObjectFile::Atom
* existingAtom
= NULL
;
3917 if ( pos
!= fTable
.end() )
3918 existingAtom
= pos
->second
;
3919 if ( existingAtom
!= NULL
) {
3920 // already have atom with same name in symbol table
3921 switch ( (AllDefinitionCombinations
)((existingAtom
->getDefinitionKind() << 3) | newAtom
.getDefinitionKind()) ) {
3923 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3925 // ignore new weak atom, because we already have a non-weak one
3929 // ignore new tentative atom, because we already have a regular one
3931 checkVisibilityMismatch
= true;
3932 if ( newAtom
.getSize() > existingAtom
->getSize() ) {
3933 warning("for symbol %s tentative definition of size %llu from %s is "
3934 "is smaller than the real definition of size %llu from %s",
3935 newAtom
.getDisplayName(), newAtom
.getSize(), newAtom
.getFile()->getPath(),
3936 existingAtom
->getSize(), existingAtom
->getFile()->getPath());
3940 // ignore external atom, because we already have a one
3943 case kRegAndExternWeak
:
3944 // ignore external atom, because we already have a one
3947 case kRegAndAbsolute
:
3948 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
3951 // replace existing weak atom with regular one
3954 // have another weak atom, use whichever has largest alignment requirement
3955 // because codegen of some client may require alignment
3956 useNew
= ( newAtom
.getAlignment().trailingZeros() > existingAtom
->getAlignment().trailingZeros() );
3957 checkVisibilityMismatch
= true;
3960 // replace existing weak atom with tentative one ???
3962 case kWeakAndExtern
:
3963 // keep weak atom, at runtime external one may override
3966 case kWeakAndExternWeak
:
3967 // keep weak atom, at runtime external one may override
3970 case kWeakAndAbsolute
:
3971 // replace existing weak atom with absolute one
3974 // replace existing tentative atom with regular one
3975 checkVisibilityMismatch
= true;
3976 if ( newAtom
.getSize() < existingAtom
->getSize() ) {
3977 warning("for symbol %s tentative definition of size %llu from %s is "
3978 "being replaced by a real definition of size %llu from %s",
3979 newAtom
.getDisplayName(), existingAtom
->getSize(), existingAtom
->getFile()->getPath(),
3980 newAtom
.getSize(), newAtom
.getFile()->getPath());
3984 // replace existing tentative atom with weak one ???
3988 checkVisibilityMismatch
= true;
3989 if ( newAtom
.getSize() < existingAtom
->getSize() ) {
3993 if ( newAtom
.getAlignment().trailingZeros() < existingAtom
->getAlignment().trailingZeros() )
3994 warning("alignment lost in merging tentative definition %s", newAtom
.getDisplayName());
3997 case kTentAndExtern
:
3998 case kTentAndExternWeak
:
3999 // a tentative definition and a dylib definition, so commons-mode decides how to handle
4000 switch ( fOwner
.fOptions
.commonsMode() ) {
4001 case Options::kCommonsIgnoreDylibs
:
4002 if ( fOwner
.fOptions
.warnCommons() )
4003 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
4004 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
4007 case Options::kCommonsOverriddenByDylibs
:
4008 if ( fOwner
.fOptions
.warnCommons() )
4009 warning("replacing common symbol %s from %s with true definition from dylib %s",
4010 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
4012 case Options::kCommonsConflictsDylibsError
:
4013 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
4014 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
4017 case kTentAndAbsolute
:
4018 // replace tentative with absolute (can't size check because absolutes have no size)
4021 // replace external atom with regular one
4023 case kExternAndWeak
:
4024 // replace external atom with weak one
4026 case kExternAndTent
:
4027 // a tentative definition and a dylib definition, so commons-mode decides how to handle
4028 switch ( fOwner
.fOptions
.commonsMode() ) {
4029 case Options::kCommonsIgnoreDylibs
:
4030 if ( fOwner
.fOptions
.warnCommons() )
4031 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
4032 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
4034 case Options::kCommonsOverriddenByDylibs
:
4035 if ( fOwner
.fOptions
.warnCommons() )
4036 warning("replacing defintion of %s from dylib %s with common symbol from %s",
4037 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
4040 case Options::kCommonsConflictsDylibsError
:
4041 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
4042 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
4045 case kExternAndExtern
:
4046 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
4047 case kExternAndExternWeak
:
4048 // keep strong dylib atom, ignore weak one
4051 case kExternAndAbsolute
:
4052 // replace external atom with absolute one
4054 case kExternWeakAndReg
:
4055 // replace existing weak external with regular
4057 case kExternWeakAndWeak
:
4058 // replace existing weak external with weak (let dyld decide at runtime which to use)
4060 case kExternWeakAndTent
:
4061 // a tentative definition and a dylib definition, so commons-mode decides how to handle
4062 switch ( fOwner
.fOptions
.commonsMode() ) {
4063 case Options::kCommonsIgnoreDylibs
:
4064 if ( fOwner
.fOptions
.warnCommons() )
4065 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
4066 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
4068 case Options::kCommonsOverriddenByDylibs
:
4069 if ( fOwner
.fOptions
.warnCommons() )
4070 warning("replacing defintion of %s from dylib %s with common symbol from %s",
4071 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
4074 case Options::kCommonsConflictsDylibsError
:
4075 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
4076 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
4079 case kExternWeakAndExtern
:
4080 // replace existing weak external with external
4082 case kExternWeakAndExternWeak
:
4083 // keep existing external weak
4086 case kExternWeakAndAbsolute
:
4087 // replace existing weak external with absolute
4089 case kAbsoluteAndReg
:
4090 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
4091 case kAbsoluteAndWeak
:
4092 // ignore new weak atom, because we already have a non-weak one
4095 case kAbsoluteAndTent
:
4096 // ignore new tentative atom, because we already have a regular one
4099 case kAbsoluteAndExtern
:
4100 // ignore external atom, because we already have a one
4103 case kAbsoluteAndExternWeak
:
4104 // ignore external atom, because we already have a one
4107 case kAbsoluteAndAbsolute
:
4108 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
4112 if ( (existingAtom
!= NULL
) && checkVisibilityMismatch
&& (newAtom
.getScope() != existingAtom
->getScope()) ) {
4113 warning("%s has different visibility (%s) in %s and (%s) in %s",
4114 newAtom
.getDisplayName(), (newAtom
.getScope() == 1 ? "hidden" : "default"), newAtom
.getFile()->getPath(), (existingAtom
->getScope() == 1 ? "hidden" : "default"), existingAtom
->getFile()->getPath());
4117 fTable
[name
] = &newAtom
;
4118 if ( existingAtom
!= NULL
) {
4119 fOwner
.markDead(existingAtom
);
4120 if ( fOwner
.fInitialLoadsDone
) {
4121 //fprintf(stderr, "existing %p %s overridden by %p\n", existingAtom, existingAtom->getName(), &newAtom);
4122 fOwner
.fAtomsOverriddenByLateLoads
.insert(existingAtom
);
4125 if ( newAtom
.getScope() == ObjectFile::Atom::scopeGlobal
) {
4126 switch ( newAtom
.getDefinitionKind() ) {
4127 case ObjectFile::Atom::kTentativeDefinition
:
4128 fHasExternalTentativeDefinitions
= true;
4129 ++fRequireCount
; // added a tentative definition means loadUndefines() needs to continue
4131 case ObjectFile::Atom::kWeakDefinition
:
4132 if ( newAtom
.getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn
)
4133 fHasExternalWeakDefinitions
= true;
4135 case ObjectFile::Atom::kExternalDefinition
:
4136 case ObjectFile::Atom::kExternalWeakDefinition
:
4137 ++fDylibSymbolCount
;
4145 fOwner
.markDead(&newAtom
);
4152 ObjectFile::Atom
* Linker::SymbolTable::find(const char* name
)
4154 Mapper::iterator pos
= fTable
.find(name
);
4155 if ( pos
!= fTable
.end() ) {
4161 void Linker::SymbolTable::erase(const char* name
) {
4165 void Linker::SymbolTable::getUndefinesNames(std::vector
<const char*>& undefines
)
4167 for (Mapper::iterator it
=fTable
.begin(); it
!= fTable
.end(); it
++) {
4168 if ( it
->second
== NULL
) {
4169 undefines
.push_back(it
->first
);
4174 void Linker::SymbolTable::getTentativesNames(std::vector
<const char*>& tents
)
4176 for (Mapper::iterator it
=fTable
.begin(); it
!= fTable
.end(); it
++) {
4177 if ( it
->second
!= NULL
) {
4178 if ( (it
->second
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
)
4179 && (it
->second
->getScope() == ObjectFile::Atom::scopeGlobal
) ) {
4180 tents
.push_back(it
->first
);
4188 bool Linker::AtomSorter::operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
)
4190 if ( left
== right
)
4193 // first sort by section order (which is already sorted by segment)
4194 unsigned int leftSectionIndex
= left
->getSection()->getIndex();
4195 unsigned int rightSectionIndex
= right
->getSection()->getIndex();
4196 if ( leftSectionIndex
!= rightSectionIndex
)
4197 return (leftSectionIndex
< rightSectionIndex
);
4199 // magic section$start symbol always sorts to the start of its section
4200 if ( left
->getContentType() == ObjectFile::Atom::kSectionStart
)
4202 if ( right
->getContentType() == ObjectFile::Atom::kSectionStart
)
4205 // if a -order_file is specified, then sorting is altered to sort those symbols first
4206 if ( fOverriddenOrdinalMap
!= NULL
) {
4207 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator leftPos
= fOverriddenOrdinalMap
->find(left
);
4208 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator rightPos
= fOverriddenOrdinalMap
->find(right
);
4209 std::map
<const ObjectFile::Atom
*, uint32_t>::iterator end
= fOverriddenOrdinalMap
->end();
4210 if ( leftPos
!= end
) {
4211 if ( rightPos
!= end
) {
4212 // both left and right are overridden, so compare overridden ordinals
4213 return leftPos
->second
< rightPos
->second
;
4216 // left is overridden and right is not, so left < right
4221 if ( rightPos
!= end
) {
4222 // right is overridden and left is not, so right < left
4226 // neither are overridden, do default sort
4227 // fall into default sorting below
4232 // magic section$end symbol always sorts to the end of its section
4233 if ( left
->getContentType() == ObjectFile::Atom::kSectionEnd
)
4235 if ( right
->getContentType() == ObjectFile::Atom::kSectionEnd
)
4238 // the __common section can have real or tentative definitions
4239 // we want the real ones to sort before tentative ones
4240 bool leftIsTent
= (left
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
);
4241 bool rightIsTent
= (right
->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition
);
4242 if ( leftIsTent
!= rightIsTent
)
4245 // initializers are auto sorted to start of section
4246 if ( !fInitializerSet
.empty() ) {
4247 bool leftFirst
= (fInitializerSet
.count(left
) != 0);
4248 bool rightFirst
= (fInitializerSet
.count(right
) != 0);
4249 if ( leftFirst
!= rightFirst
)
4253 // terminators are auto sorted to end of section
4254 if ( !fTerminatorSet
.empty() ) {
4255 bool leftLast
= (fTerminatorSet
.count(left
) != 0);
4256 bool rightLast
= (fTerminatorSet
.count(right
) != 0);
4257 if ( leftLast
!= rightLast
)
4261 // lastly sort by atom ordinal. this is already sorted by .o order
4262 return left
->getOrdinal() < right
->getOrdinal();
4266 int main(int argc
, const char* argv
[])
4268 const char* archName
= NULL
;
4269 bool showArch
= false;
4270 bool archInferred
= false;
4272 // create linker object given command line arguments
4273 Linker
ld(argc
, argv
);
4275 // save error message prefix
4276 archName
= ld
.architectureName();
4277 archInferred
= ld
.isInferredArchitecture();
4278 showArch
= ld
.showArchitectureInErrors();
4280 // open all input files
4289 catch (const char* msg
) {
4291 fprintf(stderr
, "ld: %s for inferred architecture %s\n", msg
, archName
);
4292 else if ( showArch
)
4293 fprintf(stderr
, "ld: %s for architecture %s\n", msg
, archName
);
4295 fprintf(stderr
, "ld: %s\n", msg
);