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