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