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