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