1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
28 #include <sys/sysctl.h>
32 #include <mach/mach_time.h>
33 #include <mach/vm_statistics.h>
34 #include <mach/mach_init.h>
35 #include <mach/mach_host.h>
36 #include <mach-o/fat.h>
45 #include <ext/hash_map>
49 #include "ObjectFile.h"
51 #include "MachOReaderRelocatable.hpp"
52 #include "MachOReaderArchive.hpp"
53 #include "MachOReaderDylib.hpp"
54 #include "MachOWriterExecutable.hpp"
56 #include "SectCreate.h"
59 static void dumpAtom(ObjectFile::Atom
* atom
)
61 //printf("atom: %p\n", atom);
64 printf("name: %s\n", atom
->getDisplayName());
67 switch ( atom
->getScope() ) {
68 case ObjectFile::Atom::scopeTranslationUnit
:
69 printf("scope: translation unit\n");
71 case ObjectFile::Atom::scopeLinkageUnit
:
72 printf("scope: linkage unit\n");
74 case ObjectFile::Atom::scopeGlobal
:
75 printf("scope: global\n");
78 printf("scope: unknown\n");
82 switch ( atom
->getDefinitinonKind() ) {
83 case ObjectFile::Atom::kRegularDefinition
:
84 printf("kind: regular\n");
86 case ObjectFile::Atom::kWeakDefinition
:
87 printf("kind: weak\n");
89 case ObjectFile::Atom::kTentativeDefinition
:
90 printf("kind: tentative\n");
92 case ObjectFile::Atom::kExternalDefinition
:
93 printf("kind: import\n");
95 case ObjectFile::Atom::kExternalWeakDefinition
:
96 printf("kind: weak import\n");
99 printf("scope: unknown\n");
102 // segment and section
103 printf("section: %s,%s\n", atom
->getSegment().getName(), atom
->getSectionName());
107 if ( atom
->dontDeadStrip() )
108 printf("dont-dead-strip ");
109 if ( atom
->isZeroFill() )
110 printf("zero-fill ");
114 printf("size: 0x%012llX\n", atom
->getSize());
117 uint8_t content
[atom
->getSize()];
118 atom
->copyRawContent(content
);
120 if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
121 printf("\"%s\"", content
);
124 for (unsigned int i
=0; i
< sizeof(content
); ++i
)
125 printf("%02X ", content
[i
]);
130 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
131 const int refCount
= references
.size();
132 printf("references: (%u)\n", refCount
);
133 for (int i
=0; i
< refCount
; ++i
) {
134 ObjectFile::Reference
* ref
= references
[i
];
135 printf(" %s\n", ref
->getDescription());
144 class CStringComparor
147 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) < 0); }
153 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
156 class Section
: public ObjectFile::Section
159 static Section
* find(const char* sectionName
, const char* segmentName
, bool zeroFill
);
160 static void assignIndexes();
163 Section(const char* sectionName
, const char* segmentName
, bool zeroFill
);
166 static int segmentOrdinal(const char* segName
);
167 bool operator()(Section
* left
, Section
* right
);
170 typedef __gnu_cxx::hash_map
<const char*, class Section
*, __gnu_cxx::hash
<const char*>, CStringEquals
> NameToSection
;
171 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
173 const char* fSectionName
;
174 const char* fSegmentName
;
177 static NameToSection fgMapping
;
178 static std::vector
<Section
*> fgSections
;
181 Section::NameToSection
Section::fgMapping
;
182 std::vector
<Section
*> Section::fgSections
;
184 Section::Section(const char* sectionName
, const char* segmentName
, bool zeroFill
)
185 : fSectionName(sectionName
), fSegmentName(segmentName
), fZeroFill(zeroFill
)
187 //fprintf(stderr, "new Section(%s, %s)\n", sectionName, segmentName);
190 Section
* Section::find(const char* sectionName
, const char* segmentName
, bool zeroFill
)
192 NameToSection::iterator pos
= fgMapping
.find(sectionName
);
193 if ( pos
!= fgMapping
.end() ) {
194 if ( strcmp(pos
->second
->fSegmentName
, segmentName
) == 0 )
196 // otherwise same section name is used in different segments, look slow way
197 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++) {
198 if ( (strcmp((*it
)->fSectionName
, sectionName
) == 0) && (strcmp((*it
)->fSegmentName
, segmentName
) == 0) )
203 // does not exist, so make a new one
204 Section
* sect
= new Section(sectionName
, segmentName
, zeroFill
);
205 sect
->fIndex
= fgMapping
.size();
206 fgMapping
[sectionName
] = sect
;
207 fgSections
.push_back(sect
);
209 if ( (strcmp(sectionName
, "__text") == 0) && (strcmp(segmentName
, "__TEXT") == 0) ) {
210 // special case __textcoal_nt to be right after __text
211 find("__textcoal_nt", "__TEXT", false);
217 int Section::Sorter::segmentOrdinal(const char* segName
)
219 if ( strcmp(segName
, "__PAGEZERO") == 0 )
221 if ( strcmp(segName
, "__TEXT") == 0 )
223 if ( strcmp(segName
, "__DATA") == 0 )
225 if ( strcmp(segName
, "__OBJC") == 0 )
227 if ( strcmp(segName
, "__LINKEDIT") == 0 )
228 return INT_MAX
; // linkedit segment should always sort last
234 bool Section::Sorter::operator()(Section
* left
, Section
* right
)
236 // Segment is primary sort key
237 const char* leftSegName
= left
->fSegmentName
;
238 const char* rightSegName
= right
->fSegmentName
;
239 int segNameCmp
= strcmp(leftSegName
, rightSegName
);
240 if ( segNameCmp
!= 0 )
242 int leftSegOrdinal
= segmentOrdinal(leftSegName
);
243 int rightSegOrdinal
= segmentOrdinal(rightSegName
);
244 if ( leftSegOrdinal
< rightSegOrdinal
)
246 if ( leftSegOrdinal
== rightSegOrdinal
)
247 return segNameCmp
< 0;
251 // zerofill section sort to the end
252 if ( !left
->fZeroFill
&& right
->fZeroFill
)
254 if ( left
->fZeroFill
&& !right
->fZeroFill
)
257 // section discovery order is last sort key
258 return left
->fIndex
< right
->fIndex
;
261 void Section::assignIndexes()
263 //printf("unsorted:\n");
264 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
265 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
269 std::sort(fgSections
.begin(), fgSections
.end(), Section::Sorter());
271 // assign correct section ordering to each Section object
272 unsigned int newOrder
= 1;
273 for (std::vector
<Section
*>::iterator it
=fgSections
.begin(); it
!= fgSections
.end(); it
++)
274 (*it
)->fIndex
= newOrder
++;
276 //printf("sorted:\n");
277 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
278 // printf("section: name=%s\n", (*it)->fSectionName);
284 Linker(int argc
, const char* argv
[]);
286 void createReaders();
288 void addInputFile(ObjectFile::Reader
* reader
);
289 void setOutputFile(ExecutableFile::Writer
* writer
);
294 ObjectFile::Reader
* createReader(const Options::FileInfo
&);
295 void addAtom(ObjectFile::Atom
& atom
);
296 void addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
);
297 void buildAtomList();
298 void loadUndefines();
299 void addWeakAtomOverrides();
300 void resolveReferences();
304 void writeDotOutput();
305 static bool minimizeStab(ObjectFile::Reader::Stab
& stab
);
306 static const char* truncateStabString(const char* str
);
309 ObjectFile::Atom
* entryPoint();
310 ObjectFile::Atom
* dyldHelper();
311 const char* assureFullPath(const char* path
);
312 void markLive(ObjectFile::Atom
* atom
, std::set
<ObjectFile::Atom
*>& liveAtoms
);
313 void collectStabs(ObjectFile::Reader
* reader
);
314 void synthesizeStabs(ObjectFile::Reader
* reader
);
315 void printStatistics();
316 void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
);
317 char* commatize(uint64_t in
, char* out
);
318 void getVMInfo(vm_statistics_data_t
& info
);
319 cpu_type_t
inferArchitecture();
321 void resolve(ObjectFile::Reference
* reference
);
322 void resolveFrom(ObjectFile::Reference
* reference
);
323 void addJustInTimeAtoms(const char* name
);
325 ObjectFile::Reader
* addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
326 ObjectFile::Reader
* addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
327 ObjectFile::Reader
* addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
);
328 void addIndirectLibraries(ObjectFile::Reader
* reader
);
329 bool haveIndirectLibrary(const char* path
, ObjectFile::Reader
* reader
);
330 bool haveDirectLibrary(const char* path
);
332 void logTraceInfo(const char* format
, ...);
336 SymbolTable(Linker
&);
337 void require(const char* name
);
338 bool add(ObjectFile::Atom
& atom
);
339 ObjectFile::Atom
* find(const char* name
);
340 unsigned int getRequireCount() { return fRequireCount
; }
341 void getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
);
343 typedef __gnu_cxx::hash_map
<const char*, ObjectFile::Atom
*, __gnu_cxx::hash
<const char*>, CStringEquals
> Mapper
;
346 unsigned int fRequireCount
;
351 bool operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
);
354 typedef std::map
<const char*, uint32_t, CStringComparor
> SectionOrder
;
356 struct IndirectLibrary
{
359 ObjectFile::Reader
* reader
;
360 std::set
<ObjectFile::Reader
*> parents
;
361 ObjectFile::Reader
* reExportedViaDirectLibrary
;
364 ObjectFile::Reader
* findDirectLibraryWhichReExports(struct IndirectLibrary
& indirectLib
);
367 SymbolTable fGlobalSymbolTable
;
368 unsigned int fWeakSymbolsAddedCount
;
369 std::vector
<class ObjectFile::Reader
*> fInputFiles
;
370 ExecutableFile::Writer
* fOutputFile
;
371 std::vector
<ExecutableFile::DyLibUsed
> fDynamicLibraries
;
372 std::list
<IndirectLibrary
> fIndirectDynamicLibraries
;
373 std::vector
<class ObjectFile::Reader
*> fReadersThatHaveSuppliedAtoms
;
374 std::vector
<class ObjectFile::Atom
*> fAllAtoms
;
375 std::set
<class ObjectFile::Atom
*> fDeadAtoms
;
376 std::vector
<class ObjectFile::Reader::Stab
> fStabs
;
378 SectionOrder fSectionOrder
;
379 unsigned int fNextSortOrder
;
380 unsigned int fNextObjectFileOrder
;
381 cpu_type_t fArchitecture
;
382 bool fDirectLibrariesComplete
;
383 uint64_t fOutputFileSize
;
385 uint64_t fStartCreateReadersTime
;
386 uint64_t fStartCreateWriterTime
;
387 uint64_t fStartBuildAtomsTime
;
388 uint64_t fStartLoadUndefinesTime
;
389 uint64_t fStartResolveTime
;
390 uint64_t fStartSortTime
;
391 uint64_t fStartWriteTime
;
393 uint64_t fTotalObjectSize
;
394 uint64_t fTotalArchiveSize
;
395 uint32_t fTotalObjectLoaded
;
396 uint32_t fTotalArchivesLoaded
;
397 uint32_t fTotalDylibsLoaded
;
398 vm_statistics_data_t fStartVMInfo
;
402 Linker::Linker(int argc
, const char* argv
[])
403 : fOptions(argc
, argv
), fGlobalSymbolTable(*this), fOutputFile(NULL
), fCreateUUID(false), fNextSortOrder(1),
404 fNextObjectFileOrder(1), fArchitecture(0), fDirectLibrariesComplete(false), fOutputFileSize(0), fTotalObjectSize(0),
405 fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0)
407 fStartTime
= mach_absolute_time();
408 if ( fOptions
.printStatistics() )
409 getVMInfo(fStartVMInfo
);
411 fArchitecture
= fOptions
.architecture();
412 if ( fArchitecture
== 0 ) {
413 // -arch not specified, scan .o files to figure out what it should be
414 fArchitecture
= inferArchitecture();
418 cpu_type_t
Linker::inferArchitecture()
420 // scan all input files, looking for a thin .o file.
421 // the first one found is presumably the architecture to link
422 uint8_t buffer
[sizeof(mach_header_64
)];
423 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
424 for (std::vector
<Options::FileInfo
>::iterator it
= files
.begin(); it
!= files
.end(); ++it
) {
425 int fd
= ::open(it
->path
, O_RDONLY
, 0);
427 ssize_t amount
= read(fd
, buffer
, sizeof(buffer
));
429 if ( amount
>= (ssize_t
)sizeof(buffer
) ) {
430 if ( mach_o::relocatable::Reader
<ppc
>::validFile(buffer
) ) {
431 fprintf(stderr
, "ld64 warning: -arch not used, infering -arch ppc based on %s\n", it
->path
);
432 return CPU_TYPE_POWERPC
;
434 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(buffer
) ) {
435 fprintf(stderr
, "ld64 warning: -arch not used, infering -arch ppc64 based on %s\n", it
->path
);
436 return CPU_TYPE_POWERPC64
;
438 else if ( mach_o::relocatable::Reader
<x86
>::validFile(buffer
) ) {
439 fprintf(stderr
, "ld64 warning: -arch not used, infering -arch i386 based on %s\n", it
->path
);
440 return CPU_TYPE_I386
;
446 // no thin .o files found, so default to same architecture this was built as
447 fprintf(stderr
, "ld64 warning: -arch not specified\n");
449 return CPU_TYPE_POWERPC
;
451 return CPU_TYPE_I386
;
453 return CPU_TYPE_POWERPC64
;
455 #error unknown default architecture
460 void Linker::addInputFile(ObjectFile::Reader
* reader
)
462 reader
->setSortOrder(fNextObjectFileOrder
++);
463 fInputFiles
.push_back(reader
);
466 void Linker::setOutputFile(ExecutableFile::Writer
* writer
)
468 fOutputFile
= writer
;
473 this->buildAtomList();
474 this->loadUndefines();
475 this->resolveReferences();
479 this->writeDotOutput();
480 this->collectStabs();
482 this->printStatistics();
484 if ( fOptions
.pauseAtEnd() )
488 void Linker::printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
)
490 static uint64_t sUnitsPerSecond
= 0;
491 if ( sUnitsPerSecond
== 0 ) {
492 struct mach_timebase_info timeBaseInfo
;
493 if ( mach_timebase_info(&timeBaseInfo
) == KERN_SUCCESS
) {
494 sUnitsPerSecond
= 1000000000LL * timeBaseInfo
.denom
/ timeBaseInfo
.numer
;
495 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
498 if ( partTime
< sUnitsPerSecond
) {
499 uint32_t milliSecondsTimeTen
= (partTime
*10000)/sUnitsPerSecond
;
500 uint32_t milliSeconds
= milliSecondsTimeTen
/10;
501 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
502 uint32_t percent
= percentTimesTen
/10;
503 fprintf(stderr
, "%s: %u.%u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimeTen
-milliSeconds
*10, percent
, percentTimesTen
-percent
*10);
506 uint32_t secondsTimeTen
= (partTime
*10)/sUnitsPerSecond
;
507 uint32_t seconds
= secondsTimeTen
/10;
508 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
509 uint32_t percent
= percentTimesTen
/10;
510 fprintf(stderr
, "%s: %u.%u seconds (%u.%u%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10);
514 char* Linker::commatize(uint64_t in
, char* out
)
518 sprintf(rawNum
, "%llu", in
);
519 const int rawNumLen
= strlen(rawNum
);
520 for(int i
=0; i
< rawNumLen
-1; ++i
) {
522 if ( ((rawNumLen
-i
) % 3) == 1 )
525 *out
++ = rawNum
[rawNumLen
-1];
530 void Linker::getVMInfo(vm_statistics_data_t
& info
)
532 mach_msg_type_number_t count
= sizeof(vm_statistics_data_t
) / sizeof(natural_t
);
533 kern_return_t error
= host_statistics(mach_host_self(), HOST_VM_INFO
,
534 (host_info_t
)&info
, &count
);
535 if (error
!= KERN_SUCCESS
) {
536 bzero(&info
, sizeof(vm_statistics_data_t
));
540 void Linker::printStatistics()
542 fEndTime
= mach_absolute_time();
543 if ( fOptions
.printStatistics() ) {
544 vm_statistics_data_t endVMInfo
;
545 getVMInfo(endVMInfo
);
547 uint64_t totalTime
= fEndTime
- fStartTime
;
548 printTime("ld64 total time", totalTime
, totalTime
);
549 printTime(" option parsing time", fStartCreateReadersTime
- fStartTime
, totalTime
);
550 printTime(" object file processing",fStartCreateWriterTime
- fStartCreateReadersTime
, totalTime
);
551 printTime(" output file setup", fStartBuildAtomsTime
- fStartCreateWriterTime
, totalTime
);
552 printTime(" build atom list", fStartLoadUndefinesTime
- fStartBuildAtomsTime
, totalTime
);
553 printTime(" load undefines", fStartResolveTime
- fStartLoadUndefinesTime
, totalTime
);
554 printTime(" resolve references", fStartSortTime
- fStartResolveTime
, totalTime
);
555 printTime(" sort output", fStartWriteTime
- fStartSortTime
, totalTime
);
556 printTime(" write output", fEndTime
- fStartWriteTime
, totalTime
);
557 fprintf(stderr
, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo
.pageins
-fStartVMInfo
.pageins
,
558 endVMInfo
.pageouts
-fStartVMInfo
.pageouts
, endVMInfo
.faults
-fStartVMInfo
.faults
);
560 fprintf(stderr
, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded
, commatize(fTotalObjectSize
, temp
));
561 fprintf(stderr
, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded
, commatize(fTotalArchiveSize
, temp
));
562 fprintf(stderr
, "processed %3u dylib files\n", fTotalDylibsLoaded
);
563 fprintf(stderr
, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize
, temp
));
567 inline void Linker::addAtom(ObjectFile::Atom
& atom
)
569 // add to list of all atoms
570 fAllAtoms
.push_back(&atom
);
572 // add atom's references's names to symbol table as to-be-resolved-later
573 std::vector
<class ObjectFile::Reference
*>& references
= atom
.getReferences();
574 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
575 ObjectFile::Reference
* reference
= *it
;
576 if ( reference
->isTargetUnbound() ) {
577 fGlobalSymbolTable
.require(reference
->getTargetName());
579 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() )
580 fGlobalSymbolTable
.require(reference
->getFromTargetName());
583 // if in global namespace, add atom itself to symbol table
584 ObjectFile::Atom::Scope scope
= atom
.getScope();
585 const char* name
= atom
.getName();
586 if ( (scope
!= ObjectFile::Atom::scopeTranslationUnit
) && (name
!= NULL
) ) {
587 fGlobalSymbolTable
.add(atom
);
589 // update scope based on export list (possible that globals are downgraded to private_extern)
590 if ( (scope
== ObjectFile::Atom::scopeGlobal
) && fOptions
.hasExportRestrictList() ) {
591 bool doExport
= fOptions
.shouldExport(name
);
593 atom
.setScope(ObjectFile::Atom::scopeLinkageUnit
);
598 // record section orders so output file can have same order
599 atom
.setSection(Section::find(atom
.getSectionName(), atom
.getSegment().getName(), atom
.isZeroFill()));
601 // assign order in which this atom was originally seen
602 if ( atom
.getSortOrder() == 0 )
603 fNextSortOrder
= atom
.setSortOrder(fNextSortOrder
);
606 inline void Linker::addAtoms(std::vector
<class ObjectFile::Atom
*>& atoms
)
608 bool first
= true; // assume all atoms are from same reader
609 for (std::vector
<ObjectFile::Atom
*>::iterator it
=atoms
.begin(); it
!= atoms
.end(); it
++) {
611 // update fReadersThatHaveSuppliedAtoms
612 ObjectFile::Reader
* reader
= (*it
)->getFile();
613 if ( std::find(fReadersThatHaveSuppliedAtoms
.begin(), fReadersThatHaveSuppliedAtoms
.end(), reader
)
614 == fReadersThatHaveSuppliedAtoms
.end() ) {
615 fReadersThatHaveSuppliedAtoms
.push_back(reader
);
623 void Linker::buildAtomList()
625 fStartBuildAtomsTime
= mach_absolute_time();
626 // add initial undefines from -u option
627 std::vector
<const char*>& initialUndefines
= fOptions
.initialUndefines();
628 for (std::vector
<const char*>::iterator it
=initialUndefines
.begin(); it
!= initialUndefines
.end(); it
++) {
629 fGlobalSymbolTable
.require(*it
);
632 // writer can contribute atoms
633 this->addAtoms(fOutputFile
->getAtoms());
635 // each reader contributes atoms
636 const int readerCount
= fInputFiles
.size();
637 for (int i
=0; i
< readerCount
; ++i
) {
638 this->addAtoms(fInputFiles
[i
]->getAtoms());
641 // extra command line section always at end
642 std::vector
<Options::ExtraSection
>& extraSections
= fOptions
.extraSections();
643 for( std::vector
<Options::ExtraSection
>::iterator it
=extraSections
.begin(); it
!= extraSections
.end(); ++it
) {
644 this->addAtoms(SectCreate::MakeReader(it
->segmentName
, it
->sectionName
, it
->path
, it
->data
, it
->dataLen
)->getAtoms());
648 static const char* pathLeafName(const char* path
)
650 const char* shortPath
= strrchr(path
, '/');
651 if ( shortPath
== NULL
)
654 return &shortPath
[1];
657 void Linker::loadUndefines()
659 fStartLoadUndefinesTime
= mach_absolute_time();
660 // keep looping until no more undefines were added in last loop
661 unsigned int undefineCount
= 0xFFFFFFFF;
662 while ( undefineCount
!= fGlobalSymbolTable
.getRequireCount() ) {
663 undefineCount
= fGlobalSymbolTable
.getRequireCount();
664 std::vector
<const char*> undefineNames
;
665 fGlobalSymbolTable
.getNeededNames(false, undefineNames
);
666 for(std::vector
<const char*>::iterator it
= undefineNames
.begin(); it
!= undefineNames
.end(); ++it
) {
667 const char* name
= *it
;
668 ObjectFile::Atom
* possibleAtom
= fGlobalSymbolTable
.find(name
);
669 if ( (possibleAtom
== NULL
)
670 || ((possibleAtom
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
) && (fOptions
.outputKind() != Options::kObjectFile
) && (possibleAtom
->getScope() == ObjectFile::Atom::scopeGlobal
)) )
671 this->addJustInTimeAtoms(name
);
675 if ( fOptions
.outputKind() != Options::kObjectFile
) {
676 // error out on any remaining undefines
679 switch ( fOptions
.undefinedTreatment() ) {
680 case Options::kUndefinedError
:
682 case Options::kUndefinedDynamicLookup
:
685 case Options::kUndefinedWarning
:
688 case Options::kUndefinedSuppress
:
693 std::vector
<const char*> unresolvableUndefines
;
694 fGlobalSymbolTable
.getNeededNames(false, unresolvableUndefines
);
695 const int unresolvableCount
= unresolvableUndefines
.size();
696 int unresolvableExportsCount
= 0;
697 if ( unresolvableCount
!= 0 ) {
699 fprintf(stderr
, "can't resolve symbols:\n");
700 for (int i
=0; i
< unresolvableCount
; ++i
) {
701 const char* name
= unresolvableUndefines
[i
];
702 fprintf(stderr
, " %s, referenced from:\n", name
);
703 // scan all atoms for references
704 bool foundAtomReference
= false;
705 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
706 ObjectFile::Atom
* atom
= *it
;
707 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
708 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
709 ObjectFile::Reference
* reference
= *rit
;
710 if ( reference
->isTargetUnbound() ) {
711 if ( strcmp(reference
->getTargetName(), name
) == 0 ) {
712 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
713 foundAtomReference
= true;
716 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() ) {
717 if ( strcmp(reference
->getFromTargetName(), name
) == 0 ) {
718 fprintf(stderr
, " %s in %s\n", atom
->getDisplayName(), pathLeafName(atom
->getFile()->getPath()));
719 foundAtomReference
= true;
724 // scan command line options
725 if ( !foundAtomReference
&& fOptions
.hasExportRestrictList() && fOptions
.shouldExport(name
) ) {
726 fprintf(stderr
, " -exported_symbols_list command line option\n");
727 ++unresolvableExportsCount
;
731 if ( doError
&& (unresolvableCount
> unresolvableExportsCount
) ) // last check should be removed. It exists so broken projects still build
732 throw "symbol(s) not found";
735 // now verify that -init routine exists
736 if ( fOptions
.initFunctionName() != NULL
) {
737 if ( fGlobalSymbolTable
.find(fOptions
.initFunctionName()) == NULL
)
738 throwf("symbol %s not found for -init", fOptions
.initFunctionName());
745 void Linker::addJustInTimeAtoms(const char* name
)
747 // when creating final linked image, writer gets first chance
748 if ( fOptions
.outputKind() != Options::kObjectFile
) {
749 std::vector
<class ObjectFile::Atom
*>* atoms
= fOutputFile
->getJustInTimeAtomsFor(name
);
750 if ( atoms
!= NULL
) {
751 this->addAtoms(*atoms
);
753 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
754 return; // found a definition, no need to search anymore
758 // give direct readers a chance
759 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fInputFiles
.begin(); it
!= fInputFiles
.end(); it
++) {
760 ObjectFile::Reader
* reader
= *it
;
761 if ( reader
!= NULL
) {
762 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
763 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
764 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
765 if ( atoms
!= NULL
) {
766 this->addAtoms(*atoms
);
768 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fInputFiles[i]->getPath() );
769 return; // found a definition, no need to search anymore
774 // give indirect readers a chance
775 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
776 ObjectFile::Reader
* reader
= it
->reader
;
777 if ( reader
!= NULL
) {
778 std::vector
<class ObjectFile::Atom
*>* atoms
= reader
->getJustInTimeAtomsFor(name
);
779 if ( atoms
!= NULL
) {
780 this->addAtoms(*atoms
);
781 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
783 return; // found a definition, no need to search anymore
788 // when creating .o file, writer goes last (this is so any static archives will be searched above)
789 if ( (fOptions
.outputKind() == Options::kObjectFile
) || (fOptions
.undefinedTreatment() != Options::kUndefinedError
) ) {
790 ObjectFile::Atom
* atom
= fOutputFile
->getUndefinedProxyAtom(name
);
791 if ( atom
!= NULL
) {
792 this->addAtom(*atom
);
796 //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
799 void Linker::resolve(ObjectFile::Reference
* reference
)
801 // look in global symbol table
802 const char* targetName
= reference
->getTargetName();
803 ObjectFile::Atom
* target
= fGlobalSymbolTable
.find(targetName
);
804 if ( target
== NULL
) {
805 fprintf(stderr
, "can't resolve: %s\n", targetName
);
807 reference
->setTarget(*target
, reference
->getTargetOffset());
810 void Linker::resolveFrom(ObjectFile::Reference
* reference
)
812 // handle references that have two (from and to) targets
813 const char* fromTargetName
= reference
->getFromTargetName();
814 ObjectFile::Atom
* fromTarget
= fGlobalSymbolTable
.find(fromTargetName
);
815 if ( fromTarget
== NULL
) {
816 fprintf(stderr
, "can't resolve: %s\n", fromTargetName
);
818 reference
->setFromTarget(*fromTarget
);
822 void Linker::resolveReferences()
824 fStartResolveTime
= mach_absolute_time();
825 // note: the atom list may grow during this loop as libraries supply needed atoms
826 for (unsigned int j
=0; j
< fAllAtoms
.size(); ++j
) {
827 ObjectFile::Atom
* atom
= fAllAtoms
[j
];
828 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
829 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
830 ObjectFile::Reference
* reference
= *it
;
831 if ( reference
->isTargetUnbound() )
832 this->resolve(reference
);
833 if ( reference
->hasFromTarget() && reference
->isFromTargetUnbound() )
834 this->resolveFrom(reference
);
842 InSet(std::set
<ObjectFile::Atom
*>& deadAtoms
) : fDeadAtoms(deadAtoms
) {}
844 bool operator()(ObjectFile::Atom
*& atom
) const {
845 return ( fDeadAtoms
.count(atom
) != 0 );
849 std::set
<ObjectFile::Atom
*>& fDeadAtoms
;
852 // used to remove stabs associated with atoms that won't be in output file
856 NotInSet(std::set
<ObjectFile::Atom
*>& theSet
) : fSet(theSet
) {}
858 bool operator()(const ObjectFile::Reader::Stab
& stab
) const {
859 if ( stab
.atom
== NULL
)
860 return false; // leave stabs that are not associated with any atome
862 return ( fSet
.count(stab
.atom
) == 0 );
866 std::set
<ObjectFile::Atom
*>& fSet
;
875 bool operator()(ObjectFile::Atom
*& atom
) const {
876 //if ( ! atom->dontDeadStrip() )
877 // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
878 return ( ! atom
->dontDeadStrip() );
882 void Linker::markLive(ObjectFile::Atom
* atom
, std::set
<ObjectFile::Atom
*>& liveAtoms
)
884 if ( liveAtoms
.count(atom
) == 0 ) {
886 liveAtoms
.insert(atom
);
887 // so don't dead strip
888 atom
->setDontDeadStrip();
890 // and all atoms it references
891 std::vector
<class ObjectFile::Reference
*>& references
= atom
->getReferences();
892 for (std::vector
<ObjectFile::Reference
*>::iterator it
=references
.begin(); it
!= references
.end(); it
++) {
893 ObjectFile::Reference
* reference
= *it
;
894 // mark target of reference as live
895 this->markLive(&reference
->getTarget(), liveAtoms
);
896 // mark from-target (if it exists) as live
897 if ( reference
->hasFromTarget() )
898 this->markLive(&reference
->getFromTarget(), liveAtoms
);
903 void Linker::deadStrip()
905 if ( fOptions
.deadStrip() != Options::kDeadStripOff
) {
906 std::set
<ObjectFile::Atom
*> liveAtoms
;
908 // mark main() and all atoms reachable from it as live
909 ObjectFile::Atom
* entryPoint
= this->entryPoint();
910 if ( entryPoint
!= NULL
)
911 markLive(entryPoint
, liveAtoms
);
913 ObjectFile::Atom
* dyldHelper
= this->dyldHelper();
914 if ( dyldHelper
!= NULL
)
915 markLive(dyldHelper
, liveAtoms
);
917 // mark initializers and all atoms reachable from them as live
918 // mark all exported atoms and atoms reachable from them as live
919 Section
* initSection
= Section::find("__mod_init_func", "__DATA", false);
920 Section
* termSection
= Section::find("__mod_term_func", "__DATA", false);
921 const bool globalsAreRoots
= ( fOptions
.outputKind() != Options::kDynamicExecutable
);
922 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
923 ObjectFile::Atom
* atom
= *it
;
924 //fprintf(stderr,"%d %s\n", atom->dontDeadStrip(), atom->getDisplayName());
925 if ( (globalsAreRoots
&& (atom
->getScope() == ObjectFile::Atom::scopeGlobal
))
926 || (atom
->getSection() == initSection
) || (atom
->getSection() == termSection
) )
927 markLive(atom
, liveAtoms
);
930 // now remove dead strippable atoms from fAllAtoms
931 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), DeadStrippable()), fAllAtoms
.end());
934 //printf("Stripping atoms:\n");
935 //for (std::set<ObjectFile::Atom*>::iterator it=fDeadAtoms.begin(); it != fDeadAtoms.end(); it++) {
936 // printf("\t%s\n", (*it)->getDisplayName());
939 // if not dead stripping, just remove atoms weak atoms that have been overridden
940 fAllAtoms
.erase(std::remove_if(fAllAtoms
.begin(), fAllAtoms
.end(), InSet(fDeadAtoms
)), fAllAtoms
.end());
946 void Linker::sortAtoms()
948 fStartSortTime
= mach_absolute_time();
949 Section::assignIndexes();
950 std::sort(fAllAtoms
.begin(), fAllAtoms
.end(), Linker::AtomSorter());
951 //fprintf(stderr, "Sorted atoms:\n");
952 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
953 // fprintf(stderr, "\t%s\n", (*it)->getDisplayName());
959 // make sure given addresses are within reach of branches, etc
960 void Linker::tweakLayout()
965 void Linker::writeDotOutput()
967 const char* dotOutFilePath
= fOptions
.dotOutputFile();
968 if ( dotOutFilePath
!= NULL
) {
969 FILE* out
= fopen(dotOutFilePath
, "w");
972 fprintf(out
, "digraph dg\n{\n");
973 fprintf(out
, "\tconcentrate = true;\n");
974 fprintf(out
, "\trankdir = LR;\n");
976 // print each atom as a node
977 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
978 ObjectFile::Atom
* atom
= *it
;
979 if ( atom
->getFile() != fOutputFile
) {
980 const char* name
= atom
->getDisplayName();
981 // don't create nodes for stubs, lazy pointers or non-lazy pointers
982 const char* lastDollar
= strrchr(name
, '$');
983 if ( lastDollar
!= NULL
) {
984 if ( (strcmp(lastDollar
, "$stub") == 0) || (strcmp(lastDollar
, "$lazy_ptr") == 0) || (strcmp(lastDollar
, "$non_lazy_ptr") == 0) )
987 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
988 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
989 char temp
[strlen(name
)+2];
991 temp
[strlen(name
)-7] = '\0'; // strip trailing "$import"
992 fprintf(out
, "\t%s [ shape = plaintext ];\n", temp
);
994 else if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
995 char cstring
[atom
->getSize()+2];
996 atom
->copyRawContent((uint8_t*)cstring
);
997 fprintf(out
, "\taddr%p [ label = \"string: '", atom
);
998 for (const char* s
=cstring
; *s
!= '\0'; ++s
) {
1000 fprintf(out
, "\\\\n");
1004 fprintf(out
, "'\" ];\n");
1007 fprintf(out
, "\taddr%p [ label = \"%s\" ];\n", atom
, name
);
1013 // print each reference as an edge
1014 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1015 ObjectFile::Atom
* fromAtom
= *it
;
1016 if ( fromAtom
->getFile() != fOutputFile
) {
1017 std::vector
<ObjectFile::Reference
*>& references
= fromAtom
->getReferences();
1018 std::set
<ObjectFile::Atom
*> seenTargets
;
1019 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1020 ObjectFile::Reference
* reference
= *rit
;
1021 ObjectFile::Atom
* toAtom
= &(reference
->getTarget());
1022 if ( seenTargets
.count(toAtom
) == 0 ) {
1023 seenTargets
.insert(toAtom
);
1024 const char* toName
= toAtom
->getDisplayName();
1025 const char* lastDollar
= strrchr(toName
, '$');
1026 if ( (lastDollar
!= NULL
) && (strcmp(lastDollar
, "$stub") == 0) ) {
1027 char temp
[strlen(toName
)+2];
1028 strcpy(temp
, toName
);
1029 temp
[strlen(toName
)-5] = '\0'; // strip trailing "$stub"
1030 fprintf(out
, "\taddr%p -> %s;\n", fromAtom
, temp
);
1032 else if ( lastDollar
!= NULL
&& (strcmp(lastDollar
, "$non_lazy_ptr") == 0) ) {
1033 ObjectFile::Atom
* nonLazyTargetAtom
= &(toAtom
->getReferences()[0]->getTarget());
1034 if ( (nonLazyTargetAtom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
1035 || (nonLazyTargetAtom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1036 char temp
[strlen(toName
)+2];
1037 strcpy(temp
, toName
);
1038 temp
[strlen(toName
)-13] = '\0'; // strip trailing "$non_lazy_ptr"
1039 fprintf(out
, "\taddr%p -> %s;\n", fromAtom
, temp
);
1042 fprintf(out
, "\taddr%p -> addr%p;\n", fromAtom
, nonLazyTargetAtom
);
1046 // don't list references from stubs, lazy pointers or non-lazy pointers
1047 const char* name
= fromAtom
->getDisplayName();
1048 const char* lastDollar
= strrchr(name
, '$');
1049 if ( lastDollar
!= NULL
) {
1050 if ( (strcmp(lastDollar
, "$stub") == 0) || (strcmp(lastDollar
, "$lazy_ptr") == 0) || (strcmp(lastDollar
, "$non_lazy_ptr") == 0) )
1053 fprintf(out
, "\taddr%p -> addr%p;\n", fromAtom
, toAtom
);
1061 // push all imports to bottom of graph
1062 fprintf(out
, "{ rank = same; ");
1063 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); it
++) {
1064 ObjectFile::Atom
* atom
= *it
;
1065 if ( atom
->getFile() != fOutputFile
)
1066 if ( (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition
)
1067 || (atom
->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition
) ) {
1068 const char* name
= atom
->getDisplayName();
1069 char temp
[strlen(name
)+2];
1071 temp
[strlen(name
)-7] = '\0'; // strip trailing "$import"
1072 fprintf(out
, "%s; ", temp
);
1075 fprintf(out
, "};\n ");
1078 fprintf(out
, "}\n");
1082 fprintf(stderr
, "ld64 warning: could not write dot output file: %s\n", dotOutFilePath
);
1087 ObjectFile::Atom
* Linker::entryPoint()
1089 // if main executable, find entry point atom
1090 ObjectFile::Atom
* entryPoint
= NULL
;
1091 switch ( fOptions
.outputKind() ) {
1092 case Options::kDynamicExecutable
:
1093 case Options::kStaticExecutable
:
1094 case Options::kDyld
:
1095 entryPoint
= fGlobalSymbolTable
.find(fOptions
.entryName());
1096 if ( entryPoint
== NULL
) {
1097 throwf("could not find entry point: %s", fOptions
.entryName());
1100 case Options::kDynamicLibrary
:
1101 if ( fOptions
.initFunctionName() != NULL
) {
1102 entryPoint
= fGlobalSymbolTable
.find(fOptions
.initFunctionName());
1103 if ( entryPoint
== NULL
) {
1104 throwf("could not find -init function: %s", fOptions
.initFunctionName());
1108 case Options::kObjectFile
:
1109 case Options::kDynamicBundle
:
1116 ObjectFile::Atom
* Linker::dyldHelper()
1118 return fGlobalSymbolTable
.find("dyld_stub_binding_helper");
1121 const char* Linker::assureFullPath(const char* path
)
1123 if ( path
[0] == '/' )
1125 char cwdbuff
[MAXPATHLEN
];
1126 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
1128 asprintf(&result
, "%s/%s", cwdbuff
, path
);
1129 if ( result
!= NULL
)
1137 // The stab strings are of the form:
1138 // <name> ':' <type-code> <number-pari>
1139 // but the <name> contain a colon.
1140 // For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
1141 // For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
1143 const char* Linker::truncateStabString(const char* str
)
1145 enum { start
, inObjc
} state
= start
;
1146 for (const char* s
= str
; *s
!= 0; ++s
) {
1155 if ( s
[1] == ':' ) {
1160 // Duplicate strndup behavior here.
1161 int trunStrLen
= s
-str
+2;
1162 char* temp
= new char[trunStrLen
+1];
1163 memcpy(temp
, str
, trunStrLen
);
1164 temp
[trunStrLen
] = '\0';
1182 bool Linker::minimizeStab(ObjectFile::Reader::Stab
& stab
)
1189 // these all need truncated strings
1190 stab
.string
= truncateStabString(stab
.string
);
1196 // these are included in the minimal stabs, but they keep their full string
1203 struct HeaderRange
{
1204 std::vector
<ObjectFile::Reader::Stab
>::iterator begin
;
1205 std::vector
<ObjectFile::Reader::Stab
>::iterator end
;
1206 int parentRangeIndex
;
1208 bool sumPrecomputed
;
1210 bool cannotEXCL
; // because of SLINE, etc stabs
1214 typedef __gnu_cxx::hash_map
<const char*, std::vector
<uint32_t>, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToSums
;
1216 // hash table that maps header path to a vector of known checksums for that path
1217 static PathToSums sKnownBINCLs
;
1220 void Linker::collectStabs(ObjectFile::Reader
* reader
)
1223 bool minimal
= ( fOptions
.readerOptions().fDebugInfoStripping
== ObjectFile::ReaderOptions::kDebugInfoMinimal
);
1224 std::vector
<class ObjectFile::Reader::Stab
>* readerStabs
= reader
->getStabs();
1225 if ( readerStabs
== NULL
)
1228 if ( log
) fprintf(stderr
, "processesing %lu stabs for %s\n", readerStabs
->size(), reader
->getPath());
1229 // Find all (possibly nested) BINCL/EINCL ranges and their checksums
1230 std::vector
<HeaderRange
> ranges
;
1231 int curRangeIndex
= -1;
1233 for(std::vector
<class ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
1235 switch ( it
->type
) {
1240 range
.end
= readerStabs
->end();
1241 range
.parentRangeIndex
= curRangeIndex
;
1242 range
.sum
= it
->value
;
1243 range
.sumPrecomputed
= (range
.sum
!= 0);
1244 range
.useEXCL
= false;
1245 range
.cannotEXCL
= false;
1246 curRangeIndex
= ranges
.size();
1247 if ( log
) fprintf(stderr
, "[%d]BINCL %s\n", curRangeIndex
, it
->string
);
1248 ranges
.push_back(range
);
1252 if ( curRangeIndex
== -1 ) {
1253 fprintf(stderr
, "ld64 warning: EINCL missing BINCL in %s\n", reader
->getPath());
1256 ranges
[curRangeIndex
].end
= it
+1;
1257 if ( log
) fprintf(stderr
, "[%d->%d]EINCL %s\n", curRangeIndex
, ranges
[curRangeIndex
].parentRangeIndex
, it
->string
);
1258 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
1269 if ( curRangeIndex
!= -1 ) {
1270 ranges
[curRangeIndex
].cannotEXCL
= true;
1271 if ( fOptions
.warnStabs() )
1272 fprintf(stderr
, "ld64: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
1276 if ( curRangeIndex
!= -1 ) {
1277 if ( ! ranges
[curRangeIndex
].sumPrecomputed
) {
1279 const char* s
= it
->string
;
1281 while ( (c
= *s
++) != 0 ) {
1283 // don't checkusm first number (file index) after open paren in string
1289 ranges
[curRangeIndex
].sum
+= sum
;
1295 if ( log
) fprintf(stderr
, "processesed %d stabs for %s\n", count
, reader
->getPath());
1296 if ( curRangeIndex
!= -1 )
1297 fprintf(stderr
, "ld64 warning: BINCL (%s) missing EINCL in %s\n", ranges
[curRangeIndex
].begin
->string
, reader
->getPath());
1300 if ( ranges
.size() == 0 ) {
1302 // only copy minimal stabs
1303 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
1304 if ( minimizeStab(*it
) )
1305 fStabs
.push_back(*it
);
1310 fStabs
.insert(fStabs
.end(), readerStabs
->begin(), readerStabs
->end());
1315 //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
1316 //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
1317 // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
1320 // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
1321 for(std::vector
<HeaderRange
>::iterator it
=ranges
.begin(); it
!= ranges
.end(); ++it
) {
1322 if ( ! it
->cannotEXCL
) {
1323 const char* header
= it
->begin
->string
;
1324 uint32_t sum
= it
->sum
;
1325 PathToSums::iterator pos
= sKnownBINCLs
.find(header
);
1326 if ( pos
!= sKnownBINCLs
.end() ) {
1327 std::vector
<uint32_t>& sums
= pos
->second
;
1328 for(std::vector
<uint32_t>::iterator sit
=sums
.begin(); sit
!= sums
.end(); ++sit
) {
1330 //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
1335 if ( ! it
->useEXCL
) {
1336 // have seen this path, but not this checksum
1337 //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
1338 sums
.push_back(sum
);
1342 // have not seen this path, so add to known BINCLs
1343 std::vector
<uint32_t> empty
;
1344 sKnownBINCLs
[header
] = empty
;
1345 sKnownBINCLs
[header
].push_back(sum
);
1346 //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
1351 // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
1353 const int maxRangeIndex
= ranges
.size();
1354 for(std::vector
<ObjectFile::Reader::Stab
>::iterator it
=readerStabs
->begin(); it
!= readerStabs
->end(); ++it
) {
1355 switch ( it
->type
) {
1357 for(int i
=curRangeIndex
+1; i
< maxRangeIndex
; ++i
) {
1358 if ( ranges
[i
].begin
== it
) {
1360 HeaderRange
& range
= ranges
[curRangeIndex
];
1361 ObjectFile::Reader::Stab stab
= *it
;
1362 stab
.value
= range
.sum
; // BINCL and EXCL have n_value set to checksum
1363 if ( range
.useEXCL
)
1364 stab
.type
= N_EXCL
; // transform BINCL into EXCL
1366 fStabs
.push_back(stab
);
1372 if ( curRangeIndex
!= -1 ) {
1373 if ( !ranges
[curRangeIndex
].useEXCL
&& !minimal
)
1374 fStabs
.push_back(*it
);
1375 curRangeIndex
= ranges
[curRangeIndex
].parentRangeIndex
;
1379 if ( (curRangeIndex
== -1) || !ranges
[curRangeIndex
].useEXCL
) {
1380 if ( !minimal
|| minimizeStab(*it
) )
1381 fStabs
.push_back(*it
);
1389 void Linker::synthesizeStabs(ObjectFile::Reader
* reader
)
1391 // synthesize "debug notes" and add them to master stabs vector
1392 const char* dirPath
= NULL
;
1393 const char* filename
= NULL
;
1394 bool wroteStartSO
= false;
1395 std::vector
<const char*> seenFiles
;
1396 for (std::vector
<class ObjectFile::Atom
*>::iterator it
=fAllAtoms
.begin(); it
!= fAllAtoms
.end(); ++it
) {
1397 ObjectFile::Atom
* atom
= *it
;
1398 if ( atom
->getFile() == reader
) {
1399 const char* name
= atom
->getName();
1400 if ( (name
!= NULL
) && (name
[0] == '_' ) && (atom
->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn
) ) {
1401 const char* newDirPath
;
1402 const char* newFilename
;
1403 if ( atom
->getTranslationUnitSource(&newDirPath
, &newFilename
) ) {
1404 // need SO's whenever the translation unit source file changes
1405 if ( newFilename
!= filename
) {
1406 if ( filename
!= NULL
) {
1407 // translation unit change, emit ending SO
1408 ObjectFile::Reader::Stab endFileStab
;
1409 endFileStab
.atom
= NULL
;
1410 endFileStab
.type
= N_SO
;
1411 endFileStab
.other
= 1;
1412 endFileStab
.desc
= 0;
1413 endFileStab
.value
= 0;
1414 endFileStab
.string
= "";
1415 fStabs
.push_back(endFileStab
);
1417 // new translation unit, emit start SO's
1418 ObjectFile::Reader::Stab dirPathStab
;
1419 dirPathStab
.atom
= NULL
;
1420 dirPathStab
.type
= N_SO
;
1421 dirPathStab
.other
= 0;
1422 dirPathStab
.desc
= 0;
1423 dirPathStab
.value
= 0;
1424 dirPathStab
.string
= newDirPath
;
1425 fStabs
.push_back(dirPathStab
);
1426 ObjectFile::Reader::Stab fileStab
;
1427 fileStab
.atom
= NULL
;
1428 fileStab
.type
= N_SO
;
1432 fileStab
.string
= newFilename
;
1433 fStabs
.push_back(fileStab
);
1434 // Synthesize OSO for start of file
1435 ObjectFile::Reader::Stab objStab
;
1436 objStab
.atom
= NULL
;
1437 objStab
.type
= N_OSO
;
1440 objStab
.value
= reader
->getModificationTime();
1441 objStab
.string
= assureFullPath(reader
->getPath());
1442 fStabs
.push_back(objStab
);
1443 wroteStartSO
= true;
1445 filename
= newFilename
;
1446 dirPath
= newDirPath
;
1447 seenFiles
.push_back(filename
);
1448 if ( atom
->getSegment().isContentExecutable() && (strncmp(atom
->getSectionName(), "__text", 6) == 0) ) {
1449 // Synthesize BNSYM and start FUN stabs
1450 ObjectFile::Reader::Stab beginSym
;
1451 beginSym
.atom
= atom
;
1452 beginSym
.type
= N_BNSYM
;
1456 beginSym
.string
= "";
1457 fStabs
.push_back(beginSym
);
1458 ObjectFile::Reader::Stab startFun
;
1459 startFun
.atom
= atom
;
1460 startFun
.type
= N_FUN
;
1464 startFun
.string
= name
;
1465 fStabs
.push_back(startFun
);
1466 // Synthesize any SOL stabs needed
1467 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
1468 if ( lineInfo
!= NULL
) {
1469 // might be nice to set the source file path to seenFiles so it does not show up in SOLs
1470 const char* curFile
= NULL
;
1471 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
1472 if ( it
->fileName
!= curFile
) {
1473 bool alreadySeen
= false;
1474 for (std::vector
<const char*>::iterator sit
= seenFiles
.begin(); sit
!= seenFiles
.end(); ++sit
) {
1475 if ( strcmp(it
->fileName
, *sit
) == 0 ) {
1480 if ( ! alreadySeen
) {
1481 seenFiles
.push_back(it
->fileName
);
1482 ObjectFile::Reader::Stab sol
;
1488 sol
.string
= it
->fileName
;
1489 fStabs
.push_back(sol
);
1491 curFile
= it
->fileName
;
1495 // Synthesize end FUN and ENSYM stabs
1496 ObjectFile::Reader::Stab endFun
;
1498 endFun
.type
= N_FUN
;
1503 fStabs
.push_back(endFun
);
1504 ObjectFile::Reader::Stab endSym
;
1506 endSym
.type
= N_ENSYM
;
1511 fStabs
.push_back(endSym
);
1514 ObjectFile::Reader::Stab globalsStab
;
1515 if ( atom
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) {
1516 // Synthesize STSYM stab for statics
1517 const char* name
= atom
->getName();
1518 if ( name
[0] == '_' ) {
1519 globalsStab
.atom
= atom
;
1520 globalsStab
.type
= N_STSYM
;
1521 globalsStab
.other
= 1;
1522 globalsStab
.desc
= 0;
1523 globalsStab
.value
= 0;
1524 globalsStab
.string
= name
;
1525 fStabs
.push_back(globalsStab
);
1529 // Synthesize GSYM stab for other globals (but not .eh exception frame symbols)
1530 const char* name
= atom
->getName();
1531 if ( (name
[0] == '_') && (strcmp(atom
->getSectionName(), "__eh_frame") != 0) ) {
1532 globalsStab
.atom
= atom
;
1533 globalsStab
.type
= N_GSYM
;
1534 globalsStab
.other
= 1;
1535 globalsStab
.desc
= 0;
1536 globalsStab
.value
= 0;
1537 globalsStab
.string
= name
;
1538 fStabs
.push_back(globalsStab
);
1546 if ( wroteStartSO
) {
1548 ObjectFile::Reader::Stab endFileStab
;
1549 endFileStab
.atom
= NULL
;
1550 endFileStab
.type
= N_SO
;
1551 endFileStab
.other
= 1;
1552 endFileStab
.desc
= 0;
1553 endFileStab
.value
= 0;
1554 endFileStab
.string
= "";
1555 fStabs
.push_back(endFileStab
);
1559 void Linker::collectStabs()
1561 if ( fOptions
.readerOptions().fDebugInfoStripping
!= ObjectFile::ReaderOptions::kDebugInfoNone
) {
1562 fStabs
.reserve(1024); // try to minimize re-allocations
1563 // get stabs from each reader, in command line order
1564 for (std::vector
<class ObjectFile::Reader
*>::iterator it
=fReadersThatHaveSuppliedAtoms
.begin();
1565 it
!= fReadersThatHaveSuppliedAtoms
.end();
1567 ObjectFile::Reader
* reader
= *it
;
1568 if ( reader
!= NULL
) {
1569 switch ( reader
->getDebugInfoKind() ) {
1570 case ObjectFile::Reader::kDebugInfoNone
:
1573 case ObjectFile::Reader::kDebugInfoStabs
:
1574 collectStabs(reader
);
1576 case ObjectFile::Reader::kDebugInfoDwarf
:
1577 synthesizeStabs(reader
);
1580 case ObjectFile::Reader::kDebugInfoStabsUUID
:
1581 collectStabs(reader
);
1585 throw "Unhandled type of debug information";
1589 // remove stabs associated with atoms that won't be in output
1590 std::set
<class ObjectFile::Atom
*> allAtomsSet
;
1591 allAtomsSet
.insert(fAllAtoms
.begin(), fAllAtoms
.end());
1592 fStabs
.erase(std::remove_if(fStabs
.begin(), fStabs
.end(), NotInSet(allAtomsSet
)), fStabs
.end());
1596 void Linker::writeOutput()
1598 fStartWriteTime
= mach_absolute_time();
1599 // tell writer about each segment's atoms
1600 fOutputFileSize
= fOutputFile
->write(fAllAtoms
, fStabs
, this->entryPoint(), this->dyldHelper(), (fCreateUUID
&& fOptions
.emitUUID()));
1603 ObjectFile::Reader
* Linker::createReader(const Options::FileInfo
& info
)
1605 // map in whole file
1606 uint64_t len
= info
.fileLen
;
1607 int fd
= ::open(info
.path
, O_RDONLY
, 0);
1609 throwf("can't open file, errno=%d", errno
);
1610 if ( info
.fileLen
< 20 )
1611 throw "file too small";
1613 uint8_t* p
= (uint8_t*)::mmap(NULL
, info
.fileLen
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1614 if ( p
== (uint8_t*)(-1) )
1615 throwf("can't map file, errno=%d", errno
);
1617 // if fat file, skip to architecture we want
1618 const fat_header
* fh
= (fat_header
*)p
;
1619 if ( fh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1620 // Fat header is always big-endian
1621 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1622 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1623 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)fArchitecture
) {
1624 uint32_t fileOffset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1625 len
= OSSwapBigToHostInt32(archs
[i
].size
);
1626 // if requested architecture is page aligned within fat file, then remap just that portion of file
1627 if ( (fileOffset
&& 0x00000FFF) == 0 ) {
1629 munmap((caddr_t
)p
, info
.fileLen
);
1630 // re-map just part we need
1631 p
= (uint8_t*)::mmap(NULL
, len
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, fileOffset
);
1632 if ( p
== (uint8_t*)(-1) )
1633 throwf("can't re-map file, errno=%d", errno
);
1644 switch (fArchitecture
) {
1645 case CPU_TYPE_POWERPC
:
1646 if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
1647 return this->addObject(mach_o::relocatable::Reader
<ppc
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1648 else if ( mach_o::dylib::Reader
<ppc
>::validFile(p
) )
1649 return this->addDylib(mach_o::dylib::Reader
<ppc
>::make(p
, len
, info
.path
, fOptions
.readerOptions()), info
, len
);
1650 else if ( mach_o::archive::Reader
<ppc
>::validFile(p
, len
) )
1651 return this->addArchive(mach_o::archive::Reader
<ppc
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1653 case CPU_TYPE_POWERPC64
:
1654 if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
1655 return this->addObject(mach_o::relocatable::Reader
<ppc64
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1656 else if ( mach_o::dylib::Reader
<ppc64
>::validFile(p
) )
1657 return this->addDylib(mach_o::dylib::Reader
<ppc64
>::make(p
, len
, info
.path
, fOptions
.readerOptions()), info
, len
);
1658 else if ( mach_o::archive::Reader
<ppc64
>::validFile(p
, len
) )
1659 return this->addArchive(mach_o::archive::Reader
<ppc64
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1662 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
1663 return this->addObject(mach_o::relocatable::Reader
<x86
>::make(p
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1664 else if ( mach_o::dylib::Reader
<x86
>::validFile(p
) )
1665 return this->addDylib(mach_o::dylib::Reader
<x86
>::make(p
, len
, info
.path
, fOptions
.readerOptions()), info
, len
);
1666 else if ( mach_o::archive::Reader
<x86
>::validFile(p
, len
) )
1667 return this->addArchive(mach_o::archive::Reader
<x86
>::make(p
, len
, info
.path
, info
.modTime
, fOptions
.readerOptions()), info
, len
);
1672 if ( ((fat_header
*)p
)->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1673 const char* archName
= "unknown";
1674 switch (fArchitecture
) {
1675 case CPU_TYPE_POWERPC
:
1678 case CPU_TYPE_POWERPC64
:
1685 throwf("missing required architecture %s in fat file", archName
);
1688 throw "file is not of required architecture";
1693 void Linker::createReaders()
1695 fStartCreateReadersTime
= mach_absolute_time();
1696 std::vector
<Options::FileInfo
>& files
= fOptions
.getInputFiles();
1697 const int count
= files
.size();
1699 throw "no object files specified";
1700 // add all direct object, archives, and dylibs
1701 for (int i
=0; i
< count
; ++i
) {
1702 Options::FileInfo
& entry
= files
[i
];
1703 // ignore /usr/lib/dyld on command line in crt.o build
1704 if ( strcmp(entry
.path
, "/usr/lib/dyld") != 0 ) {
1706 this->addInputFile(this->createReader(entry
));
1708 catch (const char* msg
) {
1709 if ( strstr(msg
, "architecture") != NULL
) {
1710 if ( fOptions
.ignoreOtherArchInputFiles() ) {
1711 // ignore, because this is about an architecture not in use
1714 fprintf(stderr
, "ld64 warning: in %s, %s\n", entry
.path
, msg
);
1718 throwf("in %s, %s", entry
.path
, msg
);
1724 // add first level of indirect dylibs
1725 fDirectLibrariesComplete
= true;
1726 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator it
=fDynamicLibraries
.begin(); it
!= fDynamicLibraries
.end(); it
++) {
1727 this->addIndirectLibraries(it
->reader
);
1730 // indirect handling depends on namespace
1731 switch ( fOptions
.nameSpace() ) {
1732 case Options::kFlatNameSpace
:
1733 case Options::kForceFlatNameSpace
:
1734 // with flat namespace, blindly load all indirect libraries
1735 // the indirect list will grow as indirect libraries are loaded
1736 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
1738 it
->reader
= this->createReader(fOptions
.findFile(it
->path
));
1739 it
->reader
->setSortOrder(fNextObjectFileOrder
++);
1741 catch (const char* msg
) {
1742 fprintf(stderr
, "ld64 warning: indirect library %s could not be loaded: %s\n", it
->path
, msg
);
1747 case Options::kTwoLevelNameSpace
:
1748 // with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
1750 bool indirectAdded
= true;
1751 while ( indirectAdded
) {
1752 indirectAdded
= false;
1753 // instantiate a reader for each indirect library and try to find parent that re-exports it
1754 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
1755 if ( it
->reader
== NULL
) {
1757 it
->reader
= this->createReader(fOptions
.findFile(it
->path
));
1758 it
->reader
->setSortOrder(fNextObjectFileOrder
++);
1759 indirectAdded
= true;
1761 catch (const char* msg
) {
1762 fprintf(stderr
, "ld64 warning: indirect library %s could not be loaded: %s\n", it
->path
, msg
);
1765 // if an indirect library does not have an assigned parent, look for one
1766 if ( (it
->reader
!= NULL
) && (it
->reExportedViaDirectLibrary
== NULL
) ) {
1767 it
->reExportedViaDirectLibrary
= this->findDirectLibraryWhichReExports(*it
);
1775 // add relevant indirect libraries to the end of fDynamicLibraries
1776 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
1777 if ( (it
->reader
!= NULL
) && (it
->reExportedViaDirectLibrary
!= NULL
) || (fOptions
.nameSpace() != Options::kTwoLevelNameSpace
) ) {
1778 ExecutableFile::DyLibUsed dylibInfo
;
1779 dylibInfo
.reader
= it
->reader
;
1780 dylibInfo
.options
.fWeakImport
= false;
1781 dylibInfo
.options
.fReExport
= false;
1782 dylibInfo
.options
.fInstallPathOverride
= NULL
;
1783 dylibInfo
.indirect
= true;
1784 dylibInfo
.directReader
= it
->reExportedViaDirectLibrary
;
1785 fDynamicLibraries
.push_back(dylibInfo
);
1786 if ( fOptions
.readerOptions().fTraceIndirectDylibs
) {
1787 const char* fullPath
= it
->reader
->getPath();
1788 char realName
[MAXPATHLEN
];
1789 if ( realpath(fullPath
, realName
) != NULL
)
1790 fullPath
= realName
;
1791 logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath
);
1798 ObjectFile::Reader
* Linker::findDirectLibraryWhichReExports(IndirectLibrary
& indirectLib
)
1800 // ask each parent if they re-export this dylib
1801 for (std::set
<ObjectFile::Reader
*>::iterator pit
=indirectLib
.parents
.begin(); pit
!= indirectLib
.parents
.end(); pit
++) {
1802 if ( (*pit
)->reExports(indirectLib
.reader
) ) {
1803 ObjectFile::Reader
* lib
= *pit
;
1804 // first check if we found a direct library, if so return it
1805 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator dit
=fDynamicLibraries
.begin(); dit
!= fDynamicLibraries
.end(); dit
++) {
1806 if ( dit
->reader
== lib
&& dit
->indirect
== false )
1809 // otherwise search indirects for parent and see how it is reexported
1810 for (std::list
<IndirectLibrary
>::iterator iit
=fIndirectDynamicLibraries
.begin(); iit
!= fIndirectDynamicLibraries
.end(); iit
++) {
1811 if ( iit
->reader
== lib
) {
1812 ObjectFile::Reader
* lib2
= this->findDirectLibraryWhichReExports(*iit
);
1824 ObjectFile::Reader
* Linker::addArchive(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
1826 if (fOptions
.readerOptions().fTraceArchives
) {
1827 const char* fullPath
= reader
->getPath();
1828 char realName
[MAXPATHLEN
];
1829 if ( realpath(fullPath
, realName
) != NULL
)
1830 fullPath
= realName
;
1831 logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath
);
1835 fTotalArchiveSize
+= mappedLen
;
1836 ++fTotalArchivesLoaded
;
1840 ObjectFile::Reader
* Linker::addObject(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
1843 fTotalObjectSize
+= mappedLen
;
1844 ++fTotalObjectLoaded
;
1848 ObjectFile::Reader
* Linker::addDylib(ObjectFile::Reader
* reader
, const Options::FileInfo
& info
, uint64_t mappedLen
)
1850 if ( reader
->getInstallPath() == NULL
) {
1851 // this is a "blank" stub
1852 // silently ignore it
1856 if ( fDirectLibrariesComplete
) {
1857 this->addIndirectLibraries(reader
);
1860 if ( fOptions
.readerOptions().fTraceDylibs
) {
1861 const char* fullPath
= reader
->getPath();
1862 char realName
[MAXPATHLEN
];
1863 if ( realpath(fullPath
, realName
) != NULL
)
1864 fullPath
= realName
;
1865 logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath
);
1867 ExecutableFile::DyLibUsed dylibInfo
;
1868 dylibInfo
.reader
= reader
;
1869 dylibInfo
.options
= info
.options
;
1870 dylibInfo
.indirect
= false;
1871 dylibInfo
.directReader
= NULL
;
1872 fDynamicLibraries
.push_back(dylibInfo
);
1875 // Verify that a client is allowed to link to this dylib. There are three cases.
1876 bool okToLink
= true;
1877 const char* outputFilePath
= fOptions
.installPath();
1878 const char* outputFilePathLastSlash
= strrchr(outputFilePath
, '/');
1879 if ( reader
->parentUmbrella() != NULL
) {
1880 // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
1881 okToLink
= ( (outputFilePathLastSlash
!= NULL
) && (strcmp(&outputFilePathLastSlash
[1], reader
->parentUmbrella()) == 0) );
1884 if ( !okToLink
&& (reader
->parentUmbrella() != NULL
) ) {
1885 // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
1886 okToLink
= ( (outputFilePathLastSlash
!= NULL
)
1887 && (fOptions
.umbrellaName() != NULL
)
1888 && (strcmp(fOptions
.umbrellaName(), reader
->parentUmbrella()) == 0) );
1891 std::vector
<const char*>* clients
= reader
->getAllowableClients();
1892 if ( !okToLink
&& (clients
!= NULL
) ) {
1893 // case 3) the dylib has a list of allowable clients, and we are creating one of them
1894 const char* clientName
= fOptions
.clientName();
1895 int clientNameLen
= 0;
1896 if ( clientName
!= NULL
) {
1897 // use client name as specified on command line
1898 clientNameLen
= strlen(clientName
);
1901 // infer client name from output path (e.g. xxx/libfoo.A.dylib --> foo, Bar.framework/Bar --> Bar)
1902 clientName
= outputFilePath
;
1903 // starts after last slash
1904 if ( outputFilePathLastSlash
!= NULL
)
1905 clientName
= &outputFilePathLastSlash
[1];
1906 if ( strncmp(clientName
, "lib", 3) == 0 )
1907 clientName
= &clientName
[3];
1909 const char* firstDot
= strchr(clientName
, '.');
1910 if ( firstDot
== NULL
)
1911 clientNameLen
= strlen(clientName
);
1913 clientNameLen
= firstDot
- clientName
;
1916 // Use clientName to check if this dylib is able to link against the allowable clients.
1917 for (std::vector
<const char*>::iterator it
= clients
->begin(); it
!= clients
->end(); it
++) {
1918 if ( strncmp(*it
, clientName
, clientNameLen
) == 0 )
1923 // error out if we are not allowed to link
1925 //throwf("'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
1926 fprintf(stderr
, "'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
1927 reader
->getPath(), reader
->parentUmbrella());
1931 ++fTotalDylibsLoaded
;
1937 void Linker::addIndirectLibraries(ObjectFile::Reader
* reader
)
1939 std::vector
<const char*>* dependentLibs
= reader
->getDependentLibraryPaths();
1940 if ( dependentLibs
!= NULL
) {
1941 for (std::vector
<const char*>::iterator it
=dependentLibs
->begin(); it
!= dependentLibs
->end(); it
++) {
1942 if ( this->haveDirectLibrary(*it
) ) {
1943 // do nothing, direct library already exists
1945 else if ( this->haveIndirectLibrary(*it
, reader
) ) {
1946 // side effect of haveIndirectLibrary() added reader to parent list
1949 // add to list of indirect libraries
1950 IndirectLibrary indirectLib
;
1951 indirectLib
.path
= *it
;
1952 indirectLib
.fileLen
= 0;
1953 indirectLib
.reader
= NULL
;
1954 indirectLib
.parents
.insert(reader
);
1955 indirectLib
.reExportedViaDirectLibrary
= NULL
;
1956 fIndirectDynamicLibraries
.push_back(indirectLib
);
1957 //fprintf(stderr, "add indirect library: %s\n", *it);
1963 bool Linker::haveIndirectLibrary(const char* path
, ObjectFile::Reader
* parentReader
)
1965 for (std::list
<IndirectLibrary
>::iterator it
=fIndirectDynamicLibraries
.begin(); it
!= fIndirectDynamicLibraries
.end(); it
++) {
1966 if ( strcmp(path
, it
->path
) == 0 ) {
1967 it
->parents
.insert(parentReader
);
1970 if ( it
->reader
!= NULL
) {
1971 const char* installPath
= it
->reader
->getInstallPath();
1972 if ( (installPath
!= NULL
) && (strcmp(path
, installPath
) == 0) )
1979 bool Linker::haveDirectLibrary(const char* path
)
1981 for (std::vector
<ExecutableFile::DyLibUsed
>::iterator it
=fDynamicLibraries
.begin(); it
!= fDynamicLibraries
.end(); it
++) {
1982 if ( strcmp(path
, it
->reader
->getPath()) == 0 )
1984 const char* installPath
= it
->reader
->getInstallPath();
1985 if ( (installPath
!= NULL
) && (strcmp(path
, installPath
) == 0) )
1991 void Linker::logTraceInfo (const char* format
, ...)
1993 static int trace_file
= -1;
1994 char trace_buffer
[MAXPATHLEN
* 2];
1997 ssize_t amount_written
;
1998 const char *trace_file_path
= fOptions
.readerOptions().fTraceOutputFile
;
2000 if(trace_file
== -1) {
2001 if(trace_file_path
!= NULL
) {
2002 trace_file
= open(trace_file_path
, O_WRONLY
| O_APPEND
| O_CREAT
, 0666);
2003 if(trace_file
== -1)
2004 throwf("Could not open or create trace file: %s\n", trace_file_path
);
2007 trace_file
= fileno(stderr
);
2012 va_start(ap
, format
);
2013 length
= vsnprintf(trace_buffer
, sizeof(trace_buffer
), format
, ap
);
2015 buffer_ptr
= trace_buffer
;
2018 amount_written
= write(trace_file
, buffer_ptr
, length
);
2019 if(amount_written
== -1)
2020 /* Failure to write shouldn't fail the build. */
2022 buffer_ptr
+= amount_written
;
2023 length
-= amount_written
;
2029 void Linker::createWriter()
2031 fStartCreateWriterTime
= mach_absolute_time();
2032 const char* path
= fOptions
.getOutputFilePath();
2033 switch ( fArchitecture
) {
2034 case CPU_TYPE_POWERPC
:
2035 this->setOutputFile(new mach_o::executable::Writer
<ppc
>(path
, fOptions
, fDynamicLibraries
));
2037 case CPU_TYPE_POWERPC64
:
2038 this->setOutputFile(new mach_o::executable::Writer
<ppc64
>(path
, fOptions
, fDynamicLibraries
));
2041 this->setOutputFile(new mach_o::executable::Writer
<x86
>(path
, fOptions
, fDynamicLibraries
));
2044 throw "unknown architecture";
2049 Linker::SymbolTable::SymbolTable(Linker
& owner
)
2050 : fOwner(owner
), fRequireCount(0)
2054 void Linker::SymbolTable::require(const char* name
)
2056 //fprintf(stderr, "require(%s)\n", name);
2057 Mapper::iterator pos
= fTable
.find(name
);
2058 if ( pos
== fTable
.end() ) {
2059 fTable
[name
] = NULL
;
2064 // convenience labels for 2-dimensional switch statement
2066 kRegAndReg
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2067 kRegAndWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2068 kRegAndTent
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2069 kRegAndExtern
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2070 kRegAndExternWeak
= (ObjectFile::Atom::kRegularDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2071 kWeakAndReg
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2072 kWeakAndWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2073 kWeakAndTent
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2074 kWeakAndExtern
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2075 kWeakAndExternWeak
= (ObjectFile::Atom::kWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2076 kTentAndReg
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2077 kTentAndWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2078 kTentAndTent
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2079 kTentAndExtern
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2080 kTentAndExternWeak
= (ObjectFile::Atom::kTentativeDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2081 kExternAndReg
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2082 kExternAndWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2083 kExternAndTent
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2084 kExternAndExtern
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2085 kExternAndExternWeak
= (ObjectFile::Atom::kExternalDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
,
2086 kExternWeakAndReg
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kRegularDefinition
,
2087 kExternWeakAndWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kWeakDefinition
,
2088 kExternWeakAndTent
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kTentativeDefinition
,
2089 kExternWeakAndExtern
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalDefinition
,
2090 kExternWeakAndExternWeak
= (ObjectFile::Atom::kExternalWeakDefinition
<< 3) | ObjectFile::Atom::kExternalWeakDefinition
2093 bool Linker::SymbolTable::add(ObjectFile::Atom
& newAtom
)
2096 const char* name
= newAtom
.getName();
2097 //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
2098 Mapper::iterator pos
= fTable
.find(name
);
2099 ObjectFile::Atom
* existingAtom
= NULL
;
2100 if ( pos
!= fTable
.end() )
2101 existingAtom
= pos
->second
;
2102 if ( existingAtom
!= NULL
) {
2103 // already have atom with same name in symbol table
2104 switch ( (existingAtom
->getDefinitionKind() << 3) | newAtom
.getDefinitionKind() ) {
2106 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2108 // ignore new weak atom, because we already have a non-weak one
2112 // ignore new tentative atom, because we already have a regular one
2116 // ignore external atom, because we already have a one
2119 case kRegAndExternWeak
:
2120 // ignore external atom, because we already have a one
2124 // replace existing weak atom with regular one
2127 // have another weak atom, use whichever has largest alignment requirement
2128 // because codegen of some client may require alignment
2129 useNew
= ( newAtom
.getAlignment() > existingAtom
->getAlignment() );
2132 // replace existing weak atom with tentative one ???
2134 case kWeakAndExtern
:
2135 // keep weak atom, at runtime external one may override
2138 case kWeakAndExternWeak
:
2139 // keep weak atom, at runtime external one may override
2143 // replace existing tentative atom with regular one
2146 // replace existing tentative atom with weak one ???
2150 if ( newAtom
.getSize() < existingAtom
->getSize() ) {
2154 case kTentAndExtern
:
2155 case kTentAndExternWeak
:
2156 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2157 switch ( fOwner
.fOptions
.commonsMode() ) {
2158 case Options::kCommonsIgnoreDylibs
:
2159 if ( fOwner
.fOptions
.warnCommons() )
2160 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2161 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2164 case Options::kCommonsOverriddenByDylibs
:
2165 if ( fOwner
.fOptions
.warnCommons() )
2166 fprintf(stderr
, "ld64: replacing common symbol %s from %s with true definition from dylib %s\n",
2167 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2169 case Options::kCommonsConflictsDylibsError
:
2170 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2171 existingAtom
->getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2175 // replace external atom with regular one
2177 case kExternAndWeak
:
2178 // replace external atom with weak one
2180 case kExternAndTent
:
2181 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2182 switch ( fOwner
.fOptions
.commonsMode() ) {
2183 case Options::kCommonsIgnoreDylibs
:
2184 if ( fOwner
.fOptions
.warnCommons() )
2185 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2186 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2188 case Options::kCommonsOverriddenByDylibs
:
2189 if ( fOwner
.fOptions
.warnCommons() )
2190 fprintf(stderr
, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2191 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2194 case Options::kCommonsConflictsDylibsError
:
2195 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2196 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2199 case kExternAndExtern
:
2200 throwf("duplicate symbol %s in %s and %s\n", name
, newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2201 case kExternAndExternWeak
:
2202 // keep strong dylib atom, ignore weak one
2205 case kExternWeakAndReg
:
2206 // replace existing weak external with regular
2208 case kExternWeakAndWeak
:
2209 // replace existing weak external with weak (let dyld decide at runtime which to use)
2211 case kExternWeakAndTent
:
2212 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2213 switch ( fOwner
.fOptions
.commonsMode() ) {
2214 case Options::kCommonsIgnoreDylibs
:
2215 if ( fOwner
.fOptions
.warnCommons() )
2216 fprintf(stderr
, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2217 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2219 case Options::kCommonsOverriddenByDylibs
:
2220 if ( fOwner
.fOptions
.warnCommons() )
2221 fprintf(stderr
, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2222 newAtom
.getName(), existingAtom
->getFile()->getPath(), newAtom
.getFile()->getPath());
2225 case Options::kCommonsConflictsDylibsError
:
2226 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2227 newAtom
.getName(), newAtom
.getFile()->getPath(), existingAtom
->getFile()->getPath());
2230 case kExternWeakAndExtern
:
2231 // replace existing weak external with external
2233 case kExternWeakAndExternWeak
:
2234 // keep existing external weak
2240 fTable
[name
] = &newAtom
;
2241 if ( existingAtom
!= NULL
)
2242 fOwner
.fDeadAtoms
.insert(existingAtom
);
2245 fOwner
.fDeadAtoms
.insert(&newAtom
);
2252 ObjectFile::Atom
* Linker::SymbolTable::find(const char* name
)
2254 Mapper::iterator pos
= fTable
.find(name
);
2255 if ( pos
!= fTable
.end() ) {
2262 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions
, std::vector
<const char*>& undefines
)
2264 for (Mapper::iterator it
=fTable
.begin(); it
!= fTable
.end(); it
++) {
2265 if ( (it
->second
== NULL
) || (andWeakDefintions
&& (it
->second
->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition
)) ) {
2266 undefines
.push_back(it
->first
);
2274 bool Linker::AtomSorter::operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
)
2276 // first sort by section order (which is already sorted by segment)
2277 unsigned int leftSectionIndex
= left
->getSection()->getIndex();
2278 unsigned int rightSectionIndex
= right
->getSection()->getIndex();
2279 if ( leftSectionIndex
!= rightSectionIndex
)
2280 return (leftSectionIndex
< rightSectionIndex
);
2282 // then sort by .o file order
2283 ObjectFile::Reader
* leftReader
= left
->getFile();
2284 ObjectFile::Reader
* rightReader
= right
->getFile();
2285 if ( leftReader
!= rightReader
)
2286 return leftReader
->getSortOrder() < rightReader
->getSortOrder();
2288 // lastly sort by atom within a .o file
2289 return left
->getSortOrder() < right
->getSortOrder();
2293 int main(int argc
, const char* argv
[])
2296 // create linker object given command line arguments
2297 Linker
ld(argc
, argv
);
2299 // open all input files
2308 catch (const char* msg
) {
2309 fprintf(stderr
, "ld64 failed: %s\n", msg
);