]> git.saurik.com Git - apple/ld64.git/blob - src/ld.cpp
e98df10b0c335dd3f1cad8fcbafbb85d8bb543be
[apple/ld64.git] / src / ld.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <sys/sysctl.h>
29 #include <fcntl.h>
30 #include <errno.h>
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>
36 #include <mach-o/fat.h>
37
38
39 #include <string>
40 #include <set>
41 #include <string>
42 #include <vector>
43 #include <list>
44 #include <algorithm>
45 #include <ext/hash_map>
46
47 #include "Options.h"
48
49 #include "ObjectFile.h"
50
51 #include "MachOReaderRelocatable.hpp"
52 #include "MachOReaderArchive.hpp"
53 #include "MachOReaderDylib.hpp"
54 #include "MachOWriterExecutable.hpp"
55
56 #include "SectCreate.h"
57
58 #if 0
59 static void dumpAtom(ObjectFile::Atom* atom)
60 {
61 //printf("atom: %p\n", atom);
62
63 // name
64 printf("name: %s\n", atom->getDisplayName());
65
66 // scope
67 switch ( atom->getScope() ) {
68 case ObjectFile::Atom::scopeTranslationUnit:
69 printf("scope: translation unit\n");
70 break;
71 case ObjectFile::Atom::scopeLinkageUnit:
72 printf("scope: linkage unit\n");
73 break;
74 case ObjectFile::Atom::scopeGlobal:
75 printf("scope: global\n");
76 break;
77 default:
78 printf("scope: unknown\n");
79 }
80
81 // kind
82 switch ( atom->getDefinitinonKind() ) {
83 case ObjectFile::Atom::kRegularDefinition:
84 printf("kind: regular\n");
85 break;
86 case ObjectFile::Atom::kWeakDefinition:
87 printf("kind: weak\n");
88 break;
89 case ObjectFile::Atom::kTentativeDefinition:
90 printf("kind: tentative\n");
91 break;
92 case ObjectFile::Atom::kExternalDefinition:
93 printf("kind: import\n");
94 break;
95 case ObjectFile::Atom::kExternalWeakDefinition:
96 printf("kind: weak import\n");
97 break;
98 default:
99 printf("scope: unknown\n");
100 }
101
102 // segment and section
103 printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
104
105 // attributes
106 printf("attrs: ");
107 if ( atom->dontDeadStrip() )
108 printf("dont-dead-strip ");
109 if ( atom->isZeroFill() )
110 printf("zero-fill ");
111 printf("\n");
112
113 // size
114 printf("size: 0x%012llX\n", atom->getSize());
115
116 // content
117 uint8_t content[atom->getSize()];
118 atom->copyRawContent(content);
119 printf("content: ");
120 if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
121 printf("\"%s\"", content);
122 }
123 else {
124 for (unsigned int i=0; i < sizeof(content); ++i)
125 printf("%02X ", content[i]);
126 }
127 printf("\n");
128
129 // references
130 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
131 const int refCount = references.size();
132 printf("references: (%u)\n", refCount);
133 for (int i=0; i < refCount; ++i) {
134 ObjectFile::Reference* ref = references[i];
135 printf(" %s\n", ref->getDescription());
136 }
137
138 // attributes
139
140 }
141
142 #endif
143
144 class CStringComparor
145 {
146 public:
147 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
148 };
149
150 class CStringEquals
151 {
152 public:
153 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
154 };
155
156 class Section : public ObjectFile::Section
157 {
158 public:
159 static Section* find(const char* sectionName, const char* segmentName, bool zeroFill);
160 static void assignIndexes();
161
162 private:
163 Section(const char* sectionName, const char* segmentName, bool zeroFill);
164
165 struct Sorter {
166 static int segmentOrdinal(const char* segName);
167 bool operator()(Section* left, Section* right);
168 };
169
170 typedef __gnu_cxx::hash_map<const char*, class Section*, __gnu_cxx::hash<const char*>, CStringEquals> NameToSection;
171 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
172
173 const char* fSectionName;
174 const char* fSegmentName;
175 bool fZeroFill;
176
177 static NameToSection fgMapping;
178 static std::vector<Section*> fgSections;
179 };
180
181 Section::NameToSection Section::fgMapping;
182 std::vector<Section*> Section::fgSections;
183
184 Section::Section(const char* sectionName, const char* segmentName, bool zeroFill)
185 : fSectionName(sectionName), fSegmentName(segmentName), fZeroFill(zeroFill)
186 {
187 //fprintf(stderr, "new Section(%s, %s)\n", sectionName, segmentName);
188 }
189
190 Section* Section::find(const char* sectionName, const char* segmentName, bool zeroFill)
191 {
192 NameToSection::iterator pos = fgMapping.find(sectionName);
193 if ( pos != fgMapping.end() ) {
194 if ( strcmp(pos->second->fSegmentName, segmentName) == 0 )
195 return pos->second;
196 // otherwise same section name is used in different segments, look slow way
197 for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
198 if ( (strcmp((*it)->fSectionName, sectionName) == 0) && (strcmp((*it)->fSegmentName, segmentName) == 0) )
199 return *it;
200 }
201 }
202
203 // does not exist, so make a new one
204 Section* sect = new Section(sectionName, segmentName, zeroFill);
205 sect->fIndex = fgMapping.size();
206 fgMapping[sectionName] = sect;
207 fgSections.push_back(sect);
208
209 if ( (strcmp(sectionName, "__text") == 0) && (strcmp(segmentName, "__TEXT") == 0) ) {
210 // special case __textcoal_nt to be right after __text
211 find("__textcoal_nt", "__TEXT", false);
212 }
213
214 return sect;
215 }
216
217 int Section::Sorter::segmentOrdinal(const char* segName)
218 {
219 if ( strcmp(segName, "__PAGEZERO") == 0 )
220 return 1;
221 if ( strcmp(segName, "__TEXT") == 0 )
222 return 2;
223 if ( strcmp(segName, "__DATA") == 0 )
224 return 3;
225 if ( strcmp(segName, "__OBJC") == 0 )
226 return 4;
227 if ( strcmp(segName, "__LINKEDIT") == 0 )
228 return INT_MAX; // linkedit segment should always sort last
229 else
230 return 5;
231 }
232
233
234 bool Section::Sorter::operator()(Section* left, Section* right)
235 {
236 // Segment is primary sort key
237 const char* leftSegName = left->fSegmentName;
238 const char* rightSegName = right->fSegmentName;
239 int segNameCmp = strcmp(leftSegName, rightSegName);
240 if ( segNameCmp != 0 )
241 {
242 int leftSegOrdinal = segmentOrdinal(leftSegName);
243 int rightSegOrdinal = segmentOrdinal(rightSegName);
244 if ( leftSegOrdinal < rightSegOrdinal )
245 return true;
246 if ( leftSegOrdinal == rightSegOrdinal )
247 return segNameCmp < 0;
248 return false;
249 }
250
251 // zerofill section sort to the end
252 if ( !left->fZeroFill && right->fZeroFill )
253 return true;
254 if ( left->fZeroFill && !right->fZeroFill )
255 return false;
256
257 // section discovery order is last sort key
258 return left->fIndex < right->fIndex;
259 }
260
261 void Section::assignIndexes()
262 {
263 //printf("unsorted:\n");
264 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
265 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
266 //}
267
268 // sort it
269 std::sort(fgSections.begin(), fgSections.end(), Section::Sorter());
270
271 // assign correct section ordering to each Section object
272 unsigned int newOrder = 1;
273 for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++)
274 (*it)->fIndex = newOrder++;
275
276 //printf("sorted:\n");
277 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
278 // printf("section: name=%s\n", (*it)->fSectionName);
279 //}
280 }
281
282 class Linker {
283 public:
284 Linker(int argc, const char* argv[]);
285
286 void createReaders();
287 void createWriter();
288 void addInputFile(ObjectFile::Reader* reader);
289 void setOutputFile(ExecutableFile::Writer* writer);
290 void link();
291
292
293 private:
294 ObjectFile::Reader* createReader(const Options::FileInfo&);
295 void addAtom(ObjectFile::Atom& atom);
296 void addAtoms(std::vector<class ObjectFile::Atom*>& atoms);
297 void buildAtomList();
298 void loadUndefines();
299 void addWeakAtomOverrides();
300 void resolveReferences();
301 void deadStrip();
302 void sortAtoms();
303 void tweakLayout();
304 void writeDotOutput();
305 static bool minimizeStab(ObjectFile::Reader::Stab& stab);
306 static const char* truncateStabString(const char* str);
307 void collectStabs();
308 void writeOutput();
309 ObjectFile::Atom* entryPoint();
310 ObjectFile::Atom* dyldHelper();
311 const char* assureFullPath(const char* path);
312 void markLive(ObjectFile::Atom* atom, std::set<ObjectFile::Atom*>& liveAtoms);
313 void collectStabs(ObjectFile::Reader* reader);
314 void synthesizeStabs(ObjectFile::Reader* reader);
315 void printStatistics();
316 void printTime(const char* msg, uint64_t partTime, uint64_t totalTime);
317 char* commatize(uint64_t in, char* out);
318 void getVMInfo(vm_statistics_data_t& info);
319 cpu_type_t inferArchitecture();
320
321 void resolve(ObjectFile::Reference* reference);
322 void resolveFrom(ObjectFile::Reference* reference);
323 void addJustInTimeAtoms(const char* name);
324
325 ObjectFile::Reader* addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
326 ObjectFile::Reader* addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
327 ObjectFile::Reader* addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
328 void addIndirectLibraries(ObjectFile::Reader* reader);
329 bool haveIndirectLibrary(const char* path, ObjectFile::Reader* reader);
330 bool haveDirectLibrary(const char* path);
331
332 void logTraceInfo(const char* format, ...);
333 class SymbolTable
334 {
335 public:
336 SymbolTable(Linker&);
337 void require(const char* name);
338 bool add(ObjectFile::Atom& atom);
339 ObjectFile::Atom* find(const char* name);
340 unsigned int getRequireCount() { return fRequireCount; }
341 void getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines);
342 private:
343 typedef __gnu_cxx::hash_map<const char*, ObjectFile::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> Mapper;
344 Linker& fOwner;
345 Mapper fTable;
346 unsigned int fRequireCount;
347 };
348
349 struct AtomSorter
350 {
351 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right);
352 };
353
354 typedef std::map<const char*, uint32_t, CStringComparor> SectionOrder;
355
356 struct IndirectLibrary {
357 const char* path;
358 uint64_t fileLen;
359 ObjectFile::Reader* reader;
360 std::set<ObjectFile::Reader*> parents;
361 ObjectFile::Reader* reExportedViaDirectLibrary;
362 };
363
364 ObjectFile::Reader* findDirectLibraryWhichReExports(struct IndirectLibrary& indirectLib);
365
366 Options fOptions;
367 SymbolTable fGlobalSymbolTable;
368 unsigned int fWeakSymbolsAddedCount;
369 std::vector<class ObjectFile::Reader*> fInputFiles;
370 ExecutableFile::Writer* fOutputFile;
371 std::vector<ExecutableFile::DyLibUsed> fDynamicLibraries;
372 std::list<IndirectLibrary> fIndirectDynamicLibraries;
373 std::vector<class ObjectFile::Reader*> fReadersThatHaveSuppliedAtoms;
374 std::vector<class ObjectFile::Atom*> fAllAtoms;
375 std::set<class ObjectFile::Atom*> fDeadAtoms;
376 std::vector<class ObjectFile::Reader::Stab> fStabs;
377 bool fCreateUUID;
378 SectionOrder fSectionOrder;
379 unsigned int fNextSortOrder;
380 unsigned int fNextObjectFileOrder;
381 cpu_type_t fArchitecture;
382 bool fDirectLibrariesComplete;
383 uint64_t fOutputFileSize;
384 uint64_t fStartTime;
385 uint64_t fStartCreateReadersTime;
386 uint64_t fStartCreateWriterTime;
387 uint64_t fStartBuildAtomsTime;
388 uint64_t fStartLoadUndefinesTime;
389 uint64_t fStartResolveTime;
390 uint64_t fStartSortTime;
391 uint64_t fStartWriteTime;
392 uint64_t fEndTime;
393 uint64_t fTotalObjectSize;
394 uint64_t fTotalArchiveSize;
395 uint32_t fTotalObjectLoaded;
396 uint32_t fTotalArchivesLoaded;
397 uint32_t fTotalDylibsLoaded;
398 vm_statistics_data_t fStartVMInfo;
399 };
400
401
402 Linker::Linker(int argc, const char* argv[])
403 : fOptions(argc, argv), fGlobalSymbolTable(*this), fOutputFile(NULL), fCreateUUID(false), fNextSortOrder(1),
404 fNextObjectFileOrder(1), fArchitecture(0), fDirectLibrariesComplete(false), fOutputFileSize(0), fTotalObjectSize(0),
405 fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0)
406 {
407 fStartTime = mach_absolute_time();
408 if ( fOptions.printStatistics() )
409 getVMInfo(fStartVMInfo);
410
411 fArchitecture = fOptions.architecture();
412 if ( fArchitecture == 0 ) {
413 // -arch not specified, scan .o files to figure out what it should be
414 fArchitecture = inferArchitecture();
415 }
416 }
417
418 cpu_type_t Linker::inferArchitecture()
419 {
420 // scan all input files, looking for a thin .o file.
421 // the first one found is presumably the architecture to link
422 uint8_t buffer[sizeof(mach_header_64)];
423 std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
424 for (std::vector<Options::FileInfo>::iterator it = files.begin(); it != files.end(); ++it) {
425 int fd = ::open(it->path, O_RDONLY, 0);
426 if ( fd != -1 ) {
427 ssize_t amount = read(fd, buffer, sizeof(buffer));
428 ::close(fd);
429 if ( amount >= (ssize_t)sizeof(buffer) ) {
430 if ( mach_o::relocatable::Reader<ppc>::validFile(buffer) ) {
431 fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc based on %s\n", it->path);
432 return CPU_TYPE_POWERPC;
433 }
434 else if ( mach_o::relocatable::Reader<ppc64>::validFile(buffer) ) {
435 fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc64 based on %s\n", it->path);
436 return CPU_TYPE_POWERPC64;
437 }
438 else if ( mach_o::relocatable::Reader<x86>::validFile(buffer) ) {
439 fprintf(stderr, "ld64 warning: -arch not used, infering -arch i386 based on %s\n", it->path);
440 return CPU_TYPE_I386;
441 }
442 }
443 }
444 }
445
446 // no thin .o files found, so default to same architecture this was built as
447 fprintf(stderr, "ld64 warning: -arch not specified\n");
448 #if __ppc__
449 return CPU_TYPE_POWERPC;
450 #elif __i386__
451 return CPU_TYPE_I386;
452 #elif __ppc64__
453 return CPU_TYPE_POWERPC64;
454 #else
455 #error unknown default architecture
456 #endif
457 }
458
459
460 void Linker::addInputFile(ObjectFile::Reader* reader)
461 {
462 reader->setSortOrder(fNextObjectFileOrder++);
463 fInputFiles.push_back(reader);
464 }
465
466 void Linker::setOutputFile(ExecutableFile::Writer* writer)
467 {
468 fOutputFile = writer;
469 }
470
471 void Linker::link()
472 {
473 this->buildAtomList();
474 this->loadUndefines();
475 this->resolveReferences();
476 this->deadStrip();
477 this->sortAtoms();
478 this->tweakLayout();
479 this->writeDotOutput();
480 this->collectStabs();
481 this->writeOutput();
482 this->printStatistics();
483
484 if ( fOptions.pauseAtEnd() )
485 sleep(10);
486 }
487
488 void Linker::printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
489 {
490 static uint64_t sUnitsPerSecond = 0;
491 if ( sUnitsPerSecond == 0 ) {
492 struct mach_timebase_info timeBaseInfo;
493 if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
494 sUnitsPerSecond = 1000000000LL * timeBaseInfo.denom / timeBaseInfo.numer;
495 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
496 }
497 }
498 if ( partTime < sUnitsPerSecond ) {
499 uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
500 uint32_t milliSeconds = milliSecondsTimeTen/10;
501 uint32_t percentTimesTen = (partTime*1000)/totalTime;
502 uint32_t percent = percentTimesTen/10;
503 fprintf(stderr, "%s: %u.%u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
504 }
505 else {
506 uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
507 uint32_t seconds = secondsTimeTen/10;
508 uint32_t percentTimesTen = (partTime*1000)/totalTime;
509 uint32_t percent = percentTimesTen/10;
510 fprintf(stderr, "%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
511 }
512 }
513
514 char* Linker::commatize(uint64_t in, char* out)
515 {
516 char* result = out;
517 char rawNum[30];
518 sprintf(rawNum, "%llu", in);
519 const int rawNumLen = strlen(rawNum);
520 for(int i=0; i < rawNumLen-1; ++i) {
521 *out++ = rawNum[i];
522 if ( ((rawNumLen-i) % 3) == 1 )
523 *out++ = ',';
524 }
525 *out++ = rawNum[rawNumLen-1];
526 *out = '\0';
527 return result;
528 }
529
530 void Linker::getVMInfo(vm_statistics_data_t& info)
531 {
532 mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t);
533 kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO,
534 (host_info_t)&info, &count);
535 if (error != KERN_SUCCESS) {
536 bzero(&info, sizeof(vm_statistics_data_t));
537 }
538 }
539
540 void Linker::printStatistics()
541 {
542 fEndTime = mach_absolute_time();
543 if ( fOptions.printStatistics() ) {
544 vm_statistics_data_t endVMInfo;
545 getVMInfo(endVMInfo);
546
547 uint64_t totalTime = fEndTime - fStartTime;
548 printTime("ld64 total time", totalTime, totalTime);
549 printTime(" option parsing time", fStartCreateReadersTime - fStartTime, totalTime);
550 printTime(" object file processing",fStartCreateWriterTime - fStartCreateReadersTime, totalTime);
551 printTime(" output file setup", fStartBuildAtomsTime - fStartCreateWriterTime, totalTime);
552 printTime(" build atom list", fStartLoadUndefinesTime - fStartBuildAtomsTime, totalTime);
553 printTime(" load undefines", fStartResolveTime - fStartLoadUndefinesTime, totalTime);
554 printTime(" resolve references", fStartSortTime - fStartResolveTime, totalTime);
555 printTime(" sort output", fStartWriteTime - fStartSortTime, totalTime);
556 printTime(" write output", fEndTime - fStartWriteTime, totalTime);
557 fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo.pageins-fStartVMInfo.pageins,
558 endVMInfo.pageouts-fStartVMInfo.pageouts, endVMInfo.faults-fStartVMInfo.faults);
559 char temp[40];
560 fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded, commatize(fTotalObjectSize, temp));
561 fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded, commatize(fTotalArchiveSize, temp));
562 fprintf(stderr, "processed %3u dylib files\n", fTotalDylibsLoaded);
563 fprintf(stderr, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize, temp));
564 }
565 }
566
567 inline void Linker::addAtom(ObjectFile::Atom& atom)
568 {
569 // add to list of all atoms
570 fAllAtoms.push_back(&atom);
571
572 // add atom's references's names to symbol table as to-be-resolved-later
573 std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
574 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
575 ObjectFile::Reference* reference = *it;
576 if ( reference->isTargetUnbound() ) {
577 fGlobalSymbolTable.require(reference->getTargetName());
578 }
579 if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
580 fGlobalSymbolTable.require(reference->getFromTargetName());
581 }
582
583 // if in global namespace, add atom itself to symbol table
584 ObjectFile::Atom::Scope scope = atom.getScope();
585 const char* name = atom.getName();
586 if ( (scope != ObjectFile::Atom::scopeTranslationUnit) && (name != NULL) ) {
587 fGlobalSymbolTable.add(atom);
588
589 // update scope based on export list (possible that globals are downgraded to private_extern)
590 if ( (scope == ObjectFile::Atom::scopeGlobal) && fOptions.hasExportRestrictList() ) {
591 bool doExport = fOptions.shouldExport(name);
592 if ( !doExport ) {
593 atom.setScope(ObjectFile::Atom::scopeLinkageUnit);
594 }
595 }
596 }
597
598 // record section orders so output file can have same order
599 atom.setSection(Section::find(atom.getSectionName(), atom.getSegment().getName(), atom.isZeroFill()));
600
601 // assign order in which this atom was originally seen
602 if ( atom.getSortOrder() == 0 )
603 fNextSortOrder = atom.setSortOrder(fNextSortOrder);
604 }
605
606 inline void Linker::addAtoms(std::vector<class ObjectFile::Atom*>& atoms)
607 {
608 bool first = true; // assume all atoms are from same reader
609 for (std::vector<ObjectFile::Atom*>::iterator it=atoms.begin(); it != atoms.end(); it++) {
610 if ( first ) {
611 // update fReadersThatHaveSuppliedAtoms
612 ObjectFile::Reader* reader = (*it)->getFile();
613 if ( std::find(fReadersThatHaveSuppliedAtoms.begin(), fReadersThatHaveSuppliedAtoms.end(), reader)
614 == fReadersThatHaveSuppliedAtoms.end() ) {
615 fReadersThatHaveSuppliedAtoms.push_back(reader);
616 }
617 }
618 this->addAtom(**it);
619 first = false;
620 }
621 }
622
623 void Linker::buildAtomList()
624 {
625 fStartBuildAtomsTime = mach_absolute_time();
626 // add initial undefines from -u option
627 std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
628 for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++) {
629 fGlobalSymbolTable.require(*it);
630 }
631
632 // writer can contribute atoms
633 this->addAtoms(fOutputFile->getAtoms());
634
635 // each reader contributes atoms
636 const int readerCount = fInputFiles.size();
637 for (int i=0; i < readerCount; ++i) {
638 this->addAtoms(fInputFiles[i]->getAtoms());
639 }
640
641 // extra command line section always at end
642 std::vector<Options::ExtraSection>& extraSections = fOptions.extraSections();
643 for( std::vector<Options::ExtraSection>::iterator it=extraSections.begin(); it != extraSections.end(); ++it) {
644 this->addAtoms(SectCreate::MakeReader(it->segmentName, it->sectionName, it->path, it->data, it->dataLen)->getAtoms());
645 }
646 }
647
648 static const char* pathLeafName(const char* path)
649 {
650 const char* shortPath = strrchr(path, '/');
651 if ( shortPath == NULL )
652 return path;
653 else
654 return &shortPath[1];
655 }
656
657 void Linker::loadUndefines()
658 {
659 fStartLoadUndefinesTime = mach_absolute_time();
660 // keep looping until no more undefines were added in last loop
661 unsigned int undefineCount = 0xFFFFFFFF;
662 while ( undefineCount != fGlobalSymbolTable.getRequireCount() ) {
663 undefineCount = fGlobalSymbolTable.getRequireCount();
664 std::vector<const char*> undefineNames;
665 fGlobalSymbolTable.getNeededNames(false, undefineNames);
666 for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
667 const char* name = *it;
668 ObjectFile::Atom* possibleAtom = fGlobalSymbolTable.find(name);
669 if ( (possibleAtom == NULL)
670 || ((possibleAtom->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition) && (fOptions.outputKind() != Options::kObjectFile) && (possibleAtom->getScope() == ObjectFile::Atom::scopeGlobal)) )
671 this->addJustInTimeAtoms(name);
672 }
673 }
674
675 if ( fOptions.outputKind() != Options::kObjectFile ) {
676 // error out on any remaining undefines
677 bool doPrint = true;
678 bool doError = true;
679 switch ( fOptions.undefinedTreatment() ) {
680 case Options::kUndefinedError:
681 break;
682 case Options::kUndefinedDynamicLookup:
683 doError = false;
684 break;
685 case Options::kUndefinedWarning:
686 doError = false;
687 break;
688 case Options::kUndefinedSuppress:
689 doError = false;
690 doPrint = false;
691 break;
692 }
693 std::vector<const char*> unresolvableUndefines;
694 fGlobalSymbolTable.getNeededNames(false, unresolvableUndefines);
695 const int unresolvableCount = unresolvableUndefines.size();
696 int unresolvableExportsCount = 0;
697 if ( unresolvableCount != 0 ) {
698 if ( doPrint ) {
699 fprintf(stderr, "can't resolve symbols:\n");
700 for (int i=0; i < unresolvableCount; ++i) {
701 const char* name = unresolvableUndefines[i];
702 fprintf(stderr, " %s, referenced from:\n", name);
703 // scan all atoms for references
704 bool foundAtomReference = false;
705 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
706 ObjectFile::Atom* atom = *it;
707 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
708 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
709 ObjectFile::Reference* reference = *rit;
710 if ( reference->isTargetUnbound() ) {
711 if ( strcmp(reference->getTargetName(), name) == 0 ) {
712 fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
713 foundAtomReference = true;
714 }
715 }
716 if ( reference->hasFromTarget() && reference->isFromTargetUnbound() ) {
717 if ( strcmp(reference->getFromTargetName(), name) == 0 ) {
718 fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
719 foundAtomReference = true;
720 }
721 }
722 }
723 }
724 // scan command line options
725 if ( !foundAtomReference && fOptions.hasExportRestrictList() && fOptions.shouldExport(name) ) {
726 fprintf(stderr, " -exported_symbols_list command line option\n");
727 ++unresolvableExportsCount;
728 }
729 }
730 }
731 if ( doError && (unresolvableCount > unresolvableExportsCount) ) // last check should be removed. It exists so broken projects still build
732 throw "symbol(s) not found";
733 }
734
735 // now verify that -init routine exists
736 if ( fOptions.initFunctionName() != NULL ) {
737 if ( fGlobalSymbolTable.find(fOptions.initFunctionName()) == NULL )
738 throwf("symbol %s not found for -init", fOptions.initFunctionName());
739 }
740 }
741 }
742
743
744
745 void Linker::addJustInTimeAtoms(const char* name)
746 {
747 // when creating final linked image, writer gets first chance
748 if ( fOptions.outputKind() != Options::kObjectFile ) {
749 std::vector<class ObjectFile::Atom*>* atoms = fOutputFile->getJustInTimeAtomsFor(name);
750 if ( atoms != NULL ) {
751 this->addAtoms(*atoms);
752 delete atoms;
753 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
754 return; // found a definition, no need to search anymore
755 }
756 }
757
758 // give direct readers a chance
759 for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
760 ObjectFile::Reader* reader = *it;
761 if ( reader != NULL ) {
762 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
763 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
764 std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
765 if ( atoms != NULL ) {
766 this->addAtoms(*atoms);
767 delete atoms;
768 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fInputFiles[i]->getPath() );
769 return; // found a definition, no need to search anymore
770 }
771 }
772 }
773
774 // give indirect readers a chance
775 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
776 ObjectFile::Reader* reader = it->reader;
777 if ( reader != NULL ) {
778 std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
779 if ( atoms != NULL ) {
780 this->addAtoms(*atoms);
781 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
782 delete atoms;
783 return; // found a definition, no need to search anymore
784 }
785 }
786 }
787
788 // when creating .o file, writer goes last (this is so any static archives will be searched above)
789 if ( (fOptions.outputKind() == Options::kObjectFile) || (fOptions.undefinedTreatment() != Options::kUndefinedError) ) {
790 ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
791 if ( atom != NULL ) {
792 this->addAtom(*atom);
793 return;
794 }
795 }
796 //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
797 }
798
799 void Linker::resolve(ObjectFile::Reference* reference)
800 {
801 // look in global symbol table
802 const char* targetName = reference->getTargetName();
803 ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
804 if ( target == NULL ) {
805 fprintf(stderr, "can't resolve: %s\n", targetName);
806 }
807 reference->setTarget(*target, reference->getTargetOffset());
808 }
809
810 void Linker::resolveFrom(ObjectFile::Reference* reference)
811 {
812 // handle references that have two (from and to) targets
813 const char* fromTargetName = reference->getFromTargetName();
814 ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName);
815 if ( fromTarget == NULL ) {
816 fprintf(stderr, "can't resolve: %s\n", fromTargetName);
817 }
818 reference->setFromTarget(*fromTarget);
819 }
820
821
822 void Linker::resolveReferences()
823 {
824 fStartResolveTime = mach_absolute_time();
825 // note: the atom list may grow during this loop as libraries supply needed atoms
826 for (unsigned int j=0; j < fAllAtoms.size(); ++j) {
827 ObjectFile::Atom* atom = fAllAtoms[j];
828 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
829 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
830 ObjectFile::Reference* reference = *it;
831 if ( reference->isTargetUnbound() )
832 this->resolve(reference);
833 if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
834 this->resolveFrom(reference);
835 }
836 }
837 }
838
839 class InSet
840 {
841 public:
842 InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
843
844 bool operator()(ObjectFile::Atom*& atom) const {
845 return ( fDeadAtoms.count(atom) != 0 );
846 }
847
848 private:
849 std::set<ObjectFile::Atom*>& fDeadAtoms;
850 };
851
852 // used to remove stabs associated with atoms that won't be in output file
853 class NotInSet
854 {
855 public:
856 NotInSet(std::set<ObjectFile::Atom*>& theSet) : fSet(theSet) {}
857
858 bool operator()(const ObjectFile::Reader::Stab& stab) const {
859 if ( stab.atom == NULL )
860 return false; // leave stabs that are not associated with any atome
861 else
862 return ( fSet.count(stab.atom) == 0 );
863 }
864
865 private:
866 std::set<ObjectFile::Atom*>& fSet;
867 };
868
869
870 class DeadStrippable
871 {
872 public:
873 DeadStrippable() {}
874
875 bool operator()(ObjectFile::Atom*& atom) const {
876 //if ( ! atom->dontDeadStrip() )
877 // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
878 return ( ! atom->dontDeadStrip() );
879 }
880 };
881
882 void Linker::markLive(ObjectFile::Atom* atom, std::set<ObjectFile::Atom*>& liveAtoms)
883 {
884 if ( liveAtoms.count(atom) == 0 ) {
885 // this atom is live
886 liveAtoms.insert(atom);
887 // so don't dead strip
888 atom->setDontDeadStrip();
889
890 // and all atoms it references
891 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
892 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
893 ObjectFile::Reference* reference = *it;
894 // mark target of reference as live
895 this->markLive(&reference->getTarget(), liveAtoms);
896 // mark from-target (if it exists) as live
897 if ( reference->hasFromTarget() )
898 this->markLive(&reference->getFromTarget(), liveAtoms);
899 }
900 }
901 }
902
903 void Linker::deadStrip()
904 {
905 if ( fOptions.deadStrip() != Options::kDeadStripOff ) {
906 std::set<ObjectFile::Atom*> liveAtoms;
907
908 // mark main() and all atoms reachable from it as live
909 ObjectFile::Atom* entryPoint = this->entryPoint();
910 if ( entryPoint != NULL )
911 markLive(entryPoint, liveAtoms);
912
913 ObjectFile::Atom* dyldHelper = this->dyldHelper();
914 if ( dyldHelper != NULL )
915 markLive(dyldHelper, liveAtoms);
916
917 // mark initializers and all atoms reachable from them as live
918 // mark all exported atoms and atoms reachable from them as live
919 Section* initSection = Section::find("__mod_init_func", "__DATA", false);
920 Section* termSection = Section::find("__mod_term_func", "__DATA", false);
921 const bool globalsAreRoots = ( fOptions.outputKind() != Options::kDynamicExecutable );
922 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
923 ObjectFile::Atom* atom = *it;
924 //fprintf(stderr,"%d %s\n", atom->dontDeadStrip(), atom->getDisplayName());
925 if ( (globalsAreRoots && (atom->getScope() == ObjectFile::Atom::scopeGlobal))
926 || (atom->getSection() == initSection) || (atom->getSection() == termSection) )
927 markLive(atom, liveAtoms);
928 }
929
930 // now remove dead strippable atoms from fAllAtoms
931 fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), DeadStrippable()), fAllAtoms.end());
932 }
933 else {
934 //printf("Stripping atoms:\n");
935 //for (std::set<ObjectFile::Atom*>::iterator it=fDeadAtoms.begin(); it != fDeadAtoms.end(); it++) {
936 // printf("\t%s\n", (*it)->getDisplayName());
937 //}
938
939 // if not dead stripping, just remove atoms weak atoms that have been overridden
940 fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
941 }
942 }
943
944
945
946 void Linker::sortAtoms()
947 {
948 fStartSortTime = mach_absolute_time();
949 Section::assignIndexes();
950 std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter());
951 //fprintf(stderr, "Sorted atoms:\n");
952 //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
953 // fprintf(stderr, "\t%s\n", (*it)->getDisplayName());
954 //}
955 }
956
957
958
959 // make sure given addresses are within reach of branches, etc
960 void Linker::tweakLayout()
961 {
962 }
963
964
965 void Linker::writeDotOutput()
966 {
967 const char* dotOutFilePath = fOptions.dotOutputFile();
968 if ( dotOutFilePath != NULL ) {
969 FILE* out = fopen(dotOutFilePath, "w");
970 if ( out != NULL ) {
971 // print header
972 fprintf(out, "digraph dg\n{\n");
973 fprintf(out, "\tconcentrate = true;\n");
974 fprintf(out, "\trankdir = LR;\n");
975
976 // print each atom as a node
977 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
978 ObjectFile::Atom* atom = *it;
979 if ( atom->getFile() != fOutputFile ) {
980 const char* name = atom->getDisplayName();
981 // don't create nodes for stubs, lazy pointers or non-lazy pointers
982 const char* lastDollar = strrchr(name, '$');
983 if ( lastDollar != NULL ) {
984 if ( (strcmp(lastDollar, "$stub") == 0) || (strcmp(lastDollar, "$lazy_ptr") == 0) || (strcmp(lastDollar, "$non_lazy_ptr") == 0) )
985 continue;
986 }
987 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
988 || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
989 char temp[strlen(name)+2];
990 strcpy(temp, name);
991 temp[strlen(name)-7] = '\0'; // strip trailing "$import"
992 fprintf(out, "\t%s [ shape = plaintext ];\n", temp);
993 }
994 else if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
995 char cstring[atom->getSize()+2];
996 atom->copyRawContent((uint8_t*)cstring);
997 fprintf(out, "\taddr%p [ label = \"string: '", atom);
998 for (const char* s=cstring; *s != '\0'; ++s) {
999 if ( *s == '\n' )
1000 fprintf(out, "\\\\n");
1001 else
1002 fputc(*s, out);
1003 }
1004 fprintf(out, "'\" ];\n");
1005 }
1006 else {
1007 fprintf(out, "\taddr%p [ label = \"%s\" ];\n", atom, name);
1008 }
1009 }
1010 }
1011 fprintf(out, "\n");
1012
1013 // print each reference as an edge
1014 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1015 ObjectFile::Atom* fromAtom = *it;
1016 if ( fromAtom->getFile() != fOutputFile ) {
1017 std::vector<ObjectFile::Reference*>& references = fromAtom->getReferences();
1018 std::set<ObjectFile::Atom*> seenTargets;
1019 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1020 ObjectFile::Reference* reference = *rit;
1021 ObjectFile::Atom* toAtom = &(reference->getTarget());
1022 if ( seenTargets.count(toAtom) == 0 ) {
1023 seenTargets.insert(toAtom);
1024 const char* toName = toAtom->getDisplayName();
1025 const char* lastDollar = strrchr(toName, '$');
1026 if ( (lastDollar != NULL) && (strcmp(lastDollar, "$stub") == 0) ) {
1027 char temp[strlen(toName)+2];
1028 strcpy(temp, toName);
1029 temp[strlen(toName)-5] = '\0'; // strip trailing "$stub"
1030 fprintf(out, "\taddr%p -> %s;\n", fromAtom, temp);
1031 }
1032 else if ( lastDollar != NULL && (strcmp(lastDollar, "$non_lazy_ptr") == 0) ) {
1033 ObjectFile::Atom* nonLazyTargetAtom = &(toAtom->getReferences()[0]->getTarget());
1034 if ( (nonLazyTargetAtom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
1035 || (nonLazyTargetAtom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
1036 char temp[strlen(toName)+2];
1037 strcpy(temp, toName);
1038 temp[strlen(toName)-13] = '\0'; // strip trailing "$non_lazy_ptr"
1039 fprintf(out, "\taddr%p -> %s;\n", fromAtom, temp);
1040 }
1041 else {
1042 fprintf(out, "\taddr%p -> addr%p;\n", fromAtom, nonLazyTargetAtom);
1043 }
1044 }
1045 else {
1046 // don't list references from stubs, lazy pointers or non-lazy pointers
1047 const char* name = fromAtom->getDisplayName();
1048 const char* lastDollar = strrchr(name, '$');
1049 if ( lastDollar != NULL ) {
1050 if ( (strcmp(lastDollar, "$stub") == 0) || (strcmp(lastDollar, "$lazy_ptr") == 0) || (strcmp(lastDollar, "$non_lazy_ptr") == 0) )
1051 continue;
1052 }
1053 fprintf(out, "\taddr%p -> addr%p;\n", fromAtom, toAtom);
1054 }
1055 }
1056 }
1057 }
1058 }
1059 fprintf(out, "\n");
1060
1061 // push all imports to bottom of graph
1062 fprintf(out, "{ rank = same; ");
1063 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
1064 ObjectFile::Atom* atom = *it;
1065 if ( atom->getFile() != fOutputFile )
1066 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
1067 || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
1068 const char* name = atom->getDisplayName();
1069 char temp[strlen(name)+2];
1070 strcpy(temp, name);
1071 temp[strlen(name)-7] = '\0'; // strip trailing "$import"
1072 fprintf(out, "%s; ", temp);
1073 }
1074 }
1075 fprintf(out, "};\n ");
1076
1077 // print footer
1078 fprintf(out, "}\n");
1079 fclose(out);
1080 }
1081 else {
1082 fprintf(stderr, "ld64 warning: could not write dot output file: %s\n", dotOutFilePath);
1083 }
1084 }
1085 }
1086
1087 ObjectFile::Atom* Linker::entryPoint()
1088 {
1089 // if main executable, find entry point atom
1090 ObjectFile::Atom* entryPoint = NULL;
1091 switch ( fOptions.outputKind() ) {
1092 case Options::kDynamicExecutable:
1093 case Options::kStaticExecutable:
1094 case Options::kDyld:
1095 entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
1096 if ( entryPoint == NULL ) {
1097 throwf("could not find entry point: %s", fOptions.entryName());
1098 }
1099 break;
1100 case Options::kDynamicLibrary:
1101 if ( fOptions.initFunctionName() != NULL ) {
1102 entryPoint = fGlobalSymbolTable.find(fOptions.initFunctionName());
1103 if ( entryPoint == NULL ) {
1104 throwf("could not find -init function: %s", fOptions.initFunctionName());
1105 }
1106 }
1107 break;
1108 case Options::kObjectFile:
1109 case Options::kDynamicBundle:
1110 entryPoint = NULL;
1111 break;
1112 }
1113 return entryPoint;
1114 }
1115
1116 ObjectFile::Atom* Linker::dyldHelper()
1117 {
1118 return fGlobalSymbolTable.find("dyld_stub_binding_helper");
1119 }
1120
1121 const char* Linker::assureFullPath(const char* path)
1122 {
1123 if ( path[0] == '/' )
1124 return path;
1125 char cwdbuff[MAXPATHLEN];
1126 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
1127 char* result;
1128 asprintf(&result, "%s/%s", cwdbuff, path);
1129 if ( result != NULL )
1130 return result;
1131 }
1132 return path;
1133 }
1134
1135
1136 //
1137 // The stab strings are of the form:
1138 // <name> ':' <type-code> <number-pari>
1139 // but the <name> contain a colon.
1140 // For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
1141 // For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
1142 //
1143 const char* Linker::truncateStabString(const char* str)
1144 {
1145 enum { start, inObjc } state = start;
1146 for (const char* s = str; *s != 0; ++s) {
1147 char c = *s;
1148 switch (state) {
1149 case start:
1150 if ( c == '[' ) {
1151 state = inObjc;
1152 }
1153 else {
1154 if ( c == ':' ) {
1155 if ( s[1] == ':' ) {
1156 ++s;
1157 }
1158 else {
1159 // found colon
1160 // Duplicate strndup behavior here.
1161 int trunStrLen = s-str+2;
1162 char* temp = new char[trunStrLen+1];
1163 memcpy(temp, str, trunStrLen);
1164 temp[trunStrLen] = '\0';
1165 return temp;
1166 }
1167 }
1168 }
1169 break;
1170 case inObjc:
1171 if ( c == ']' ) {
1172 state = start;
1173 }
1174 break;
1175 }
1176 }
1177 // malformed
1178 return str;
1179 }
1180
1181
1182 bool Linker::minimizeStab(ObjectFile::Reader::Stab& stab)
1183 {
1184 switch(stab.type){
1185 case N_GSYM:
1186 case N_STSYM:
1187 case N_LCSYM:
1188 case N_FUN:
1189 // these all need truncated strings
1190 stab.string = truncateStabString(stab.string);
1191 return true;
1192 case N_SO:
1193 case N_OSO:
1194 case N_OPT:
1195 case N_SOL:
1196 // these are included in the minimal stabs, but they keep their full string
1197 return true;
1198 default:
1199 return false;
1200 }
1201 }
1202
1203 struct HeaderRange {
1204 std::vector<ObjectFile::Reader::Stab>::iterator begin;
1205 std::vector<ObjectFile::Reader::Stab>::iterator end;
1206 int parentRangeIndex;
1207 uint32_t sum;
1208 bool sumPrecomputed;
1209 bool useEXCL;
1210 bool cannotEXCL; // because of SLINE, etc stabs
1211 };
1212
1213
1214 typedef __gnu_cxx::hash_map<const char*, std::vector<uint32_t>, __gnu_cxx::hash<const char*>, CStringEquals> PathToSums;
1215
1216 // hash table that maps header path to a vector of known checksums for that path
1217 static PathToSums sKnownBINCLs;
1218
1219
1220 void Linker::collectStabs(ObjectFile::Reader* reader)
1221 {
1222 bool log = false;
1223 bool minimal = ( fOptions.readerOptions().fDebugInfoStripping == ObjectFile::ReaderOptions::kDebugInfoMinimal );
1224 std::vector<class ObjectFile::Reader::Stab>* readerStabs = reader->getStabs();
1225 if ( readerStabs == NULL )
1226 return;
1227
1228 if ( log ) fprintf(stderr, "processesing %lu stabs for %s\n", readerStabs->size(), reader->getPath());
1229 // Find all (possibly nested) BINCL/EINCL ranges and their checksums
1230 std::vector<HeaderRange> ranges;
1231 int curRangeIndex = -1;
1232 int count = 0;
1233 for(std::vector<class ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
1234 ++count;
1235 switch ( it->type ) {
1236 case N_BINCL:
1237 {
1238 HeaderRange range;
1239 range.begin = it;
1240 range.end = readerStabs->end();
1241 range.parentRangeIndex = curRangeIndex;
1242 range.sum = it->value;
1243 range.sumPrecomputed = (range.sum != 0);
1244 range.useEXCL = false;
1245 range.cannotEXCL = false;
1246 curRangeIndex = ranges.size();
1247 if ( log ) fprintf(stderr, "[%d]BINCL %s\n", curRangeIndex, it->string);
1248 ranges.push_back(range);
1249 }
1250 break;
1251 case N_EINCL:
1252 if ( curRangeIndex == -1 ) {
1253 fprintf(stderr, "ld64 warning: EINCL missing BINCL in %s\n", reader->getPath());
1254 }
1255 else {
1256 ranges[curRangeIndex].end = it+1;
1257 if ( log ) fprintf(stderr, "[%d->%d]EINCL %s\n", curRangeIndex, ranges[curRangeIndex].parentRangeIndex, it->string);
1258 curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
1259 }
1260 break;
1261 case N_FUN:
1262 case N_BNSYM:
1263 case N_ENSYM:
1264 case N_LBRAC:
1265 case N_RBRAC:
1266 case N_SLINE:
1267 case N_STSYM:
1268 case N_LCSYM:
1269 if ( curRangeIndex != -1 ) {
1270 ranges[curRangeIndex].cannotEXCL = true;
1271 if ( fOptions.warnStabs() )
1272 fprintf(stderr, "ld64: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
1273 }
1274 break;
1275 default:
1276 if ( curRangeIndex != -1 ) {
1277 if ( ! ranges[curRangeIndex].sumPrecomputed ) {
1278 uint32_t sum = 0;
1279 const char* s = it->string;
1280 char c;
1281 while ( (c = *s++) != 0 ) {
1282 sum += c;
1283 // don't checkusm first number (file index) after open paren in string
1284 if ( c == '(' ) {
1285 while(isdigit(*s))
1286 ++s;
1287 }
1288 }
1289 ranges[curRangeIndex].sum += sum;
1290 }
1291 }
1292
1293 }
1294 }
1295 if ( log ) fprintf(stderr, "processesed %d stabs for %s\n", count, reader->getPath());
1296 if ( curRangeIndex != -1 )
1297 fprintf(stderr, "ld64 warning: BINCL (%s) missing EINCL in %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
1298
1299 // if no BINCLs
1300 if ( ranges.size() == 0 ) {
1301 if ( minimal ) {
1302 // only copy minimal stabs
1303 for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
1304 if ( minimizeStab(*it) )
1305 fStabs.push_back(*it);
1306 }
1307 }
1308 else {
1309 // copy all stabs
1310 fStabs.insert(fStabs.end(), readerStabs->begin(), readerStabs->end());
1311 }
1312 return;
1313 }
1314
1315 //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
1316 //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
1317 // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
1318 //}
1319
1320 // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
1321 for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
1322 if ( ! it->cannotEXCL ) {
1323 const char* header = it->begin->string;
1324 uint32_t sum = it->sum;
1325 PathToSums::iterator pos = sKnownBINCLs.find(header);
1326 if ( pos != sKnownBINCLs.end() ) {
1327 std::vector<uint32_t>& sums = pos->second;
1328 for(std::vector<uint32_t>::iterator sit=sums.begin(); sit != sums.end(); ++sit) {
1329 if (*sit == sum) {
1330 //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
1331 it->useEXCL = true;
1332 break;
1333 }
1334 }
1335 if ( ! it->useEXCL ) {
1336 // have seen this path, but not this checksum
1337 //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
1338 sums.push_back(sum);
1339 }
1340 }
1341 else {
1342 // have not seen this path, so add to known BINCLs
1343 std::vector<uint32_t> empty;
1344 sKnownBINCLs[header] = empty;
1345 sKnownBINCLs[header].push_back(sum);
1346 //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
1347 }
1348 }
1349 }
1350
1351 // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
1352 curRangeIndex = -1;
1353 const int maxRangeIndex = ranges.size();
1354 for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
1355 switch ( it->type ) {
1356 case N_BINCL:
1357 for(int i=curRangeIndex+1; i < maxRangeIndex; ++i) {
1358 if ( ranges[i].begin == it ) {
1359 curRangeIndex = i;
1360 HeaderRange& range = ranges[curRangeIndex];
1361 ObjectFile::Reader::Stab stab = *it;
1362 stab.value = range.sum; // BINCL and EXCL have n_value set to checksum
1363 if ( range.useEXCL )
1364 stab.type = N_EXCL; // transform BINCL into EXCL
1365 if ( !minimal )
1366 fStabs.push_back(stab);
1367 break;
1368 }
1369 }
1370 break;
1371 case N_EINCL:
1372 if ( curRangeIndex != -1 ) {
1373 if ( !ranges[curRangeIndex].useEXCL && !minimal )
1374 fStabs.push_back(*it);
1375 curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
1376 }
1377 break;
1378 default:
1379 if ( (curRangeIndex == -1) || !ranges[curRangeIndex].useEXCL ) {
1380 if ( !minimal || minimizeStab(*it) )
1381 fStabs.push_back(*it);
1382 }
1383 }
1384 }
1385
1386 }
1387
1388
1389 void Linker::synthesizeStabs(ObjectFile::Reader* reader)
1390 {
1391 // synthesize "debug notes" and add them to master stabs vector
1392 const char* dirPath = NULL;
1393 const char* filename = NULL;
1394 bool wroteStartSO = false;
1395 std::vector<const char*> seenFiles;
1396 for (std::vector<class ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); ++it) {
1397 ObjectFile::Atom* atom = *it;
1398 if ( atom->getFile() == reader ) {
1399 const char* name = atom->getName();
1400 if ( (name != NULL) && (name[0] == '_' ) && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) ) {
1401 const char* newDirPath;
1402 const char* newFilename;
1403 if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) {
1404 // need SO's whenever the translation unit source file changes
1405 if ( newFilename != filename ) {
1406 if ( filename != NULL ) {
1407 // translation unit change, emit ending SO
1408 ObjectFile::Reader::Stab endFileStab;
1409 endFileStab.atom = NULL;
1410 endFileStab.type = N_SO;
1411 endFileStab.other = 1;
1412 endFileStab.desc = 0;
1413 endFileStab.value = 0;
1414 endFileStab.string = "";
1415 fStabs.push_back(endFileStab);
1416 }
1417 // new translation unit, emit start SO's
1418 ObjectFile::Reader::Stab dirPathStab;
1419 dirPathStab.atom = NULL;
1420 dirPathStab.type = N_SO;
1421 dirPathStab.other = 0;
1422 dirPathStab.desc = 0;
1423 dirPathStab.value = 0;
1424 dirPathStab.string = newDirPath;
1425 fStabs.push_back(dirPathStab);
1426 ObjectFile::Reader::Stab fileStab;
1427 fileStab.atom = NULL;
1428 fileStab.type = N_SO;
1429 fileStab.other = 0;
1430 fileStab.desc = 0;
1431 fileStab.value = 0;
1432 fileStab.string = newFilename;
1433 fStabs.push_back(fileStab);
1434 // Synthesize OSO for start of file
1435 ObjectFile::Reader::Stab objStab;
1436 objStab.atom = NULL;
1437 objStab.type = N_OSO;
1438 objStab.other = 0;
1439 objStab.desc = 1;
1440 objStab.value = reader->getModificationTime();
1441 objStab.string = assureFullPath(reader->getPath());
1442 fStabs.push_back(objStab);
1443 wroteStartSO = true;
1444 }
1445 filename = newFilename;
1446 dirPath = newDirPath;
1447 seenFiles.push_back(filename);
1448 if ( atom->getSegment().isContentExecutable() && (strncmp(atom->getSectionName(), "__text", 6) == 0) ) {
1449 // Synthesize BNSYM and start FUN stabs
1450 ObjectFile::Reader::Stab beginSym;
1451 beginSym.atom = atom;
1452 beginSym.type = N_BNSYM;
1453 beginSym.other = 1;
1454 beginSym.desc = 0;
1455 beginSym.value = 0;
1456 beginSym.string = "";
1457 fStabs.push_back(beginSym);
1458 ObjectFile::Reader::Stab startFun;
1459 startFun.atom = atom;
1460 startFun.type = N_FUN;
1461 startFun.other = 1;
1462 startFun.desc = 0;
1463 startFun.value = 0;
1464 startFun.string = name;
1465 fStabs.push_back(startFun);
1466 // Synthesize any SOL stabs needed
1467 std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
1468 if ( lineInfo != NULL ) {
1469 // might be nice to set the source file path to seenFiles so it does not show up in SOLs
1470 const char* curFile = NULL;
1471 for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
1472 if ( it->fileName != curFile ) {
1473 bool alreadySeen = false;
1474 for (std::vector<const char*>::iterator sit = seenFiles.begin(); sit != seenFiles.end(); ++sit) {
1475 if ( strcmp(it->fileName, *sit) == 0 ) {
1476 alreadySeen = true;
1477 break;
1478 }
1479 }
1480 if ( ! alreadySeen ) {
1481 seenFiles.push_back(it->fileName);
1482 ObjectFile::Reader::Stab sol;
1483 sol.atom = 0;
1484 sol.type = N_SOL;
1485 sol.other = 0;
1486 sol.desc = 0;
1487 sol.value = 0;
1488 sol.string = it->fileName;
1489 fStabs.push_back(sol);
1490 }
1491 curFile = it->fileName;
1492 }
1493 }
1494 }
1495 // Synthesize end FUN and ENSYM stabs
1496 ObjectFile::Reader::Stab endFun;
1497 endFun.atom = atom;
1498 endFun.type = N_FUN;
1499 endFun.other = 0;
1500 endFun.desc = 0;
1501 endFun.value = 0;
1502 endFun.string = "";
1503 fStabs.push_back(endFun);
1504 ObjectFile::Reader::Stab endSym;
1505 endSym.atom = atom;
1506 endSym.type = N_ENSYM;
1507 endSym.other = 1;
1508 endSym.desc = 0;
1509 endSym.value = 0;
1510 endSym.string = "";
1511 fStabs.push_back(endSym);
1512 }
1513 else {
1514 ObjectFile::Reader::Stab globalsStab;
1515 if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
1516 // Synthesize STSYM stab for statics
1517 const char* name = atom->getName();
1518 if ( name[0] == '_' ) {
1519 globalsStab.atom = atom;
1520 globalsStab.type = N_STSYM;
1521 globalsStab.other = 1;
1522 globalsStab.desc = 0;
1523 globalsStab.value = 0;
1524 globalsStab.string = name;
1525 fStabs.push_back(globalsStab);
1526 }
1527 }
1528 else {
1529 // Synthesize GSYM stab for other globals (but not .eh exception frame symbols)
1530 const char* name = atom->getName();
1531 if ( (name[0] == '_') && (strcmp(atom->getSectionName(), "__eh_frame") != 0) ) {
1532 globalsStab.atom = atom;
1533 globalsStab.type = N_GSYM;
1534 globalsStab.other = 1;
1535 globalsStab.desc = 0;
1536 globalsStab.value = 0;
1537 globalsStab.string = name;
1538 fStabs.push_back(globalsStab);
1539 }
1540 }
1541 }
1542 }
1543 }
1544 }
1545 }
1546 if ( wroteStartSO ) {
1547 // emit ending SO
1548 ObjectFile::Reader::Stab endFileStab;
1549 endFileStab.atom = NULL;
1550 endFileStab.type = N_SO;
1551 endFileStab.other = 1;
1552 endFileStab.desc = 0;
1553 endFileStab.value = 0;
1554 endFileStab.string = "";
1555 fStabs.push_back(endFileStab);
1556 }
1557 }
1558
1559 void Linker::collectStabs()
1560 {
1561 if ( fOptions.readerOptions().fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone ) {
1562 fStabs.reserve(1024); // try to minimize re-allocations
1563 // get stabs from each reader, in command line order
1564 for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
1565 it != fReadersThatHaveSuppliedAtoms.end();
1566 it++) {
1567 ObjectFile::Reader* reader = *it;
1568 if ( reader != NULL ) {
1569 switch ( reader->getDebugInfoKind() ) {
1570 case ObjectFile::Reader::kDebugInfoNone:
1571 // do nothing
1572 break;
1573 case ObjectFile::Reader::kDebugInfoStabs:
1574 collectStabs(reader);
1575 break;
1576 case ObjectFile::Reader::kDebugInfoDwarf:
1577 synthesizeStabs(reader);
1578 fCreateUUID = true;
1579 break;
1580 case ObjectFile::Reader::kDebugInfoStabsUUID:
1581 collectStabs(reader);
1582 fCreateUUID = true;
1583 break;
1584 default:
1585 throw "Unhandled type of debug information";
1586 }
1587 }
1588 }
1589 // remove stabs associated with atoms that won't be in output
1590 std::set<class ObjectFile::Atom*> allAtomsSet;
1591 allAtomsSet.insert(fAllAtoms.begin(), fAllAtoms.end());
1592 fStabs.erase(std::remove_if(fStabs.begin(), fStabs.end(), NotInSet(allAtomsSet)), fStabs.end());
1593 }
1594 }
1595
1596 void Linker::writeOutput()
1597 {
1598 fStartWriteTime = mach_absolute_time();
1599 // tell writer about each segment's atoms
1600 fOutputFileSize = fOutputFile->write(fAllAtoms, fStabs, this->entryPoint(), this->dyldHelper(), (fCreateUUID && fOptions.emitUUID()));
1601 }
1602
1603 ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
1604 {
1605 // map in whole file
1606 uint64_t len = info.fileLen;
1607 int fd = ::open(info.path, O_RDONLY, 0);
1608 if ( fd == -1 )
1609 throwf("can't open file, errno=%d", errno);
1610 if ( info.fileLen < 20 )
1611 throw "file too small";
1612
1613 uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
1614 if ( p == (uint8_t*)(-1) )
1615 throwf("can't map file, errno=%d", errno);
1616
1617 // if fat file, skip to architecture we want
1618 const fat_header* fh = (fat_header*)p;
1619 if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
1620 // Fat header is always big-endian
1621 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
1622 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
1623 if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fArchitecture ) {
1624 uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
1625 len = OSSwapBigToHostInt32(archs[i].size);
1626 // if requested architecture is page aligned within fat file, then remap just that portion of file
1627 if ( (fileOffset && 0x00000FFF) == 0 ) {
1628 // unmap whole file
1629 munmap((caddr_t)p, info.fileLen);
1630 // re-map just part we need
1631 p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset);
1632 if ( p == (uint8_t*)(-1) )
1633 throwf("can't re-map file, errno=%d", errno);
1634 }
1635 else {
1636 p = &p[fileOffset];
1637 }
1638 break;
1639 }
1640 }
1641 }
1642 ::close(fd);
1643
1644 switch (fArchitecture) {
1645 case CPU_TYPE_POWERPC:
1646 if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
1647 return this->addObject(mach_o::relocatable::Reader<ppc>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
1648 else if ( mach_o::dylib::Reader<ppc>::validFile(p) )
1649 return this->addDylib(mach_o::dylib::Reader<ppc>::make(p, len, info.path, fOptions.readerOptions()), info, len);
1650 else if ( mach_o::archive::Reader<ppc>::validFile(p, len) )
1651 return this->addArchive(mach_o::archive::Reader<ppc>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
1652 break;
1653 case CPU_TYPE_POWERPC64:
1654 if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
1655 return this->addObject(mach_o::relocatable::Reader<ppc64>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
1656 else if ( mach_o::dylib::Reader<ppc64>::validFile(p) )
1657 return this->addDylib(mach_o::dylib::Reader<ppc64>::make(p, len, info.path, fOptions.readerOptions()), info, len);
1658 else if ( mach_o::archive::Reader<ppc64>::validFile(p, len) )
1659 return this->addArchive(mach_o::archive::Reader<ppc64>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
1660 break;
1661 case CPU_TYPE_I386:
1662 if ( mach_o::relocatable::Reader<x86>::validFile(p) )
1663 return this->addObject(mach_o::relocatable::Reader<x86>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
1664 else if ( mach_o::dylib::Reader<x86>::validFile(p) )
1665 return this->addDylib(mach_o::dylib::Reader<x86>::make(p, len, info.path, fOptions.readerOptions()), info, len);
1666 else if ( mach_o::archive::Reader<x86>::validFile(p, len) )
1667 return this->addArchive(mach_o::archive::Reader<x86>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
1668 break;
1669 }
1670
1671 // error handling
1672 if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
1673 const char* archName = "unknown";
1674 switch (fArchitecture) {
1675 case CPU_TYPE_POWERPC:
1676 archName = "ppc";
1677 break;
1678 case CPU_TYPE_POWERPC64:
1679 archName = "ppc64";
1680 break;
1681 case CPU_TYPE_I386:
1682 archName = "i386";
1683 break;
1684 }
1685 throwf("missing required architecture %s in fat file", archName);
1686 }
1687 else {
1688 throw "file is not of required architecture";
1689 }
1690 }
1691
1692
1693 void Linker::createReaders()
1694 {
1695 fStartCreateReadersTime = mach_absolute_time();
1696 std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
1697 const int count = files.size();
1698 if ( count == 0 )
1699 throw "no object files specified";
1700 // add all direct object, archives, and dylibs
1701 for (int i=0; i < count; ++i) {
1702 Options::FileInfo& entry = files[i];
1703 // ignore /usr/lib/dyld on command line in crt.o build
1704 if ( strcmp(entry.path, "/usr/lib/dyld") != 0 ) {
1705 try {
1706 this->addInputFile(this->createReader(entry));
1707 }
1708 catch (const char* msg) {
1709 if ( strstr(msg, "architecture") != NULL ) {
1710 if ( fOptions.ignoreOtherArchInputFiles() ) {
1711 // ignore, because this is about an architecture not in use
1712 }
1713 else {
1714 fprintf(stderr, "ld64 warning: in %s, %s\n", entry.path, msg);
1715 }
1716 }
1717 else {
1718 throwf("in %s, %s", entry.path, msg);
1719 }
1720 }
1721 }
1722 }
1723
1724 // add first level of indirect dylibs
1725 fDirectLibrariesComplete = true;
1726 for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
1727 this->addIndirectLibraries(it->reader);
1728 }
1729
1730 // indirect handling depends on namespace
1731 switch ( fOptions.nameSpace() ) {
1732 case Options::kFlatNameSpace:
1733 case Options::kForceFlatNameSpace:
1734 // with flat namespace, blindly load all indirect libraries
1735 // the indirect list will grow as indirect libraries are loaded
1736 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
1737 try {
1738 it->reader = this->createReader(fOptions.findFile(it->path));
1739 it->reader->setSortOrder(fNextObjectFileOrder++);
1740 }
1741 catch (const char* msg) {
1742 fprintf(stderr, "ld64 warning: indirect library %s could not be loaded: %s\n", it->path, msg);
1743 }
1744 }
1745 break;
1746
1747 case Options::kTwoLevelNameSpace:
1748 // with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
1749 {
1750 bool indirectAdded = true;
1751 while ( indirectAdded ) {
1752 indirectAdded = false;
1753 // instantiate a reader for each indirect library and try to find parent that re-exports it
1754 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
1755 if ( it->reader == NULL ) {
1756 try {
1757 it->reader = this->createReader(fOptions.findFile(it->path));
1758 it->reader->setSortOrder(fNextObjectFileOrder++);
1759 indirectAdded = true;
1760 }
1761 catch (const char* msg) {
1762 fprintf(stderr, "ld64 warning: indirect library %s could not be loaded: %s\n", it->path, msg);
1763 }
1764 }
1765 // if an indirect library does not have an assigned parent, look for one
1766 if ( (it->reader != NULL) && (it->reExportedViaDirectLibrary == NULL) ) {
1767 it->reExportedViaDirectLibrary = this->findDirectLibraryWhichReExports(*it);
1768 }
1769 }
1770 }
1771 }
1772 break;
1773 }
1774
1775 // add relevant indirect libraries to the end of fDynamicLibraries
1776 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
1777 if ( (it->reader != NULL) && (it->reExportedViaDirectLibrary != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace) ) {
1778 ExecutableFile::DyLibUsed dylibInfo;
1779 dylibInfo.reader = it->reader;
1780 dylibInfo.options.fWeakImport = false;
1781 dylibInfo.options.fReExport = false;
1782 dylibInfo.options.fInstallPathOverride = NULL;
1783 dylibInfo.indirect = true;
1784 dylibInfo.directReader = it->reExportedViaDirectLibrary;
1785 fDynamicLibraries.push_back(dylibInfo);
1786 if ( fOptions.readerOptions().fTraceIndirectDylibs ) {
1787 const char* fullPath = it->reader->getPath();
1788 char realName[MAXPATHLEN];
1789 if ( realpath(fullPath, realName) != NULL )
1790 fullPath = realName;
1791 logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
1792 }
1793 }
1794 }
1795 }
1796
1797
1798 ObjectFile::Reader* Linker::findDirectLibraryWhichReExports(IndirectLibrary& indirectLib)
1799 {
1800 // ask each parent if they re-export this dylib
1801 for (std::set<ObjectFile::Reader*>::iterator pit=indirectLib.parents.begin(); pit != indirectLib.parents.end(); pit++) {
1802 if ( (*pit)->reExports(indirectLib.reader) ) {
1803 ObjectFile::Reader* lib = *pit;
1804 // first check if we found a direct library, if so return it
1805 for (std::vector<ExecutableFile::DyLibUsed>::iterator dit=fDynamicLibraries.begin(); dit != fDynamicLibraries.end(); dit++) {
1806 if ( dit->reader == lib && dit->indirect == false )
1807 return lib;
1808 }
1809 // otherwise search indirects for parent and see how it is reexported
1810 for (std::list<IndirectLibrary>::iterator iit=fIndirectDynamicLibraries.begin(); iit != fIndirectDynamicLibraries.end(); iit++) {
1811 if ( iit->reader == lib ) {
1812 ObjectFile::Reader* lib2 = this->findDirectLibraryWhichReExports(*iit);
1813 if ( lib2 != NULL )
1814 return lib2;
1815 }
1816 }
1817 }
1818 }
1819 return NULL;
1820 }
1821
1822
1823
1824 ObjectFile::Reader* Linker::addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
1825 {
1826 if (fOptions.readerOptions().fTraceArchives) {
1827 const char* fullPath = reader->getPath();
1828 char realName[MAXPATHLEN];
1829 if ( realpath(fullPath, realName) != NULL )
1830 fullPath = realName;
1831 logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath);
1832 }
1833
1834 // update stats
1835 fTotalArchiveSize += mappedLen;
1836 ++fTotalArchivesLoaded;
1837 return reader;
1838 }
1839
1840 ObjectFile::Reader* Linker::addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
1841 {
1842 // update stats
1843 fTotalObjectSize += mappedLen;
1844 ++fTotalObjectLoaded;
1845 return reader;
1846 }
1847
1848 ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
1849 {
1850 if ( reader->getInstallPath() == NULL ) {
1851 // this is a "blank" stub
1852 // silently ignore it
1853 return reader;
1854 }
1855
1856 if ( fDirectLibrariesComplete ) {
1857 this->addIndirectLibraries(reader);
1858 }
1859 else {
1860 if ( fOptions.readerOptions().fTraceDylibs ) {
1861 const char* fullPath = reader->getPath();
1862 char realName[MAXPATHLEN];
1863 if ( realpath(fullPath, realName) != NULL )
1864 fullPath = realName;
1865 logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
1866 }
1867 ExecutableFile::DyLibUsed dylibInfo;
1868 dylibInfo.reader = reader;
1869 dylibInfo.options = info.options;
1870 dylibInfo.indirect = false;
1871 dylibInfo.directReader = NULL;
1872 fDynamicLibraries.push_back(dylibInfo);
1873
1874
1875 // Verify that a client is allowed to link to this dylib. There are three cases.
1876 bool okToLink = true;
1877 const char* outputFilePath = fOptions.installPath();
1878 const char* outputFilePathLastSlash = strrchr(outputFilePath, '/');
1879 if ( reader->parentUmbrella() != NULL ) {
1880 // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
1881 okToLink = ( (outputFilePathLastSlash != NULL) && (strcmp(&outputFilePathLastSlash[1], reader->parentUmbrella()) == 0) );
1882 }
1883
1884 if ( !okToLink && (reader->parentUmbrella() != NULL) ) {
1885 // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
1886 okToLink = ( (outputFilePathLastSlash != NULL)
1887 && (fOptions.umbrellaName() != NULL)
1888 && (strcmp(fOptions.umbrellaName(), reader->parentUmbrella()) == 0) );
1889 }
1890
1891 std::vector<const char*>* clients = reader->getAllowableClients();
1892 if ( !okToLink && (clients != NULL) ) {
1893 // case 3) the dylib has a list of allowable clients, and we are creating one of them
1894 const char* clientName = fOptions.clientName();
1895 int clientNameLen = 0;
1896 if ( clientName != NULL ) {
1897 // use client name as specified on command line
1898 clientNameLen = strlen(clientName);
1899 }
1900 else {
1901 // infer client name from output path (e.g. xxx/libfoo.A.dylib --> foo, Bar.framework/Bar --> Bar)
1902 clientName = outputFilePath;
1903 // starts after last slash
1904 if ( outputFilePathLastSlash != NULL )
1905 clientName = &outputFilePathLastSlash[1];
1906 if ( strncmp(clientName, "lib", 3) == 0 )
1907 clientName = &clientName[3];
1908 // up to first dot
1909 const char* firstDot = strchr(clientName, '.');
1910 if ( firstDot == NULL )
1911 clientNameLen = strlen(clientName);
1912 else
1913 clientNameLen = firstDot - clientName;
1914 }
1915
1916 // Use clientName to check if this dylib is able to link against the allowable clients.
1917 for (std::vector<const char*>::iterator it = clients->begin(); it != clients->end(); it++) {
1918 if ( strncmp(*it, clientName, clientNameLen) == 0 )
1919 okToLink = true;
1920 }
1921 }
1922
1923 // error out if we are not allowed to link
1924 if ( ! okToLink )
1925 //throwf("'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
1926 fprintf(stderr, "'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
1927 reader->getPath(), reader->parentUmbrella());
1928 }
1929
1930 // update stats
1931 ++fTotalDylibsLoaded;
1932
1933 return reader;
1934 }
1935
1936
1937 void Linker::addIndirectLibraries(ObjectFile::Reader* reader)
1938 {
1939 std::vector<const char*>* dependentLibs = reader->getDependentLibraryPaths();
1940 if ( dependentLibs != NULL ) {
1941 for (std::vector<const char*>::iterator it=dependentLibs->begin(); it != dependentLibs->end(); it++) {
1942 if ( this->haveDirectLibrary(*it) ) {
1943 // do nothing, direct library already exists
1944 }
1945 else if ( this->haveIndirectLibrary(*it, reader) ) {
1946 // side effect of haveIndirectLibrary() added reader to parent list
1947 }
1948 else {
1949 // add to list of indirect libraries
1950 IndirectLibrary indirectLib;
1951 indirectLib.path = *it;
1952 indirectLib.fileLen = 0;
1953 indirectLib.reader = NULL;
1954 indirectLib.parents.insert(reader);
1955 indirectLib.reExportedViaDirectLibrary = NULL;
1956 fIndirectDynamicLibraries.push_back(indirectLib);
1957 //fprintf(stderr, "add indirect library: %s\n", *it);
1958 }
1959 }
1960 }
1961 }
1962
1963 bool Linker::haveIndirectLibrary(const char* path, ObjectFile::Reader* parentReader)
1964 {
1965 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
1966 if ( strcmp(path, it->path) == 0 ) {
1967 it->parents.insert(parentReader);
1968 return true;
1969 }
1970 if ( it->reader != NULL ) {
1971 const char* installPath = it->reader->getInstallPath();
1972 if ( (installPath != NULL) && (strcmp(path, installPath) == 0) )
1973 return true;
1974 }
1975 }
1976 return false;
1977 }
1978
1979 bool Linker::haveDirectLibrary(const char* path)
1980 {
1981 for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
1982 if ( strcmp(path, it->reader->getPath()) == 0 )
1983 return true;
1984 const char* installPath = it->reader->getInstallPath();
1985 if ( (installPath != NULL) && (strcmp(path, installPath) == 0) )
1986 return true;
1987 }
1988 return false;
1989 }
1990
1991 void Linker::logTraceInfo (const char* format, ...)
1992 {
1993 static int trace_file = -1;
1994 char trace_buffer[MAXPATHLEN * 2];
1995 char *buffer_ptr;
1996 int length;
1997 ssize_t amount_written;
1998 const char *trace_file_path = fOptions.readerOptions().fTraceOutputFile;
1999
2000 if(trace_file == -1) {
2001 if(trace_file_path != NULL) {
2002 trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
2003 if(trace_file == -1)
2004 throwf("Could not open or create trace file: %s\n", trace_file_path);
2005 }
2006 else {
2007 trace_file = fileno(stderr);
2008 }
2009 }
2010
2011 va_list ap;
2012 va_start(ap, format);
2013 length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap);
2014 va_end(ap);
2015 buffer_ptr = trace_buffer;
2016
2017 while(length > 0) {
2018 amount_written = write(trace_file, buffer_ptr, length);
2019 if(amount_written == -1)
2020 /* Failure to write shouldn't fail the build. */
2021 return;
2022 buffer_ptr += amount_written;
2023 length -= amount_written;
2024 }
2025 }
2026
2027
2028
2029 void Linker::createWriter()
2030 {
2031 fStartCreateWriterTime = mach_absolute_time();
2032 const char* path = fOptions.getOutputFilePath();
2033 switch ( fArchitecture ) {
2034 case CPU_TYPE_POWERPC:
2035 this->setOutputFile(new mach_o::executable::Writer<ppc>(path, fOptions, fDynamicLibraries));
2036 break;
2037 case CPU_TYPE_POWERPC64:
2038 this->setOutputFile(new mach_o::executable::Writer<ppc64>(path, fOptions, fDynamicLibraries));
2039 break;
2040 case CPU_TYPE_I386:
2041 this->setOutputFile(new mach_o::executable::Writer<x86>(path, fOptions, fDynamicLibraries));
2042 break;
2043 default:
2044 throw "unknown architecture";
2045 }
2046 }
2047
2048
2049 Linker::SymbolTable::SymbolTable(Linker& owner)
2050 : fOwner(owner), fRequireCount(0)
2051 {
2052 }
2053
2054 void Linker::SymbolTable::require(const char* name)
2055 {
2056 //fprintf(stderr, "require(%s)\n", name);
2057 Mapper::iterator pos = fTable.find(name);
2058 if ( pos == fTable.end() ) {
2059 fTable[name] = NULL;
2060 ++fRequireCount;
2061 }
2062 }
2063
2064 // convenience labels for 2-dimensional switch statement
2065 enum {
2066 kRegAndReg = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2067 kRegAndWeak = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2068 kRegAndTent = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2069 kRegAndExtern = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2070 kRegAndExternWeak = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
2071 kWeakAndReg = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2072 kWeakAndWeak = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2073 kWeakAndTent = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2074 kWeakAndExtern = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2075 kWeakAndExternWeak = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
2076 kTentAndReg = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2077 kTentAndWeak = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2078 kTentAndTent = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2079 kTentAndExtern = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2080 kTentAndExternWeak = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
2081 kExternAndReg = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2082 kExternAndWeak = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2083 kExternAndTent = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2084 kExternAndExtern = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2085 kExternAndExternWeak = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
2086 kExternWeakAndReg = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
2087 kExternWeakAndWeak = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
2088 kExternWeakAndTent = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
2089 kExternWeakAndExtern = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
2090 kExternWeakAndExternWeak= (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition
2091 };
2092
2093 bool Linker::SymbolTable::add(ObjectFile::Atom& newAtom)
2094 {
2095 bool useNew = true;
2096 const char* name = newAtom.getName();
2097 //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
2098 Mapper::iterator pos = fTable.find(name);
2099 ObjectFile::Atom* existingAtom = NULL;
2100 if ( pos != fTable.end() )
2101 existingAtom = pos->second;
2102 if ( existingAtom != NULL ) {
2103 // already have atom with same name in symbol table
2104 switch ( (existingAtom->getDefinitionKind() << 3) | newAtom.getDefinitionKind() ) {
2105 case kRegAndReg:
2106 throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2107 case kRegAndWeak:
2108 // ignore new weak atom, because we already have a non-weak one
2109 useNew = false;
2110 break;
2111 case kRegAndTent:
2112 // ignore new tentative atom, because we already have a regular one
2113 useNew = false;
2114 break;
2115 case kRegAndExtern:
2116 // ignore external atom, because we already have a one
2117 useNew = false;
2118 break;
2119 case kRegAndExternWeak:
2120 // ignore external atom, because we already have a one
2121 useNew = false;
2122 break;
2123 case kWeakAndReg:
2124 // replace existing weak atom with regular one
2125 break;
2126 case kWeakAndWeak:
2127 // have another weak atom, use whichever has largest alignment requirement
2128 // because codegen of some client may require alignment
2129 useNew = ( newAtom.getAlignment() > existingAtom->getAlignment() );
2130 break;
2131 case kWeakAndTent:
2132 // replace existing weak atom with tentative one ???
2133 break;
2134 case kWeakAndExtern:
2135 // keep weak atom, at runtime external one may override
2136 useNew = false;
2137 break;
2138 case kWeakAndExternWeak:
2139 // keep weak atom, at runtime external one may override
2140 useNew = false;
2141 break;
2142 case kTentAndReg:
2143 // replace existing tentative atom with regular one
2144 break;
2145 case kTentAndWeak:
2146 // replace existing tentative atom with weak one ???
2147 break;
2148 case kTentAndTent:
2149 // use largest
2150 if ( newAtom.getSize() < existingAtom->getSize() ) {
2151 useNew = false;
2152 }
2153 break;
2154 case kTentAndExtern:
2155 case kTentAndExternWeak:
2156 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2157 switch ( fOwner.fOptions.commonsMode() ) {
2158 case Options::kCommonsIgnoreDylibs:
2159 if ( fOwner.fOptions.warnCommons() )
2160 fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2161 existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
2162 useNew = false;
2163 break;
2164 case Options::kCommonsOverriddenByDylibs:
2165 if ( fOwner.fOptions.warnCommons() )
2166 fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from dylib %s\n",
2167 existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
2168 break;
2169 case Options::kCommonsConflictsDylibsError:
2170 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2171 existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
2172 }
2173 break;
2174 case kExternAndReg:
2175 // replace external atom with regular one
2176 break;
2177 case kExternAndWeak:
2178 // replace external atom with weak one
2179 break;
2180 case kExternAndTent:
2181 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2182 switch ( fOwner.fOptions.commonsMode() ) {
2183 case Options::kCommonsIgnoreDylibs:
2184 if ( fOwner.fOptions.warnCommons() )
2185 fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2186 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2187 break;
2188 case Options::kCommonsOverriddenByDylibs:
2189 if ( fOwner.fOptions.warnCommons() )
2190 fprintf(stderr, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2191 newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
2192 useNew = false;
2193 break;
2194 case Options::kCommonsConflictsDylibsError:
2195 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2196 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2197 }
2198 break;
2199 case kExternAndExtern:
2200 throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2201 case kExternAndExternWeak:
2202 // keep strong dylib atom, ignore weak one
2203 useNew = false;
2204 break;
2205 case kExternWeakAndReg:
2206 // replace existing weak external with regular
2207 break;
2208 case kExternWeakAndWeak:
2209 // replace existing weak external with weak (let dyld decide at runtime which to use)
2210 break;
2211 case kExternWeakAndTent:
2212 // a tentative definition and a dylib definition, so commons-mode decides how to handle
2213 switch ( fOwner.fOptions.commonsMode() ) {
2214 case Options::kCommonsIgnoreDylibs:
2215 if ( fOwner.fOptions.warnCommons() )
2216 fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
2217 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2218 break;
2219 case Options::kCommonsOverriddenByDylibs:
2220 if ( fOwner.fOptions.warnCommons() )
2221 fprintf(stderr, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
2222 newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
2223 useNew = false;
2224 break;
2225 case Options::kCommonsConflictsDylibsError:
2226 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
2227 newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
2228 }
2229 break;
2230 case kExternWeakAndExtern:
2231 // replace existing weak external with external
2232 break;
2233 case kExternWeakAndExternWeak:
2234 // keep existing external weak
2235 useNew = false;
2236 break;
2237 }
2238 }
2239 if ( useNew ) {
2240 fTable[name] = &newAtom;
2241 if ( existingAtom != NULL )
2242 fOwner.fDeadAtoms.insert(existingAtom);
2243 }
2244 else {
2245 fOwner.fDeadAtoms.insert(&newAtom);
2246 }
2247 return useNew;
2248 }
2249
2250
2251
2252 ObjectFile::Atom* Linker::SymbolTable::find(const char* name)
2253 {
2254 Mapper::iterator pos = fTable.find(name);
2255 if ( pos != fTable.end() ) {
2256 return pos->second;
2257 }
2258 return NULL;
2259 }
2260
2261
2262 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines)
2263 {
2264 for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) {
2265 if ( (it->second == NULL) || (andWeakDefintions && (it->second->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition)) ) {
2266 undefines.push_back(it->first);
2267 }
2268 }
2269 }
2270
2271
2272
2273
2274 bool Linker::AtomSorter::operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
2275 {
2276 // first sort by section order (which is already sorted by segment)
2277 unsigned int leftSectionIndex = left->getSection()->getIndex();
2278 unsigned int rightSectionIndex = right->getSection()->getIndex();
2279 if ( leftSectionIndex != rightSectionIndex)
2280 return (leftSectionIndex < rightSectionIndex);
2281
2282 // then sort by .o file order
2283 ObjectFile::Reader* leftReader = left->getFile();
2284 ObjectFile::Reader* rightReader = right->getFile();
2285 if ( leftReader != rightReader )
2286 return leftReader->getSortOrder() < rightReader->getSortOrder();
2287
2288 // lastly sort by atom within a .o file
2289 return left->getSortOrder() < right->getSortOrder();
2290 }
2291
2292
2293 int main(int argc, const char* argv[])
2294 {
2295 try {
2296 // create linker object given command line arguments
2297 Linker ld(argc, argv);
2298
2299 // open all input files
2300 ld.createReaders();
2301
2302 // open output file
2303 ld.createWriter();
2304
2305 // do linking
2306 ld.link();
2307 }
2308 catch (const char* msg) {
2309 fprintf(stderr, "ld64 failed: %s\n", msg);
2310 return 1;
2311 }
2312
2313
2314 return 0;
2315 }