]> git.saurik.com Git - apple/ld64.git/blame - src/ld.cpp
ld64-62.1.tar.gz
[apple/ld64.git] / src / ld.cpp
CommitLineData
d696c285 1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
6e880c60 2 *
d696c285 3 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
c2646906
A
4 *
5 * @APPLE_LICENSE_HEADER_START@
d696c285 6 *
c2646906
A
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
12 * file.
d696c285 13 *
c2646906
A
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.
d696c285 21 *
c2646906
A
22 * @APPLE_LICENSE_HEADER_END@
23 */
24#include <stdlib.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/mman.h>
d696c285 28#include <sys/sysctl.h>
c2646906 29#include <fcntl.h>
6e880c60 30#include <errno.h>
69a49097 31#include <limits.h>
d696c285
A
32#include <unistd.h>
33#include <mach/mach_time.h>
34#include <mach/vm_statistics.h>
35#include <mach/mach_init.h>
36#include <mach/mach_host.h>
c2646906
A
37#include <mach-o/fat.h>
38
d696c285 39
c2646906 40#include <string>
74cfe461 41#include <map>
c2646906
A
42#include <set>
43#include <string>
44#include <vector>
45#include <list>
46#include <algorithm>
47#include <ext/hash_map>
48
49#include "Options.h"
50
51#include "ObjectFile.h"
c2646906 52
d696c285
A
53#include "MachOReaderRelocatable.hpp"
54#include "MachOReaderArchive.hpp"
55#include "MachOReaderDylib.hpp"
56#include "MachOWriterExecutable.hpp"
c2646906
A
57
58#include "SectCreate.h"
59
60#if 0
61static void dumpAtom(ObjectFile::Atom* atom)
62{
63 //printf("atom: %p\n", atom);
d696c285 64
c2646906
A
65 // name
66 printf("name: %s\n", atom->getDisplayName());
d696c285 67
c2646906
A
68 // scope
69 switch ( atom->getScope() ) {
70 case ObjectFile::Atom::scopeTranslationUnit:
71 printf("scope: translation unit\n");
72 break;
73 case ObjectFile::Atom::scopeLinkageUnit:
74 printf("scope: linkage unit\n");
75 break;
76 case ObjectFile::Atom::scopeGlobal:
77 printf("scope: global\n");
78 break;
79 default:
80 printf("scope: unknown\n");
81 }
d696c285
A
82
83 // kind
84 switch ( atom->getDefinitinonKind() ) {
85 case ObjectFile::Atom::kRegularDefinition:
86 printf("kind: regular\n");
87 break;
88 case ObjectFile::Atom::kWeakDefinition:
89 printf("kind: weak\n");
90 break;
91 case ObjectFile::Atom::kTentativeDefinition:
92 printf("kind: tentative\n");
93 break;
94 case ObjectFile::Atom::kExternalDefinition:
95 printf("kind: import\n");
96 break;
97 case ObjectFile::Atom::kExternalWeakDefinition:
98 printf("kind: weak import\n");
99 break;
100 default:
101 printf("scope: unknown\n");
102 }
103
c2646906
A
104 // segment and section
105 printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
106
107 // attributes
108 printf("attrs: ");
c2646906
A
109 if ( atom->dontDeadStrip() )
110 printf("dont-dead-strip ");
111 if ( atom->isZeroFill() )
112 printf("zero-fill ");
113 printf("\n");
d696c285 114
c2646906
A
115 // size
116 printf("size: 0x%012llX\n", atom->getSize());
d696c285 117
c2646906
A
118 // content
119 uint8_t content[atom->getSize()];
120 atom->copyRawContent(content);
121 printf("content: ");
122 if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
123 printf("\"%s\"", content);
124 }
125 else {
126 for (unsigned int i=0; i < sizeof(content); ++i)
127 printf("%02X ", content[i]);
128 }
129 printf("\n");
d696c285 130
c2646906
A
131 // references
132 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
133 const int refCount = references.size();
134 printf("references: (%u)\n", refCount);
135 for (int i=0; i < refCount; ++i) {
136 ObjectFile::Reference* ref = references[i];
137 printf(" %s\n", ref->getDescription());
138 }
d696c285 139
c2646906 140 // attributes
d696c285 141
c2646906
A
142}
143
144#endif
145
146class CStringComparor
147{
148public:
149 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
150};
151
152class CStringEquals
153{
154public:
155 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
156};
157
158class Section : public ObjectFile::Section
159{
160public:
161 static Section* find(const char* sectionName, const char* segmentName, bool zeroFill);
162 static void assignIndexes();
163
164private:
165 Section(const char* sectionName, const char* segmentName, bool zeroFill);
166
167 struct Sorter {
168 static int segmentOrdinal(const char* segName);
169 bool operator()(Section* left, Section* right);
170 };
171
172 typedef __gnu_cxx::hash_map<const char*, class Section*, __gnu_cxx::hash<const char*>, CStringEquals> NameToSection;
173 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
174
175 const char* fSectionName;
176 const char* fSegmentName;
177 bool fZeroFill;
178
179 static NameToSection fgMapping;
180 static std::vector<Section*> fgSections;
181};
182
183Section::NameToSection Section::fgMapping;
184std::vector<Section*> Section::fgSections;
185
186Section::Section(const char* sectionName, const char* segmentName, bool zeroFill)
187 : fSectionName(sectionName), fSegmentName(segmentName), fZeroFill(zeroFill)
188{
189 //fprintf(stderr, "new Section(%s, %s)\n", sectionName, segmentName);
190}
191
192Section* Section::find(const char* sectionName, const char* segmentName, bool zeroFill)
193{
c2646906
A
194 NameToSection::iterator pos = fgMapping.find(sectionName);
195 if ( pos != fgMapping.end() ) {
196 if ( strcmp(pos->second->fSegmentName, segmentName) == 0 )
197 return pos->second;
198 // otherwise same section name is used in different segments, look slow way
199 for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
200 if ( (strcmp((*it)->fSectionName, sectionName) == 0) && (strcmp((*it)->fSegmentName, segmentName) == 0) )
201 return *it;
202 }
203 }
d696c285 204
c2646906
A
205 // does not exist, so make a new one
206 Section* sect = new Section(sectionName, segmentName, zeroFill);
207 sect->fIndex = fgMapping.size();
208 fgMapping[sectionName] = sect;
209 fgSections.push_back(sect);
d696c285
A
210
211 if ( (strcmp(sectionName, "__text") == 0) && (strcmp(segmentName, "__TEXT") == 0) ) {
212 // special case __textcoal_nt to be right after __text
213 find("__textcoal_nt", "__TEXT", false);
214 }
215
c2646906
A
216 return sect;
217}
218
219int Section::Sorter::segmentOrdinal(const char* segName)
220{
221 if ( strcmp(segName, "__PAGEZERO") == 0 )
222 return 1;
223 if ( strcmp(segName, "__TEXT") == 0 )
224 return 2;
225 if ( strcmp(segName, "__DATA") == 0 )
226 return 3;
227 if ( strcmp(segName, "__OBJC") == 0 )
228 return 4;
229 if ( strcmp(segName, "__LINKEDIT") == 0 )
230 return INT_MAX; // linkedit segment should always sort last
d696c285 231 else
c2646906
A
232 return 5;
233}
234
235
236bool Section::Sorter::operator()(Section* left, Section* right)
237{
238 // Segment is primary sort key
239 const char* leftSegName = left->fSegmentName;
240 const char* rightSegName = right->fSegmentName;
241 int segNameCmp = strcmp(leftSegName, rightSegName);
242 if ( segNameCmp != 0 )
243 {
244 int leftSegOrdinal = segmentOrdinal(leftSegName);
245 int rightSegOrdinal = segmentOrdinal(rightSegName);
246 if ( leftSegOrdinal < rightSegOrdinal )
247 return true;
248 if ( leftSegOrdinal == rightSegOrdinal )
249 return segNameCmp < 0;
250 return false;
251 }
252
253 // zerofill section sort to the end
254 if ( !left->fZeroFill && right->fZeroFill )
255 return true;
256 if ( left->fZeroFill && !right->fZeroFill )
257 return false;
258
259 // section discovery order is last sort key
260 return left->fIndex < right->fIndex;
261}
262
263void Section::assignIndexes()
264{
265 //printf("unsorted:\n");
266 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
267 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
268 //}
269
270 // sort it
271 std::sort(fgSections.begin(), fgSections.end(), Section::Sorter());
d696c285 272
c2646906
A
273 // assign correct section ordering to each Section object
274 unsigned int newOrder = 1;
d696c285 275 for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++)
c2646906
A
276 (*it)->fIndex = newOrder++;
277
278 //printf("sorted:\n");
279 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
280 // printf("section: name=%s\n", (*it)->fSectionName);
281 //}
282}
283
284class Linker {
285public:
286 Linker(int argc, const char* argv[]);
287
69a49097
A
288 const char* getArchPrefix();
289 const char* architectureName();
290 bool showArchitectureInErrors();
291 bool isInferredArchitecture();
c2646906
A
292 void createReaders();
293 void createWriter();
294 void addInputFile(ObjectFile::Reader* reader);
295 void setOutputFile(ExecutableFile::Writer* writer);
296 void link();
d696c285
A
297
298
c2646906 299private:
69a49097
A
300 struct WhyLiveBackChain
301 {
302 WhyLiveBackChain* previous;
303 const char* name;
304 };
305
c2646906
A
306 ObjectFile::Reader* createReader(const Options::FileInfo&);
307 void addAtom(ObjectFile::Atom& atom);
308 void addAtoms(std::vector<class ObjectFile::Atom*>& atoms);
309 void buildAtomList();
69a49097 310 void loadAndResolve();
c2646906 311 void loadUndefines();
69a49097 312 void checkUndefines();
c2646906
A
313 void addWeakAtomOverrides();
314 void resolveReferences();
69a49097
A
315 void deadStripResolve();
316 void addLiveRoot(const char* name);
c2646906
A
317 void sortAtoms();
318 void tweakLayout();
d696c285
A
319 void writeDotOutput();
320 static bool minimizeStab(ObjectFile::Reader::Stab& stab);
321 static const char* truncateStabString(const char* str);
74cfe461 322 void collectDebugInfo();
c2646906 323 void writeOutput();
d696c285
A
324 ObjectFile::Atom* entryPoint();
325 ObjectFile::Atom* dyldHelper();
326 const char* assureFullPath(const char* path);
69a49097 327 void markLive(ObjectFile::Atom& atom, Linker::WhyLiveBackChain* previous);
74cfe461
A
328 void collectStabs(ObjectFile::Reader* reader, std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals);
329 void synthesizeDebugNotes(std::vector<class ObjectFile::Atom*>& allAtomsByReader);
d696c285
A
330 void printStatistics();
331 void printTime(const char* msg, uint64_t partTime, uint64_t totalTime);
332 char* commatize(uint64_t in, char* out);
333 void getVMInfo(vm_statistics_data_t& info);
334 cpu_type_t inferArchitecture();
335
c2646906 336 void resolve(ObjectFile::Reference* reference);
6e880c60 337 void resolveFrom(ObjectFile::Reference* reference);
c2646906 338 void addJustInTimeAtoms(const char* name);
d696c285
A
339
340 ObjectFile::Reader* addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
341 ObjectFile::Reader* addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
342 ObjectFile::Reader* addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
c2646906
A
343 void addIndirectLibraries(ObjectFile::Reader* reader);
344 bool haveIndirectLibrary(const char* path, ObjectFile::Reader* reader);
345 bool haveDirectLibrary(const char* path);
d696c285
A
346
347 void logTraceInfo(const char* format, ...);
69a49097
A
348
349
c2646906
A
350 class SymbolTable
351 {
352 public:
353 SymbolTable(Linker&);
354 void require(const char* name);
355 bool add(ObjectFile::Atom& atom);
356 ObjectFile::Atom* find(const char* name);
357 unsigned int getRequireCount() { return fRequireCount; }
358 void getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines);
359 private:
d696c285 360 typedef __gnu_cxx::hash_map<const char*, ObjectFile::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> Mapper;
c2646906
A
361 Linker& fOwner;
362 Mapper fTable;
363 unsigned int fRequireCount;
364 };
d696c285 365
c2646906
A
366 struct AtomSorter
367 {
368 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right);
369 };
d696c285 370
c2646906 371 typedef std::map<const char*, uint32_t, CStringComparor> SectionOrder;
d696c285 372
c2646906
A
373 struct IndirectLibrary {
374 const char* path;
375 uint64_t fileLen;
376 ObjectFile::Reader* reader;
377 std::set<ObjectFile::Reader*> parents;
d696c285 378 ObjectFile::Reader* reExportedViaDirectLibrary;
c2646906 379 };
d696c285
A
380
381 ObjectFile::Reader* findDirectLibraryWhichReExports(struct IndirectLibrary& indirectLib);
382
c2646906
A
383 Options fOptions;
384 SymbolTable fGlobalSymbolTable;
385 unsigned int fWeakSymbolsAddedCount;
386 std::vector<class ObjectFile::Reader*> fInputFiles;
387 ExecutableFile::Writer* fOutputFile;
388 std::vector<ExecutableFile::DyLibUsed> fDynamicLibraries;
389 std::list<IndirectLibrary> fIndirectDynamicLibraries;
d696c285 390 std::vector<class ObjectFile::Reader*> fReadersThatHaveSuppliedAtoms;
c2646906 391 std::vector<class ObjectFile::Atom*> fAllAtoms;
c2646906 392 std::set<class ObjectFile::Atom*> fDeadAtoms;
69a49097
A
393 std::set<ObjectFile::Atom*> fLiveAtoms;
394 std::set<ObjectFile::Atom*> fLiveRootAtoms;
d696c285 395 std::vector<class ObjectFile::Reader::Stab> fStabs;
74cfe461 396 std::vector<class ObjectFile::Atom*> fAtomsWithUnresolvedReferences;
d696c285 397 bool fCreateUUID;
c2646906
A
398 SectionOrder fSectionOrder;
399 unsigned int fNextSortOrder;
d696c285
A
400 unsigned int fNextObjectFileOrder;
401 cpu_type_t fArchitecture;
69a49097
A
402 const char* fArchitectureName;
403 bool fArchitectureInferred;
c2646906 404 bool fDirectLibrariesComplete;
d696c285
A
405 uint64_t fOutputFileSize;
406 uint64_t fStartTime;
407 uint64_t fStartCreateReadersTime;
408 uint64_t fStartCreateWriterTime;
409 uint64_t fStartBuildAtomsTime;
410 uint64_t fStartLoadUndefinesTime;
411 uint64_t fStartResolveTime;
412 uint64_t fStartSortTime;
74cfe461 413 uint64_t fStartDebugTime;
d696c285
A
414 uint64_t fStartWriteTime;
415 uint64_t fEndTime;
416 uint64_t fTotalObjectSize;
417 uint64_t fTotalArchiveSize;
418 uint32_t fTotalObjectLoaded;
419 uint32_t fTotalArchivesLoaded;
420 uint32_t fTotalDylibsLoaded;
421 vm_statistics_data_t fStartVMInfo;
c2646906
A
422};
423
424
c2646906 425Linker::Linker(int argc, const char* argv[])
d696c285 426 : fOptions(argc, argv), fGlobalSymbolTable(*this), fOutputFile(NULL), fCreateUUID(false), fNextSortOrder(1),
69a49097
A
427 fNextObjectFileOrder(1), fArchitecture(0), fArchitectureInferred(false), fDirectLibrariesComplete(false),
428 fOutputFileSize(0), fTotalObjectSize(0),
d696c285 429 fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0)
c2646906 430{
d696c285
A
431 fStartTime = mach_absolute_time();
432 if ( fOptions.printStatistics() )
433 getVMInfo(fStartVMInfo);
69a49097 434
d696c285
A
435 fArchitecture = fOptions.architecture();
436 if ( fArchitecture == 0 ) {
437 // -arch not specified, scan .o files to figure out what it should be
438 fArchitecture = inferArchitecture();
69a49097
A
439 fArchitectureInferred = true;
440 }
441 switch (fArchitecture) {
442 case CPU_TYPE_POWERPC:
443 fArchitectureName = "ppc";
444 break;
445 case CPU_TYPE_POWERPC64:
446 fArchitectureName = "ppc64";
447 break;
448 case CPU_TYPE_I386:
449 fArchitectureName = "i386";
450 break;
451 case CPU_TYPE_X86_64:
452 fArchitectureName = "x86_64";
453 break;
454 default:
455 fArchitectureName = "unknown architecture";
456 break;
d696c285 457 }
c2646906
A
458}
459
69a49097
A
460const char* Linker::architectureName()
461{
462 return fArchitectureName;
463}
464
465bool Linker::showArchitectureInErrors()
466{
467 return fOptions.printArchPrefix();
468}
469
470bool Linker::isInferredArchitecture()
471{
472 return fArchitectureInferred;
473}
474
d696c285
A
475cpu_type_t Linker::inferArchitecture()
476{
69a49097 477 // scan all input files, looking for a thin .o file.
d696c285
A
478 // the first one found is presumably the architecture to link
479 uint8_t buffer[sizeof(mach_header_64)];
480 std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
481 for (std::vector<Options::FileInfo>::iterator it = files.begin(); it != files.end(); ++it) {
482 int fd = ::open(it->path, O_RDONLY, 0);
483 if ( fd != -1 ) {
484 ssize_t amount = read(fd, buffer, sizeof(buffer));
485 ::close(fd);
486 if ( amount >= (ssize_t)sizeof(buffer) ) {
487 if ( mach_o::relocatable::Reader<ppc>::validFile(buffer) ) {
69a49097 488 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc based on %s\n", it->path);
d696c285
A
489 return CPU_TYPE_POWERPC;
490 }
491 else if ( mach_o::relocatable::Reader<ppc64>::validFile(buffer) ) {
69a49097 492 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc64 based on %s\n", it->path);
d696c285
A
493 return CPU_TYPE_POWERPC64;
494 }
495 else if ( mach_o::relocatable::Reader<x86>::validFile(buffer) ) {
69a49097 496 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch i386 based on %s\n", it->path);
d696c285
A
497 return CPU_TYPE_I386;
498 }
69a49097
A
499 else if ( mach_o::relocatable::Reader<x86_64>::validFile(buffer) ) {
500 //fprintf(stderr, "ld64 warning: -arch not used, infering -arch x86_64 based on %s\n", it->path);
501 return CPU_TYPE_X86_64;
502 }
d696c285
A
503 }
504 }
505 }
69a49097 506
d696c285
A
507 // no thin .o files found, so default to same architecture this was built as
508 fprintf(stderr, "ld64 warning: -arch not specified\n");
509#if __ppc__
510 return CPU_TYPE_POWERPC;
511#elif __i386__
512 return CPU_TYPE_I386;
513#elif __ppc64__
514 return CPU_TYPE_POWERPC64;
69a49097
A
515#elif __x86_64__
516 return CPU_TYPE_X86_64;
d696c285
A
517#else
518 #error unknown default architecture
519#endif
520}
521
522
c2646906
A
523void Linker::addInputFile(ObjectFile::Reader* reader)
524{
d696c285 525 reader->setSortOrder(fNextObjectFileOrder++);
c2646906
A
526 fInputFiles.push_back(reader);
527}
528
529void Linker::setOutputFile(ExecutableFile::Writer* writer)
530{
531 fOutputFile = writer;
532}
533
69a49097
A
534class InSet
535{
536public:
537 InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
538
539 bool operator()(ObjectFile::Atom*& atom) const {
540 return ( fDeadAtoms.count(atom) != 0 );
541 }
542
543private:
544 std::set<ObjectFile::Atom*>& fDeadAtoms;
545};
546
547void Linker::loadAndResolve()
548{
549 if ( fOptions.deadStrip() == Options::kDeadStripOff ) {
550 // without dead-code-stripping:
551 // find atoms to resolve all undefines
552 this->loadUndefines();
553 // verify nothing is missing
554 this->checkUndefines();
555 // once all undefines fulfill, then bind all references
556 this->resolveReferences();
557 // remove atoms weak atoms that have been overridden
558 fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
559 }
560 else {
561 // with dead code stripping:
562 // start binding references from roots,
563 this->deadStripResolve();
564 // verify nothing is missing
565 this->checkUndefines();
566 }
567}
568
c2646906 569void Linker::link()
d696c285 570{
c2646906 571 this->buildAtomList();
69a49097 572 this->loadAndResolve();
c2646906
A
573 this->sortAtoms();
574 this->tweakLayout();
d696c285 575 this->writeDotOutput();
74cfe461 576 this->collectDebugInfo();
c2646906 577 this->writeOutput();
d696c285
A
578 this->printStatistics();
579
580 if ( fOptions.pauseAtEnd() )
581 sleep(10);
582}
583
584void Linker::printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
585{
586 static uint64_t sUnitsPerSecond = 0;
587 if ( sUnitsPerSecond == 0 ) {
588 struct mach_timebase_info timeBaseInfo;
589 if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
590 sUnitsPerSecond = 1000000000LL * timeBaseInfo.denom / timeBaseInfo.numer;
591 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
592 }
593 }
594 if ( partTime < sUnitsPerSecond ) {
595 uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
596 uint32_t milliSeconds = milliSecondsTimeTen/10;
597 uint32_t percentTimesTen = (partTime*1000)/totalTime;
598 uint32_t percent = percentTimesTen/10;
599 fprintf(stderr, "%s: %u.%u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
600 }
601 else {
602 uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
603 uint32_t seconds = secondsTimeTen/10;
604 uint32_t percentTimesTen = (partTime*1000)/totalTime;
605 uint32_t percent = percentTimesTen/10;
606 fprintf(stderr, "%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
607 }
608}
609
610char* Linker::commatize(uint64_t in, char* out)
611{
612 char* result = out;
613 char rawNum[30];
614 sprintf(rawNum, "%llu", in);
615 const int rawNumLen = strlen(rawNum);
616 for(int i=0; i < rawNumLen-1; ++i) {
617 *out++ = rawNum[i];
618 if ( ((rawNumLen-i) % 3) == 1 )
619 *out++ = ',';
620 }
621 *out++ = rawNum[rawNumLen-1];
622 *out = '\0';
623 return result;
624}
625
626void Linker::getVMInfo(vm_statistics_data_t& info)
627{
628 mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t);
629 kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO,
630 (host_info_t)&info, &count);
631 if (error != KERN_SUCCESS) {
632 bzero(&info, sizeof(vm_statistics_data_t));
633 }
634}
635
636void Linker::printStatistics()
637{
638 fEndTime = mach_absolute_time();
639 if ( fOptions.printStatistics() ) {
640 vm_statistics_data_t endVMInfo;
641 getVMInfo(endVMInfo);
642
643 uint64_t totalTime = fEndTime - fStartTime;
644 printTime("ld64 total time", totalTime, totalTime);
645 printTime(" option parsing time", fStartCreateReadersTime - fStartTime, totalTime);
646 printTime(" object file processing",fStartCreateWriterTime - fStartCreateReadersTime, totalTime);
647 printTime(" output file setup", fStartBuildAtomsTime - fStartCreateWriterTime, totalTime);
648 printTime(" build atom list", fStartLoadUndefinesTime - fStartBuildAtomsTime, totalTime);
649 printTime(" load undefines", fStartResolveTime - fStartLoadUndefinesTime, totalTime);
650 printTime(" resolve references", fStartSortTime - fStartResolveTime, totalTime);
74cfe461
A
651 printTime(" sort output", fStartDebugTime - fStartSortTime, totalTime);
652 printTime(" process debug info", fStartWriteTime - fStartDebugTime, totalTime);
d696c285
A
653 printTime(" write output", fEndTime - fStartWriteTime, totalTime);
654 fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo.pageins-fStartVMInfo.pageins,
655 endVMInfo.pageouts-fStartVMInfo.pageouts, endVMInfo.faults-fStartVMInfo.faults);
656 char temp[40];
657 fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded, commatize(fTotalObjectSize, temp));
658 fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded, commatize(fTotalArchiveSize, temp));
659 fprintf(stderr, "processed %3u dylib files\n", fTotalDylibsLoaded);
660 fprintf(stderr, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize, temp));
661 }
c2646906
A
662}
663
664inline void Linker::addAtom(ObjectFile::Atom& atom)
665{
666 // add to list of all atoms
667 fAllAtoms.push_back(&atom);
d696c285 668
69a49097
A
669 if ( fOptions.deadStrip() == Options::kDeadStripOff ) {
670 // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later
671 std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
672 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
673 ObjectFile::Reference* reference = *it;
674 if ( reference->isTargetUnbound() ) {
675 fGlobalSymbolTable.require(reference->getTargetName());
676 }
677 if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
678 fGlobalSymbolTable.require(reference->getFromTargetName());
c2646906 679 }
69a49097
A
680 }
681 else {
682 if ( atom.dontDeadStrip() )
683 fLiveRootAtoms.insert(&atom);
c2646906 684 }
d696c285 685
c2646906
A
686 // if in global namespace, add atom itself to symbol table
687 ObjectFile::Atom::Scope scope = atom.getScope();
688 const char* name = atom.getName();
689 if ( (scope != ObjectFile::Atom::scopeTranslationUnit) && (name != NULL) ) {
690 fGlobalSymbolTable.add(atom);
d696c285 691
c2646906
A
692 // update scope based on export list (possible that globals are downgraded to private_extern)
693 if ( (scope == ObjectFile::Atom::scopeGlobal) && fOptions.hasExportRestrictList() ) {
694 bool doExport = fOptions.shouldExport(name);
695 if ( !doExport ) {
696 atom.setScope(ObjectFile::Atom::scopeLinkageUnit);
697 }
698 }
699 }
d696c285 700
c2646906
A
701 // record section orders so output file can have same order
702 atom.setSection(Section::find(atom.getSectionName(), atom.getSegment().getName(), atom.isZeroFill()));
d696c285 703
c2646906
A
704 // assign order in which this atom was originally seen
705 if ( atom.getSortOrder() == 0 )
706 fNextSortOrder = atom.setSortOrder(fNextSortOrder);
707}
708
709inline void Linker::addAtoms(std::vector<class ObjectFile::Atom*>& atoms)
710{
d696c285 711 bool first = true; // assume all atoms are from same reader
c2646906 712 for (std::vector<ObjectFile::Atom*>::iterator it=atoms.begin(); it != atoms.end(); it++) {
d696c285
A
713 if ( first ) {
714 // update fReadersThatHaveSuppliedAtoms
715 ObjectFile::Reader* reader = (*it)->getFile();
716 if ( std::find(fReadersThatHaveSuppliedAtoms.begin(), fReadersThatHaveSuppliedAtoms.end(), reader)
717 == fReadersThatHaveSuppliedAtoms.end() ) {
718 fReadersThatHaveSuppliedAtoms.push_back(reader);
719 }
720 }
c2646906 721 this->addAtom(**it);
d696c285 722 first = false;
c2646906
A
723 }
724}
725
726void Linker::buildAtomList()
727{
d696c285 728 fStartBuildAtomsTime = mach_absolute_time();
c2646906
A
729 // add initial undefines from -u option
730 std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
731 for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++) {
732 fGlobalSymbolTable.require(*it);
733 }
d696c285
A
734
735 // writer can contribute atoms
c2646906 736 this->addAtoms(fOutputFile->getAtoms());
d696c285 737
c2646906
A
738 // each reader contributes atoms
739 const int readerCount = fInputFiles.size();
740 for (int i=0; i < readerCount; ++i) {
741 this->addAtoms(fInputFiles[i]->getAtoms());
742 }
d696c285 743
c2646906
A
744 // extra command line section always at end
745 std::vector<Options::ExtraSection>& extraSections = fOptions.extraSections();
746 for( std::vector<Options::ExtraSection>::iterator it=extraSections.begin(); it != extraSections.end(); ++it) {
747 this->addAtoms(SectCreate::MakeReader(it->segmentName, it->sectionName, it->path, it->data, it->dataLen)->getAtoms());
748 }
749}
750
d696c285
A
751static const char* pathLeafName(const char* path)
752{
753 const char* shortPath = strrchr(path, '/');
754 if ( shortPath == NULL )
755 return path;
756 else
757 return &shortPath[1];
758}
759
c2646906
A
760void Linker::loadUndefines()
761{
d696c285 762 fStartLoadUndefinesTime = mach_absolute_time();
c2646906
A
763 // keep looping until no more undefines were added in last loop
764 unsigned int undefineCount = 0xFFFFFFFF;
765 while ( undefineCount != fGlobalSymbolTable.getRequireCount() ) {
766 undefineCount = fGlobalSymbolTable.getRequireCount();
767 std::vector<const char*> undefineNames;
d696c285
A
768 fGlobalSymbolTable.getNeededNames(false, undefineNames);
769 for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
770 const char* name = *it;
c2646906 771 ObjectFile::Atom* possibleAtom = fGlobalSymbolTable.find(name);
d696c285
A
772 if ( (possibleAtom == NULL)
773 || ((possibleAtom->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition) && (fOptions.outputKind() != Options::kObjectFile) && (possibleAtom->getScope() == ObjectFile::Atom::scopeGlobal)) )
c2646906
A
774 this->addJustInTimeAtoms(name);
775 }
776 }
69a49097 777}
d696c285 778
69a49097
A
779void Linker::checkUndefines()
780{
c2646906
A
781 if ( fOptions.outputKind() != Options::kObjectFile ) {
782 // error out on any remaining undefines
783 bool doPrint = true;
784 bool doError = true;
785 switch ( fOptions.undefinedTreatment() ) {
786 case Options::kUndefinedError:
787 break;
788 case Options::kUndefinedDynamicLookup:
789 doError = false;
790 break;
791 case Options::kUndefinedWarning:
792 doError = false;
793 break;
794 case Options::kUndefinedSuppress:
795 doError = false;
796 doPrint = false;
797 break;
798 }
799 std::vector<const char*> unresolvableUndefines;
800 fGlobalSymbolTable.getNeededNames(false, unresolvableUndefines);
801 const int unresolvableCount = unresolvableUndefines.size();
6e880c60 802 int unresolvableExportsCount = 0;
c2646906
A
803 if ( unresolvableCount != 0 ) {
804 if ( doPrint ) {
69a49097
A
805 if ( fOptions.printArchPrefix() )
806 fprintf(stderr, "Undefined symbols for architecture %s:\n", fArchitectureName);
807 else
808 fprintf(stderr, "Undefined symbols:\n");
c2646906
A
809 for (int i=0; i < unresolvableCount; ++i) {
810 const char* name = unresolvableUndefines[i];
c2646906 811 fprintf(stderr, " %s, referenced from:\n", name);
6e880c60
A
812 // scan all atoms for references
813 bool foundAtomReference = false;
c2646906
A
814 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
815 ObjectFile::Atom* atom = *it;
816 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
817 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
818 ObjectFile::Reference* reference = *rit;
6e880c60 819 if ( reference->isTargetUnbound() ) {
d696c285
A
820 if ( strcmp(reference->getTargetName(), name) == 0 ) {
821 fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
6e880c60
A
822 foundAtomReference = true;
823 }
824 }
825 if ( reference->hasFromTarget() && reference->isFromTargetUnbound() ) {
d696c285
A
826 if ( strcmp(reference->getFromTargetName(), name) == 0 ) {
827 fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
6e880c60 828 foundAtomReference = true;
c2646906
A
829 }
830 }
831 }
832 }
6e880c60
A
833 // scan command line options
834 if ( !foundAtomReference && fOptions.hasExportRestrictList() && fOptions.shouldExport(name) ) {
835 fprintf(stderr, " -exported_symbols_list command line option\n");
836 ++unresolvableExportsCount;
837 }
c2646906
A
838 }
839 }
6e880c60 840 if ( doError && (unresolvableCount > unresolvableExportsCount) ) // last check should be removed. It exists so broken projects still build
c2646906
A
841 throw "symbol(s) not found";
842 }
c2646906
A
843 }
844}
845
846
847
848void Linker::addJustInTimeAtoms(const char* name)
849{
d696c285 850 // when creating final linked image, writer gets first chance
6e880c60 851 if ( fOptions.outputKind() != Options::kObjectFile ) {
d696c285 852 std::vector<class ObjectFile::Atom*>* atoms = fOutputFile->getJustInTimeAtomsFor(name);
6e880c60
A
853 if ( atoms != NULL ) {
854 this->addAtoms(*atoms);
855 delete atoms;
d696c285 856 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
6e880c60 857 return; // found a definition, no need to search anymore
6e880c60
A
858 }
859 }
d696c285
A
860
861 // give direct readers a chance
862 for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
863 ObjectFile::Reader* reader = *it;
864 if ( reader != NULL ) {
865 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
866 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
867 std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
868 if ( atoms != NULL ) {
869 this->addAtoms(*atoms);
870 delete atoms;
871 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fInputFiles[i]->getPath() );
872 return; // found a definition, no need to search anymore
873 }
874 }
875 }
876
6e880c60
A
877 // give indirect readers a chance
878 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
879 ObjectFile::Reader* reader = it->reader;
74cfe461
A
880 // for two-level namespace, only search re-exported indirect libraries
881 if ( (reader != NULL) && ((it->reExportedViaDirectLibrary != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace)) ) {
6e880c60 882 std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
c2646906
A
883 if ( atoms != NULL ) {
884 this->addAtoms(*atoms);
d696c285 885 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
c2646906 886 delete atoms;
d696c285 887 return; // found a definition, no need to search anymore
c2646906
A
888 }
889 }
6e880c60 890 }
d696c285 891
6e880c60 892 // when creating .o file, writer goes last (this is so any static archives will be searched above)
d696c285 893 if ( (fOptions.outputKind() == Options::kObjectFile) || (fOptions.undefinedTreatment() != Options::kUndefinedError) ) {
6e880c60
A
894 ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
895 if ( atom != NULL ) {
896 this->addAtom(*atom);
897 return;
c2646906
A
898 }
899 }
d696c285 900 //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
c2646906
A
901}
902
903void Linker::resolve(ObjectFile::Reference* reference)
904{
c2646906 905 // look in global symbol table
d696c285
A
906 const char* targetName = reference->getTargetName();
907 ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
c2646906 908 if ( target == NULL ) {
69a49097 909 fprintf(stderr, "Undefined symbol: %s\n", targetName);
c2646906 910 }
6e880c60 911 reference->setTarget(*target, reference->getTargetOffset());
6e880c60
A
912}
913
914void Linker::resolveFrom(ObjectFile::Reference* reference)
d696c285 915{
c2646906 916 // handle references that have two (from and to) targets
6e880c60
A
917 const char* fromTargetName = reference->getFromTargetName();
918 ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName);
919 if ( fromTarget == NULL ) {
69a49097 920 fprintf(stderr, "Undefined symbol: %s\n", fromTargetName);
c2646906 921 }
6e880c60 922 reference->setFromTarget(*fromTarget);
c2646906
A
923}
924
925
926void Linker::resolveReferences()
927{
d696c285 928 fStartResolveTime = mach_absolute_time();
c2646906
A
929 // note: the atom list may grow during this loop as libraries supply needed atoms
930 for (unsigned int j=0; j < fAllAtoms.size(); ++j) {
931 ObjectFile::Atom* atom = fAllAtoms[j];
932 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
933 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
934 ObjectFile::Reference* reference = *it;
d696c285 935 if ( reference->isTargetUnbound() )
c2646906 936 this->resolve(reference);
d696c285 937 if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
6e880c60 938 this->resolveFrom(reference);
c2646906
A
939 }
940 }
941}
942
c2646906 943
d696c285
A
944// used to remove stabs associated with atoms that won't be in output file
945class NotInSet
946{
947public:
948 NotInSet(std::set<ObjectFile::Atom*>& theSet) : fSet(theSet) {}
949
950 bool operator()(const ObjectFile::Reader::Stab& stab) const {
951 if ( stab.atom == NULL )
952 return false; // leave stabs that are not associated with any atome
953 else
954 return ( fSet.count(stab.atom) == 0 );
955 }
956
957private:
958 std::set<ObjectFile::Atom*>& fSet;
959};
960
961
69a49097 962class NotLive
d696c285
A
963{
964public:
69a49097 965 NotLive(std::set<ObjectFile::Atom*>& set) : fLiveAtoms(set) {}
d696c285
A
966
967 bool operator()(ObjectFile::Atom*& atom) const {
69a49097 968 //if ( fLiveAtoms.count(atom) == 0 )
d696c285 969 // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
69a49097 970 return ( fLiveAtoms.count(atom) == 0 );
d696c285 971 }
69a49097
A
972private:
973 std::set<ObjectFile::Atom*>& fLiveAtoms;
d696c285
A
974};
975
69a49097
A
976
977
978void Linker::markLive(ObjectFile::Atom& atom, struct Linker::WhyLiveBackChain* previous)
d696c285 979{
69a49097
A
980 if ( fLiveAtoms.count(&atom) == 0 ) {
981 // if -whylive cares about this symbol, then dump chain
982 if ( (previous->name != NULL) && fOptions.printWhyLive(previous->name) ) {
983 int depth = 0;
984 for(WhyLiveBackChain* p = previous; p != NULL; p = p->previous, ++depth) {
985 for(int i=depth; i > 0; --i)
986 fprintf(stderr, " ");
987 fprintf(stderr, "%s\n", p->name);
988 }
989 }
990 // set up next chain
991 WhyLiveBackChain thisChain;
992 thisChain.previous = previous;
d696c285 993 // this atom is live
69a49097 994 fLiveAtoms.insert(&atom);
d696c285 995 // and all atoms it references
69a49097 996 std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
d696c285
A
997 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
998 ObjectFile::Reference* reference = *it;
69a49097
A
999 if ( reference->isTargetUnbound() ) {
1000 // look in global symbol table
1001 const char* targetName = reference->getTargetName();
1002 ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
1003 if ( target == NULL ) {
1004 // load archives or dylibs
1005 this->addJustInTimeAtoms(targetName);
1006 }
1007 // look again
1008 target = fGlobalSymbolTable.find(targetName);
1009 if ( target != NULL ) {
1010 reference->setTarget(*target, reference->getTargetOffset());
1011 }
1012 else {
1013 // mark as undefined, for later error processing
74cfe461 1014 fAtomsWithUnresolvedReferences.push_back(&atom);
69a49097
A
1015 fGlobalSymbolTable.require(targetName);
1016 }
1017 }
1018 if ( ! reference->isTargetUnbound() ) {
1019 thisChain.name = reference->getTargetName();
1020 markLive(reference->getTarget(), &thisChain);
1021 }
1022 if ( reference->hasFromTarget() ) {
1023 // do the same as above, for from target
1024 if ( reference->isFromTargetUnbound() ) {
1025 // look in global symbol table
1026 const char* targetName = reference->getFromTargetName();
1027 ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
1028 if ( target == NULL ) {
1029 // load archives or dylibs
1030 this->addJustInTimeAtoms(targetName);
1031 }
1032 // look again
1033 target = fGlobalSymbolTable.find(targetName);
1034 if ( target != NULL ) {
1035 reference->setFromTarget(*target);
1036 }
1037 else {
1038 // mark as undefined, for later error processing
1039 fGlobalSymbolTable.require(targetName);
1040 }
1041 }
1042 if ( ! reference->isFromTargetUnbound() ) {
1043 thisChain.name = reference->getFromTargetName();
1044 markLive(reference->getFromTarget(), &thisChain);
1045 }
1046 }
d696c285
A
1047 }
1048 }
1049}
c2646906 1050
69a49097
A
1051
1052void Linker::addLiveRoot(const char* name)
1053{
1054 ObjectFile::Atom* target = fGlobalSymbolTable.find(name);
1055 if ( target == NULL ) {
1056 this->addJustInTimeAtoms(name);
1057 target = fGlobalSymbolTable.find(name);
1058 }
1059 if ( target != NULL )
1060 fLiveRootAtoms.insert(target);
1061}
1062
1063
1064void Linker::deadStripResolve()
c2646906 1065{
69a49097
A
1066 // add main() to live roots
1067 ObjectFile::Atom* entryPoint = this->entryPoint();
1068 if ( entryPoint != NULL )
1069 fLiveRootAtoms.insert(entryPoint);
d696c285 1070
69a49097
A
1071 // add dyld_stub_binding_helper() to live roots
1072 ObjectFile::Atom* dyldHelper = this->dyldHelper();
1073 if ( dyldHelper != NULL )
1074 fLiveRootAtoms.insert(dyldHelper);
d696c285 1075
69a49097
A
1076 // add -exported_symbols_list, -init, and -u entries to live roots
1077 std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
1078 for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++)
1079 addLiveRoot(*it);
d696c285 1080
69a49097
A
1081 // in some cases, every global scope atom in initial .o files is a root
1082 if ( fOptions.allGlobalsAreDeadStripRoots() ) {
d696c285
A
1083 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1084 ObjectFile::Atom* atom = *it;
69a49097
A
1085 if ( atom->getScope() == ObjectFile::Atom::scopeGlobal )
1086 fLiveRootAtoms.insert(atom);
d696c285 1087 }
d696c285 1088 }
c2646906 1089
69a49097
A
1090 // mark all roots as live, and all atoms they reference
1091 for (std::set<ObjectFile::Atom*>::iterator it=fLiveRootAtoms.begin(); it != fLiveRootAtoms.end(); it++) {
1092 WhyLiveBackChain rootChain;
1093 rootChain.previous = NULL;
1094 rootChain.name = (*it)->getDisplayName();
1095 markLive(**it, &rootChain);
d696c285 1096 }
c2646906 1097
74cfe461
A
1098 // it is possible that there are unresolved references that can be resolved now
1099 // this can happen if the first reference to a common symbol in an archive.
1100 // common symbols are not in the archive TOC, but the .o could have been pulled in later.
1101 // <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
1102 for (std::vector<ObjectFile::Atom*>::iterator it=fAtomsWithUnresolvedReferences.begin(); it != fAtomsWithUnresolvedReferences.end(); it++) {
1103 std::vector<class ObjectFile::Reference*>& references = (*it)->getReferences();
1104 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1105 ObjectFile::Reference* reference = *rit;
1106 if ( reference->isTargetUnbound() ) {
1107 ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getTargetName());
1108 if ( target != NULL ) {
1109 reference->setTarget(*target, reference->getTargetOffset());
1110 fLiveAtoms.insert(target);
1111 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1112 // references, which is true for commons.
1113 if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition )
1114 fprintf(stderr, "warning: ld64 internal error %s is not a tentative definition\n", target->getDisplayName());
1115 }
1116 }
1117 if ( reference->hasFromTarget() && reference->isFromTargetUnbound() ) {
1118 ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getFromTargetName());
1119 if ( target != NULL ) {
1120 reference->setFromTarget(*target);
1121 fLiveAtoms.insert(target);
1122 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1123 // references, which is true for commons.
1124 if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition )
1125 fprintf(stderr, "warning: ld64 internal error %s is not a tentative definition\n", target->getDisplayName());
1126 }
1127 }
1128 }
1129 }
1130
69a49097
A
1131 // now remove all non-live atoms from fAllAtoms
1132 fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), NotLive(fLiveAtoms)), fAllAtoms.end());
1133}
c2646906
A
1134
1135void Linker::sortAtoms()
1136{
d696c285 1137 fStartSortTime = mach_absolute_time();
c2646906
A
1138 Section::assignIndexes();
1139 std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter());
6e880c60
A
1140 //fprintf(stderr, "Sorted atoms:\n");
1141 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1142 // fprintf(stderr, "\t%s\n", (*it)->getDisplayName());
1143 //}
c2646906
A
1144}
1145
1146
c2646906
A
1147// make sure given addresses are within reach of branches, etc
1148void Linker::tweakLayout()
1149{
c2646906
A
1150}
1151
d696c285
A
1152
1153void Linker::writeDotOutput()
1154{
1155 const char* dotOutFilePath = fOptions.dotOutputFile();
1156 if ( dotOutFilePath != NULL ) {
1157 FILE* out = fopen(dotOutFilePath, "w");
1158 if ( out != NULL ) {
1159 // print header
1160 fprintf(out, "digraph dg\n{\n");
1161 fprintf(out, "\tconcentrate = true;\n");
1162 fprintf(out, "\trankdir = LR;\n");
1163
1164 // print each atom as a node
1165 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1166 ObjectFile::Atom* atom = *it;
1167 if ( atom->getFile() != fOutputFile ) {
1168 const char* name = atom->getDisplayName();
d696c285
A
1169 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
1170 || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
69a49097 1171 fprintf(out, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom, name);
d696c285
A
1172 }
1173 else if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
1174 char cstring[atom->getSize()+2];
1175 atom->copyRawContent((uint8_t*)cstring);
1176 fprintf(out, "\taddr%p [ label = \"string: '", atom);
1177 for (const char* s=cstring; *s != '\0'; ++s) {
1178 if ( *s == '\n' )
1179 fprintf(out, "\\\\n");
1180 else
1181 fputc(*s, out);
1182 }
1183 fprintf(out, "'\" ];\n");
1184 }
1185 else {
1186 fprintf(out, "\taddr%p [ label = \"%s\" ];\n", atom, name);
1187 }
1188 }
1189 }
1190 fprintf(out, "\n");
1191
1192 // print each reference as an edge
1193 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1194 ObjectFile::Atom* fromAtom = *it;
1195 if ( fromAtom->getFile() != fOutputFile ) {
1196 std::vector<ObjectFile::Reference*>& references = fromAtom->getReferences();
1197 std::set<ObjectFile::Atom*> seenTargets;
1198 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1199 ObjectFile::Reference* reference = *rit;
1200 ObjectFile::Atom* toAtom = &(reference->getTarget());
1201 if ( seenTargets.count(toAtom) == 0 ) {
1202 seenTargets.insert(toAtom);
69a49097 1203 fprintf(out, "\taddr%p -> addr%p;\n", fromAtom, toAtom);
d696c285
A
1204 }
1205 }
1206 }
1207 }
1208 fprintf(out, "\n");
1209
1210 // push all imports to bottom of graph
1211 fprintf(out, "{ rank = same; ");
1212 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1213 ObjectFile::Atom* atom = *it;
1214 if ( atom->getFile() != fOutputFile )
1215 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
1216 || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
69a49097 1217 fprintf(out, "addr%p; ", atom);
d696c285
A
1218 }
1219 }
1220 fprintf(out, "};\n ");
1221
1222 // print footer
1223 fprintf(out, "}\n");
1224 fclose(out);
1225 }
1226 else {
1227 fprintf(stderr, "ld64 warning: could not write dot output file: %s\n", dotOutFilePath);
1228 }
1229 }
1230}
1231
1232ObjectFile::Atom* Linker::entryPoint()
c2646906
A
1233{
1234 // if main executable, find entry point atom
6e880c60 1235 ObjectFile::Atom* entryPoint = NULL;
c2646906
A
1236 switch ( fOptions.outputKind() ) {
1237 case Options::kDynamicExecutable:
1238 case Options::kStaticExecutable:
1239 case Options::kDyld:
1240 entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
1241 if ( entryPoint == NULL ) {
69a49097 1242 throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions.entryName());
c2646906
A
1243 }
1244 break;
1245 case Options::kDynamicLibrary:
1246 if ( fOptions.initFunctionName() != NULL ) {
1247 entryPoint = fGlobalSymbolTable.find(fOptions.initFunctionName());
1248 if ( entryPoint == NULL ) {
69a49097 1249 throwf("could not find -init function: \"%s\"", fOptions.initFunctionName());
c2646906
A
1250 }
1251 }
1252 break;
6e880c60
A
1253 case Options::kObjectFile:
1254 case Options::kDynamicBundle:
c2646906 1255 entryPoint = NULL;
6e880c60 1256 break;
c2646906 1257 }
d696c285
A
1258 return entryPoint;
1259}
1260
1261ObjectFile::Atom* Linker::dyldHelper()
1262{
1263 return fGlobalSymbolTable.find("dyld_stub_binding_helper");
1264}
1265
1266const char* Linker::assureFullPath(const char* path)
1267{
1268 if ( path[0] == '/' )
1269 return path;
1270 char cwdbuff[MAXPATHLEN];
1271 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
1272 char* result;
1273 asprintf(&result, "%s/%s", cwdbuff, path);
1274 if ( result != NULL )
1275 return result;
1276 }
1277 return path;
1278}
1279
1280
1281//
1282// The stab strings are of the form:
1283// <name> ':' <type-code> <number-pari>
69a49097 1284// but the <name> contain a colon.
d696c285
A
1285// For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
1286// For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
1287//
1288const char* Linker::truncateStabString(const char* str)
1289{
1290 enum { start, inObjc } state = start;
1291 for (const char* s = str; *s != 0; ++s) {
1292 char c = *s;
1293 switch (state) {
1294 case start:
1295 if ( c == '[' ) {
1296 state = inObjc;
1297 }
1298 else {
1299 if ( c == ':' ) {
1300 if ( s[1] == ':' ) {
1301 ++s;
1302 }
1303 else {
1304 // found colon
1305 // Duplicate strndup behavior here.
1306 int trunStrLen = s-str+2;
1307 char* temp = new char[trunStrLen+1];
1308 memcpy(temp, str, trunStrLen);
1309 temp[trunStrLen] = '\0';
1310 return temp;
1311 }
1312 }
1313 }
1314 break;
1315 case inObjc:
1316 if ( c == ']' ) {
1317 state = start;
1318 }
1319 break;
1320 }
1321 }
1322 // malformed
1323 return str;
1324}
1325
1326
1327bool Linker::minimizeStab(ObjectFile::Reader::Stab& stab)
1328{
1329 switch(stab.type){
1330 case N_GSYM:
1331 case N_STSYM:
1332 case N_LCSYM:
1333 case N_FUN:
1334 // these all need truncated strings
1335 stab.string = truncateStabString(stab.string);
1336 return true;
1337 case N_SO:
1338 case N_OSO:
1339 case N_OPT:
1340 case N_SOL:
1341 // these are included in the minimal stabs, but they keep their full string
1342 return true;
1343 default:
1344 return false;
1345 }
1346}
1347
69a49097
A
1348
1349struct HeaderRange {
1350 std::vector<ObjectFile::Reader::Stab>::iterator begin;
d696c285
A
1351 std::vector<ObjectFile::Reader::Stab>::iterator end;
1352 int parentRangeIndex;
1353 uint32_t sum;
1354 bool sumPrecomputed;
1355 bool useEXCL;
1356 bool cannotEXCL; // because of SLINE, etc stabs
1357};
1358
1359
1360typedef __gnu_cxx::hash_map<const char*, std::vector<uint32_t>, __gnu_cxx::hash<const char*>, CStringEquals> PathToSums;
1361
1362// hash table that maps header path to a vector of known checksums for that path
1363static PathToSums sKnownBINCLs;
1364
1365
74cfe461 1366void Linker::collectStabs(ObjectFile::Reader* reader, std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals)
d696c285
A
1367{
1368 bool log = false;
1369 bool minimal = ( fOptions.readerOptions().fDebugInfoStripping == ObjectFile::ReaderOptions::kDebugInfoMinimal );
1370 std::vector<class ObjectFile::Reader::Stab>* readerStabs = reader->getStabs();
1371 if ( readerStabs == NULL )
1372 return;
69a49097 1373
d696c285 1374 if ( log ) fprintf(stderr, "processesing %lu stabs for %s\n", readerStabs->size(), reader->getPath());
d696c285
A
1375 std::vector<HeaderRange> ranges;
1376 int curRangeIndex = -1;
1377 int count = 0;
69a49097
A
1378 ObjectFile::Atom* atomWithLowestOrdinal = NULL;
1379 ObjectFile::Atom* atomWithHighestOrdinal = NULL;
1380 uint32_t highestOrdinal = 0;
1381 uint32_t lowestOrdinal = UINT_MAX;
1382 std::vector<std::pair<ObjectFile::Atom*,ObjectFile::Atom*> > soRanges;
1383 // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums
1384 // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein
d696c285
A
1385 for(std::vector<class ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
1386 ++count;
1387 switch ( it->type ) {
1388 case N_BINCL:
1389 {
1390 HeaderRange range;
1391 range.begin = it;
1392 range.end = readerStabs->end();
1393 range.parentRangeIndex = curRangeIndex;
69a49097 1394 range.sum = it->value;
d696c285
A
1395 range.sumPrecomputed = (range.sum != 0);
1396 range.useEXCL = false;
1397 range.cannotEXCL = false;
1398 curRangeIndex = ranges.size();
1399 if ( log ) fprintf(stderr, "[%d]BINCL %s\n", curRangeIndex, it->string);
1400 ranges.push_back(range);
1401 }
1402 break;
1403 case N_EINCL:
1404 if ( curRangeIndex == -1 ) {
1405 fprintf(stderr, "ld64 warning: EINCL missing BINCL in %s\n", reader->getPath());
1406 }
1407 else {
1408 ranges[curRangeIndex].end = it+1;
1409 if ( log ) fprintf(stderr, "[%d->%d]EINCL %s\n", curRangeIndex, ranges[curRangeIndex].parentRangeIndex, it->string);
1410 curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
1411 }
69a49097 1412 break;
d696c285 1413 case N_FUN:
69a49097 1414 {
74cfe461 1415 std::map<const class ObjectFile::Atom*, uint32_t>::iterator pos = atomOrdinals.find(it->atom);
69a49097
A
1416 if ( pos != atomOrdinals.end() ) {
1417 uint32_t ordinal = pos->second;
1418 if ( ordinal > highestOrdinal ) {
1419 highestOrdinal = ordinal;
1420 atomWithHighestOrdinal = it->atom;
1421 }
1422 if ( ordinal < lowestOrdinal ) {
1423 lowestOrdinal = ordinal;
1424 atomWithLowestOrdinal = it->atom;
1425 }
1426 }
1427 }
1428 // fall through
d696c285
A
1429 case N_BNSYM:
1430 case N_ENSYM:
1431 case N_LBRAC:
1432 case N_RBRAC:
1433 case N_SLINE:
1434 case N_STSYM:
1435 case N_LCSYM:
1436 if ( curRangeIndex != -1 ) {
1437 ranges[curRangeIndex].cannotEXCL = true;
1438 if ( fOptions.warnStabs() )
1439 fprintf(stderr, "ld64: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
1440 }
1441 break;
69a49097
A
1442 case N_SO:
1443 if ( (it->string != NULL) && (strlen(it->string) > 0) ) {
1444 // start SO, reset hi/low FUN tracking
1445 atomWithLowestOrdinal = NULL;
1446 atomWithHighestOrdinal = NULL;
1447 highestOrdinal = 0;
1448 lowestOrdinal = UINT_MAX;
1449 }
1450 else {
1451 // end SO, record hi/low atoms for this SO range
1452 soRanges.push_back(std::make_pair<ObjectFile::Atom*,ObjectFile::Atom*>(atomWithLowestOrdinal, atomWithHighestOrdinal));
1453 }
1454 // fall through
d696c285
A
1455 default:
1456 if ( curRangeIndex != -1 ) {
1457 if ( ! ranges[curRangeIndex].sumPrecomputed ) {
1458 uint32_t sum = 0;
1459 const char* s = it->string;
1460 char c;
1461 while ( (c = *s++) != 0 ) {
1462 sum += c;
1463 // don't checkusm first number (file index) after open paren in string
1464 if ( c == '(' ) {
1465 while(isdigit(*s))
1466 ++s;
1467 }
1468 }
1469 ranges[curRangeIndex].sum += sum;
1470 }
1471 }
69a49097 1472
d696c285
A
1473 }
1474 }
1475 if ( log ) fprintf(stderr, "processesed %d stabs for %s\n", count, reader->getPath());
1476 if ( curRangeIndex != -1 )
1477 fprintf(stderr, "ld64 warning: BINCL (%s) missing EINCL in %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
69a49097 1478
d696c285
A
1479 // if no BINCLs
1480 if ( ranges.size() == 0 ) {
69a49097
A
1481 int soIndex = 0;
1482 for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
1483 // copy minimal or all stabs
1484 ObjectFile::Reader::Stab stab = *it;
1485 if ( !minimal || minimizeStab(stab) ) {
1486 if ( stab.type == N_SO ) {
1487 if ( (stab.string != NULL) && (strlen(stab.string) > 0) ) {
1488 // starting SO is associated with first atom
1489 stab.atom = soRanges[soIndex].first;
1490 }
1491 else {
1492 // ending SO is associated with last atom
1493 stab.atom = soRanges[soIndex].second;
1494 ++soIndex;
1495 }
1496 }
1497 fStabs.push_back(stab);
d696c285
A
1498 }
1499 }
d696c285
A
1500 return;
1501 }
69a49097 1502
d696c285
A
1503 //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
1504 //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
1505 // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
1506 //}
69a49097 1507
d696c285
A
1508 // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
1509 for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
1510 if ( ! it->cannotEXCL ) {
1511 const char* header = it->begin->string;
1512 uint32_t sum = it->sum;
1513 PathToSums::iterator pos = sKnownBINCLs.find(header);
1514 if ( pos != sKnownBINCLs.end() ) {
1515 std::vector<uint32_t>& sums = pos->second;
1516 for(std::vector<uint32_t>::iterator sit=sums.begin(); sit != sums.end(); ++sit) {
1517 if (*sit == sum) {
1518 //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
1519 it->useEXCL = true;
1520 break;
1521 }
1522 }
1523 if ( ! it->useEXCL ) {
1524 // have seen this path, but not this checksum
1525 //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
1526 sums.push_back(sum);
1527 }
1528 }
1529 else {
1530 // have not seen this path, so add to known BINCLs
1531 std::vector<uint32_t> empty;
1532 sKnownBINCLs[header] = empty;
1533 sKnownBINCLs[header].push_back(sum);
1534 //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
1535 }
1536 }
1537 }
69a49097 1538
d696c285
A
1539 // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
1540 curRangeIndex = -1;
1541 const int maxRangeIndex = ranges.size();
69a49097 1542 int soIndex = 0;
d696c285
A
1543 for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
1544 switch ( it->type ) {
1545 case N_BINCL:
1546 for(int i=curRangeIndex+1; i < maxRangeIndex; ++i) {
1547 if ( ranges[i].begin == it ) {
1548 curRangeIndex = i;
1549 HeaderRange& range = ranges[curRangeIndex];
1550 ObjectFile::Reader::Stab stab = *it;
1551 stab.value = range.sum; // BINCL and EXCL have n_value set to checksum
69a49097 1552 if ( range.useEXCL )
d696c285
A
1553 stab.type = N_EXCL; // transform BINCL into EXCL
1554 if ( !minimal )
1555 fStabs.push_back(stab);
1556 break;
1557 }
1558 }
1559 break;
1560 case N_EINCL:
1561 if ( curRangeIndex != -1 ) {
1562 if ( !ranges[curRangeIndex].useEXCL && !minimal )
1563 fStabs.push_back(*it);
1564 curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
1565 }
69a49097 1566 break;
d696c285
A
1567 default:
1568 if ( (curRangeIndex == -1) || !ranges[curRangeIndex].useEXCL ) {
69a49097
A
1569 ObjectFile::Reader::Stab stab = *it;
1570 if ( !minimal || minimizeStab(stab) ) {
1571 if ( stab.type == N_SO ) {
1572 if ( (stab.string != NULL) || (strlen(stab.string) > 0) ) {
1573 // starting SO is associated with first atom
1574 stab.atom = soRanges[soIndex].first;
1575 }
1576 else {
1577 // ending SO is associated with last atom
1578 stab.atom = soRanges[soIndex].second;
1579 ++soIndex;
1580 }
1581 }
1582 fStabs.push_back(stab);
1583 }
d696c285
A
1584 }
1585 }
1586 }
1587
c2646906
A
1588}
1589
1590
74cfe461
A
1591// used to prune out atoms that don't need debug notes generated
1592class NoDebugNoteAtom
1593{
1594public:
1595 NoDebugNoteAtom(const std::map<class ObjectFile::Reader*, uint32_t>& readersWithDwarfOrdinals)
1596 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals) {}
1597
1598 bool operator()(const ObjectFile::Atom* atom) const {
1599 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
1600 return true;
1601 if ( atom->getName() == NULL )
1602 return true;
1603 if ( fReadersWithDwarfOrdinals.find(atom->getFile()) == fReadersWithDwarfOrdinals.end() )
1604 return true;
1605 return false;
1606 }
1607
1608private:
1609 const std::map<class ObjectFile::Reader*, uint32_t>& fReadersWithDwarfOrdinals;
1610};
1611
1612// used to sort atoms with debug notes
1613class ReadersWithDwarfSorter
1614{
1615public:
1616 ReadersWithDwarfSorter(const std::map<class ObjectFile::Reader*, uint32_t>& readersWithDwarfOrdinals,
1617 const std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals)
1618 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals), fAtomOrdinals(atomOrdinals) {}
1619
1620 bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right) const
1621 {
1622 // first sort by reader
1623 unsigned int leftReaderIndex = fReadersWithDwarfOrdinals.find(left->getFile())->second;
1624 unsigned int rightReaderIndex = fReadersWithDwarfOrdinals.find(right->getFile())->second;
1625 if ( leftReaderIndex != rightReaderIndex )
1626 return (leftReaderIndex < rightReaderIndex);
1627
1628 // then sort by atom ordinal
1629 unsigned int leftAtomIndex = fAtomOrdinals.find(left)->second;
1630 unsigned int rightAtomIndex = fAtomOrdinals.find(right)->second;
1631 return leftAtomIndex < rightAtomIndex;
1632 }
1633
1634private:
1635 const std::map<class ObjectFile::Reader*, uint32_t>& fReadersWithDwarfOrdinals;
1636 const std::map<const class ObjectFile::Atom*, uint32_t>& fAtomOrdinals;
1637};
1638
1639
1640
1641
1642
1643void Linker::synthesizeDebugNotes(std::vector<class ObjectFile::Atom*>& allAtomsByReader)
d696c285
A
1644{
1645 // synthesize "debug notes" and add them to master stabs vector
1646 const char* dirPath = NULL;
1647 const char* filename = NULL;
1648 bool wroteStartSO = false;
74cfe461
A
1649 __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> seenFiles;
1650 for (std::vector<ObjectFile::Atom*>::iterator it=allAtomsByReader.begin(); it != allAtomsByReader.end(); it++) {
d696c285 1651 ObjectFile::Atom* atom = *it;
74cfe461
A
1652 const char* newDirPath;
1653 const char* newFilename;
1654 //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
1655 if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) {
1656 // need SO's whenever the translation unit source file changes
1657 if ( newFilename != filename ) {
1658 // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
1659 if ( (newDirPath != NULL) && (strlen(newDirPath) > 1 ) && (newDirPath[strlen(newDirPath)-1] != '/') )
1660 asprintf((char**)&newDirPath, "%s/", newDirPath);
1661 if ( filename != NULL ) {
1662 // translation unit change, emit ending SO
1663 ObjectFile::Reader::Stab endFileStab;
1664 endFileStab.atom = NULL;
1665 endFileStab.type = N_SO;
1666 endFileStab.other = 1;
1667 endFileStab.desc = 0;
1668 endFileStab.value = 0;
1669 endFileStab.string = "";
1670 fStabs.push_back(endFileStab);
1671 }
1672 // new translation unit, emit start SO's
1673 ObjectFile::Reader::Stab dirPathStab;
1674 dirPathStab.atom = NULL;
1675 dirPathStab.type = N_SO;
1676 dirPathStab.other = 0;
1677 dirPathStab.desc = 0;
1678 dirPathStab.value = 0;
1679 dirPathStab.string = newDirPath;
1680 fStabs.push_back(dirPathStab);
1681 ObjectFile::Reader::Stab fileStab;
1682 fileStab.atom = NULL;
1683 fileStab.type = N_SO;
1684 fileStab.other = 0;
1685 fileStab.desc = 0;
1686 fileStab.value = 0;
1687 fileStab.string = newFilename;
1688 fStabs.push_back(fileStab);
1689 // Synthesize OSO for start of file
1690 ObjectFile::Reader::Stab objStab;
1691 objStab.atom = NULL;
1692 objStab.type = N_OSO;
1693 objStab.other = 0;
1694 objStab.desc = 1;
1695 objStab.value = atom->getFile()->getModificationTime();
1696 objStab.string = assureFullPath(atom->getFile()->getPath());
1697 fStabs.push_back(objStab);
1698 wroteStartSO = true;
1699 // add the source file path to seenFiles so it does not show up in SOLs
1700 seenFiles.insert(newFilename);
1701 }
1702 filename = newFilename;
1703 dirPath = newDirPath;
1704 if ( atom->getSegment().isContentExecutable() && (strncmp(atom->getSectionName(), "__text", 6) == 0) ) {
1705 // Synthesize BNSYM and start FUN stabs
1706 ObjectFile::Reader::Stab beginSym;
1707 beginSym.atom = atom;
1708 beginSym.type = N_BNSYM;
1709 beginSym.other = 1;
1710 beginSym.desc = 0;
1711 beginSym.value = 0;
1712 beginSym.string = "";
1713 fStabs.push_back(beginSym);
1714 ObjectFile::Reader::Stab startFun;
1715 startFun.atom = atom;
1716 startFun.type = N_FUN;
1717 startFun.other = 1;
1718 startFun.desc = 0;
1719 startFun.value = 0;
1720 startFun.string = atom->getName();
1721 fStabs.push_back(startFun);
1722 // Synthesize any SOL stabs needed
1723 std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
1724 if ( lineInfo != NULL ) {
1725 const char* curFile = NULL;
1726 for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
1727 if ( it->fileName != curFile ) {
1728 if ( seenFiles.count(it->fileName) == 0 ) {
1729 seenFiles.insert(it->fileName);
1730 ObjectFile::Reader::Stab sol;
1731 sol.atom = 0;
1732 sol.type = N_SOL;
1733 sol.other = 0;
1734 sol.desc = 0;
1735 sol.value = 0;
1736 sol.string = it->fileName;
1737 fStabs.push_back(sol);
d696c285 1738 }
74cfe461 1739 curFile = it->fileName;
d696c285 1740 }
d696c285 1741 }
74cfe461
A
1742 }
1743 // Synthesize end FUN and ENSYM stabs
1744 ObjectFile::Reader::Stab endFun;
1745 endFun.atom = atom;
1746 endFun.type = N_FUN;
1747 endFun.other = 0;
1748 endFun.desc = 0;
1749 endFun.value = 0;
1750 endFun.string = "";
1751 fStabs.push_back(endFun);
1752 ObjectFile::Reader::Stab endSym;
1753 endSym.atom = atom;
1754 endSym.type = N_ENSYM;
1755 endSym.other = 1;
1756 endSym.desc = 0;
1757 endSym.value = 0;
1758 endSym.string = "";
1759 fStabs.push_back(endSym);
1760 }
1761 else {
1762 ObjectFile::Reader::Stab globalsStab;
1763 if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
1764 // Synthesize STSYM stab for statics
1765 const char* name = atom->getName();
1766 if ( name[0] == '_' ) {
1767 globalsStab.atom = atom;
1768 globalsStab.type = N_STSYM;
1769 globalsStab.other = 1;
1770 globalsStab.desc = 0;
1771 globalsStab.value = 0;
1772 globalsStab.string = name;
1773 fStabs.push_back(globalsStab);
1774 }
1775 }
1776 else {
1777 // Synthesize GSYM stab for other globals (but not .eh exception frame symbols)
1778 const char* name = atom->getName();
1779 if ( (name[0] == '_') && (strcmp(atom->getSectionName(), "__eh_frame") != 0) ) {
1780 globalsStab.atom = atom;
1781 globalsStab.type = N_GSYM;
1782 globalsStab.other = 1;
1783 globalsStab.desc = 0;
1784 globalsStab.value = 0;
1785 globalsStab.string = name;
1786 fStabs.push_back(globalsStab);
d696c285
A
1787 }
1788 }
1789 }
1790 }
1791 }
74cfe461 1792
d696c285
A
1793 if ( wroteStartSO ) {
1794 // emit ending SO
1795 ObjectFile::Reader::Stab endFileStab;
1796 endFileStab.atom = NULL;
1797 endFileStab.type = N_SO;
1798 endFileStab.other = 1;
1799 endFileStab.desc = 0;
1800 endFileStab.value = 0;
1801 endFileStab.string = "";
1802 fStabs.push_back(endFileStab);
1803 }
1804}
1805
74cfe461
A
1806
1807
1808
1809void Linker::collectDebugInfo()
d696c285 1810{
74cfe461
A
1811 std::map<const class ObjectFile::Atom*, uint32_t> atomOrdinals;
1812 fStartDebugTime = mach_absolute_time();
d696c285 1813 if ( fOptions.readerOptions().fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone ) {
69a49097 1814
74cfe461
A
1815 // determine mixture of stabs and dwarf
1816 bool someStabs = false;
1817 bool someDwarf = false;
d696c285
A
1818 for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
1819 it != fReadersThatHaveSuppliedAtoms.end();
1820 it++) {
1821 ObjectFile::Reader* reader = *it;
1822 if ( reader != NULL ) {
1823 switch ( reader->getDebugInfoKind() ) {
1824 case ObjectFile::Reader::kDebugInfoNone:
d696c285
A
1825 break;
1826 case ObjectFile::Reader::kDebugInfoStabs:
74cfe461 1827 someStabs = true;
d696c285
A
1828 break;
1829 case ObjectFile::Reader::kDebugInfoDwarf:
74cfe461 1830 someDwarf = true;
d696c285
A
1831 fCreateUUID = true;
1832 break;
1833 case ObjectFile::Reader::kDebugInfoStabsUUID:
74cfe461 1834 someStabs = true;
d696c285
A
1835 fCreateUUID = true;
1836 break;
1837 default:
1838 throw "Unhandled type of debug information";
1839 }
1840 }
1841 }
74cfe461
A
1842
1843 if ( someDwarf || someStabs ) {
1844 // try to minimize re-allocations
1845 fStabs.reserve(1024);
1846
1847 // make mapping from atoms to ordinal
1848 uint32_t ordinal = 1;
1849 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1850 atomOrdinals[*it] = ordinal++;
1851 }
1852 }
1853
1854 // process all dwarf .o files as a batch
1855 if ( someDwarf ) {
1856 // make mapping from readers with dwarf to ordinal
1857 std::map<class ObjectFile::Reader*, uint32_t> readersWithDwarfOrdinals;
1858 uint32_t readerOrdinal = 1;
1859 for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
1860 it != fReadersThatHaveSuppliedAtoms.end();
1861 it++) {
1862 ObjectFile::Reader* reader = *it;
1863 if ( (reader != NULL) && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoDwarf) ) {
1864 readersWithDwarfOrdinals[reader] = readerOrdinal++;
1865 }
1866 }
1867
1868 // make a vector of atoms
1869 std::vector<class ObjectFile::Atom*> allAtomsByReader(fAllAtoms.begin(), fAllAtoms.end());
1870 // remove those not from a reader that has dwarf
1871 allAtomsByReader.erase(std::remove_if(allAtomsByReader.begin(), allAtomsByReader.end(),
1872 NoDebugNoteAtom(readersWithDwarfOrdinals)), allAtomsByReader.end());
1873 // sort by reader then atom ordinal
1874 std::sort(allAtomsByReader.begin(), allAtomsByReader.end(), ReadersWithDwarfSorter(readersWithDwarfOrdinals, atomOrdinals));
1875 // add debug notes for each atom
1876 this->synthesizeDebugNotes(allAtomsByReader);
1877 }
1878
1879 // process all stabs .o files one by one
1880 if ( someStabs ) {
1881 // get stabs from each reader, in command line order
1882 for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
1883 it != fReadersThatHaveSuppliedAtoms.end();
1884 it++) {
1885 ObjectFile::Reader* reader = *it;
1886 if ( reader != NULL ) {
1887 switch ( reader->getDebugInfoKind() ) {
1888 case ObjectFile::Reader::kDebugInfoDwarf:
1889 case ObjectFile::Reader::kDebugInfoNone:
1890 // do nothing
1891 break;
1892 case ObjectFile::Reader::kDebugInfoStabs:
1893 case ObjectFile::Reader::kDebugInfoStabsUUID:
1894 collectStabs(reader, atomOrdinals);
1895 break;
1896 default:
1897 throw "Unhandled type of debug information";
1898 }
1899 }
1900 }
1901 // remove stabs associated with atoms that won't be in output
1902 std::set<class ObjectFile::Atom*> allAtomsSet;
1903 allAtomsSet.insert(fAllAtoms.begin(), fAllAtoms.end());
1904 fStabs.erase(std::remove_if(fStabs.begin(), fStabs.end(), NotInSet(allAtomsSet)), fStabs.end());
1905 }
d696c285
A
1906 }
1907}
c2646906 1908
d696c285
A
1909void Linker::writeOutput()
1910{
1911 fStartWriteTime = mach_absolute_time();
1912 // tell writer about each segment's atoms
1913 fOutputFileSize = fOutputFile->write(fAllAtoms, fStabs, this->entryPoint(), this->dyldHelper(), (fCreateUUID && fOptions.emitUUID()));
1914}
c2646906
A
1915
1916ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
1917{
1918 // map in whole file
1919 uint64_t len = info.fileLen;
1920 int fd = ::open(info.path, O_RDONLY, 0);
1921 if ( fd == -1 )
6e880c60 1922 throwf("can't open file, errno=%d", errno);
c2646906
A
1923 if ( info.fileLen < 20 )
1924 throw "file too small";
d696c285
A
1925
1926 uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
1927 if ( p == (uint8_t*)(-1) )
6e880c60 1928 throwf("can't map file, errno=%d", errno);
d696c285 1929
c2646906 1930 // if fat file, skip to architecture we want
d696c285
A
1931 const fat_header* fh = (fat_header*)p;
1932 if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
c2646906 1933 // Fat header is always big-endian
c2646906
A
1934 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
1935 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
d696c285
A
1936 if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fArchitecture ) {
1937 uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
c2646906 1938 len = OSSwapBigToHostInt32(archs[i].size);
d696c285 1939 // if requested architecture is page aligned within fat file, then remap just that portion of file
74cfe461 1940 if ( (fileOffset & 0x00000FFF) == 0 ) {
d696c285
A
1941 // unmap whole file
1942 munmap((caddr_t)p, info.fileLen);
1943 // re-map just part we need
1944 p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset);
1945 if ( p == (uint8_t*)(-1) )
1946 throwf("can't re-map file, errno=%d", errno);
1947 }
1948 else {
1949 p = &p[fileOffset];
1950 }
c2646906
A
1951 break;
1952 }
1953 }
1954 }
d696c285
A
1955 ::close(fd);
1956
1957 switch (fArchitecture) {
1958 case CPU_TYPE_POWERPC:
1959 if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
1960 return this->addObject(mach_o::relocatable::Reader<ppc>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
69a49097
A
1961 else if ( mach_o::dylib::Reader<ppc>::validFile(p, info.options.fBundleLoader) )
1962 return this->addDylib(mach_o::dylib::Reader<ppc>::make(p, len, info.path, info.options.fBundleLoader, fOptions.readerOptions()), info, len);
d696c285
A
1963 else if ( mach_o::archive::Reader<ppc>::validFile(p, len) )
1964 return this->addArchive(mach_o::archive::Reader<ppc>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
1965 break;
1966 case CPU_TYPE_POWERPC64:
1967 if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
1968 return this->addObject(mach_o::relocatable::Reader<ppc64>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
69a49097
A
1969 else if ( mach_o::dylib::Reader<ppc64>::validFile(p, info.options.fBundleLoader) )
1970 return this->addDylib(mach_o::dylib::Reader<ppc64>::make(p, len, info.path, info.options.fBundleLoader, fOptions.readerOptions()), info, len);
d696c285
A
1971 else if ( mach_o::archive::Reader<ppc64>::validFile(p, len) )
1972 return this->addArchive(mach_o::archive::Reader<ppc64>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
1973 break;
1974 case CPU_TYPE_I386:
1975 if ( mach_o::relocatable::Reader<x86>::validFile(p) )
1976 return this->addObject(mach_o::relocatable::Reader<x86>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
69a49097
A
1977 else if ( mach_o::dylib::Reader<x86>::validFile(p, info.options.fBundleLoader) )
1978 return this->addDylib(mach_o::dylib::Reader<x86>::make(p, len, info.path, info.options.fBundleLoader, fOptions.readerOptions()), info, len);
d696c285
A
1979 else if ( mach_o::archive::Reader<x86>::validFile(p, len) )
1980 return this->addArchive(mach_o::archive::Reader<x86>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
1981 break;
69a49097
A
1982 case CPU_TYPE_X86_64:
1983 if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
1984 return this->addObject(mach_o::relocatable::Reader<x86_64>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
1985 else if ( mach_o::dylib::Reader<x86_64>::validFile(p, info.options.fBundleLoader) )
1986 return this->addDylib(mach_o::dylib::Reader<x86_64>::make(p, len, info.path, info.options.fBundleLoader, fOptions.readerOptions()), info, len);
1987 else if ( mach_o::archive::Reader<x86_64>::validFile(p, len) )
1988 return this->addArchive(mach_o::archive::Reader<x86_64>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
1989 break;
d696c285
A
1990 }
1991
1992 // error handling
1993 if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
69a49097 1994 throwf("missing required architecture %s in file", fArchitectureName);
c2646906 1995 }
c2646906 1996 else {
d696c285 1997 throw "file is not of required architecture";
c2646906 1998 }
c2646906
A
1999}
2000
2001
2002void Linker::createReaders()
2003{
d696c285 2004 fStartCreateReadersTime = mach_absolute_time();
c2646906
A
2005 std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
2006 const int count = files.size();
2007 if ( count == 0 )
2008 throw "no object files specified";
2009 // add all direct object, archives, and dylibs
2010 for (int i=0; i < count; ++i) {
2011 Options::FileInfo& entry = files[i];
2012 // ignore /usr/lib/dyld on command line in crt.o build
2013 if ( strcmp(entry.path, "/usr/lib/dyld") != 0 ) {
2014 try {
2015 this->addInputFile(this->createReader(entry));
2016 }
2017 catch (const char* msg) {
2018 if ( strstr(msg, "architecture") != NULL ) {
2019 if ( fOptions.ignoreOtherArchInputFiles() ) {
2020 // ignore, because this is about an architecture not in use
2021 }
2022 else {
2023 fprintf(stderr, "ld64 warning: in %s, %s\n", entry.path, msg);
2024 }
2025 }
2026 else {
2027 throwf("in %s, %s", entry.path, msg);
2028 }
2029 }
2030 }
2031 }
d696c285 2032
c2646906
A
2033 // add first level of indirect dylibs
2034 fDirectLibrariesComplete = true;
2035 for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
2036 this->addIndirectLibraries(it->reader);
2037 }
d696c285 2038
c2646906
A
2039 // indirect handling depends on namespace
2040 switch ( fOptions.nameSpace() ) {
2041 case Options::kFlatNameSpace:
2042 case Options::kForceFlatNameSpace:
2043 // with flat namespace, blindly load all indirect libraries
2044 // the indirect list will grow as indirect libraries are loaded
2045 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
6e880c60
A
2046 try {
2047 it->reader = this->createReader(fOptions.findFile(it->path));
d696c285 2048 it->reader->setSortOrder(fNextObjectFileOrder++);
c2646906 2049 }
6e880c60
A
2050 catch (const char* msg) {
2051 fprintf(stderr, "ld64 warning: indirect library %s could not be loaded: %s\n", it->path, msg);
c2646906
A
2052 }
2053 }
2054 break;
d696c285 2055
c2646906
A
2056 case Options::kTwoLevelNameSpace:
2057 // with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
2058 {
2059 bool indirectAdded = true;
2060 while ( indirectAdded ) {
2061 indirectAdded = false;
2062 // instantiate a reader for each indirect library and try to find parent that re-exports it
2063 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
2064 if ( it->reader == NULL ) {
2065 try {
6e880c60 2066 it->reader = this->createReader(fOptions.findFile(it->path));
d696c285 2067 it->reader->setSortOrder(fNextObjectFileOrder++);
c2646906
A
2068 indirectAdded = true;
2069 }
2070 catch (const char* msg) {
2071 fprintf(stderr, "ld64 warning: indirect library %s could not be loaded: %s\n", it->path, msg);
2072 }
2073 }
2074 // if an indirect library does not have an assigned parent, look for one
d696c285
A
2075 if ( (it->reader != NULL) && (it->reExportedViaDirectLibrary == NULL) ) {
2076 it->reExportedViaDirectLibrary = this->findDirectLibraryWhichReExports(*it);
c2646906
A
2077 }
2078 }
2079 }
2080 }
2081 break;
2082 }
d696c285 2083
c2646906
A
2084 // add relevant indirect libraries to the end of fDynamicLibraries
2085 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
d696c285 2086 if ( (it->reader != NULL) && (it->reExportedViaDirectLibrary != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace) ) {
c2646906
A
2087 ExecutableFile::DyLibUsed dylibInfo;
2088 dylibInfo.reader = it->reader;
2089 dylibInfo.options.fWeakImport = false;
2090 dylibInfo.options.fReExport = false;
2091 dylibInfo.options.fInstallPathOverride = NULL;
2092 dylibInfo.indirect = true;
d696c285 2093 dylibInfo.directReader = it->reExportedViaDirectLibrary;
c2646906 2094 fDynamicLibraries.push_back(dylibInfo);
d696c285
A
2095 if ( fOptions.readerOptions().fTraceIndirectDylibs ) {
2096 const char* fullPath = it->reader->getPath();
2097 char realName[MAXPATHLEN];
2098 if ( realpath(fullPath, realName) != NULL )
2099 fullPath = realName;
2100 logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
2101 }
2102 }
2103 }
2104}
2105
2106
2107ObjectFile::Reader* Linker::findDirectLibraryWhichReExports(IndirectLibrary& indirectLib)
2108{
2109 // ask each parent if they re-export this dylib
2110 for (std::set<ObjectFile::Reader*>::iterator pit=indirectLib.parents.begin(); pit != indirectLib.parents.end(); pit++) {
2111 if ( (*pit)->reExports(indirectLib.reader) ) {
2112 ObjectFile::Reader* lib = *pit;
2113 // first check if we found a direct library, if so return it
2114 for (std::vector<ExecutableFile::DyLibUsed>::iterator dit=fDynamicLibraries.begin(); dit != fDynamicLibraries.end(); dit++) {
2115 if ( dit->reader == lib && dit->indirect == false )
2116 return lib;
2117 }
2118 // otherwise search indirects for parent and see how it is reexported
2119 for (std::list<IndirectLibrary>::iterator iit=fIndirectDynamicLibraries.begin(); iit != fIndirectDynamicLibraries.end(); iit++) {
2120 if ( iit->reader == lib ) {
2121 ObjectFile::Reader* lib2 = this->findDirectLibraryWhichReExports(*iit);
2122 if ( lib2 != NULL )
2123 return lib2;
2124 }
2125 }
c2646906
A
2126 }
2127 }
d696c285 2128 return NULL;
c2646906
A
2129}
2130
2131
2132
d696c285 2133ObjectFile::Reader* Linker::addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
c2646906 2134{
d696c285
A
2135 if (fOptions.readerOptions().fTraceArchives) {
2136 const char* fullPath = reader->getPath();
2137 char realName[MAXPATHLEN];
2138 if ( realpath(fullPath, realName) != NULL )
2139 fullPath = realName;
2140 logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath);
2141 }
2142
2143 // update stats
2144 fTotalArchiveSize += mappedLen;
2145 ++fTotalArchivesLoaded;
2146 return reader;
2147}
2148
2149ObjectFile::Reader* Linker::addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
2150{
2151 // update stats
2152 fTotalObjectSize += mappedLen;
2153 ++fTotalObjectLoaded;
2154 return reader;
2155}
2156
2157ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
2158{
69a49097 2159 if ( (reader->getInstallPath() == NULL) && !info.options.fBundleLoader ) {
d696c285
A
2160 // this is a "blank" stub
2161 // silently ignore it
2162 return reader;
2163 }
2164
c2646906
A
2165 if ( fDirectLibrariesComplete ) {
2166 this->addIndirectLibraries(reader);
2167 }
2168 else {
d696c285
A
2169 if ( fOptions.readerOptions().fTraceDylibs ) {
2170 const char* fullPath = reader->getPath();
2171 char realName[MAXPATHLEN];
2172 if ( realpath(fullPath, realName) != NULL )
2173 fullPath = realName;
2174 logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
2175 }
c2646906
A
2176 ExecutableFile::DyLibUsed dylibInfo;
2177 dylibInfo.reader = reader;
2178 dylibInfo.options = info.options;
2179 dylibInfo.indirect = false;
2180 dylibInfo.directReader = NULL;
2181 fDynamicLibraries.push_back(dylibInfo);
69a49097 2182
d696c285
A
2183
2184 // Verify that a client is allowed to link to this dylib. There are three cases.
2185 bool okToLink = true;
2186 const char* outputFilePath = fOptions.installPath();
2187 const char* outputFilePathLastSlash = strrchr(outputFilePath, '/');
2188 if ( reader->parentUmbrella() != NULL ) {
2189 // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
2190 okToLink = ( (outputFilePathLastSlash != NULL) && (strcmp(&outputFilePathLastSlash[1], reader->parentUmbrella()) == 0) );
2191 }
69a49097 2192
d696c285
A
2193 if ( !okToLink && (reader->parentUmbrella() != NULL) ) {
2194 // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
69a49097
A
2195 okToLink = ( (outputFilePathLastSlash != NULL)
2196 && (fOptions.umbrellaName() != NULL)
d696c285
A
2197 && (strcmp(fOptions.umbrellaName(), reader->parentUmbrella()) == 0) );
2198 }
2199
2200 std::vector<const char*>* clients = reader->getAllowableClients();
2201 if ( !okToLink && (clients != NULL) ) {
2202 // case 3) the dylib has a list of allowable clients, and we are creating one of them
2203 const char* clientName = fOptions.clientName();
2204 int clientNameLen = 0;
2205 if ( clientName != NULL ) {
2206 // use client name as specified on command line
2207 clientNameLen = strlen(clientName);
2208 }
2209 else {
2210 // infer client name from output path (e.g. xxx/libfoo.A.dylib --> foo, Bar.framework/Bar --> Bar)
2211 clientName = outputFilePath;
2212 // starts after last slash
2213 if ( outputFilePathLastSlash != NULL )
2214 clientName = &outputFilePathLastSlash[1];
2215 if ( strncmp(clientName, "lib", 3) == 0 )
2216 clientName = &clientName[3];
2217 // up to first dot
2218 const char* firstDot = strchr(clientName, '.');
2219 if ( firstDot == NULL )
2220 clientNameLen = strlen(clientName);
2221 else
2222 clientNameLen = firstDot - clientName;
2223 }
69a49097 2224
d696c285
A
2225 // Use clientName to check if this dylib is able to link against the allowable clients.
2226 for (std::vector<const char*>::iterator it = clients->begin(); it != clients->end(); it++) {
2227 if ( strncmp(*it, clientName, clientNameLen) == 0 )
2228 okToLink = true;
2229 }
2230 }
69a49097 2231
d696c285
A
2232 // error out if we are not allowed to link
2233 if ( ! okToLink )
2234 //throwf("'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
2235 fprintf(stderr, "'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
2236 reader->getPath(), reader->parentUmbrella());
c2646906 2237 }
69a49097 2238
d696c285
A
2239 // update stats
2240 ++fTotalDylibsLoaded;
2241
2242 return reader;
c2646906
A
2243}
2244
2245
2246void Linker::addIndirectLibraries(ObjectFile::Reader* reader)
2247{
2248 std::vector<const char*>* dependentLibs = reader->getDependentLibraryPaths();
2249 if ( dependentLibs != NULL ) {
2250 for (std::vector<const char*>::iterator it=dependentLibs->begin(); it != dependentLibs->end(); it++) {
2251 if ( this->haveDirectLibrary(*it) ) {
2252 // do nothing, direct library already exists
2253 }
2254 else if ( this->haveIndirectLibrary(*it, reader) ) {
2255 // side effect of haveIndirectLibrary() added reader to parent list
2256 }
2257 else {
2258 // add to list of indirect libraries
2259 IndirectLibrary indirectLib;
2260 indirectLib.path = *it;
2261 indirectLib.fileLen = 0;
2262 indirectLib.reader = NULL;
2263 indirectLib.parents.insert(reader);
d696c285 2264 indirectLib.reExportedViaDirectLibrary = NULL;
c2646906
A
2265 fIndirectDynamicLibraries.push_back(indirectLib);
2266 //fprintf(stderr, "add indirect library: %s\n", *it);
2267 }
2268 }
2269 }
2270}
2271
2272bool Linker::haveIndirectLibrary(const char* path, ObjectFile::Reader* parentReader)
2273{
2274 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
2275 if ( strcmp(path, it->path) == 0 ) {
2276 it->parents.insert(parentReader);
2277 return true;
2278 }
2279 if ( it->reader != NULL ) {
2280 const char* installPath = it->reader->getInstallPath();
2281 if ( (installPath != NULL) && (strcmp(path, installPath) == 0) )
2282 return true;
2283 }
2284 }
2285 return false;
2286}
2287
2288bool Linker::haveDirectLibrary(const char* path)
2289{
2290 for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
2291 if ( strcmp(path, it->reader->getPath()) == 0 )
2292 return true;
2293 const char* installPath = it->reader->getInstallPath();
2294 if ( (installPath != NULL) && (strcmp(path, installPath) == 0) )
2295 return true;
2296 }
2297 return false;
2298}
2299
d696c285
A
2300void Linker::logTraceInfo (const char* format, ...)
2301{
2302 static int trace_file = -1;
2303 char trace_buffer[MAXPATHLEN * 2];
2304 char *buffer_ptr;
2305 int length;
2306 ssize_t amount_written;
2307 const char *trace_file_path = fOptions.readerOptions().fTraceOutputFile;
2308
2309 if(trace_file == -1) {
2310 if(trace_file_path != NULL) {
2311 trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
2312 if(trace_file == -1)
2313 throwf("Could not open or create trace file: %s\n", trace_file_path);
2314 }
2315 else {
2316 trace_file = fileno(stderr);
2317 }
2318 }
2319
2320 va_list ap;
2321 va_start(ap, format);
2322 length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap);
2323 va_end(ap);
2324 buffer_ptr = trace_buffer;
2325
2326 while(length > 0) {
2327 amount_written = write(trace_file, buffer_ptr, length);
2328 if(amount_written == -1)
2329 /* Failure to write shouldn't fail the build. */
2330 return;
2331 buffer_ptr += amount_written;
2332 length -= amount_written;
2333 }
2334}
c2646906
A
2335
2336
2337
2338void Linker::createWriter()
2339{
d696c285 2340 fStartCreateWriterTime = mach_absolute_time();
c2646906 2341 const char* path = fOptions.getOutputFilePath();
d696c285 2342 switch ( fArchitecture ) {
c2646906 2343 case CPU_TYPE_POWERPC:
d696c285 2344 this->setOutputFile(new mach_o::executable::Writer<ppc>(path, fOptions, fDynamicLibraries));
c2646906
A
2345 break;
2346 case CPU_TYPE_POWERPC64:
d696c285 2347 this->setOutputFile(new mach_o::executable::Writer<ppc64>(path, fOptions, fDynamicLibraries));
c2646906
A
2348 break;
2349 case CPU_TYPE_I386:
d696c285 2350 this->setOutputFile(new mach_o::executable::Writer<x86>(path, fOptions, fDynamicLibraries));
c2646906 2351 break;
69a49097
A
2352 case CPU_TYPE_X86_64:
2353 this->setOutputFile(new mach_o::executable::Writer<x86_64>(path, fOptions, fDynamicLibraries));
2354 break;
c2646906
A
2355 default:
2356 throw "unknown architecture";
2357 }
2358}
2359
2360
2361Linker::SymbolTable::SymbolTable(Linker& owner)
2362 : fOwner(owner), fRequireCount(0)
2363{
2364}
2365
2366void Linker::SymbolTable::require(const char* name)
2367{
2368 //fprintf(stderr, "require(%s)\n", name);
2369 Mapper::iterator pos = fTable.find(name);
2370 if ( pos == fTable.end() ) {
2371 fTable[name] = NULL;
2372 ++fRequireCount;
2373 }
2374}
2375
d696c285
A
2376// convenience labels for 2-dimensional switch statement
2377enum {
2378 kRegAndReg = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2379 kRegAndWeak = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2380 kRegAndTent = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2381 kRegAndExtern = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2382 kRegAndExternWeak = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
2383 kWeakAndReg = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2384 kWeakAndWeak = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2385 kWeakAndTent = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2386 kWeakAndExtern = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2387 kWeakAndExternWeak = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
2388 kTentAndReg = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2389 kTentAndWeak = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2390 kTentAndTent = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2391 kTentAndExtern = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2392 kTentAndExternWeak = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
2393 kExternAndReg = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2394 kExternAndWeak = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2395 kExternAndTent = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2396 kExternAndExtern = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2397 kExternAndExternWeak = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
2398 kExternWeakAndReg = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2399 kExternWeakAndWeak = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2400 kExternWeakAndTent = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2401 kExternWeakAndExtern = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2402 kExternWeakAndExternWeak= (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition
2403};
2404
2405bool Linker::SymbolTable::add(ObjectFile::Atom& newAtom)
c2646906 2406{
d696c285
A
2407 bool useNew = true;
2408 const char* name = newAtom.getName();
2409 //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
c2646906 2410 Mapper::iterator pos = fTable.find(name);
d696c285
A
2411 ObjectFile::Atom* existingAtom = NULL;
2412 if ( pos != fTable.end() )
2413 existingAtom = pos->second;
2414 if ( existingAtom != NULL ) {
2415 // already have atom with same name in symbol table
2416 switch ( (existingAtom->getDefinitionKind() << 3) | newAtom.getDefinitionKind() ) {
2417 case kRegAndReg:
2418 throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2419 case kRegAndWeak:
2420 // ignore new weak atom, because we already have a non-weak one
2421 useNew = false;
2422 break;
2423 case kRegAndTent:
2424 // ignore new tentative atom, because we already have a regular one
2425 useNew = false;
2426 break;
2427 case kRegAndExtern:
2428 // ignore external atom, because we already have a one
2429 useNew = false;
2430 break;
2431 case kRegAndExternWeak:
2432 // ignore external atom, because we already have a one
2433 useNew = false;
2434 break;
2435 case kWeakAndReg:
2436 // replace existing weak atom with regular one
2437 break;
2438 case kWeakAndWeak:
2439 // have another weak atom, use whichever has largest alignment requirement
2440 // because codegen of some client may require alignment
74cfe461 2441 useNew = ( newAtom.getAlignment().leadingZeros() > existingAtom->getAlignment().leadingZeros() );
d696c285
A
2442 break;
2443 case kWeakAndTent:
2444 // replace existing weak atom with tentative one ???
2445 break;
2446 case kWeakAndExtern:
2447 // keep weak atom, at runtime external one may override
2448 useNew = false;
2449 break;
2450 case kWeakAndExternWeak:
2451 // keep weak atom, at runtime external one may override
2452 useNew = false;
2453 break;
2454 case kTentAndReg:
2455 // replace existing tentative atom with regular one
2456 break;
2457 case kTentAndWeak:
2458 // replace existing tentative atom with weak one ???
2459 break;
2460 case kTentAndTent:
2461 // use largest
2462 if ( newAtom.getSize() < existingAtom->getSize() ) {
2463 useNew = false;
74cfe461
A
2464 } else {
2465 if ( newAtom.getAlignment().leadingZeros() < existingAtom->getAlignment().leadingZeros() )
2466 fprintf(stderr, "ld64 warning: alignment lost in merging tentative definition %s\n", newAtom.getDisplayName());
c2646906 2467 }
d696c285
A
2468 break;
2469 case kTentAndExtern:
2470 case kTentAndExternWeak:
2471 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2472 switch ( fOwner.fOptions.commonsMode() ) {
2473 case Options::kCommonsIgnoreDylibs:
2474 if ( fOwner.fOptions.warnCommons() )
2475 fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2476 existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
2477 useNew = false;
2478 break;
2479 case Options::kCommonsOverriddenByDylibs:
2480 if ( fOwner.fOptions.warnCommons() )
2481 fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from dylib %s\n",
2482 existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
2483 break;
2484 case Options::kCommonsConflictsDylibsError:
2485 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2486 existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
c2646906 2487 }
d696c285
A
2488 break;
2489 case kExternAndReg:
2490 // replace external atom with regular one
2491 break;
2492 case kExternAndWeak:
2493 // replace external atom with weak one
2494 break;
2495 case kExternAndTent:
2496 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2497 switch ( fOwner.fOptions.commonsMode() ) {
2498 case Options::kCommonsIgnoreDylibs:
2499 if ( fOwner.fOptions.warnCommons() )
2500 fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2501 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2502 break;
2503 case Options::kCommonsOverriddenByDylibs:
2504 if ( fOwner.fOptions.warnCommons() )
2505 fprintf(stderr, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2506 newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
2507 useNew = false;
2508 break;
2509 case Options::kCommonsConflictsDylibsError:
2510 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2511 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
c2646906 2512 }
d696c285
A
2513 break;
2514 case kExternAndExtern:
2515 throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2516 case kExternAndExternWeak:
2517 // keep strong dylib atom, ignore weak one
2518 useNew = false;
2519 break;
2520 case kExternWeakAndReg:
2521 // replace existing weak external with regular
2522 break;
2523 case kExternWeakAndWeak:
2524 // replace existing weak external with weak (let dyld decide at runtime which to use)
2525 break;
2526 case kExternWeakAndTent:
2527 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2528 switch ( fOwner.fOptions.commonsMode() ) {
2529 case Options::kCommonsIgnoreDylibs:
2530 if ( fOwner.fOptions.warnCommons() )
2531 fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2532 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2533 break;
2534 case Options::kCommonsOverriddenByDylibs:
2535 if ( fOwner.fOptions.warnCommons() )
2536 fprintf(stderr, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2537 newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
2538 useNew = false;
2539 break;
2540 case Options::kCommonsConflictsDylibsError:
2541 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2542 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
c2646906 2543 }
d696c285
A
2544 break;
2545 case kExternWeakAndExtern:
2546 // replace existing weak external with external
2547 break;
2548 case kExternWeakAndExternWeak:
2549 // keep existing external weak
2550 useNew = false;
2551 break;
c2646906
A
2552 }
2553 }
d696c285
A
2554 if ( useNew ) {
2555 fTable[name] = &newAtom;
2556 if ( existingAtom != NULL )
2557 fOwner.fDeadAtoms.insert(existingAtom);
2558 }
2559 else {
2560 fOwner.fDeadAtoms.insert(&newAtom);
2561 }
2562 return useNew;
c2646906
A
2563}
2564
d696c285
A
2565
2566
c2646906
A
2567ObjectFile::Atom* Linker::SymbolTable::find(const char* name)
2568{
2569 Mapper::iterator pos = fTable.find(name);
2570 if ( pos != fTable.end() ) {
2571 return pos->second;
2572 }
2573 return NULL;
2574}
2575
2576
2577void Linker::SymbolTable::getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines)
2578{
2579 for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) {
d696c285 2580 if ( (it->second == NULL) || (andWeakDefintions && (it->second->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition)) ) {
c2646906
A
2581 undefines.push_back(it->first);
2582 }
2583 }
2584}
2585
2586
2587
2588
2589bool Linker::AtomSorter::operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
2590{
2591 // first sort by section order (which is already sorted by segment)
2592 unsigned int leftSectionIndex = left->getSection()->getIndex();
2593 unsigned int rightSectionIndex = right->getSection()->getIndex();
2594 if ( leftSectionIndex != rightSectionIndex)
2595 return (leftSectionIndex < rightSectionIndex);
d696c285
A
2596
2597 // then sort by .o file order
2598 ObjectFile::Reader* leftReader = left->getFile();
2599 ObjectFile::Reader* rightReader = right->getFile();
2600 if ( leftReader != rightReader )
2601 return leftReader->getSortOrder() < rightReader->getSortOrder();
2602
2603 // lastly sort by atom within a .o file
c2646906
A
2604 return left->getSortOrder() < right->getSortOrder();
2605}
2606
2607
2608int main(int argc, const char* argv[])
2609{
69a49097
A
2610 const char* archName = NULL;
2611 bool showArch = false;
2612 bool archInferred = false;
c2646906
A
2613 try {
2614 // create linker object given command line arguments
2615 Linker ld(argc, argv);
d696c285 2616
69a49097
A
2617 // save error message prefix
2618 archName = ld.architectureName();
2619 archInferred = ld.isInferredArchitecture();
2620 showArch = ld.showArchitectureInErrors();
2621
c2646906
A
2622 // open all input files
2623 ld.createReaders();
d696c285 2624
c2646906
A
2625 // open output file
2626 ld.createWriter();
d696c285 2627
c2646906
A
2628 // do linking
2629 ld.link();
2630 }
2631 catch (const char* msg) {
69a49097
A
2632 extern const double ld64VersionNumber;
2633 if ( archInferred )
2634 fprintf(stderr, "ld64-%g failed: %s for inferred architecture %s\n", ld64VersionNumber, msg, archName);
2635 else if ( showArch )
2636 fprintf(stderr, "ld64-%g failed: %s for architecture %s\n", ld64VersionNumber, msg, archName);
2637 else
2638 fprintf(stderr, "ld64-%g failed: %s\n", ld64VersionNumber, msg);
c2646906
A
2639 return 1;
2640 }
c2646906 2641
d696c285
A
2642 return 0;
2643}