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