]> git.saurik.com Git - apple/ld64.git/blob - src/ld.cpp
ld64-77.1.tar.gz
[apple/ld64.git] / src / ld.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
2 * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/mman.h>
27 #include <sys/sysctl.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <limits.h>
31 #include <unistd.h>
32 #include <mach/mach_time.h>
33 #include <mach/vm_statistics.h>
34 #include <mach/mach_init.h>
35 #include <mach/mach_host.h>
36 #include <mach-o/fat.h>
37 #include <dlfcn.h>
38
39 #include <string>
40 #include <map>
41 #include <set>
42 #include <string>
43 #include <vector>
44 #include <list>
45 #include <algorithm>
46 #include <ext/hash_map>
47 #include <dlfcn.h>
48 #include <AvailabilityMacros.h>
49
50 #include "Options.h"
51
52 #include "ObjectFile.h"
53
54 #include "MachOReaderRelocatable.hpp"
55 #include "MachOReaderArchive.hpp"
56 #include "MachOReaderDylib.hpp"
57 #include "MachOWriterExecutable.hpp"
58
59 #define LLVM_SUPPORT 0
60
61 #if LLVM_SUPPORT
62 #include "LLVMReader.hpp"
63 #endif
64
65 #include "OpaqueSection.hpp"
66
67
68 class CStringComparor
69 {
70 public:
71 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
72 };
73
74 class CStringEquals
75 {
76 public:
77 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
78 };
79
80 class Section : public ObjectFile::Section
81 {
82 public:
83 static Section* find(const char* sectionName, const char* segmentName, bool zeroFill);
84 static void assignIndexes();
85 const char* getName() { return fSectionName; }
86 private:
87 Section(const char* sectionName, const char* segmentName, bool zeroFill);
88
89 struct Sorter {
90 static int segmentOrdinal(const char* segName);
91 bool operator()(Section* left, Section* right);
92 };
93
94 typedef __gnu_cxx::hash_map<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEquals> NameToOrdinal;
95 typedef __gnu_cxx::hash_map<const char*, class Section*, __gnu_cxx::hash<const char*>, CStringEquals> NameToSection;
96 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
97
98 const char* fSectionName;
99 const char* fSegmentName;
100 bool fZeroFill;
101
102 static NameToSection fgMapping;
103 static std::vector<Section*> fgSections;
104 static NameToOrdinal fgSegmentDiscoverOrder;
105 };
106
107 Section::NameToSection Section::fgMapping;
108 std::vector<Section*> Section::fgSections;
109 Section::NameToOrdinal Section::fgSegmentDiscoverOrder;
110
111 Section::Section(const char* sectionName, const char* segmentName, bool zeroFill)
112 : fSectionName(sectionName), fSegmentName(segmentName), fZeroFill(zeroFill)
113 {
114 this->fIndex = fgSections.size();
115 //fprintf(stderr, "new Section(%s, %s) => %p, %u\n", sectionName, segmentName, this, this->getIndex());
116 }
117
118 Section* Section::find(const char* sectionName, const char* segmentName, bool zeroFill)
119 {
120 NameToSection::iterator pos = fgMapping.find(sectionName);
121 if ( pos != fgMapping.end() ) {
122 if ( strcmp(pos->second->fSegmentName, segmentName) == 0 )
123 return pos->second;
124 // otherwise same section name is used in different segments, look slow way
125 for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
126 if ( (strcmp((*it)->fSectionName, sectionName) == 0) && (strcmp((*it)->fSegmentName, segmentName) == 0) )
127 return *it;
128 }
129 }
130
131 // does not exist, so make a new one
132 Section* sect = new Section(sectionName, segmentName, zeroFill);
133 fgMapping[sectionName] = sect;
134 fgSections.push_back(sect);
135
136 if ( (strcmp(sectionName, "__text") == 0) && (strcmp(segmentName, "__TEXT") == 0) ) {
137 // special case __textcoal_nt to be right after __text
138 find("__textcoal_nt", "__TEXT", false);
139 }
140
141 // remember segment discovery order
142 if ( fgSegmentDiscoverOrder.find(segmentName) == fgSegmentDiscoverOrder.end() )
143 fgSegmentDiscoverOrder[segmentName] = fgSegmentDiscoverOrder.size();
144
145 return sect;
146 }
147
148 int Section::Sorter::segmentOrdinal(const char* segName)
149 {
150 if ( strcmp(segName, "__PAGEZERO") == 0 )
151 return 1;
152 if ( strcmp(segName, "__TEXT") == 0 )
153 return 2;
154 if ( strcmp(segName, "__DATA") == 0 )
155 return 3;
156 if ( strcmp(segName, "__OBJC") == 0 )
157 return 4;
158 if ( strcmp(segName, "__OBJC2") == 0 )
159 return 5;
160 if ( strcmp(segName, "__LINKEDIT") == 0 )
161 return INT_MAX; // linkedit segment should always sort last
162 else
163 return fgSegmentDiscoverOrder[segName]+6;
164 }
165
166
167 bool Section::Sorter::operator()(Section* left, Section* right)
168 {
169 // Segment is primary sort key
170 int leftSegOrdinal = segmentOrdinal(left->fSegmentName);
171 int rightSegOrdinal = segmentOrdinal(right->fSegmentName);
172 if ( leftSegOrdinal < rightSegOrdinal )
173 return true;
174 if ( leftSegOrdinal > rightSegOrdinal )
175 return false;
176
177 // zerofill section sort to the end
178 if ( !left->fZeroFill && right->fZeroFill )
179 return true;
180 if ( left->fZeroFill && !right->fZeroFill )
181 return false;
182
183 // section discovery order is last sort key
184 return left->fIndex < right->fIndex;
185 }
186
187 void Section::assignIndexes()
188 {
189 //printf("unsorted sections:\n");
190 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
191 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
192 //}
193
194 // sort it
195 std::sort(fgSections.begin(), fgSections.end(), Section::Sorter());
196
197 // assign correct section ordering to each Section object
198 unsigned int newOrder = 1;
199 for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++)
200 (*it)->fIndex = newOrder++;
201
202 //printf("sorted sections:\n");
203 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
204 // printf("section: index=%d, obj=%p, name=%s\n", (*it)->fIndex, (*it), (*it)->fSectionName);
205 //}
206 }
207
208 class Linker : public ObjectFile::Reader::DylibHander {
209 public:
210 Linker(int argc, const char* argv[]);
211
212 const char* getArchPrefix();
213 const char* architectureName();
214 bool showArchitectureInErrors();
215 bool isInferredArchitecture();
216 void createReaders();
217 void createWriter();
218 void addInputFile(ObjectFile::Reader* reader, const Options::FileInfo& );
219 void setOutputFile(ExecutableFile::Writer* writer);
220 void link();
221 void optimize();
222
223 // implemenation from ObjectFile::Reader::DylibHander
224 virtual ObjectFile::Reader* findDylib(const char* installPath, const char* fromPath);
225
226 private:
227 struct WhyLiveBackChain
228 {
229 WhyLiveBackChain* previous;
230 const char* name;
231 };
232
233 ObjectFile::Reader* createReader(const Options::FileInfo&);
234 void addAtom(ObjectFile::Atom& atom);
235 void addAtoms(std::vector<class ObjectFile::Atom*>& atoms);
236 void buildAtomList();
237 void processDylibs();
238 void updateContraints(ObjectFile::Reader* reader);
239 void loadAndResolve();
240 void processDTrace();
241 void checkObjC();
242 void loadUndefines();
243 void checkUndefines();
244 void addWeakAtomOverrides();
245 void resolveReferences();
246 void deadStripResolve();
247 void addLiveRoot(const char* name);
248 ObjectFile::Atom* findAtom(const Options::OrderedSymbol& pair);
249 void logArchive(ObjectFile::Reader* reader);
250 void sortSections();
251 void sortAtoms();
252 void tweakLayout();
253 void writeDotOutput();
254 static bool minimizeStab(ObjectFile::Reader::Stab& stab);
255 static const char* truncateStabString(const char* str);
256 void collectDebugInfo();
257 void writeOutput();
258 ObjectFile::Atom* entryPoint();
259 ObjectFile::Atom* dyldHelper();
260 const char* assureFullPath(const char* path);
261 void markLive(ObjectFile::Atom& atom, Linker::WhyLiveBackChain* previous);
262 void collectStabs(ObjectFile::Reader* reader, std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals);
263 void synthesizeDebugNotes(std::vector<class ObjectFile::Atom*>& allAtomsByReader);
264 void printStatistics();
265 void printTime(const char* msg, uint64_t partTime, uint64_t totalTime);
266 char* commatize(uint64_t in, char* out);
267 void getVMInfo(vm_statistics_data_t& info);
268 cpu_type_t inferArchitecture();
269 void addDtraceProbe(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* probeName);
270 void checkDylibClientRestrictions(ObjectFile::Reader* reader);
271 void logDylib(ObjectFile::Reader* reader, bool indirect);
272
273 void resolve(ObjectFile::Reference* reference);
274 void resolveFrom(ObjectFile::Reference* reference);
275 std::vector<class ObjectFile::Atom*>* addJustInTimeAtoms(const char* name);
276 void addJustInTimeAtomsAndMarkLive(const char* name);
277
278 ObjectFile::Reader* addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
279 ObjectFile::Reader* addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
280 ObjectFile::Reader* addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
281
282 void logTraceInfo(const char* format, ...);
283
284
285 class SymbolTable
286 {
287 public:
288 SymbolTable(Linker&);
289 void require(const char* name);
290 bool add(ObjectFile::Atom& atom);
291 ObjectFile::Atom* find(const char* name);
292 unsigned int getRequireCount() { return fRequireCount; }
293 void getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines);
294 typedef __gnu_cxx::hash_map<const char*, ObjectFile::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> Mapper;
295 private:
296 Linker& fOwner;
297 Mapper fTable;
298 unsigned int fRequireCount;
299 };
300
301 class AtomSorter
302 {
303 public:
304 AtomSorter(std::map<const ObjectFile::Atom*, uint32_t>* map) : fOverriddenOrdinalMap(map) {}
305 bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right);
306 private:
307 std::map<const ObjectFile::Atom*, uint32_t>* fOverriddenOrdinalMap;
308 };
309
310 typedef std::map<const char*, uint32_t, CStringComparor> SectionOrder;
311
312 struct DTraceProbeInfo {
313 DTraceProbeInfo(const ObjectFile::Atom* a, uint32_t o, const char* n) : atom(a), offset(o), probeName(n) {}
314 const ObjectFile::Atom* atom;
315 uint32_t offset;
316 const char* probeName;
317 };
318 typedef __gnu_cxx::hash_map<const char*, std::vector<DTraceProbeInfo>, __gnu_cxx::hash<const char*>, CStringEquals> ProviderToProbes;
319 typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> CStringSet;
320 typedef __gnu_cxx::hash_map<const char*, ObjectFile::Reader*, __gnu_cxx::hash<const char*>, CStringEquals> InstallNameToReader;
321
322 struct IndirectLibrary {
323 const char* path;
324 uint64_t fileLen;
325 ObjectFile::Reader* reader;
326 std::set<ObjectFile::Reader*> parents;
327 ObjectFile::Reader* reExportedViaDirectLibrary;
328 };
329
330 ObjectFile::Reader* findDirectLibraryWhichReExports(struct IndirectLibrary& indirectLib);
331
332 Options fOptions;
333 SymbolTable fGlobalSymbolTable;
334 uint32_t fNextInputOrdinal;
335 std::vector<class ObjectFile::Reader*> fInputFiles;
336 ExecutableFile::Writer* fOutputFile;
337 InstallNameToReader fDylibMap;
338 std::map<ObjectFile::Reader*,DynamicLibraryOptions> fDylibOptionsMap;
339 std::set<ObjectFile::Reader*> fDylibsProcessed;
340 ObjectFile::Reader* fBundleLoaderReader;
341 std::vector<class ObjectFile::Reader*> fReadersThatHaveSuppliedAtoms;
342 std::vector<class ObjectFile::Atom*> fAllAtoms;
343 std::set<class ObjectFile::Reader*> fArchiveReaders;
344 std::set<class ObjectFile::Reader*> fArchiveReadersLogged;
345 std::set<class ObjectFile::Atom*> fDeadAtoms;
346 std::set<ObjectFile::Atom*> fLiveAtoms;
347 std::set<ObjectFile::Atom*> fLiveRootAtoms;
348 std::vector<class ObjectFile::Reader::Stab> fStabs;
349 std::vector<class ObjectFile::Atom*> fAtomsWithUnresolvedReferences;
350 std::vector<DTraceProbeInfo> fDtraceProbes;
351 std::vector<DTraceProbeInfo> fDtraceProbeSites;
352 std::vector<DTraceProbeInfo> fDtraceIsEnabledSites;
353 std::map<const ObjectFile::Atom*,CStringSet> fDtraceAtomToTypes;
354 bool fCreateUUID;
355 bool fCanScatter;
356 SectionOrder fSectionOrder;
357 cpu_type_t fArchitecture;
358 const char* fArchitectureName;
359 bool fArchitectureInferred;
360 bool fDirectLibrariesComplete;
361 bool fBiggerThanTwoGigOutput;
362 uint64_t fOutputFileSize;
363 uint64_t fTotalZeroFillSize;
364 uint64_t fTotalSize;
365 uint64_t fStartTime;
366 uint64_t fStartCreateReadersTime;
367 uint64_t fStartCreateWriterTime;
368 uint64_t fStartBuildAtomsTime;
369 uint64_t fStartLoadAndResolveTime;
370 uint64_t fStartSortTime;
371 uint64_t fStartDebugTime;
372 uint64_t fStartWriteTime;
373 uint64_t fEndTime;
374 uint64_t fTotalObjectSize;
375 uint64_t fTotalArchiveSize;
376 uint32_t fTotalObjectLoaded;
377 uint32_t fTotalArchivesLoaded;
378 uint32_t fTotalDylibsLoaded;
379 vm_statistics_data_t fStartVMInfo;
380 ObjectFile::Reader::ObjcConstraint fCurrentObjCConstraint;
381 ObjectFile::Reader::CpuConstraint fCurrentCpuConstraint;
382 bool fObjcReplacmentClasses;
383 bool fAllDirectDylibsLoaded;
384 };
385
386
387 Linker::Linker(int argc, const char* argv[])
388 : fOptions(argc, argv), fGlobalSymbolTable(*this), fNextInputOrdinal(1), fOutputFile(NULL), fBundleLoaderReader(NULL),
389 fCreateUUID(false), fCanScatter(true),
390 fArchitecture(0), fArchitectureInferred(false), fDirectLibrariesComplete(false), fBiggerThanTwoGigOutput(false),
391 fOutputFileSize(0), fTotalZeroFillSize(0), fTotalSize(0), fTotalObjectSize(0),
392 fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0),
393 fCurrentObjCConstraint(ObjectFile::Reader::kObjcNone), fCurrentCpuConstraint(ObjectFile::Reader::kCpuAny),
394 fObjcReplacmentClasses(false), fAllDirectDylibsLoaded(false)
395 {
396 fStartTime = mach_absolute_time();
397 if ( fOptions.printStatistics() )
398 getVMInfo(fStartVMInfo);
399
400 fArchitecture = fOptions.architecture();
401 if ( fArchitecture == 0 ) {
402 // -arch not specified, scan .o files to figure out what it should be
403 fArchitecture = inferArchitecture();
404 fArchitectureInferred = true;
405 }
406 switch (fArchitecture) {
407 case CPU_TYPE_POWERPC:
408 fArchitectureName = "ppc";
409 break;
410 case CPU_TYPE_POWERPC64:
411 fArchitectureName = "ppc64";
412 break;
413 case CPU_TYPE_I386:
414 fArchitectureName = "i386";
415 break;
416 case CPU_TYPE_X86_64:
417 fArchitectureName = "x86_64";
418 break;
419 default:
420 fArchitectureName = "unknown architecture";
421 break;
422 }
423 }
424
425 const char* Linker::architectureName()
426 {
427 return fArchitectureName;
428 }
429
430 bool Linker::showArchitectureInErrors()
431 {
432 return fOptions.printArchPrefix();
433 }
434
435 bool Linker::isInferredArchitecture()
436 {
437 return fArchitectureInferred;
438 }
439
440 cpu_type_t Linker::inferArchitecture()
441 {
442 // scan all input files, looking for a thin .o file.
443 // the first one found is presumably the architecture to link
444 uint8_t buffer[sizeof(mach_header_64)];
445 std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
446 for (std::vector<Options::FileInfo>::iterator it = files.begin(); it != files.end(); ++it) {
447 int fd = ::open(it->path, O_RDONLY, 0);
448 if ( fd != -1 ) {
449 ssize_t amount = read(fd, buffer, sizeof(buffer));
450 ::close(fd);
451 if ( amount >= (ssize_t)sizeof(buffer) ) {
452 if ( mach_o::relocatable::Reader<ppc>::validFile(buffer) ) {
453 //fprintf(stderr, "ld: warning -arch not used, infering -arch ppc based on %s\n", it->path);
454 return CPU_TYPE_POWERPC;
455 }
456 else if ( mach_o::relocatable::Reader<ppc64>::validFile(buffer) ) {
457 //fprintf(stderr, "ld: warning -arch not used, infering -arch ppc64 based on %s\n", it->path);
458 return CPU_TYPE_POWERPC64;
459 }
460 else if ( mach_o::relocatable::Reader<x86>::validFile(buffer) ) {
461 //fprintf(stderr, "ld: warning -arch not used, infering -arch i386 based on %s\n", it->path);
462 return CPU_TYPE_I386;
463 }
464 else if ( mach_o::relocatable::Reader<x86_64>::validFile(buffer) ) {
465 //fprintf(stderr, "ld: warning -arch not used, infering -arch x86_64 based on %s\n", it->path);
466 return CPU_TYPE_X86_64;
467 }
468 }
469 }
470 }
471
472 // no thin .o files found, so default to same architecture this was built as
473 fprintf(stderr, "ld: warning -arch not specified\n");
474 #if __ppc__
475 return CPU_TYPE_POWERPC;
476 #elif __i386__
477 return CPU_TYPE_I386;
478 #elif __ppc64__
479 return CPU_TYPE_POWERPC64;
480 #elif __x86_64__
481 return CPU_TYPE_X86_64;
482 #else
483 #error unknown default architecture
484 #endif
485 }
486
487
488 void Linker::addInputFile(ObjectFile::Reader* reader, const Options::FileInfo& info)
489 {
490 fInputFiles.push_back(reader);
491 fDylibOptionsMap[reader] = info.options;
492 }
493
494 void Linker::setOutputFile(ExecutableFile::Writer* writer)
495 {
496 fOutputFile = writer;
497 }
498
499 class InSet
500 {
501 public:
502 InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
503
504 bool operator()(ObjectFile::Atom*& atom) const {
505 return ( fDeadAtoms.count(atom) != 0 );
506 }
507
508 private:
509 std::set<ObjectFile::Atom*>& fDeadAtoms;
510 };
511
512 void Linker::loadAndResolve()
513 {
514 fStartLoadAndResolveTime = mach_absolute_time();
515 if ( fOptions.deadStrip() == Options::kDeadStripOff ) {
516 // without dead-code-stripping:
517 // find atoms to resolve all undefines
518 this->loadUndefines();
519 // verify nothing is missing
520 this->checkUndefines();
521 // once all undefines fulfill, then bind all references
522 this->resolveReferences();
523 // remove atoms weak atoms that have been overridden
524 fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
525 }
526 else {
527 // with dead code stripping:
528 // start binding references from roots,
529 this->deadStripResolve();
530 // verify nothing is missing
531 this->checkUndefines();
532 }
533 }
534
535 void Linker::optimize()
536 {
537 std::vector<class ObjectFile::Atom*> newAtoms;
538
539 const int readerCount = fInputFiles.size();
540 for (int i=0; i < readerCount; ++i) {
541 fInputFiles[i]->optimize(fAllAtoms, newAtoms, fNextInputOrdinal);
542 }
543 // note: When writer start generating stubs and non-lazy-pointers for all architecture, do not insert
544 // newAtoms into fGlobalSymbolTable. Instead directly insert them in fAllAtoms and set their order appropriately.
545 this->addAtoms(newAtoms);
546
547 // Some of the optimized atoms may not have identified section properly, if they
548 // were created before optimizer produces corrosponding real atom. Here, input
549 // file readers are not able to patch it themselves because Section::find() is
550 // linker specific.
551 for(std::vector<class ObjectFile::Atom*>::iterator itr = fAllAtoms.begin();
552 itr != fAllAtoms.end(); ++itr) {
553
554 ObjectFile::Atom *atom = *itr;
555 if (atom->getSectionName() && !atom->getSection())
556 atom->setSection(Section::find(atom->getSectionName(), atom->getSegment().getName(), atom->isZeroFill()));
557 }
558
559 if ( fOptions.deadStrip() != Options::kDeadStripOff ) {
560 fLiveAtoms.clear();
561 deadStripResolve();
562 }
563 else
564 resolveReferences();
565 }
566
567 void Linker::link()
568 {
569 this->buildAtomList();
570 this->loadAndResolve();
571 this->optimize();
572 this->checkObjC();
573 this->processDTrace();
574 this->tweakLayout();
575 this->sortSections();
576 this->sortAtoms();
577 this->writeDotOutput();
578 this->collectDebugInfo();
579 this->writeOutput();
580 this->printStatistics();
581
582 if ( fOptions.pauseAtEnd() )
583 sleep(10);
584 }
585
586 void Linker::printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
587 {
588 static uint64_t sUnitsPerSecond = 0;
589 if ( sUnitsPerSecond == 0 ) {
590 struct mach_timebase_info timeBaseInfo;
591 if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
592 sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
593 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
594 }
595 }
596 if ( partTime < sUnitsPerSecond ) {
597 uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
598 uint32_t milliSeconds = milliSecondsTimeTen/10;
599 uint32_t percentTimesTen = (partTime*1000)/totalTime;
600 uint32_t percent = percentTimesTen/10;
601 fprintf(stderr, "%s: %u.%u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
602 }
603 else {
604 uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
605 uint32_t seconds = secondsTimeTen/10;
606 uint32_t percentTimesTen = (partTime*1000)/totalTime;
607 uint32_t percent = percentTimesTen/10;
608 fprintf(stderr, "%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
609 }
610 }
611
612 char* Linker::commatize(uint64_t in, char* out)
613 {
614 char* result = out;
615 char rawNum[30];
616 sprintf(rawNum, "%llu", in);
617 const int rawNumLen = strlen(rawNum);
618 for(int i=0; i < rawNumLen-1; ++i) {
619 *out++ = rawNum[i];
620 if ( ((rawNumLen-i) % 3) == 1 )
621 *out++ = ',';
622 }
623 *out++ = rawNum[rawNumLen-1];
624 *out = '\0';
625 return result;
626 }
627
628 void Linker::getVMInfo(vm_statistics_data_t& info)
629 {
630 mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t);
631 kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO,
632 (host_info_t)&info, &count);
633 if (error != KERN_SUCCESS) {
634 bzero(&info, sizeof(vm_statistics_data_t));
635 }
636 }
637
638 void Linker::printStatistics()
639 {
640 fEndTime = mach_absolute_time();
641 if ( fOptions.printStatistics() ) {
642 vm_statistics_data_t endVMInfo;
643 getVMInfo(endVMInfo);
644
645 uint64_t totalTime = fEndTime - fStartTime;
646 printTime("ld total time", totalTime, totalTime);
647 printTime(" option parsing time", fStartCreateReadersTime - fStartTime, totalTime);
648 printTime(" object file processing",fStartCreateWriterTime - fStartCreateReadersTime, totalTime);
649 printTime(" output file setup", fStartBuildAtomsTime - fStartCreateWriterTime, totalTime);
650 printTime(" build atom list", fStartLoadAndResolveTime - fStartBuildAtomsTime, totalTime);
651 printTime(" resolve references", fStartSortTime - fStartLoadAndResolveTime, totalTime);
652 printTime(" sort output", fStartDebugTime - fStartSortTime, totalTime);
653 printTime(" process debug info", fStartWriteTime - fStartDebugTime, totalTime);
654 printTime(" write output", fEndTime - fStartWriteTime, totalTime);
655 fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo.pageins-fStartVMInfo.pageins,
656 endVMInfo.pageouts-fStartVMInfo.pageouts, endVMInfo.faults-fStartVMInfo.faults);
657 char temp[40];
658 fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded, commatize(fTotalObjectSize, temp));
659 fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded, commatize(fTotalArchiveSize, temp));
660 fprintf(stderr, "processed %3u dylib files\n", fTotalDylibsLoaded);
661 fprintf(stderr, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize, temp));
662 }
663 }
664
665 inline void Linker::addAtom(ObjectFile::Atom& atom)
666 {
667 // add to list of all atoms
668 fAllAtoms.push_back(&atom);
669
670 if ( fOptions.deadStrip() == Options::kDeadStripOff ) {
671 // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later
672 std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
673 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
674 ObjectFile::Reference* reference = *it;
675 if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName )
676 fGlobalSymbolTable.require(reference->getTargetName());
677 if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName )
678 fGlobalSymbolTable.require(reference->getFromTargetName());
679 if ( reference->getTargetBinding() == ObjectFile::Reference::kDontBind )
680 addDtraceProbe(atom, reference->getFixUpOffset(), reference->getTargetName());
681 }
682 // update total size info (except for __ZEROPAGE atom)
683 if ( atom.getSegment().isContentReadable() ) {
684 fTotalSize += atom.getSize();
685 if ( atom.isZeroFill() )
686 fTotalZeroFillSize += atom.getSize();
687 }
688 }
689 else {
690 if ( atom.dontDeadStrip() )
691 fLiveRootAtoms.insert(&atom);
692 }
693
694 // if in global namespace, add atom itself to symbol table
695 ObjectFile::Atom::Scope scope = atom.getScope();
696 const char* name = atom.getName();
697 if ( (scope != ObjectFile::Atom::scopeTranslationUnit) && (name != NULL) ) {
698 // update scope based on export list (possible that globals are downgraded to private_extern)
699 if ( (scope == ObjectFile::Atom::scopeGlobal) && fOptions.hasExportRestrictList() ) {
700 bool doExport = fOptions.shouldExport(name);
701 if ( !doExport ) {
702 atom.setScope(ObjectFile::Atom::scopeLinkageUnit);
703 }
704 }
705 // add to symbol table
706 fGlobalSymbolTable.add(atom);
707 }
708
709 // record section orders so output file can have same order
710 if (atom.getSectionName())
711 atom.setSection(Section::find(atom.getSectionName(), atom.getSegment().getName(), atom.isZeroFill()));
712 }
713
714 void Linker::updateContraints(ObjectFile::Reader* reader)
715 {
716 // check objc objects were compiled compatibly
717 ObjectFile::Reader::ObjcConstraint objcAddition = reader->getObjCConstraint();
718 if ( reader->getInstallPath() == NULL ) {
719 // adding a .o file
720 switch ( fCurrentObjCConstraint ) {
721 case ObjectFile::Reader::kObjcNone:
722 fCurrentObjCConstraint = objcAddition;
723 break;
724 case ObjectFile::Reader::kObjcRetainRelease:
725 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
726 case ObjectFile::Reader::kObjcGC:
727 if ( (fCurrentObjCConstraint != objcAddition) && (objcAddition != ObjectFile::Reader::kObjcNone) )
728 throwf("%s built with different Garbage Collection settings", reader->getPath());
729 break;
730 }
731 }
732 if ( reader->objcReplacementClasses() )
733 fObjcReplacmentClasses = true;
734
735 // check cpu sub-types
736 ObjectFile::Reader::CpuConstraint cpuAddition = reader->getCpuConstraint();
737 switch ( fCurrentCpuConstraint ) {
738 case ObjectFile::Reader::kCpuAny:
739 fCurrentCpuConstraint = cpuAddition;
740 break;
741 case ObjectFile::Reader::kCpuG3:
742 switch ( cpuAddition ) {
743 case ObjectFile::Reader::kCpuAny:
744 case ObjectFile::Reader::kCpuG3:
745 break;
746 case ObjectFile::Reader::kCpuG4:
747 case ObjectFile::Reader::kCpuG5:
748 // previous file for G3 this one is more contrained, use it
749 fCurrentCpuConstraint = cpuAddition;
750 break;
751 }
752 break;
753 case ObjectFile::Reader::kCpuG4:
754 switch ( cpuAddition ) {
755 case ObjectFile::Reader::kCpuAny:
756 case ObjectFile::Reader::kCpuG3:
757 case ObjectFile::Reader::kCpuG4:
758 break;
759 case ObjectFile::Reader::kCpuG5:
760 // previous file for G5 this one is more contrained, use it
761 fCurrentCpuConstraint = cpuAddition;
762 break;
763 }
764 break;
765 case ObjectFile::Reader::kCpuG5:
766 // G5 can run everything
767 break;
768 }
769 }
770
771 inline void Linker::addAtoms(std::vector<class ObjectFile::Atom*>& atoms)
772 {
773 bool scanAll = fOptions.readerOptions().fFullyLoadArchives || fOptions.readerOptions().fLoadAllObjcObjectsFromArchives;
774 bool first = true;
775 for (std::vector<ObjectFile::Atom*>::iterator it=atoms.begin(); it != atoms.end(); it++) {
776 // usually we only need to get the first atom's reader, but
777 // with -all_load all atoms from all .o files come come back together
778 // so we need to scan all atoms
779 if ( first || scanAll ) {
780 // update fReadersThatHaveSuppliedAtoms
781 ObjectFile::Reader* reader = (*it)->getFile();
782 if ( std::find(fReadersThatHaveSuppliedAtoms.begin(), fReadersThatHaveSuppliedAtoms.end(), reader)
783 == fReadersThatHaveSuppliedAtoms.end() ) {
784 fReadersThatHaveSuppliedAtoms.push_back(reader);
785 updateContraints(reader);
786 }
787 }
788 this->addAtom(**it);
789 first = false;
790 }
791 }
792
793 void Linker::logArchive(ObjectFile::Reader* reader)
794 {
795 if ( (fArchiveReaders.count(reader) != 0) && (fArchiveReadersLogged.count(reader) == 0) ) {
796 fArchiveReadersLogged.insert(reader);
797 const char* fullPath = reader->getPath();
798 char realName[MAXPATHLEN];
799 if ( realpath(fullPath, realName) != NULL )
800 fullPath = realName;
801 logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath);
802 }
803 }
804
805
806 void Linker::buildAtomList()
807 {
808 fStartBuildAtomsTime = mach_absolute_time();
809 // add initial undefines from -u option
810 std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
811 for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++) {
812 fGlobalSymbolTable.require(*it);
813 }
814
815 // writer can contribute atoms
816 this->addAtoms(fOutputFile->getAtoms());
817
818 // each reader contributes atoms
819 for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
820 ObjectFile::Reader* reader = *it;
821 std::vector<class ObjectFile::Atom*>& atoms = reader->getAtoms();
822 this->addAtoms(atoms);
823 if ( fOptions.readerOptions().fTraceArchives && (atoms.size() != 0) )
824 logArchive(reader);
825 }
826
827 // extra command line section always at end
828 std::vector<Options::ExtraSection>& extraSections = fOptions.extraSections();
829 for( std::vector<Options::ExtraSection>::iterator it=extraSections.begin(); it != extraSections.end(); ++it) {
830 this->addAtoms((new opaque_section::Reader(it->segmentName, it->sectionName, it->path, it->data, it->dataLen, fNextInputOrdinal))->getAtoms());
831 fNextInputOrdinal += it->dataLen;
832 }
833 }
834
835 static const char* pathLeafName(const char* path)
836 {
837 const char* shortPath = strrchr(path, '/');
838 if ( shortPath == NULL )
839 return path;
840 else
841 return &shortPath[1];
842 }
843
844 void Linker::loadUndefines()
845 {
846 // keep looping until no more undefines were added in last loop
847 unsigned int undefineCount = 0xFFFFFFFF;
848 while ( undefineCount != fGlobalSymbolTable.getRequireCount() ) {
849 undefineCount = fGlobalSymbolTable.getRequireCount();
850 std::vector<const char*> undefineNames;
851 fGlobalSymbolTable.getNeededNames(false, undefineNames);
852 for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
853 const char* name = *it;
854 ObjectFile::Atom* possibleAtom = fGlobalSymbolTable.find(name);
855 if ( (possibleAtom == NULL)
856 || ((possibleAtom->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition)
857 && (fOptions.outputKind() != Options::kObjectFile)
858 && (possibleAtom->getScope() == ObjectFile::Atom::scopeGlobal)) ) {
859 std::vector<class ObjectFile::Atom*>* atoms = this->addJustInTimeAtoms(name);
860 if ( atoms != NULL )
861 delete atoms;
862 }
863 }
864 }
865 }
866
867 // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
868 class ExportedObjcClass
869 {
870 public:
871 ExportedObjcClass(Options& opt) : fOptions(opt) {}
872
873 bool operator()(const char* name) const {
874 if ( fOptions.shouldExport(name) ) {
875 if ( strncmp(name, ".objc_class_name_", 17) == 0 )
876 return true;
877 if ( strncmp(name, "_OBJC_CLASS_$_", 14) == 0 )
878 return true;
879 if ( strncmp(name, "_OBJC_METACLASS_$_", 18) == 0 )
880 return true;
881 }
882 //fprintf(stderr, "%s is not exported\n", name);
883 return false;
884 }
885 private:
886 Options& fOptions;
887 };
888
889
890 void Linker::checkUndefines()
891 {
892 // error out on any remaining undefines
893 bool doPrint = true;
894 bool doError = true;
895 switch ( fOptions.undefinedTreatment() ) {
896 case Options::kUndefinedError:
897 break;
898 case Options::kUndefinedDynamicLookup:
899 doError = false;
900 break;
901 case Options::kUndefinedWarning:
902 doError = false;
903 break;
904 case Options::kUndefinedSuppress:
905 doError = false;
906 doPrint = false;
907 break;
908 }
909 std::vector<const char*> unresolvableUndefines;
910 fGlobalSymbolTable.getNeededNames(false, unresolvableUndefines);
911
912 // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
913 // ignore unresolved references to Objc class names that are listed in -exported_symbols_list
914 if ( fOptions.hasExportRestrictList() )
915 unresolvableUndefines.erase(std::remove_if(unresolvableUndefines.begin(), unresolvableUndefines.end(), ExportedObjcClass(fOptions)), unresolvableUndefines.end());
916
917 const int unresolvableCount = unresolvableUndefines.size();
918 int unresolvableExportsCount = 0;
919 if ( unresolvableCount != 0 ) {
920 if ( doPrint ) {
921 if ( fOptions.printArchPrefix() )
922 fprintf(stderr, "Undefined symbols for architecture %s:\n", fArchitectureName);
923 else
924 fprintf(stderr, "Undefined symbols:\n");
925 for (int i=0; i < unresolvableCount; ++i) {
926 const char* name = unresolvableUndefines[i];
927 fprintf(stderr, " \"%s\", referenced from:\n", name);
928 // scan all atoms for references
929 bool foundAtomReference = false;
930 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
931 ObjectFile::Atom* atom = *it;
932 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
933 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
934 ObjectFile::Reference* reference = *rit;
935 if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
936 if ( strcmp(reference->getTargetName(), name) == 0 ) {
937 fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
938 foundAtomReference = true;
939 }
940 }
941 if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
942 if ( strcmp(reference->getFromTargetName(), name) == 0 ) {
943 fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
944 foundAtomReference = true;
945 }
946 }
947 }
948 }
949 // scan command line options
950 if ( !foundAtomReference && fOptions.hasExportRestrictList() && fOptions.shouldExport(name) ) {
951 fprintf(stderr, " -exported_symbols_list command line option\n");
952 ++unresolvableExportsCount;
953 }
954 }
955 }
956 if ( doError )
957 throw "symbol(s) not found";
958 }
959 }
960
961
962
963 std::vector<class ObjectFile::Atom*>* Linker::addJustInTimeAtoms(const char* name)
964 {
965 // when creating final linked image, writer gets first chance
966 if ( fOptions.outputKind() != Options::kObjectFile ) {
967 std::vector<class ObjectFile::Atom*>* atoms = fOutputFile->getJustInTimeAtomsFor(name);
968 if ( atoms != NULL ) {
969 this->addAtoms(*atoms);
970 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
971 return atoms; // found a definition, no need to search anymore
972 }
973 }
974
975 // give readers a chance
976 for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
977 ObjectFile::Reader* reader = *it;
978 if ( reader != NULL ) {
979 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
980 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
981 //fprintf(stderr, "addJustInTimeAtoms(%s), looking in reader %s\n", name, reader->getPath() );
982 std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
983 if ( atoms != NULL ) {
984 this->addAtoms(*atoms);
985 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
986 if ( fOptions.readerOptions().fTraceArchives ) {
987 logArchive(reader);
988 }
989 // if this is a weak definition in a dylib
990 if ( (atoms->size() == 1) && (reader->getInstallPath() != NULL) && (atoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
991 // keep looking for a non-weak definition
992 }
993 else {
994 // found a definition, no need to search anymore
995 return atoms;
996 }
997 }
998 }
999 }
1000
1001 // for two level namesapce, give all implicitly link dylibs a chance
1002 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
1003 for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
1004 if ( it->second->implicitlyLinked() ) {
1005 //fprintf(stderr, "addJustInTimeAtoms(%s), looking in implicitly linked %s\n", name, it->second->getPath() );
1006 std::vector<class ObjectFile::Atom*>* atoms = it->second->getJustInTimeAtomsFor(name);
1007 if ( atoms != NULL ) {
1008 this->addAtoms(*atoms);
1009 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1010 // if this is a weak definition in a dylib
1011 if ( (atoms->size() == 1) && (atoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
1012 // keep looking for a non-weak definition
1013 }
1014 else {
1015 // found a definition, no need to search anymore
1016 return atoms;
1017 }
1018 }
1019 }
1020 }
1021 }
1022
1023 // for flat namespace, give indirect dylibs
1024 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace ) {
1025 for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
1026 if ( ! it->second->explicitlyLinked() ) {
1027 std::vector<class ObjectFile::Atom*>* atoms = it->second->getJustInTimeAtomsFor(name);
1028 if ( atoms != NULL ) {
1029 this->addAtoms(*atoms);
1030 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
1031 return atoms; // found a definition, no need to search anymore
1032 }
1033 }
1034 }
1035 }
1036
1037 // when creating .o file, writer goes last (this is so any static archives will be searched above)
1038 if ( (fOptions.outputKind() == Options::kObjectFile)
1039 || (fOptions.undefinedTreatment() != Options::kUndefinedError)
1040 || fOptions.someAllowedUndefines() ) {
1041 ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
1042 if ( atom != NULL ) {
1043 this->addAtom(*atom);
1044 return NULL;
1045 }
1046 }
1047 //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
1048 return NULL;
1049 }
1050
1051 void Linker::resolve(ObjectFile::Reference* reference)
1052 {
1053 // look in global symbol table
1054 const char* targetName = reference->getTargetName();
1055 ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
1056 if ( target == NULL ) {
1057 fprintf(stderr, "Undefined symbol: %s\n", targetName);
1058 }
1059 reference->setTarget(*target, reference->getTargetOffset());
1060 }
1061
1062 void Linker::resolveFrom(ObjectFile::Reference* reference)
1063 {
1064 // handle references that have two (from and to) targets
1065 const char* fromTargetName = reference->getFromTargetName();
1066 ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName);
1067 if ( fromTarget == NULL ) {
1068 fprintf(stderr, "Undefined symbol: %s\n", fromTargetName);
1069 }
1070 reference->setFromTarget(*fromTarget);
1071 }
1072
1073
1074 void Linker::resolveReferences()
1075 {
1076 // note: the atom list may grow during this loop as libraries supply needed atoms
1077 for (unsigned int j=0; j < fAllAtoms.size(); ++j) {
1078 ObjectFile::Atom* atom = fAllAtoms[j];
1079 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
1080 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
1081 ObjectFile::Reference* reference = *it;
1082 if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName )
1083 this->resolve(reference);
1084 if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName )
1085 this->resolveFrom(reference);
1086 }
1087 }
1088 }
1089
1090
1091 // used to remove stabs associated with atoms that won't be in output file
1092 class NotInSet
1093 {
1094 public:
1095 NotInSet(std::set<ObjectFile::Atom*>& theSet) : fSet(theSet) {}
1096
1097 bool operator()(const ObjectFile::Reader::Stab& stab) const {
1098 if ( stab.atom == NULL )
1099 return false; // leave stabs that are not associated with any atome
1100 else
1101 return ( fSet.count(stab.atom) == 0 );
1102 }
1103
1104 private:
1105 std::set<ObjectFile::Atom*>& fSet;
1106 };
1107
1108
1109 class NotLive
1110 {
1111 public:
1112 NotLive(std::set<ObjectFile::Atom*>& set) : fLiveAtoms(set) {}
1113
1114 bool operator()(ObjectFile::Atom*& atom) const {
1115 //if ( fLiveAtoms.count(atom) == 0 )
1116 // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
1117 return ( fLiveAtoms.count(atom) == 0 );
1118 }
1119 private:
1120 std::set<ObjectFile::Atom*>& fLiveAtoms;
1121 };
1122
1123
1124 void Linker::addJustInTimeAtomsAndMarkLive(const char* name)
1125 {
1126 std::vector<class ObjectFile::Atom*>* atoms = this->addJustInTimeAtoms(name);
1127 if ( atoms != NULL ) {
1128 if ( fOptions.allGlobalsAreDeadStripRoots() ) {
1129 for (std::vector<ObjectFile::Atom*>::iterator it=atoms->begin(); it != atoms->end(); it++) {
1130 ObjectFile::Atom* atom = *it;
1131 if ( atom->getScope() == ObjectFile::Atom::scopeGlobal ) {
1132 WhyLiveBackChain rootChain;
1133 rootChain.previous = NULL;
1134 rootChain.name = atom->getDisplayName();
1135 this->markLive(*atom, &rootChain);
1136 }
1137 }
1138 }
1139 delete atoms;
1140 }
1141 }
1142
1143 void Linker::markLive(ObjectFile::Atom& atom, struct Linker::WhyLiveBackChain* previous)
1144 {
1145 if ( fLiveAtoms.count(&atom) == 0 ) {
1146 // if -whylive cares about this symbol, then dump chain
1147 if ( (previous->name != NULL) && fOptions.printWhyLive(previous->name) ) {
1148 int depth = 0;
1149 for(WhyLiveBackChain* p = previous; p != NULL; p = p->previous, ++depth) {
1150 for(int i=depth; i > 0; --i)
1151 fprintf(stderr, " ");
1152 fprintf(stderr, "%s\n", p->name);
1153 }
1154 }
1155 // set up next chain
1156 WhyLiveBackChain thisChain;
1157 thisChain.previous = previous;
1158 // this atom is live
1159 fLiveAtoms.insert(&atom);
1160 // update total size info (except for __ZEROPAGE atom)
1161 if ( atom.getSegment().isContentReadable() ) {
1162 fTotalSize += atom.getSize();
1163 if ( atom.isZeroFill() )
1164 fTotalZeroFillSize += atom.getSize();
1165 }
1166 // and all atoms it references
1167 std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
1168 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
1169 ObjectFile::Reference* reference = *it;
1170 if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
1171 // look in global symbol table
1172 const char* targetName = reference->getTargetName();
1173 ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
1174 if ( target == NULL ) {
1175 // load archives or dylibs
1176 this->addJustInTimeAtomsAndMarkLive(targetName);
1177 }
1178 // look again
1179 target = fGlobalSymbolTable.find(targetName);
1180 if ( target != NULL ) {
1181 reference->setTarget(*target, reference->getTargetOffset());
1182 }
1183 else {
1184 // mark as undefined, for later error processing
1185 fAtomsWithUnresolvedReferences.push_back(&atom);
1186 fGlobalSymbolTable.require(targetName);
1187 }
1188 }
1189 switch ( reference->getTargetBinding() ) {
1190 case ObjectFile::Reference::kBoundDirectly:
1191 case ObjectFile::Reference::kBoundByName:
1192 thisChain.name = reference->getTargetName();
1193 markLive(reference->getTarget(), &thisChain);
1194 break;
1195 case ObjectFile::Reference::kDontBind:
1196 addDtraceProbe(atom, reference->getFixUpOffset(), reference->getTargetName());
1197 break;
1198 case ObjectFile::Reference::kUnboundByName:
1199 // do nothing
1200 break;
1201 }
1202 // do the same as above, for "from target"
1203 if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
1204 // look in global symbol table
1205 const char* targetName = reference->getFromTargetName();
1206 ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
1207 if ( target == NULL ) {
1208 // load archives or dylibs
1209 this->addJustInTimeAtomsAndMarkLive(targetName);
1210 }
1211 // look again
1212 target = fGlobalSymbolTable.find(targetName);
1213 if ( target != NULL ) {
1214 reference->setFromTarget(*target);
1215 }
1216 else {
1217 // mark as undefined, for later error processing
1218 fGlobalSymbolTable.require(targetName);
1219 }
1220 }
1221 switch ( reference->getFromTargetBinding() ) {
1222 case ObjectFile::Reference::kBoundDirectly:
1223 case ObjectFile::Reference::kBoundByName:
1224 thisChain.name = reference->getFromTargetName();
1225 markLive(reference->getFromTarget(), &thisChain);
1226 break;
1227 case ObjectFile::Reference::kUnboundByName:
1228 case ObjectFile::Reference::kDontBind:
1229 // do nothing
1230 break;
1231 }
1232 }
1233 }
1234 }
1235
1236
1237 void Linker::addLiveRoot(const char* name)
1238 {
1239 ObjectFile::Atom* target = fGlobalSymbolTable.find(name);
1240 if ( target == NULL ) {
1241 this->addJustInTimeAtomsAndMarkLive(name);
1242 target = fGlobalSymbolTable.find(name);
1243 }
1244 if ( target != NULL )
1245 fLiveRootAtoms.insert(target);
1246 }
1247
1248
1249 void Linker::deadStripResolve()
1250 {
1251 // add main() to live roots
1252 ObjectFile::Atom* entryPoint = this->entryPoint();
1253 if ( entryPoint != NULL )
1254 fLiveRootAtoms.insert(entryPoint);
1255
1256 // add dyld_stub_binding_helper() to live roots
1257 ObjectFile::Atom* dyldHelper = this->dyldHelper();
1258 if ( dyldHelper != NULL )
1259 fLiveRootAtoms.insert(dyldHelper);
1260
1261 // add -exported_symbols_list, -init, and -u entries to live roots
1262 std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
1263 for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++)
1264 addLiveRoot(*it);
1265
1266 // in some cases, every global scope atom in initial .o files is a root
1267 if ( fOptions.allGlobalsAreDeadStripRoots() ) {
1268 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1269 ObjectFile::Atom* atom = *it;
1270 if ( (atom->getScope() == ObjectFile::Atom::scopeGlobal) && (fDeadAtoms.count(atom) == 0) )
1271 fLiveRootAtoms.insert(atom);
1272 }
1273 }
1274
1275 // mark all roots as live, and all atoms they reference
1276 for (std::set<ObjectFile::Atom*>::iterator it=fLiveRootAtoms.begin(); it != fLiveRootAtoms.end(); it++) {
1277 WhyLiveBackChain rootChain;
1278 rootChain.previous = NULL;
1279 rootChain.name = (*it)->getDisplayName();
1280 markLive(**it, &rootChain);
1281 }
1282
1283 // it is possible that there are unresolved references that can be resolved now
1284 // this can happen if the first reference to a common symbol in an archive.
1285 // common symbols are not in the archive TOC, but the .o could have been pulled in later.
1286 // <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
1287 for (std::vector<ObjectFile::Atom*>::iterator it=fAtomsWithUnresolvedReferences.begin(); it != fAtomsWithUnresolvedReferences.end(); it++) {
1288 std::vector<class ObjectFile::Reference*>& references = (*it)->getReferences();
1289 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1290 ObjectFile::Reference* reference = *rit;
1291 if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
1292 ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getTargetName());
1293 if ( target != NULL ) {
1294 reference->setTarget(*target, reference->getTargetOffset());
1295 fLiveAtoms.insert(target);
1296 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1297 // references, which is true for commons.
1298 if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition )
1299 fprintf(stderr, "warning: ld64 internal error %s is not a tentative definition\n", target->getDisplayName());
1300 }
1301 }
1302 if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
1303 ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getFromTargetName());
1304 if ( target != NULL ) {
1305 reference->setFromTarget(*target);
1306 fLiveAtoms.insert(target);
1307 // by just adding this atom to fLiveAtoms set, we are assuming it has no
1308 // references, which is true for commons.
1309 if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition )
1310 fprintf(stderr, "warning: ld64 internal error %s is not a tentative definition\n", target->getDisplayName());
1311 }
1312 }
1313 }
1314 }
1315
1316 // now remove all non-live atoms from fAllAtoms
1317 fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), NotLive(fLiveAtoms)), fAllAtoms.end());
1318 }
1319
1320 void Linker::checkObjC()
1321 {
1322 // check dylibs
1323 switch ( fCurrentObjCConstraint ) {
1324 case ObjectFile::Reader::kObjcNone:
1325 // can link against any dylib
1326 break;
1327 case ObjectFile::Reader::kObjcRetainRelease:
1328 // cannot link against GC-only dylibs
1329 for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
1330 if ( it->second->explicitlyLinked() ) {
1331 if ( it->second->getObjCConstraint() == ObjectFile::Reader::kObjcGC )
1332 throwf("this linkage unit uses Retain/Release. It cannot link against the GC-only dylib: %s", it->second->getPath());
1333 }
1334 }
1335 break;
1336 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
1337 // can link against GC or RR dylibs
1338 break;
1339 case ObjectFile::Reader::kObjcGC:
1340 // cannot link against RR-only dylibs
1341 for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
1342 if ( it->second->explicitlyLinked() ) {
1343 if ( it->second->getObjCConstraint() == ObjectFile::Reader::kObjcRetainRelease )
1344 throwf("this linkage unit requires GC. It cannot link against Retain/Release dylib: %s", it->second->getPath());
1345 }
1346 }
1347 break;
1348 }
1349
1350 // synthesize __OBJC __image_info atom if needed
1351 if ( fCurrentObjCConstraint != ObjectFile::Reader::kObjcNone ) {
1352 this->addAtom(fOutputFile->makeObjcInfoAtom(fCurrentObjCConstraint, fObjcReplacmentClasses));
1353 }
1354 }
1355
1356 void Linker::addDtraceProbe(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* probeName)
1357 {
1358 if ( probeName != NULL ) {
1359 if ( strncmp(probeName, "___dtrace_probe$", 16) == 0 )
1360 fDtraceProbeSites.push_back(DTraceProbeInfo(&atom, offsetInAtom, probeName));
1361 else if ( strncmp(probeName, "___dtrace_isenabled$", 20) == 0 )
1362 fDtraceIsEnabledSites.push_back(DTraceProbeInfo(&atom, offsetInAtom, probeName));
1363 else if ( strncmp(probeName, "___dtrace_", 10) == 0 )
1364 fDtraceAtomToTypes[&atom].insert(probeName);
1365 else if ( fOptions.dTrace() && (strncmp(probeName, "__dtrace_probe$", 15) == 0) )
1366 fDtraceProbes.push_back(DTraceProbeInfo(&atom, offsetInAtom, probeName));
1367 }
1368 }
1369
1370 static uint8_t pointerKind(cpu_type_t arch)
1371 {
1372 switch ( arch ) {
1373 case CPU_TYPE_POWERPC:
1374 return ppc::kPointer;
1375 case CPU_TYPE_POWERPC64:
1376 return ppc64::kPointer;
1377 case CPU_TYPE_I386:
1378 return x86::kPointer;
1379 case CPU_TYPE_X86_64:
1380 return x86_64::kPointer;
1381 }
1382 throw "uknown architecture";
1383 }
1384
1385 static uint8_t pcRelKind(cpu_type_t arch)
1386 {
1387 switch ( arch ) {
1388 case CPU_TYPE_POWERPC:
1389 return ppc::kPointerDiff32;
1390 case CPU_TYPE_POWERPC64:
1391 return ppc64::kPointerDiff32;
1392 case CPU_TYPE_I386:
1393 return x86::kPointerDiff;
1394 case CPU_TYPE_X86_64:
1395 return x86_64::kPointerDiff32;
1396 }
1397 throw "uknown architecture";
1398 }
1399
1400 typedef uint8_t* (*oldcreatedof_func_t) (const char*, cpu_type_t, unsigned int, const char*[], const char*[], uint64_t offsetsInDOF[], size_t* size);
1401 typedef uint8_t* (*createdof_func_t)(cpu_type_t, unsigned int, const char*[], unsigned int, const char*[], const char*[], uint64_t offsetsInDOF[], size_t* size);
1402
1403
1404 void Linker::processDTrace()
1405 {
1406 // handle dtrace 2.0 static probes
1407 if ( (fOptions.outputKind() != Options::kObjectFile) && ((fDtraceProbeSites.size() != 0) || (fDtraceIsEnabledSites.size() != 0)) ) {
1408 // partition probes by provider name
1409 // The symbol names looks like:
1410 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
1411 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
1412 ProviderToProbes providerToProbes;
1413 std::vector<DTraceProbeInfo> emptyList;
1414 for(std::vector<DTraceProbeInfo>::iterator it = fDtraceProbeSites.begin(); it != fDtraceProbeSites.end(); ++it) {
1415 const char* providerStart = &it->probeName[16];
1416 const char* providerEnd = strchr(providerStart, '$');
1417 if ( providerEnd != NULL ) {
1418 char providerName[providerEnd-providerStart+1];
1419 strlcpy(providerName, providerStart, providerEnd-providerStart+1);
1420 ProviderToProbes::iterator pos = providerToProbes.find(providerName);
1421 if ( pos == providerToProbes.end() ) {
1422 const char* dup = strdup(providerName);
1423 providerToProbes[dup] = emptyList;
1424 }
1425 providerToProbes[providerName].push_back(*it);
1426 }
1427 }
1428 for(std::vector<DTraceProbeInfo>::iterator it = fDtraceIsEnabledSites.begin(); it != fDtraceIsEnabledSites.end(); ++it) {
1429 const char* providerStart = &it->probeName[20];
1430 const char* providerEnd = strchr(providerStart, '$');
1431 if ( providerEnd != NULL ) {
1432 char providerName[providerEnd-providerStart+1];
1433 strlcpy(providerName, providerStart, providerEnd-providerStart+1);
1434 ProviderToProbes::iterator pos = providerToProbes.find(providerName);
1435 if ( pos == providerToProbes.end() ) {
1436 const char* dup = strdup(providerName);
1437 providerToProbes[dup] = emptyList;
1438 }
1439 providerToProbes[providerName].push_back(*it);
1440 }
1441 }
1442
1443 // create a DOF section for each provider
1444 int dofIndex=1;
1445 CStringSet sectionNamesUsed;
1446 for(ProviderToProbes::iterator pit = providerToProbes.begin(); pit != providerToProbes.end(); ++pit, ++dofIndex) {
1447 const char* providerName = pit->first;
1448 const std::vector<DTraceProbeInfo>& probes = pit->second;
1449
1450 // open library and find dtrace_create_dof()
1451 void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY);
1452 if ( handle == NULL )
1453 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s\n", dlerror());
1454 createdof_func_t pCreateDOF = (createdof_func_t)dlsym(handle, "dtrace_ld_create_dof");
1455 if ( pCreateDOF == NULL )
1456 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s\n", dlerror());
1457 // build list of typedefs/stability infos for this provider
1458 CStringSet types;
1459 for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
1460 std::map<const ObjectFile::Atom*,CStringSet>::iterator pos = fDtraceAtomToTypes.find(it->atom);
1461 if ( pos != fDtraceAtomToTypes.end() ) {
1462 for(CStringSet::iterator sit = pos->second.begin(); sit != pos->second.end(); ++sit) {
1463 const char* providerStart = strchr(*sit, '$')+1;
1464 const char* providerEnd = strchr(providerStart, '$');
1465 if ( providerEnd != NULL ) {
1466 char aProviderName[providerEnd-providerStart+1];
1467 strlcpy(aProviderName, providerStart, providerEnd-providerStart+1);
1468 if ( strcmp(aProviderName, providerName) == 0 )
1469 types.insert(*sit);
1470 }
1471 }
1472 }
1473 }
1474 int typeCount = types.size();
1475 const char* typeNames[typeCount];
1476 //fprintf(stderr, "types for %s:\n", providerName);
1477 uint32_t index = 0;
1478 for(CStringSet::iterator it = types.begin(); it != types.end(); ++it) {
1479 typeNames[index] = *it;
1480 //fprintf(stderr, "\t%s\n", *it);
1481 ++index;
1482 }
1483
1484 // build list of probe/isenabled sites
1485 const uint32_t probeCount = probes.size();
1486 const char* probeNames[probeCount];
1487 const char* funtionNames[probeCount];
1488 uint64_t offsetsInDOF[probeCount];
1489 index = 0;
1490 for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
1491 probeNames[index] = it->probeName;
1492 funtionNames[index] = it->atom->getName();
1493 offsetsInDOF[index] = 0;
1494 ++index;
1495 }
1496 // call dtrace library to create DOF section
1497 size_t dofSectionSize;
1498 uint8_t* p = (*pCreateDOF)(fArchitecture, typeCount, typeNames, probeCount, probeNames, funtionNames, offsetsInDOF, &dofSectionSize);
1499 if ( p != NULL ) {
1500 char sectionName[18];
1501 strcpy(sectionName, "__dof_");
1502 strlcpy(&sectionName[6], providerName, 10);
1503 // create unique section name so each DOF is in its own section
1504 if ( sectionNamesUsed.count(sectionName) != 0 ) {
1505 sectionName[15] = '0';
1506 sectionName[16] = '\0';
1507 while ( sectionNamesUsed.count(sectionName) != 0 )
1508 ++sectionName[15];
1509 }
1510 sectionNamesUsed.insert(sectionName);
1511 char symbolName[strlen(providerName)+64];
1512 sprintf(symbolName, "__dtrace_dof_for_provider_%s", providerName);
1513 opaque_section::Reader* reader = new opaque_section::Reader("__TEXT", sectionName,
1514 "dtrace", p, dofSectionSize, fNextInputOrdinal, symbolName);
1515 fNextInputOrdinal += dofSectionSize;
1516 // add references
1517 for (uint32_t i=0; i < probeCount; ++i) {
1518 uint64_t offset = offsetsInDOF[i];
1519 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
1520 if ( offset > dofSectionSize )
1521 throwf("offsetsInDOF[i]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize);
1522 reader->addSectionReference(pcRelKind(fArchitecture), offset, probes[i].atom, probes[i].offset, reader->getAtoms()[0], 0);
1523 }
1524 this->addAtoms(reader->getAtoms());
1525 }
1526 else {
1527 throw "error creating dtrace DOF section";
1528 }
1529 }
1530 }
1531 // create a __DATA __dof section iff -dtrace option was used and static probes were found in .o files
1532 else if ( fOptions.dTrace() && (fDtraceProbes.size() != 0) ) {
1533 const uint32_t probeCount = fDtraceProbes.size();
1534 const char* labels[probeCount];
1535 const char* funtionNames[probeCount];
1536 uint64_t offsetsInDOF[probeCount];
1537
1538 // open libray and find dtrace_ld64_create_dof()
1539 void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY);
1540 if ( handle == NULL )
1541 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s\n", dlerror());
1542 oldcreatedof_func_t pCreateDOF = (oldcreatedof_func_t)dlsym(handle, "dtrace_ld64_create_dof");
1543 if ( pCreateDOF == NULL )
1544 throwf("couldn't find \"dtrace_ld64_create_dof\" in /usr/lib/libdtrace.dylib: %s\n", dlerror());
1545
1546 // build argument list
1547 uint32_t index = 0;
1548 for(std::vector<DTraceProbeInfo>::iterator it = fDtraceProbes.begin(); it != fDtraceProbes.end(); ++it) {
1549 labels[index] = it->probeName;
1550 funtionNames[index] = it->atom->getName();
1551 offsetsInDOF[index] = 0;
1552 ++index;
1553 }
1554 size_t dofSectionSize;
1555 // call dtrace library to create DOF section
1556 uint8_t* p = (*pCreateDOF)(fOptions.dTraceScriptName(), fArchitecture, probeCount, labels, funtionNames, offsetsInDOF, &dofSectionSize);
1557 if ( p != NULL ) {
1558 opaque_section::Reader* reader = new opaque_section::Reader("__DATA", "__dof", "dtrace", p, dofSectionSize, fNextInputOrdinal);
1559 fNextInputOrdinal += dofSectionSize;
1560 // add references
1561 for (uint32_t i=0; i < probeCount; ++i) {
1562 uint64_t offset = offsetsInDOF[i];
1563 if ( offset > dofSectionSize )
1564 throwf("offsetsInDOF[i]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize);
1565 reader->addSectionReference(pointerKind(fArchitecture), offset, fDtraceProbes[i].atom, fDtraceProbes[i].offset);
1566 }
1567 this->addAtoms(reader->getAtoms());
1568 }
1569 else {
1570 throw "error created dtrace DOF section";
1571 }
1572 }
1573 }
1574
1575
1576 static bool matchesObjectFile(ObjectFile::Atom* atom, const char* objectFileLeafName)
1577 {
1578 if ( objectFileLeafName == NULL )
1579 return true;
1580 const char* atomFullPath = atom->getFile()->getPath();
1581 const char* lastSlash = strrchr(atomFullPath, '/');
1582 if ( lastSlash != NULL ) {
1583 if ( strcmp(&lastSlash[1], objectFileLeafName) == 0 )
1584 return true;
1585 }
1586 else {
1587 if ( strcmp(atomFullPath, objectFileLeafName) == 0 )
1588 return true;
1589 }
1590 return false;
1591 }
1592
1593
1594 static bool usesAnonymousNamespace(const char* symbol)
1595 {
1596 return ( (strncmp(symbol, "__Z", 3) == 0) && (strstr(symbol, "_GLOBAL__N_") != NULL) );
1597 }
1598
1599
1600 //
1601 // convert:
1602 // __ZN20_GLOBAL__N__Z5main2v3barEv => _ZN-3barEv
1603 // __ZN37_GLOBAL__N_main.cxx_00000000_493A01A33barEv => _ZN-3barEv
1604 //
1605 static void canonicalizeAnonymousName(const char* inSymbol, char outSymbol[])
1606 {
1607 const char* globPtr = strstr(inSymbol, "_GLOBAL__N_");
1608 while ( isdigit(*(--globPtr)) )
1609 ; // loop
1610 char* endptr;
1611 unsigned long length = strtoul(globPtr+1, &endptr, 10);
1612 const char* globEndPtr = endptr + length;
1613 int startLen = globPtr-inSymbol+1;
1614 memcpy(outSymbol, inSymbol, startLen);
1615 outSymbol[startLen] = '-';
1616 strcpy(&outSymbol[startLen+1], globEndPtr);
1617 }
1618
1619
1620 ObjectFile::Atom* Linker::findAtom(const Options::OrderedSymbol& orderedSymbol)
1621 {
1622 ObjectFile::Atom* atom = fGlobalSymbolTable.find(orderedSymbol.symbolName);
1623 if ( atom != NULL ) {
1624 if ( matchesObjectFile(atom, orderedSymbol.objectFileName) )
1625 return atom;
1626 }
1627 else {
1628 // slow case. The requested symbol is not in symbol table, so might be static function
1629 static SymbolTable::Mapper hashTableOfTranslationUnitScopedSymbols;
1630 static SymbolTable::Mapper hashTableOfSymbolsWithAnonymousNamespace;
1631 static bool built = false;
1632 // build a hash_map the first time
1633 if ( !built ) {
1634 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1635 atom = *it;
1636 const char* name = atom->getName();
1637 if ( name != NULL) {
1638 if ( usesAnonymousNamespace(name) ) {
1639 // symbol that uses anonymous namespace
1640 char canonicalName[strlen(name)+2];
1641 canonicalizeAnonymousName(name, canonicalName);
1642 const char* hashName = strdup(canonicalName);
1643 SymbolTable::Mapper::iterator pos = hashTableOfSymbolsWithAnonymousNamespace.find(hashName);
1644 if ( pos == hashTableOfSymbolsWithAnonymousNamespace.end() )
1645 hashTableOfSymbolsWithAnonymousNamespace[hashName] = atom;
1646 else
1647 hashTableOfSymbolsWithAnonymousNamespace[hashName] = NULL; // collision, denote with NULL
1648 }
1649 else if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
1650 // static function or data
1651 SymbolTable::Mapper::iterator pos = hashTableOfTranslationUnitScopedSymbols.find(name);
1652 if ( pos == hashTableOfTranslationUnitScopedSymbols.end() )
1653 hashTableOfTranslationUnitScopedSymbols[name] = atom;
1654 else
1655 hashTableOfTranslationUnitScopedSymbols[name] = NULL; // collision, denote with NULL
1656 }
1657 }
1658 }
1659 //fprintf(stderr, "built hash table of %lu static functions\n", hashTableOfTranslationUnitScopedSymbols.size());
1660 built = true;
1661 }
1662
1663 // look for name in hashTableOfTranslationUnitScopedSymbols
1664 SymbolTable::Mapper::iterator pos = hashTableOfTranslationUnitScopedSymbols.find(orderedSymbol.symbolName);
1665 if ( pos != hashTableOfTranslationUnitScopedSymbols.end() ) {
1666 if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) {
1667 //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName);
1668 return pos->second;
1669 }
1670 if ( pos->second == NULL )
1671 // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
1672 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1673 atom = *it;
1674 if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
1675 const char* name = atom->getName();
1676 if ( (name != NULL) && (strcmp(name, orderedSymbol.symbolName) == 0) ) {
1677 if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) {
1678 if ( fOptions.printOrderFileStatistics() )
1679 fprintf(stderr, "ld: warning %s specified in order_file but it exists in multiple .o files. "
1680 "Prefix symbol with .o filename in order_file to disambiguate\n", orderedSymbol.symbolName);
1681 return atom;
1682 }
1683 }
1684 }
1685 }
1686 }
1687
1688 // look for name in hashTableOfSymbolsWithAnonymousNamespace
1689 if ( usesAnonymousNamespace(orderedSymbol.symbolName) ) {
1690 // symbol that uses anonymous namespace
1691 char canonicalName[strlen(orderedSymbol.symbolName)+2];
1692 canonicalizeAnonymousName(orderedSymbol.symbolName, canonicalName);
1693 SymbolTable::Mapper::iterator pos = hashTableOfSymbolsWithAnonymousNamespace.find(canonicalName);
1694 if ( pos != hashTableOfSymbolsWithAnonymousNamespace.end() ) {
1695 if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) {
1696 //fprintf(stderr, "found %s in anonymous namespace hash table\n", canonicalName);
1697 return pos->second;
1698 }
1699 if ( pos->second == NULL )
1700 // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
1701 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1702 atom = *it;
1703 const char* name = atom->getName();
1704 if ( (name != NULL) && usesAnonymousNamespace(name) ) {
1705 char canonicalAtomName[strlen(name)+2];
1706 canonicalizeAnonymousName(name, canonicalAtomName);
1707 if ( strcmp(canonicalAtomName, canonicalName) == 0 ) {
1708 if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) {
1709 if ( fOptions.printOrderFileStatistics() )
1710 fprintf(stderr, "ld: warning %s specified in order_file but it exists in multiple .o files. "
1711 "Prefix symbol with .o filename in order_file to disambiguate\n", orderedSymbol.symbolName);
1712 return atom;
1713 }
1714 }
1715 }
1716 }
1717 }
1718 }
1719 }
1720 return NULL;
1721 }
1722
1723
1724 void Linker::sortSections()
1725 {
1726 Section::assignIndexes();
1727 }
1728
1729
1730 //
1731 // Linker::sortAtoms()
1732 //
1733 // The purpose of this method is to take the graph of all Atoms and produce an ordered
1734 // sequence of atoms. The constraints are that: 1) all Atoms of the same Segment must
1735 // be contiguous, 2) all Atoms of the same Section must be contigous, 3) Atoms specified
1736 // in an order_file are seqenced as in the order_file and before Atoms not specified,
1737 // 4) Atoms in the same section from the same .o file should be contiguous and sequenced
1738 // in the same order they were in the .o file, 5) Atoms in the same Section but which came
1739 // from different .o files should be sequenced in the same order that the .o files
1740 // were passed to the linker (i.e. command line order).
1741 //
1742 // The way this is implemented is that the linker passes a "base ordinal" to each Reader
1743 // as it is constructed. The reader should construct it Atoms so that calling getOrdinal()
1744 // on its atoms returns a contiguous range of values starting at the base ordinal. Then
1745 // sorting is just sorting by section, then by ordinal.
1746 //
1747 // If an order_file is specified, it gets more complicated. First, an override-ordinal map
1748 // is created. It causes the sort routine to ignore the value returned by getOrdinal() and
1749 // use the override value instead. Next some Atoms must be layed out consecutively
1750 // (e.g. hand written assembly that does not end with return, but rather falls into
1751 // the next label). This is modeled in Readers via a "kFollowOn" reference. The use of
1752 // kFollowOn refernces produces "clusters" of atoms that must stay together.
1753 // If an order_file tries to move one atom, it may need to move a whole cluster. The
1754 // algorithm to do this models clusters using two maps. The "starts" maps maps any
1755 // atom in a cluster to the first Atom in the cluster. The "nexts" maps an Atom in a
1756 // cluster to the next Atom in the cluster. With this in place, while processing an
1757 // order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is
1758 // given ordinal overrides.
1759 //
1760 void Linker::sortAtoms()
1761 {
1762 fStartSortTime = mach_absolute_time();
1763 // if -order_file is used, build map of atom ordinal overrides
1764 std::map<const ObjectFile::Atom*, uint32_t>* ordinalOverrideMap = NULL;
1765 std::map<const ObjectFile::Atom*, uint32_t> theOrdinalOverrideMap;
1766 const bool log = false;
1767 if ( fOptions.orderedSymbols().size() != 0 ) {
1768 // first make a pass to find all follow-on references and build start/next maps
1769 // which are a way to represent clusters of atoms that must layout together
1770 std::map<const ObjectFile::Atom*, const ObjectFile::Atom*> followOnStarts;
1771 std::map<const ObjectFile::Atom*, const ObjectFile::Atom*> followOnNexts;
1772 for (std::vector<ObjectFile::Atom*>::iterator ait=fAllAtoms.begin(); ait != fAllAtoms.end(); ait++) {
1773 ObjectFile::Atom* atom = *ait;
1774 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
1775 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1776 ObjectFile::Reference* ref = *rit;
1777 if ( ref->getKind() == 1 ) { // FIX FIX
1778 ObjectFile::Atom* targetAtom = &ref->getTarget();
1779 if ( log ) fprintf(stderr, "ref %s -> %s", atom->getDisplayName(), targetAtom->getDisplayName());
1780 std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator startFrom = followOnStarts.find(atom);
1781 std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator startTo = followOnStarts.find(targetAtom);
1782 if ( (startFrom == followOnStarts.end()) && (startTo == followOnStarts.end()) ) {
1783 // this is first time we've seen either atom, make simple cluster of the two
1784 if ( log ) fprintf(stderr, " new cluster\n");
1785 followOnStarts[atom] = atom;
1786 followOnStarts[targetAtom] = atom;
1787 followOnNexts[atom] = targetAtom;
1788 followOnNexts[targetAtom] = NULL;
1789 }
1790 else if ( (startFrom != followOnStarts.end()) && (startTo == followOnStarts.end()) && (followOnNexts[atom] == NULL) ) {
1791 // atom is at end of an existing cluster, so append target to end of cluster
1792 if ( log ) fprintf(stderr, " end of cluster starting with %s\n", followOnStarts[atom]->getDisplayName());
1793 followOnNexts[atom] = targetAtom;
1794 followOnNexts[targetAtom] = NULL;
1795 followOnStarts[targetAtom] = followOnStarts[atom];
1796 }
1797 else {
1798 // gerneral case of inserting into an existing cluster
1799 if ( followOnNexts[atom] != NULL ) {
1800 // an atom with two follow-ons is illegal
1801 fprintf(stderr, "ld: warning can't order %s because both %s and %s must follow it\n",
1802 atom->getDisplayName(), targetAtom->getDisplayName(), followOnNexts[atom]->getDisplayName());
1803 }
1804 else {
1805 // there already exists an atom that says target must be its follow-on
1806 const ObjectFile::Atom* originalStart = startTo->second;
1807 const ObjectFile::Atom* originalPrevious = originalStart;
1808 while ( followOnNexts[originalPrevious] != targetAtom )
1809 originalPrevious = followOnNexts[originalPrevious];
1810 bool otherIsAlias = (originalPrevious->getSize() == 0);
1811 bool thisIsAlias = (atom->getSize() == 0);
1812 if ( !otherIsAlias && !thisIsAlias ) {
1813 fprintf(stderr, "ld: warning can't order %s because both %s and %s must preceed it\n",
1814 targetAtom->getDisplayName(), originalPrevious->getDisplayName(), atom->getDisplayName());
1815 }
1816 else if ( otherIsAlias ) {
1817 if ( originalPrevious == originalStart ) {
1818 // other is alias at start of cluster, make this the new start of cluster
1819 if ( log ) fprintf(stderr, " becomes new start of cluster previous starting with %s\n", originalStart->getDisplayName());
1820 followOnNexts[atom] = originalPrevious;
1821 for(const ObjectFile::Atom* nextAtom = atom; nextAtom != NULL; nextAtom = followOnNexts[nextAtom])
1822 followOnStarts[nextAtom] = atom;
1823 }
1824 else {
1825 // other is alias in middle of cluster, insert new atom before it
1826 if ( log ) fprintf(stderr, " insert into cluster starting with %s before alias %s\n", originalStart->getDisplayName(), originalPrevious->getDisplayName());
1827 followOnStarts[atom] = originalStart;
1828 followOnNexts[atom] = originalPrevious;
1829 for(const ObjectFile::Atom* a = originalStart; a != NULL; a = followOnNexts[a]) {
1830 if ( followOnNexts[a] == originalPrevious ) {
1831 followOnNexts[a] = atom;
1832 break;
1833 }
1834 }
1835 }
1836 }
1837 else {
1838 // this is alias, so it can go inbetween originalPrevious and targetAtom
1839 if ( log ) fprintf(stderr, " insert into cluster starting with %s after %s\n", originalStart->getDisplayName(), originalPrevious->getDisplayName());
1840 followOnStarts[atom] = originalStart;
1841 followOnNexts[atom] = followOnNexts[originalPrevious];
1842 followOnNexts[originalPrevious] = atom;
1843 }
1844 }
1845 }
1846 }
1847 }
1848 }
1849
1850 if ( log ) {
1851 for(std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator it = followOnStarts.begin(); it != followOnStarts.end(); ++it)
1852 fprintf(stderr, "start %s -> %s\n", it->first->getDisplayName(), it->second->getDisplayName());
1853
1854 for(std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator it = followOnNexts.begin(); it != followOnNexts.end(); ++it)
1855 fprintf(stderr, "next %s -> %s\n", it->first->getDisplayName(), (it->second != NULL) ? it->second->getDisplayName() : "null");
1856 }
1857
1858 // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals
1859 ordinalOverrideMap = &theOrdinalOverrideMap;
1860 uint32_t index = 0;
1861 uint32_t matchCount = 0;
1862 std::vector<Options::OrderedSymbol>& orderedSymbols = fOptions.orderedSymbols();
1863 for(std::vector<Options::OrderedSymbol>::iterator it = orderedSymbols.begin(); it != orderedSymbols.end(); ++it) {
1864 ObjectFile::Atom* atom = this->findAtom(*it);
1865 if ( atom != NULL ) {
1866 std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator start = followOnStarts.find(atom);
1867 if ( start != followOnStarts.end() ) {
1868 // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together
1869 for(const ObjectFile::Atom* nextAtom = start->second; nextAtom != NULL; nextAtom = followOnNexts[nextAtom]) {
1870 std::map<const ObjectFile::Atom*, uint32_t>::iterator pos = theOrdinalOverrideMap.find(nextAtom);
1871 if ( pos == theOrdinalOverrideMap.end() ) {
1872 theOrdinalOverrideMap[nextAtom] = index++;
1873 if (log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->getDisplayName(), nextAtom->getFile()->getPath());
1874 }
1875 else {
1876 if (log ) fprintf(stderr, "could not order %s as %u because it was already laid out earlier by %s as %u\n",
1877 atom->getDisplayName(), index, followOnStarts[atom]->getDisplayName(), theOrdinalOverrideMap[atom] );
1878 }
1879 }
1880 }
1881 else {
1882 theOrdinalOverrideMap[atom] = index;
1883 if (log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->getDisplayName(), atom->getFile()->getPath());
1884 }
1885 }
1886 else {
1887 ++matchCount;
1888 //fprintf(stderr, "can't find match for order_file entry %s/%s\n", it->objectFileName, it->symbolName);
1889 }
1890 ++index;
1891 }
1892 if ( fOptions.printOrderFileStatistics() && (fOptions.orderedSymbols().size() != matchCount) ) {
1893 fprintf(stderr, "ld: warning only %u out of %lu order_file symbols were applicable\n", matchCount, fOptions.orderedSymbols().size() );
1894 }
1895 }
1896
1897 // sort atoms
1898 std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter(ordinalOverrideMap));
1899
1900 //fprintf(stderr, "Sorted atoms:\n");
1901 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1902 // fprintf(stderr, "\t%p, %u %s\n", (*it)->getSection(), (*it)->getSection()->getIndex(), (*it)->getDisplayName());
1903 //}
1904 }
1905
1906
1907 // make sure given addresses are within reach of branches, etc
1908 void Linker::tweakLayout()
1909 {
1910 // > 2GB images need their large zero fill atoms sorted to the end to keep access with +/- 2GB
1911 if ( fTotalSize > 0x7F000000 ) {
1912 fBiggerThanTwoGigOutput = true;
1913
1914 if ( (fTotalSize-fTotalZeroFillSize) > 0x7F000000 )
1915 throwf("total output size exceeds 2GB (%lldMB)", (fTotalSize-fTotalZeroFillSize)/(1024*1024));
1916
1917 // move very large (>1MB) zero fill atoms to a new section at very end
1918 Section* hugeZeroFills = Section::find("__huge", "__DATA", true);
1919 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1920 ObjectFile::Atom* atom = *it;
1921 if ( atom->isZeroFill() && (atom->getSize() > 1024*1024) && atom->getSegment().isContentReadable() )
1922 atom->setSection(hugeZeroFills);
1923 }
1924 }
1925 }
1926
1927
1928 void Linker::writeDotOutput()
1929 {
1930 const char* dotOutFilePath = fOptions.dotOutputFile();
1931 if ( dotOutFilePath != NULL ) {
1932 FILE* out = fopen(dotOutFilePath, "w");
1933 if ( out != NULL ) {
1934 // print header
1935 fprintf(out, "digraph dg\n{\n");
1936 fprintf(out, "\tconcentrate = true;\n");
1937 fprintf(out, "\trankdir = LR;\n");
1938
1939 // print each atom as a node
1940 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1941 ObjectFile::Atom* atom = *it;
1942 if ( atom->getFile() != fOutputFile ) {
1943 const char* name = atom->getDisplayName();
1944 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
1945 || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
1946 fprintf(out, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom, name);
1947 }
1948 else if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
1949 char cstring[atom->getSize()+2];
1950 atom->copyRawContent((uint8_t*)cstring);
1951 fprintf(out, "\taddr%p [ label = \"string: '", atom);
1952 for (const char* s=cstring; *s != '\0'; ++s) {
1953 if ( *s == '\n' )
1954 fprintf(out, "\\\\n");
1955 else
1956 fputc(*s, out);
1957 }
1958 fprintf(out, "'\" ];\n");
1959 }
1960 else {
1961 fprintf(out, "\taddr%p [ label = \"%s\" ];\n", atom, name);
1962 }
1963 }
1964 }
1965 fprintf(out, "\n");
1966
1967 // print each reference as an edge
1968 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1969 ObjectFile::Atom* fromAtom = *it;
1970 if ( fromAtom->getFile() != fOutputFile ) {
1971 std::vector<ObjectFile::Reference*>& references = fromAtom->getReferences();
1972 std::set<ObjectFile::Atom*> seenTargets;
1973 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1974 ObjectFile::Reference* reference = *rit;
1975 ObjectFile::Atom* toAtom = &(reference->getTarget());
1976 if ( seenTargets.count(toAtom) == 0 ) {
1977 seenTargets.insert(toAtom);
1978 fprintf(out, "\taddr%p -> addr%p;\n", fromAtom, toAtom);
1979 }
1980 }
1981 }
1982 }
1983 fprintf(out, "\n");
1984
1985 // push all imports to bottom of graph
1986 fprintf(out, "{ rank = same; ");
1987 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1988 ObjectFile::Atom* atom = *it;
1989 if ( atom->getFile() != fOutputFile )
1990 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
1991 || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
1992 fprintf(out, "addr%p; ", atom);
1993 }
1994 }
1995 fprintf(out, "};\n ");
1996
1997 // print footer
1998 fprintf(out, "}\n");
1999 fclose(out);
2000 }
2001 else {
2002 fprintf(stderr, "ld: warning could not write dot output file: %s\n", dotOutFilePath);
2003 }
2004 }
2005 }
2006
2007 ObjectFile::Atom* Linker::entryPoint()
2008 {
2009 // if main executable, find entry point atom
2010 ObjectFile::Atom* entryPoint = NULL;
2011 switch ( fOptions.outputKind() ) {
2012 case Options::kDynamicExecutable:
2013 case Options::kStaticExecutable:
2014 case Options::kDyld:
2015 entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
2016 if ( entryPoint == NULL ) {
2017 throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions.entryName());
2018 }
2019 break;
2020 case Options::kDynamicLibrary:
2021 if ( fOptions.initFunctionName() != NULL ) {
2022 entryPoint = fGlobalSymbolTable.find(fOptions.initFunctionName());
2023 if ( entryPoint == NULL ) {
2024 throwf("could not find -init function: \"%s\"", fOptions.initFunctionName());
2025 }
2026 }
2027 break;
2028 case Options::kObjectFile:
2029 case Options::kDynamicBundle:
2030 entryPoint = NULL;
2031 break;
2032 }
2033 return entryPoint;
2034 }
2035
2036 ObjectFile::Atom* Linker::dyldHelper()
2037 {
2038 return fGlobalSymbolTable.find("dyld_stub_binding_helper");
2039 }
2040
2041 const char* Linker::assureFullPath(const char* path)
2042 {
2043 if ( path[0] == '/' )
2044 return path;
2045 char cwdbuff[MAXPATHLEN];
2046 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
2047 char* result;
2048 asprintf(&result, "%s/%s", cwdbuff, path);
2049 if ( result != NULL )
2050 return result;
2051 }
2052 return path;
2053 }
2054
2055
2056 //
2057 // The stab strings are of the form:
2058 // <name> ':' <type-code> <number-pari>
2059 // but the <name> contain a colon.
2060 // For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
2061 // For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
2062 //
2063 const char* Linker::truncateStabString(const char* str)
2064 {
2065 enum { start, inObjc } state = start;
2066 for (const char* s = str; *s != 0; ++s) {
2067 char c = *s;
2068 switch (state) {
2069 case start:
2070 if ( c == '[' ) {
2071 state = inObjc;
2072 }
2073 else {
2074 if ( c == ':' ) {
2075 if ( s[1] == ':' ) {
2076 ++s;
2077 }
2078 else {
2079 // found colon
2080 // Duplicate strndup behavior here.
2081 int trunStrLen = s-str+2;
2082 char* temp = new char[trunStrLen+1];
2083 memcpy(temp, str, trunStrLen);
2084 temp[trunStrLen] = '\0';
2085 return temp;
2086 }
2087 }
2088 }
2089 break;
2090 case inObjc:
2091 if ( c == ']' ) {
2092 state = start;
2093 }
2094 break;
2095 }
2096 }
2097 // malformed
2098 return str;
2099 }
2100
2101
2102 bool Linker::minimizeStab(ObjectFile::Reader::Stab& stab)
2103 {
2104 switch(stab.type){
2105 case N_GSYM:
2106 case N_STSYM:
2107 case N_LCSYM:
2108 case N_FUN:
2109 // these all need truncated strings
2110 stab.string = truncateStabString(stab.string);
2111 return true;
2112 case N_SO:
2113 case N_OSO:
2114 case N_OPT:
2115 case N_SOL:
2116 // these are included in the minimal stabs, but they keep their full string
2117 return true;
2118 default:
2119 return false;
2120 }
2121 }
2122
2123
2124 struct HeaderRange {
2125 std::vector<ObjectFile::Reader::Stab>::iterator begin;
2126 std::vector<ObjectFile::Reader::Stab>::iterator end;
2127 int parentRangeIndex;
2128 uint32_t sum;
2129 bool sumPrecomputed;
2130 bool useEXCL;
2131 bool cannotEXCL; // because of SLINE, etc stabs
2132 };
2133
2134
2135 typedef __gnu_cxx::hash_map<const char*, std::vector<uint32_t>, __gnu_cxx::hash<const char*>, CStringEquals> PathToSums;
2136
2137 // hash table that maps header path to a vector of known checksums for that path
2138 static PathToSums sKnownBINCLs;
2139
2140
2141 void Linker::collectStabs(ObjectFile::Reader* reader, std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals)
2142 {
2143 bool log = false;
2144 bool minimal = ( fOptions.readerOptions().fDebugInfoStripping == ObjectFile::ReaderOptions::kDebugInfoMinimal );
2145 std::vector<class ObjectFile::Reader::Stab>* readerStabs = reader->getStabs();
2146 if ( readerStabs == NULL )
2147 return;
2148
2149 if ( log ) fprintf(stderr, "processesing %lu stabs for %s\n", readerStabs->size(), reader->getPath());
2150 std::vector<HeaderRange> ranges;
2151 int curRangeIndex = -1;
2152 int count = 0;
2153 ObjectFile::Atom* atomWithLowestOrdinal = NULL;
2154 ObjectFile::Atom* atomWithHighestOrdinal = NULL;
2155 uint32_t highestOrdinal = 0;
2156 uint32_t lowestOrdinal = UINT_MAX;
2157 std::vector<std::pair<ObjectFile::Atom*,ObjectFile::Atom*> > soRanges;
2158 // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums
2159 // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein
2160 for(std::vector<class ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
2161 ++count;
2162 switch ( it->type ) {
2163 case N_BINCL:
2164 {
2165 HeaderRange range;
2166 range.begin = it;
2167 range.end = readerStabs->end();
2168 range.parentRangeIndex = curRangeIndex;
2169 range.sum = it->value;
2170 range.sumPrecomputed = (range.sum != 0);
2171 range.useEXCL = false;
2172 range.cannotEXCL = false;
2173 curRangeIndex = ranges.size();
2174 if ( log ) fprintf(stderr, "[%d]BINCL %s\n", curRangeIndex, it->string);
2175 ranges.push_back(range);
2176 }
2177 break;
2178 case N_EINCL:
2179 if ( curRangeIndex == -1 ) {
2180 fprintf(stderr, "ld: warning EINCL missing BINCL in %s\n", reader->getPath());
2181 }
2182 else {
2183 ranges[curRangeIndex].end = it+1;
2184 if ( log ) fprintf(stderr, "[%d->%d]EINCL %s\n", curRangeIndex, ranges[curRangeIndex].parentRangeIndex, it->string);
2185 curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
2186 }
2187 break;
2188 case N_FUN:
2189 {
2190 std::map<const class ObjectFile::Atom*, uint32_t>::iterator pos = atomOrdinals.find(it->atom);
2191 if ( pos != atomOrdinals.end() ) {
2192 uint32_t ordinal = pos->second;
2193 if ( ordinal > highestOrdinal ) {
2194 highestOrdinal = ordinal;
2195 atomWithHighestOrdinal = it->atom;
2196 }
2197 if ( ordinal < lowestOrdinal ) {
2198 lowestOrdinal = ordinal;
2199 atomWithLowestOrdinal = it->atom;
2200 }
2201 }
2202 }
2203 // fall through
2204 case N_BNSYM:
2205 case N_ENSYM:
2206 case N_LBRAC:
2207 case N_RBRAC:
2208 case N_SLINE:
2209 case N_STSYM:
2210 case N_LCSYM:
2211 if ( curRangeIndex != -1 ) {
2212 ranges[curRangeIndex].cannotEXCL = true;
2213 if ( fOptions.warnStabs() )
2214 fprintf(stderr, "ld: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
2215 }
2216 break;
2217 case N_SO:
2218 if ( (it->string != NULL) && (strlen(it->string) > 0) ) {
2219 // start SO, reset hi/low FUN tracking
2220 atomWithLowestOrdinal = NULL;
2221 atomWithHighestOrdinal = NULL;
2222 highestOrdinal = 0;
2223 lowestOrdinal = UINT_MAX;
2224 }
2225 else {
2226 // end SO, record hi/low atoms for this SO range
2227 soRanges.push_back(std::make_pair<ObjectFile::Atom*,ObjectFile::Atom*>(atomWithLowestOrdinal, atomWithHighestOrdinal));
2228 }
2229 // fall through
2230 default:
2231 if ( curRangeIndex != -1 ) {
2232 if ( ! ranges[curRangeIndex].sumPrecomputed ) {
2233 uint32_t sum = 0;
2234 const char* s = it->string;
2235 char c;
2236 while ( (c = *s++) != 0 ) {
2237 sum += c;
2238 // don't checkusm first number (file index) after open paren in string
2239 if ( c == '(' ) {
2240 while(isdigit(*s))
2241 ++s;
2242 }
2243 }
2244 ranges[curRangeIndex].sum += sum;
2245 }
2246 }
2247
2248 }
2249 }
2250 if ( log ) fprintf(stderr, "processesed %d stabs for %s\n", count, reader->getPath());
2251 if ( curRangeIndex != -1 )
2252 fprintf(stderr, "ld: warning BINCL (%s) missing EINCL in %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
2253
2254 // if no BINCLs
2255 if ( ranges.size() == 0 ) {
2256 int soIndex = 0;
2257 for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
2258 // copy minimal or all stabs
2259 ObjectFile::Reader::Stab stab = *it;
2260 if ( !minimal || minimizeStab(stab) ) {
2261 if ( stab.type == N_SO ) {
2262 if ( (stab.string != NULL) && (strlen(stab.string) > 0) ) {
2263 // starting SO is associated with first atom
2264 stab.atom = soRanges[soIndex].first;
2265 }
2266 else {
2267 // ending SO is associated with last atom
2268 stab.atom = soRanges[soIndex].second;
2269 ++soIndex;
2270 }
2271 }
2272 fStabs.push_back(stab);
2273 }
2274 }
2275 return;
2276 }
2277
2278 //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
2279 //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
2280 // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
2281 //}
2282
2283 // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
2284 for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
2285 if ( ! it->cannotEXCL ) {
2286 const char* header = it->begin->string;
2287 uint32_t sum = it->sum;
2288 PathToSums::iterator pos = sKnownBINCLs.find(header);
2289 if ( pos != sKnownBINCLs.end() ) {
2290 std::vector<uint32_t>& sums = pos->second;
2291 for(std::vector<uint32_t>::iterator sit=sums.begin(); sit != sums.end(); ++sit) {
2292 if (*sit == sum) {
2293 //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
2294 it->useEXCL = true;
2295 break;
2296 }
2297 }
2298 if ( ! it->useEXCL ) {
2299 // have seen this path, but not this checksum
2300 //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
2301 sums.push_back(sum);
2302 }
2303 }
2304 else {
2305 // have not seen this path, so add to known BINCLs
2306 std::vector<uint32_t> empty;
2307 sKnownBINCLs[header] = empty;
2308 sKnownBINCLs[header].push_back(sum);
2309 //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
2310 }
2311 }
2312 }
2313
2314 // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
2315 curRangeIndex = -1;
2316 const int maxRangeIndex = ranges.size();
2317 int soIndex = 0;
2318 for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
2319 switch ( it->type ) {
2320 case N_BINCL:
2321 for(int i=curRangeIndex+1; i < maxRangeIndex; ++i) {
2322 if ( ranges[i].begin == it ) {
2323 curRangeIndex = i;
2324 HeaderRange& range = ranges[curRangeIndex];
2325 ObjectFile::Reader::Stab stab = *it;
2326 stab.value = range.sum; // BINCL and EXCL have n_value set to checksum
2327 if ( range.useEXCL )
2328 stab.type = N_EXCL; // transform BINCL into EXCL
2329 if ( !minimal )
2330 fStabs.push_back(stab);
2331 break;
2332 }
2333 }
2334 break;
2335 case N_EINCL:
2336 if ( curRangeIndex != -1 ) {
2337 if ( !ranges[curRangeIndex].useEXCL && !minimal )
2338 fStabs.push_back(*it);
2339 curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
2340 }
2341 break;
2342 default:
2343 if ( (curRangeIndex == -1) || !ranges[curRangeIndex].useEXCL ) {
2344 ObjectFile::Reader::Stab stab = *it;
2345 if ( !minimal || minimizeStab(stab) ) {
2346 if ( stab.type == N_SO ) {
2347 if ( (stab.string != NULL) && (strlen(stab.string) > 0) ) {
2348 // starting SO is associated with first atom
2349 stab.atom = soRanges[soIndex].first;
2350 }
2351 else {
2352 // ending SO is associated with last atom
2353 stab.atom = soRanges[soIndex].second;
2354 ++soIndex;
2355 }
2356 }
2357 fStabs.push_back(stab);
2358 }
2359 }
2360 }
2361 }
2362
2363 }
2364
2365
2366 // used to prune out atoms that don't need debug notes generated
2367 class NoDebugNoteAtom
2368 {
2369 public:
2370 NoDebugNoteAtom(const std::map<class ObjectFile::Reader*, uint32_t>& readersWithDwarfOrdinals)
2371 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals) {}
2372
2373 bool operator()(const ObjectFile::Atom* atom) const {
2374 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
2375 return true;
2376 if ( atom->getName() == NULL )
2377 return true;
2378 if ( fReadersWithDwarfOrdinals.find(atom->getFile()) == fReadersWithDwarfOrdinals.end() )
2379 return true;
2380 return false;
2381 }
2382
2383 private:
2384 const std::map<class ObjectFile::Reader*, uint32_t>& fReadersWithDwarfOrdinals;
2385 };
2386
2387 // used to sort atoms with debug notes
2388 class ReadersWithDwarfSorter
2389 {
2390 public:
2391 ReadersWithDwarfSorter(const std::map<class ObjectFile::Reader*, uint32_t>& readersWithDwarfOrdinals,
2392 const std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals)
2393 : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals), fAtomOrdinals(atomOrdinals) {}
2394
2395 bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right) const
2396 {
2397 // first sort by reader
2398 unsigned int leftReaderIndex = fReadersWithDwarfOrdinals.find(left->getFile())->second;
2399 unsigned int rightReaderIndex = fReadersWithDwarfOrdinals.find(right->getFile())->second;
2400 if ( leftReaderIndex != rightReaderIndex )
2401 return (leftReaderIndex < rightReaderIndex);
2402
2403 // then sort by atom ordinal
2404 unsigned int leftAtomIndex = fAtomOrdinals.find(left)->second;
2405 unsigned int rightAtomIndex = fAtomOrdinals.find(right)->second;
2406 return leftAtomIndex < rightAtomIndex;
2407 }
2408
2409 private:
2410 const std::map<class ObjectFile::Reader*, uint32_t>& fReadersWithDwarfOrdinals;
2411 const std::map<const class ObjectFile::Atom*, uint32_t>& fAtomOrdinals;
2412 };
2413
2414
2415
2416
2417
2418 void Linker::synthesizeDebugNotes(std::vector<class ObjectFile::Atom*>& allAtomsByReader)
2419 {
2420 // synthesize "debug notes" and add them to master stabs vector
2421 const char* dirPath = NULL;
2422 const char* filename = NULL;
2423 bool wroteStartSO = false;
2424 bool useZeroOSOModTime = (getenv("RC_RELEASE") != NULL);
2425 __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> seenFiles;
2426 for (std::vector<ObjectFile::Atom*>::iterator it=allAtomsByReader.begin(); it != allAtomsByReader.end(); it++) {
2427 ObjectFile::Atom* atom = *it;
2428 const char* newDirPath;
2429 const char* newFilename;
2430 //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
2431 if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) {
2432 // need SO's whenever the translation unit source file changes
2433 if ( newFilename != filename ) {
2434 // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
2435 if ( (newDirPath != NULL) && (strlen(newDirPath) > 1 ) && (newDirPath[strlen(newDirPath)-1] != '/') )
2436 asprintf((char**)&newDirPath, "%s/", newDirPath);
2437 if ( filename != NULL ) {
2438 // translation unit change, emit ending SO
2439 ObjectFile::Reader::Stab endFileStab;
2440 endFileStab.atom = NULL;
2441 endFileStab.type = N_SO;
2442 endFileStab.other = 1;
2443 endFileStab.desc = 0;
2444 endFileStab.value = 0;
2445 endFileStab.string = "";
2446 fStabs.push_back(endFileStab);
2447 }
2448 // new translation unit, emit start SO's
2449 ObjectFile::Reader::Stab dirPathStab;
2450 dirPathStab.atom = NULL;
2451 dirPathStab.type = N_SO;
2452 dirPathStab.other = 0;
2453 dirPathStab.desc = 0;
2454 dirPathStab.value = 0;
2455 dirPathStab.string = newDirPath;
2456 fStabs.push_back(dirPathStab);
2457 ObjectFile::Reader::Stab fileStab;
2458 fileStab.atom = NULL;
2459 fileStab.type = N_SO;
2460 fileStab.other = 0;
2461 fileStab.desc = 0;
2462 fileStab.value = 0;
2463 fileStab.string = newFilename;
2464 fStabs.push_back(fileStab);
2465 // Synthesize OSO for start of file
2466 ObjectFile::Reader::Stab objStab;
2467 objStab.atom = NULL;
2468 objStab.type = N_OSO;
2469 objStab.other = 0;
2470 objStab.desc = 1;
2471 objStab.value = useZeroOSOModTime ? 0 : atom->getFile()->getModificationTime();
2472 objStab.string = assureFullPath(atom->getFile()->getPath());
2473 fStabs.push_back(objStab);
2474 wroteStartSO = true;
2475 // add the source file path to seenFiles so it does not show up in SOLs
2476 seenFiles.insert(newFilename);
2477 }
2478 filename = newFilename;
2479 dirPath = newDirPath;
2480 if ( atom->getSegment().isContentExecutable() && (strncmp(atom->getSectionName(), "__text", 6) == 0) ) {
2481 // Synthesize BNSYM and start FUN stabs
2482 ObjectFile::Reader::Stab beginSym;
2483 beginSym.atom = atom;
2484 beginSym.type = N_BNSYM;
2485 beginSym.other = 1;
2486 beginSym.desc = 0;
2487 beginSym.value = 0;
2488 beginSym.string = "";
2489 fStabs.push_back(beginSym);
2490 ObjectFile::Reader::Stab startFun;
2491 startFun.atom = atom;
2492 startFun.type = N_FUN;
2493 startFun.other = 1;
2494 startFun.desc = 0;
2495 startFun.value = 0;
2496 startFun.string = atom->getName();
2497 fStabs.push_back(startFun);
2498 // Synthesize any SOL stabs needed
2499 std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
2500 if ( lineInfo != NULL ) {
2501 const char* curFile = NULL;
2502 for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
2503 if ( it->fileName != curFile ) {
2504 if ( seenFiles.count(it->fileName) == 0 ) {
2505 seenFiles.insert(it->fileName);
2506 ObjectFile::Reader::Stab sol;
2507 sol.atom = 0;
2508 sol.type = N_SOL;
2509 sol.other = 0;
2510 sol.desc = 0;
2511 sol.value = 0;
2512 sol.string = it->fileName;
2513 fStabs.push_back(sol);
2514 }
2515 curFile = it->fileName;
2516 }
2517 }
2518 }
2519 // Synthesize end FUN and ENSYM stabs
2520 ObjectFile::Reader::Stab endFun;
2521 endFun.atom = atom;
2522 endFun.type = N_FUN;
2523 endFun.other = 0;
2524 endFun.desc = 0;
2525 endFun.value = 0;
2526 endFun.string = "";
2527 fStabs.push_back(endFun);
2528 ObjectFile::Reader::Stab endSym;
2529 endSym.atom = atom;
2530 endSym.type = N_ENSYM;
2531 endSym.other = 1;
2532 endSym.desc = 0;
2533 endSym.value = 0;
2534 endSym.string = "";
2535 fStabs.push_back(endSym);
2536 }
2537 else {
2538 ObjectFile::Reader::Stab globalsStab;
2539 if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
2540 // Synthesize STSYM stab for statics
2541 const char* name = atom->getName();
2542 if ( name[0] == '_' ) {
2543 globalsStab.atom = atom;
2544 globalsStab.type = N_STSYM;
2545 globalsStab.other = 1;
2546 globalsStab.desc = 0;
2547 globalsStab.value = 0;
2548 globalsStab.string = name;
2549 fStabs.push_back(globalsStab);
2550 }
2551 }
2552 else {
2553 // Synthesize GSYM stab for other globals (but not .eh exception frame symbols)
2554 const char* name = atom->getName();
2555 if ( (name[0] == '_') && (strcmp(atom->getSectionName(), "__eh_frame") != 0) ) {
2556 globalsStab.atom = atom;
2557 globalsStab.type = N_GSYM;
2558 globalsStab.other = 1;
2559 globalsStab.desc = 0;
2560 globalsStab.value = 0;
2561 globalsStab.string = name;
2562 fStabs.push_back(globalsStab);
2563 }
2564 }
2565 }
2566 }
2567 }
2568
2569 if ( wroteStartSO ) {
2570 // emit ending SO
2571 ObjectFile::Reader::Stab endFileStab;
2572 endFileStab.atom = NULL;
2573 endFileStab.type = N_SO;
2574 endFileStab.other = 1;
2575 endFileStab.desc = 0;
2576 endFileStab.value = 0;
2577 endFileStab.string = "";
2578 fStabs.push_back(endFileStab);
2579 }
2580 }
2581
2582
2583
2584
2585 void Linker::collectDebugInfo()
2586 {
2587 std::map<const class ObjectFile::Atom*, uint32_t> atomOrdinals;
2588 fStartDebugTime = mach_absolute_time();
2589 if ( fOptions.readerOptions().fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone ) {
2590
2591 // determine mixture of stabs and dwarf
2592 bool someStabs = false;
2593 bool someDwarf = false;
2594 for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
2595 it != fReadersThatHaveSuppliedAtoms.end();
2596 it++) {
2597 ObjectFile::Reader* reader = *it;
2598 if ( reader != NULL ) {
2599 switch ( reader->getDebugInfoKind() ) {
2600 case ObjectFile::Reader::kDebugInfoNone:
2601 break;
2602 case ObjectFile::Reader::kDebugInfoStabs:
2603 someStabs = true;
2604 break;
2605 case ObjectFile::Reader::kDebugInfoDwarf:
2606 someDwarf = true;
2607 fCreateUUID = true;
2608 break;
2609 case ObjectFile::Reader::kDebugInfoStabsUUID:
2610 someStabs = true;
2611 fCreateUUID = true;
2612 break;
2613 default:
2614 throw "Unhandled type of debug information";
2615 }
2616 }
2617 }
2618
2619 if ( someDwarf || someStabs ) {
2620 // try to minimize re-allocations
2621 fStabs.reserve(1024);
2622
2623 // make mapping from atoms to ordinal
2624 uint32_t ordinal = 1;
2625 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
2626 atomOrdinals[*it] = ordinal++;
2627 }
2628 }
2629
2630 // process all dwarf .o files as a batch
2631 if ( someDwarf ) {
2632 // make mapping from readers with dwarf to ordinal
2633 std::map<class ObjectFile::Reader*, uint32_t> readersWithDwarfOrdinals;
2634 uint32_t readerOrdinal = 1;
2635 for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
2636 it != fReadersThatHaveSuppliedAtoms.end();
2637 it++) {
2638 ObjectFile::Reader* reader = *it;
2639 if ( (reader != NULL) && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoDwarf) ) {
2640 readersWithDwarfOrdinals[reader] = readerOrdinal++;
2641 }
2642 }
2643
2644 // make a vector of atoms
2645 std::vector<class ObjectFile::Atom*> allAtomsByReader(fAllAtoms.begin(), fAllAtoms.end());
2646 // remove those not from a reader that has dwarf
2647 allAtomsByReader.erase(std::remove_if(allAtomsByReader.begin(), allAtomsByReader.end(),
2648 NoDebugNoteAtom(readersWithDwarfOrdinals)), allAtomsByReader.end());
2649 // sort by reader then atom ordinal
2650 std::sort(allAtomsByReader.begin(), allAtomsByReader.end(), ReadersWithDwarfSorter(readersWithDwarfOrdinals, atomOrdinals));
2651 // add debug notes for each atom
2652 this->synthesizeDebugNotes(allAtomsByReader);
2653 }
2654
2655 // process all stabs .o files one by one
2656 if ( someStabs ) {
2657 // get stabs from each reader, in command line order
2658 for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
2659 it != fReadersThatHaveSuppliedAtoms.end();
2660 it++) {
2661 ObjectFile::Reader* reader = *it;
2662 if ( reader != NULL ) {
2663 switch ( reader->getDebugInfoKind() ) {
2664 case ObjectFile::Reader::kDebugInfoDwarf:
2665 case ObjectFile::Reader::kDebugInfoNone:
2666 // do nothing
2667 break;
2668 case ObjectFile::Reader::kDebugInfoStabs:
2669 case ObjectFile::Reader::kDebugInfoStabsUUID:
2670 collectStabs(reader, atomOrdinals);
2671 break;
2672 default:
2673 throw "Unhandled type of debug information";
2674 }
2675 }
2676 }
2677 // remove stabs associated with atoms that won't be in output
2678 std::set<class ObjectFile::Atom*> allAtomsSet;
2679 allAtomsSet.insert(fAllAtoms.begin(), fAllAtoms.end());
2680 fStabs.erase(std::remove_if(fStabs.begin(), fStabs.end(), NotInSet(allAtomsSet)), fStabs.end());
2681 }
2682 }
2683 }
2684
2685 void Linker::writeOutput()
2686 {
2687 if ( fOptions.forceCpuSubtypeAll() )
2688 fCurrentCpuConstraint = ObjectFile::Reader::kCpuAny;
2689
2690 fStartWriteTime = mach_absolute_time();
2691 // tell writer about each segment's atoms
2692 fOutputFileSize = fOutputFile->write(fAllAtoms, fStabs, this->entryPoint(), this->dyldHelper(),
2693 fCreateUUID, fCanScatter,
2694 fCurrentCpuConstraint, fBiggerThanTwoGigOutput);
2695 }
2696
2697 ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
2698 {
2699 // map in whole file
2700 uint64_t len = info.fileLen;
2701 int fd = ::open(info.path, O_RDONLY, 0);
2702 if ( fd == -1 )
2703 throwf("can't open file, errno=%d", errno);
2704 if ( info.fileLen < 20 )
2705 throw "file too small";
2706
2707 uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
2708 if ( p == (uint8_t*)(-1) )
2709 throwf("can't map file, errno=%d", errno);
2710
2711 // if fat file, skip to architecture we want
2712 const fat_header* fh = (fat_header*)p;
2713 if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
2714 // Fat header is always big-endian
2715 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
2716 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
2717 if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fArchitecture ) {
2718 uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
2719 len = OSSwapBigToHostInt32(archs[i].size);
2720 // if requested architecture is page aligned within fat file, then remap just that portion of file
2721 if ( (fileOffset & 0x00000FFF) == 0 ) {
2722 // unmap whole file
2723 munmap((caddr_t)p, info.fileLen);
2724 // re-map just part we need
2725 p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset);
2726 if ( p == (uint8_t*)(-1) )
2727 throwf("can't re-map file, errno=%d", errno);
2728 }
2729 else {
2730 p = &p[fileOffset];
2731 }
2732 break;
2733 }
2734 }
2735 }
2736 ::close(fd);
2737
2738 switch (fArchitecture) {
2739 case CPU_TYPE_POWERPC:
2740 if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
2741 return this->addObject(new mach_o::relocatable::Reader<ppc>::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2742 else if ( mach_o::dylib::Reader<ppc>::validFile(p, info.options.fBundleLoader) )
2743 return this->addDylib(new mach_o::dylib::Reader<ppc>::Reader(p, len, info.path, info.options.fBundleLoader, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2744 else if ( mach_o::archive::Reader<ppc>::validFile(p, len) )
2745 return this->addArchive(new mach_o::archive::Reader<ppc>::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2746 break;
2747 case CPU_TYPE_POWERPC64:
2748 if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
2749 return this->addObject(new mach_o::relocatable::Reader<ppc64>::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2750 else if ( mach_o::dylib::Reader<ppc64>::validFile(p, info.options.fBundleLoader) )
2751 return this->addDylib(new mach_o::dylib::Reader<ppc64>::Reader(p, len, info.path, info.options.fBundleLoader, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2752 else if ( mach_o::archive::Reader<ppc64>::validFile(p, len) )
2753 return this->addArchive(new mach_o::archive::Reader<ppc64>::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2754 break;
2755 case CPU_TYPE_I386:
2756 if ( mach_o::relocatable::Reader<x86>::validFile(p) )
2757 return this->addObject(new mach_o::relocatable::Reader<x86>::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2758 else if ( mach_o::dylib::Reader<x86>::validFile(p, info.options.fBundleLoader) )
2759 return this->addDylib(new mach_o::dylib::Reader<x86>::Reader(p, len, info.path, info.options.fBundleLoader, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2760 else if ( mach_o::archive::Reader<x86>::validFile(p, len) )
2761 return this->addArchive(new mach_o::archive::Reader<x86>::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2762 break;
2763 case CPU_TYPE_X86_64:
2764 if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
2765 return this->addObject(new mach_o::relocatable::Reader<x86_64>::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2766 else if ( mach_o::dylib::Reader<x86_64>::validFile(p, info.options.fBundleLoader) )
2767 return this->addDylib(new mach_o::dylib::Reader<x86_64>::Reader(p, len, info.path, info.options.fBundleLoader, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2768 else if ( mach_o::archive::Reader<x86_64>::validFile(p, len) )
2769 return this->addArchive(new mach_o::archive::Reader<x86_64>::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
2770 break;
2771 }
2772
2773 #if LLVM_SUPPORT
2774 if ( LLVMReader::validFile(p, info.path, fArchitecture, fOptions) ) {
2775 return this->addObject(LLVMReader::make(p, info.path, info.modTime, fOptions), info, len);
2776 }
2777 #endif
2778 // error handling
2779 if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
2780 throwf("missing required architecture %s in file", fArchitectureName);
2781 }
2782 else {
2783 throw "file is not of required architecture";
2784 }
2785 }
2786
2787 void Linker::logDylib(ObjectFile::Reader* reader, bool indirect)
2788 {
2789 if ( fOptions.readerOptions().fTraceDylibs ) {
2790 const char* fullPath = reader->getPath();
2791 char realName[MAXPATHLEN];
2792 if ( realpath(fullPath, realName) != NULL )
2793 fullPath = realName;
2794 if ( indirect )
2795 logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
2796 else
2797 logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
2798 }
2799 }
2800
2801
2802
2803 ObjectFile::Reader* Linker::findDylib(const char* installPath, const char* fromPath)
2804 {
2805 //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
2806 InstallNameToReader::iterator pos = fDylibMap.find(installPath);
2807 if ( pos != fDylibMap.end() ) {
2808 return pos->second;
2809 }
2810 else {
2811 // allow -dylib_path option to override indirect library to use
2812 for (std::vector<Options::DylibOverride>::iterator dit = fOptions.dylibOverrides().begin(); dit != fOptions.dylibOverrides().end(); ++dit) {
2813 if ( strcmp(dit->installName,installPath) == 0 ) {\
2814 try {
2815 Options::FileInfo info = fOptions.findFile(dit->useInstead);
2816 ObjectFile::Reader* reader = this->createReader(info);
2817 fDylibMap[strdup(installPath)] = reader;
2818 this->logDylib(reader, true);
2819 return reader;
2820 }
2821 catch (const char* msg) {
2822 fprintf(stderr, "ld: warning ignoring -dylib_file option, %s\n", msg);
2823 }
2824 }
2825 }
2826 char newPath[MAXPATHLEN];
2827 // handle @loader_path
2828 if ( strncmp(installPath, "@loader_path/", 13) == 0 ) {
2829 strcpy(newPath, fromPath);
2830 char* addPoint = strrchr(newPath,'/');
2831 if ( addPoint != NULL )
2832 strcpy(&addPoint[1], &installPath[13]);
2833 else
2834 strcpy(newPath, &installPath[13]);
2835 installPath = newPath;
2836 }
2837 // note: @executable_path case is handled inside findFileUsingPaths()
2838 // search for dylib using -F and -L paths
2839 Options::FileInfo info = fOptions.findFileUsingPaths(installPath);
2840 try {
2841 ObjectFile::Reader* reader = this->createReader(info);
2842 fDylibMap[strdup(installPath)] = reader;
2843 this->logDylib(reader, true);
2844 return reader;
2845 }
2846 catch (const char* msg) {
2847 throwf("in %s, %s", info.path, msg);
2848 }
2849 }
2850 }
2851
2852
2853 void Linker::processDylibs()
2854 {
2855 fAllDirectDylibsLoaded = true;
2856
2857 // mark all dylibs initially specified as required and check if they can be used
2858 for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
2859 it->second->setExplicitlyLinked();
2860 this->checkDylibClientRestrictions(it->second);
2861 }
2862
2863 // keep processing dylibs until no more dylibs are added
2864 unsigned long lastMapSize = 0;
2865 while ( lastMapSize != fDylibMap.size() ) {
2866 lastMapSize = fDylibMap.size();
2867 // can't iterator fDylibMap while modifying it, so use temp buffer
2868 std::vector<ObjectFile::Reader*> currentUnprocessedReaders;
2869 for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
2870 if ( fDylibsProcessed.count(it->second) == 0 )
2871 currentUnprocessedReaders.push_back(it->second);
2872 }
2873 for (std::vector<ObjectFile::Reader*>::iterator it=currentUnprocessedReaders.begin(); it != currentUnprocessedReaders.end(); it++) {
2874 fDylibsProcessed.insert(*it);
2875 (*it)->processIndirectLibraries(this);
2876 }
2877 }
2878
2879 // go back over original dylibs and mark sub frameworks as re-exported
2880 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
2881 const char* myLeaf = strrchr(fOptions.installPath(), '/');
2882 if ( myLeaf != NULL ) {
2883 for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
2884 ObjectFile::Reader* reader = *it;
2885 const char* childParent = reader->parentUmbrella();
2886 if ( childParent != NULL ) {
2887 if ( strcmp(childParent, &myLeaf[1]) == 0 ) {
2888 // set re-export bit of info
2889 std::map<ObjectFile::Reader*,DynamicLibraryOptions>::iterator pos = fDylibOptionsMap.find(reader);
2890 if ( pos != fDylibOptionsMap.end() ) {
2891 pos->second.fReExport = true;
2892 }
2893 }
2894 }
2895 }
2896 }
2897 }
2898
2899 }
2900
2901
2902
2903 void Linker::createReaders()
2904 {
2905 fStartCreateReadersTime = mach_absolute_time();
2906 std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
2907 const int count = files.size();
2908 if ( count == 0 )
2909 throw "no object files specified";
2910 // add all direct object, archives, and dylibs
2911 for (int i=0; i < count; ++i) {
2912 Options::FileInfo& entry = files[i];
2913 // ignore /usr/lib/dyld on command line in crt.o build
2914 if ( strcmp(entry.path, "/usr/lib/dyld") != 0 ) {
2915 try {
2916 this->addInputFile(this->createReader(entry), entry);
2917 }
2918 catch (const char* msg) {
2919 if ( strstr(msg, "architecture") != NULL ) {
2920 if ( fOptions.ignoreOtherArchInputFiles() ) {
2921 // ignore, because this is about an architecture not in use
2922 }
2923 else {
2924 fprintf(stderr, "ld: warning in %s, %s\n", entry.path, msg);
2925 }
2926 }
2927 else {
2928 throwf("in %s, %s", entry.path, msg);
2929 }
2930 }
2931 }
2932 }
2933
2934 this->processDylibs();
2935 }
2936
2937
2938
2939 ObjectFile::Reader* Linker::addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
2940 {
2941 fNextInputOrdinal += mappedLen;
2942 // remember which readers are archives because they are logged differently
2943 fArchiveReaders.insert(reader);
2944
2945 // update stats
2946 fTotalArchiveSize += mappedLen;
2947 ++fTotalArchivesLoaded;
2948 return reader;
2949 }
2950
2951 ObjectFile::Reader* Linker::addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
2952 {
2953 fNextInputOrdinal += mappedLen;
2954 // any .o files that don't have MH_SUBSECTIONS_VIA_SYMBOLS, that means a generated .o file can't
2955 if ( (fOptions.outputKind() == Options::kObjectFile) && !reader->canScatterAtoms() )
2956 fCanScatter = false;
2957
2958 // update stats
2959 fTotalObjectSize += mappedLen;
2960 ++fTotalObjectLoaded;
2961 return reader;
2962 }
2963
2964
2965 void Linker::checkDylibClientRestrictions(ObjectFile::Reader* reader)
2966 {
2967 // Check for any restrictions on who can link with this dylib
2968 const char* readerParentName = reader->parentUmbrella() ;
2969 std::vector<const char*>* clients = reader->getAllowableClients();
2970 if ( (readerParentName != NULL) || (clients != NULL) ) {
2971 // only dylibs that are in an umbrella or have a client list need verification
2972 const char* installName = fOptions.installPath();
2973 const char* installNameLastSlash = strrchr(installName, '/');
2974 bool isParent = false;
2975 bool isSibling = false;
2976 bool isAllowableClient = false;
2977 // There are three cases:
2978 if ( (readerParentName != NULL) && (installNameLastSlash != NULL) ) {
2979 // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
2980 isParent = ( strcmp(&installNameLastSlash[1], readerParentName) == 0 );
2981
2982 // hack to support umbrella variants that encode the variant name in the install name
2983 // e.g. CoreServices_profile
2984 if ( !isParent ) {
2985 const char* underscore = strchr(&installNameLastSlash[1], '_');
2986 if ( underscore != NULL ) {
2987 isParent = ( strncmp(&installNameLastSlash[1], readerParentName, underscore-installNameLastSlash-1) == 0 );
2988 }
2989 }
2990
2991 // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
2992 isSibling = ( (fOptions.umbrellaName() != NULL) && (strcmp(fOptions.umbrellaName(), readerParentName) == 0) );
2993 }
2994
2995 if ( !isParent && !isSibling && (clients != NULL) ) {
2996 // case 3) the dylib has a list of allowable clients, and we are creating one of them
2997 const char* clientName = fOptions.clientName();
2998 int clientNameLen = 0;
2999 if ( clientName != NULL ) {
3000 // use client name as specified on command line
3001 clientNameLen = strlen(clientName);
3002 }
3003 else {
3004 // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar)
3005 clientName = installName;
3006 clientNameLen = strlen(clientName);
3007 // starts after last slash
3008 if ( installNameLastSlash != NULL )
3009 clientName = &installNameLastSlash[1];
3010 if ( strncmp(clientName, "lib", 3) == 0 )
3011 clientName = &clientName[3];
3012 // up to first dot
3013 const char* firstDot = strchr(clientName, '.');
3014 if ( firstDot != NULL )
3015 clientNameLen = firstDot - clientName;
3016 // up to first underscore
3017 const char* firstUnderscore = strchr(clientName, '_');
3018 if ( (firstUnderscore != NULL) && ((firstUnderscore - clientName) < clientNameLen) )
3019 clientNameLen = firstUnderscore - clientName;
3020 }
3021
3022 // Use clientName to check if this dylib is able to link against the allowable clients.
3023 for (std::vector<const char*>::iterator it = clients->begin(); it != clients->end(); it++) {
3024 if ( strncmp(*it, clientName, clientNameLen) == 0 )
3025 isAllowableClient = true;
3026 }
3027 }
3028
3029 if ( !isParent && !isSibling && !isAllowableClient ) {
3030 if ( readerParentName != NULL ) {
3031 throwf("cannot link directly with %s. Link against the umbrella framework '%s.framework' instead.",
3032 reader->getPath(), readerParentName);
3033 }
3034 else {
3035 throwf("cannot link directly with %s", reader->getPath());
3036 }
3037 }
3038 }
3039
3040
3041 }
3042
3043 ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
3044 {
3045 fNextInputOrdinal += mappedLen;
3046 if ( (reader->getInstallPath() == NULL) && !info.options.fBundleLoader ) {
3047 // this is a "blank" stub
3048 // silently ignore it
3049 return reader;
3050 }
3051 // add to map of loaded dylibs
3052 const char* installPath = reader->getInstallPath();
3053 if ( installPath != NULL ) {
3054 InstallNameToReader::iterator pos = fDylibMap.find(installPath);
3055 if ( pos == fDylibMap.end() ) {
3056 fDylibMap[strdup(installPath)] = reader;
3057 }
3058 else {
3059 InstallNameToReader::iterator pos2 = fDylibMap.find(reader->getPath());
3060 if ( pos2 == fDylibMap.end() )
3061 fDylibMap[strdup(reader->getPath())] = reader;
3062 else
3063 fprintf(stderr, "ld: warning, duplicate dylib %s\n", reader->getPath());
3064 }
3065 }
3066 else if ( info.options.fBundleLoader )
3067 fBundleLoaderReader = reader;
3068
3069 // log direct readers
3070 if ( !fAllDirectDylibsLoaded )
3071 this->logDylib(reader, false);
3072
3073 // update stats
3074 ++fTotalDylibsLoaded;
3075
3076 return reader;
3077 }
3078
3079
3080 void Linker::logTraceInfo (const char* format, ...)
3081 {
3082 static int trace_file = -1;
3083 char trace_buffer[MAXPATHLEN * 2];
3084 char *buffer_ptr;
3085 int length;
3086 ssize_t amount_written;
3087 const char *trace_file_path = fOptions.readerOptions().fTraceOutputFile;
3088
3089 if(trace_file == -1) {
3090 if(trace_file_path != NULL) {
3091 trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
3092 if(trace_file == -1)
3093 throwf("Could not open or create trace file: %s\n", trace_file_path);
3094 }
3095 else {
3096 trace_file = fileno(stderr);
3097 }
3098 }
3099
3100 va_list ap;
3101 va_start(ap, format);
3102 length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap);
3103 va_end(ap);
3104 buffer_ptr = trace_buffer;
3105
3106 while(length > 0) {
3107 amount_written = write(trace_file, buffer_ptr, length);
3108 if(amount_written == -1)
3109 /* Failure to write shouldn't fail the build. */
3110 return;
3111 buffer_ptr += amount_written;
3112 length -= amount_written;
3113 }
3114 }
3115
3116
3117
3118 void Linker::createWriter()
3119 {
3120 fStartCreateWriterTime = mach_absolute_time();
3121
3122 // make a vector out of all required dylibs in fDylibMap
3123 std::vector<ExecutableFile::DyLibUsed> dynamicLibraries;
3124 // need to preserve command line order
3125 for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
3126 ObjectFile::Reader* reader = *it;
3127 for (InstallNameToReader::iterator mit=fDylibMap.begin(); mit != fDylibMap.end(); mit++) {
3128 if ( reader == mit->second ) {
3129 ExecutableFile::DyLibUsed dylibInfo;
3130 dylibInfo.reader = reader;
3131 dylibInfo.options = fDylibOptionsMap[reader];
3132 dynamicLibraries.push_back(dylibInfo);
3133 break;
3134 }
3135 }
3136 }
3137 // then add any other dylibs
3138 for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
3139 if ( it->second->implicitlyLinked() ) {
3140 // if not already in dynamicLibraries
3141 bool alreadyInDynamicLibraries = false;
3142 for (std::vector<ExecutableFile::DyLibUsed>::iterator dit=dynamicLibraries.begin(); dit != dynamicLibraries.end(); dit++) {
3143 if ( dit->reader == it->second ) {
3144 alreadyInDynamicLibraries = true;
3145 break;
3146 }
3147 }
3148 if ( ! alreadyInDynamicLibraries ) {
3149 ExecutableFile::DyLibUsed dylibInfo;
3150 dylibInfo.reader = it->second;
3151 std::map<ObjectFile::Reader*,DynamicLibraryOptions>::iterator pos = fDylibOptionsMap.find(it->second);
3152 if ( pos != fDylibOptionsMap.end() ) {
3153 dylibInfo.options = pos->second;
3154 }
3155 else {
3156 dylibInfo.options.fWeakImport = false; // FIX ME
3157 dylibInfo.options.fReExport = false;
3158 dylibInfo.options.fBundleLoader = false;
3159 }
3160 dynamicLibraries.push_back(dylibInfo);
3161 }
3162 }
3163 }
3164 if ( fBundleLoaderReader != NULL ) {
3165 ExecutableFile::DyLibUsed dylibInfo;
3166 dylibInfo.reader = fBundleLoaderReader;
3167 dylibInfo.options.fWeakImport = false;
3168 dylibInfo.options.fReExport = false;
3169 dylibInfo.options.fBundleLoader = true;
3170 dynamicLibraries.push_back(dylibInfo);
3171 }
3172
3173 const char* path = fOptions.getOutputFilePath();
3174 switch ( fArchitecture ) {
3175 case CPU_TYPE_POWERPC:
3176 this->setOutputFile(new mach_o::executable::Writer<ppc>(path, fOptions, dynamicLibraries));
3177 break;
3178 case CPU_TYPE_POWERPC64:
3179 this->setOutputFile(new mach_o::executable::Writer<ppc64>(path, fOptions, dynamicLibraries));
3180 break;
3181 case CPU_TYPE_I386:
3182 this->setOutputFile(new mach_o::executable::Writer<x86>(path, fOptions, dynamicLibraries));
3183 break;
3184 case CPU_TYPE_X86_64:
3185 this->setOutputFile(new mach_o::executable::Writer<x86_64>(path, fOptions, dynamicLibraries));
3186 break;
3187 default:
3188 throw "unknown architecture";
3189 }
3190 }
3191
3192
3193 Linker::SymbolTable::SymbolTable(Linker& owner)
3194 : fOwner(owner), fRequireCount(0)
3195 {
3196 }
3197
3198 void Linker::SymbolTable::require(const char* name)
3199 {
3200 //fprintf(stderr, "require(%s)\n", name);
3201 Mapper::iterator pos = fTable.find(name);
3202 if ( pos == fTable.end() ) {
3203 fTable[name] = NULL;
3204 ++fRequireCount;
3205 }
3206 }
3207
3208 // convenience labels for 2-dimensional switch statement
3209 enum AllDefinitionCombinations {
3210 kRegAndReg = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
3211 kRegAndWeak = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
3212 kRegAndTent = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
3213 kRegAndExtern = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
3214 kRegAndExternWeak = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
3215 kRegAndAbsolute = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol,
3216 kWeakAndReg = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
3217 kWeakAndWeak = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
3218 kWeakAndTent = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
3219 kWeakAndExtern = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
3220 kWeakAndExternWeak = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
3221 kWeakAndAbsolute = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol,
3222 kTentAndReg = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
3223 kTentAndWeak = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
3224 kTentAndTent = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
3225 kTentAndExtern = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
3226 kTentAndExternWeak = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
3227 kTentAndAbsolute = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol,
3228 kExternAndReg = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
3229 kExternAndWeak = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
3230 kExternAndTent = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
3231 kExternAndExtern = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
3232 kExternAndExternWeak = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
3233 kExternAndAbsolute = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol,
3234 kExternWeakAndReg = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
3235 kExternWeakAndWeak = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
3236 kExternWeakAndTent = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
3237 kExternWeakAndExtern = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
3238 kExternWeakAndExternWeak= (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
3239 kExternWeakAndAbsolute = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol,
3240 kAbsoluteAndReg = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kRegularDefinition,
3241 kAbsoluteAndWeak = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kWeakDefinition,
3242 kAbsoluteAndTent = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kTentativeDefinition,
3243 kAbsoluteAndExtern = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kExternalDefinition,
3244 kAbsoluteAndExternWeak = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kExternalWeakDefinition,
3245 kAbsoluteAndAbsolute = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kAbsoluteSymbol
3246 };
3247
3248 bool Linker::SymbolTable::add(ObjectFile::Atom& newAtom)
3249 {
3250 bool useNew = true;
3251 const char* name = newAtom.getName();
3252 //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
3253 Mapper::iterator pos = fTable.find(name);
3254 ObjectFile::Atom* existingAtom = NULL;
3255 if ( pos != fTable.end() )
3256 existingAtom = pos->second;
3257 if ( existingAtom != NULL ) {
3258 // already have atom with same name in symbol table
3259 switch ( (AllDefinitionCombinations)((existingAtom->getDefinitionKind() << 3) | newAtom.getDefinitionKind()) ) {
3260 case kRegAndReg:
3261 throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
3262 case kRegAndWeak:
3263 // ignore new weak atom, because we already have a non-weak one
3264 useNew = false;
3265 break;
3266 case kRegAndTent:
3267 // ignore new tentative atom, because we already have a regular one
3268 useNew = false;
3269 if ( newAtom.getSize() > existingAtom->getSize() ) {
3270 fprintf(stderr, "ld: warning for symbol %s tentative definition of size %llu from %s is "
3271 "is smaller than the real definition of size %llu from %s\n",
3272 newAtom.getDisplayName(), newAtom.getSize(), newAtom.getFile()->getPath(),
3273 existingAtom->getSize(), existingAtom->getFile()->getPath());
3274 }
3275 break;
3276 case kRegAndExtern:
3277 // ignore external atom, because we already have a one
3278 useNew = false;
3279 break;
3280 case kRegAndExternWeak:
3281 // ignore external atom, because we already have a one
3282 useNew = false;
3283 break;
3284 case kRegAndAbsolute:
3285 throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
3286 break;
3287 case kWeakAndReg:
3288 // replace existing weak atom with regular one
3289 break;
3290 case kWeakAndWeak:
3291 // have another weak atom, use whichever has largest alignment requirement
3292 // because codegen of some client may require alignment
3293 useNew = ( newAtom.getAlignment().trailingZeros() > existingAtom->getAlignment().trailingZeros() );
3294 break;
3295 case kWeakAndTent:
3296 // replace existing weak atom with tentative one ???
3297 break;
3298 case kWeakAndExtern:
3299 // keep weak atom, at runtime external one may override
3300 useNew = false;
3301 break;
3302 case kWeakAndExternWeak:
3303 // keep weak atom, at runtime external one may override
3304 useNew = false;
3305 break;
3306 case kWeakAndAbsolute:
3307 // replace existing weak atom with absolute one
3308 break;
3309 case kTentAndReg:
3310 // replace existing tentative atom with regular one
3311 if ( newAtom.getSize() < existingAtom->getSize() ) {
3312 fprintf(stderr, "ld: warning for symbol %s tentative definition of size %llu from %s is "
3313 "being replaced by a real definition of size %llu from %s\n",
3314 newAtom.getDisplayName(), existingAtom->getSize(), existingAtom->getFile()->getPath(),
3315 newAtom.getSize(), newAtom.getFile()->getPath());
3316 }
3317 break;
3318 case kTentAndWeak:
3319 // replace existing tentative atom with weak one ???
3320 break;
3321 case kTentAndTent:
3322 // use largest
3323 if ( newAtom.getSize() < existingAtom->getSize() ) {
3324 useNew = false;
3325 }
3326 else {
3327 if ( newAtom.getAlignment().trailingZeros() < existingAtom->getAlignment().trailingZeros() )
3328 fprintf(stderr, "ld: warning alignment lost in merging tentative definition %s\n", newAtom.getDisplayName());
3329 }
3330 break;
3331 case kTentAndExtern:
3332 case kTentAndExternWeak:
3333 // a tentative definition and a dylib definition, so commons-mode decides how to handle
3334 switch ( fOwner.fOptions.commonsMode() ) {
3335 case Options::kCommonsIgnoreDylibs:
3336 if ( fOwner.fOptions.warnCommons() )
3337 fprintf(stderr, "ld: using common symbol %s from %s and ignoring defintion from dylib %s\n",
3338 existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
3339 useNew = false;
3340 break;
3341 case Options::kCommonsOverriddenByDylibs:
3342 if ( fOwner.fOptions.warnCommons() )
3343 fprintf(stderr, "ld: replacing common symbol %s from %s with true definition from dylib %s\n",
3344 existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
3345 break;
3346 case Options::kCommonsConflictsDylibsError:
3347 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
3348 existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
3349 }
3350 break;
3351 case kTentAndAbsolute:
3352 // replace tentative with absolute (can't size check because absolutes have no size)
3353 break;
3354 case kExternAndReg:
3355 // replace external atom with regular one
3356 break;
3357 case kExternAndWeak:
3358 // replace external atom with weak one
3359 break;
3360 case kExternAndTent:
3361 // a tentative definition and a dylib definition, so commons-mode decides how to handle
3362 switch ( fOwner.fOptions.commonsMode() ) {
3363 case Options::kCommonsIgnoreDylibs:
3364 if ( fOwner.fOptions.warnCommons() )
3365 fprintf(stderr, "ld: using common symbol %s from %s and ignoring defintion from dylib %s\n",
3366 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
3367 break;
3368 case Options::kCommonsOverriddenByDylibs:
3369 if ( fOwner.fOptions.warnCommons() )
3370 fprintf(stderr, "ld: replacing defintion of %s from dylib %s with common symbol from %s\n",
3371 newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
3372 useNew = false;
3373 break;
3374 case Options::kCommonsConflictsDylibsError:
3375 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
3376 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
3377 }
3378 break;
3379 case kExternAndExtern:
3380 throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
3381 case kExternAndExternWeak:
3382 // keep strong dylib atom, ignore weak one
3383 useNew = false;
3384 break;
3385 case kExternAndAbsolute:
3386 // replace external atom with absolute one
3387 break;
3388 case kExternWeakAndReg:
3389 // replace existing weak external with regular
3390 break;
3391 case kExternWeakAndWeak:
3392 // replace existing weak external with weak (let dyld decide at runtime which to use)
3393 break;
3394 case kExternWeakAndTent:
3395 // a tentative definition and a dylib definition, so commons-mode decides how to handle
3396 switch ( fOwner.fOptions.commonsMode() ) {
3397 case Options::kCommonsIgnoreDylibs:
3398 if ( fOwner.fOptions.warnCommons() )
3399 fprintf(stderr, "ld: using common symbol %s from %s and ignoring defintion from dylib %s\n",
3400 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
3401 break;
3402 case Options::kCommonsOverriddenByDylibs:
3403 if ( fOwner.fOptions.warnCommons() )
3404 fprintf(stderr, "ld: replacing defintion of %s from dylib %s with common symbol from %s\n",
3405 newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
3406 useNew = false;
3407 break;
3408 case Options::kCommonsConflictsDylibsError:
3409 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
3410 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
3411 }
3412 break;
3413 case kExternWeakAndExtern:
3414 // replace existing weak external with external
3415 break;
3416 case kExternWeakAndExternWeak:
3417 // keep existing external weak
3418 useNew = false;
3419 break;
3420 case kExternWeakAndAbsolute:
3421 // replace existing weak external with absolute
3422 break;
3423 case kAbsoluteAndReg:
3424 throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
3425 case kAbsoluteAndWeak:
3426 // ignore new weak atom, because we already have a non-weak one
3427 useNew = false;
3428 break;
3429 case kAbsoluteAndTent:
3430 // ignore new tentative atom, because we already have a regular one
3431 useNew = false;
3432 break;
3433 case kAbsoluteAndExtern:
3434 // ignore external atom, because we already have a one
3435 useNew = false;
3436 break;
3437 case kAbsoluteAndExternWeak:
3438 // ignore external atom, because we already have a one
3439 useNew = false;
3440 break;
3441 case kAbsoluteAndAbsolute:
3442 throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
3443 break;
3444 }
3445 }
3446 if ( (existingAtom != NULL) && (newAtom.getScope() != existingAtom->getScope()) ) {
3447 fprintf(stderr, "ld: warning %s has different visibility (%d) in %s and (%d) in %s\n",
3448 newAtom.getDisplayName(), newAtom.getScope(), newAtom.getFile()->getPath(), existingAtom->getScope(), existingAtom->getFile()->getPath());
3449 }
3450 if ( useNew ) {
3451 fTable[name] = &newAtom;
3452 if ( existingAtom != NULL )
3453 fOwner.fDeadAtoms.insert(existingAtom);
3454 }
3455 else {
3456 fOwner.fDeadAtoms.insert(&newAtom);
3457 }
3458 return useNew;
3459 }
3460
3461
3462
3463 ObjectFile::Atom* Linker::SymbolTable::find(const char* name)
3464 {
3465 Mapper::iterator pos = fTable.find(name);
3466 if ( pos != fTable.end() ) {
3467 return pos->second;
3468 }
3469 return NULL;
3470 }
3471
3472
3473 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines)
3474 {
3475 for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) {
3476 if ( (it->second == NULL) || (andWeakDefintions && (it->second->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition)) ) {
3477 undefines.push_back(it->first);
3478 }
3479 }
3480 }
3481
3482
3483
3484
3485 bool Linker::AtomSorter::operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right)
3486 {
3487 if ( left == right )
3488 return false;
3489
3490 // first sort by section order (which is already sorted by segment)
3491 unsigned int leftSectionIndex = left->getSection()->getIndex();
3492 unsigned int rightSectionIndex = right->getSection()->getIndex();
3493 if ( leftSectionIndex != rightSectionIndex)
3494 return (leftSectionIndex < rightSectionIndex);
3495
3496 // if a -order_file is specified, then sorting is altered to sort those symbols first
3497 if ( fOverriddenOrdinalMap != NULL ) {
3498 std::map<const ObjectFile::Atom*, uint32_t>::iterator leftPos = fOverriddenOrdinalMap->find(left);
3499 std::map<const ObjectFile::Atom*, uint32_t>::iterator rightPos = fOverriddenOrdinalMap->find(right);
3500 std::map<const ObjectFile::Atom*, uint32_t>::iterator end = fOverriddenOrdinalMap->end();
3501 if ( leftPos != end ) {
3502 if ( rightPos != end ) {
3503 // both left and right are overridden, so compare overridden ordinals
3504 return leftPos->second < rightPos->second;
3505 }
3506 else {
3507 // left is overridden and right is not, so left < right
3508 return true;
3509 }
3510 }
3511 else {
3512 if ( rightPos != end ) {
3513 // right is overridden and left is not, so right < left
3514 return false;
3515 }
3516 else {
3517 // neither are overridden, do default sort
3518 // fall into default sorting below
3519 }
3520 }
3521 }
3522
3523 // the __common section can have real or tentative definitions
3524 // we want the real ones to sort before tentative ones
3525 bool leftIsTent = (left->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition);
3526 bool rightIsTent = (right->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition);
3527 if ( leftIsTent != rightIsTent )
3528 return rightIsTent;
3529
3530 // lastly sort by atom ordinal. this is already sorted by .o order
3531 return left->getOrdinal() < right->getOrdinal();
3532 }
3533
3534
3535 int main(int argc, const char* argv[])
3536 {
3537 const char* archName = NULL;
3538 bool showArch = false;
3539 bool archInferred = false;
3540 try {
3541 // create linker object given command line arguments
3542 Linker ld(argc, argv);
3543
3544 // save error message prefix
3545 archName = ld.architectureName();
3546 archInferred = ld.isInferredArchitecture();
3547 showArch = ld.showArchitectureInErrors();
3548
3549 // open all input files
3550 ld.createReaders();
3551
3552 // open output file
3553 ld.createWriter();
3554
3555 // do linking
3556 ld.link();
3557 }
3558 catch (const char* msg) {
3559 if ( archInferred )
3560 fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName);
3561 else if ( showArch )
3562 fprintf(stderr, "ld: %s for architecture %s\n", msg, archName);
3563 else
3564 fprintf(stderr, "ld: %s\n", msg);
3565 return 1;
3566 }
3567
3568 return 0;
3569 }