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