]> git.saurik.com Git - apple/ld64.git/blob - src/ld.cpp
ld64-21.tar.gz
[apple/ld64.git] / src / ld.cpp
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/mman.h>
27 #include <fcntl.h>
28 #include <mach-o/loader.h>
29 #include <mach-o/fat.h>
30
31 #include <string>
32 #include <set>
33 #include <string>
34 #include <vector>
35 #include <list>
36 #include <algorithm>
37 #include <ext/hash_map>
38
39 #include "Options.h"
40
41 #include "ObjectFile.h"
42 #include "ObjectFileMachO-all.h"
43
44 #include "ExecutableFile.h"
45 #include "ExecutableFileMachO-all.h"
46
47 #include "SectCreate.h"
48
49 #if 0
50 static void dumpAtom(ObjectFile::Atom* atom)
51 {
52 //printf("atom: %p\n", atom);
53
54 // name
55 printf("name: %s\n", atom->getDisplayName());
56
57 // scope
58 switch ( atom->getScope() ) {
59 case ObjectFile::Atom::scopeTranslationUnit:
60 printf("scope: translation unit\n");
61 break;
62 case ObjectFile::Atom::scopeLinkageUnit:
63 printf("scope: linkage unit\n");
64 break;
65 case ObjectFile::Atom::scopeGlobal:
66 printf("scope: global\n");
67 break;
68 default:
69 printf("scope: unknown\n");
70 }
71
72 // segment and section
73 printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
74
75 // attributes
76 printf("attrs: ");
77 if ( atom->isTentativekDefinition() )
78 printf("tentative ");
79 else if ( atom->isWeakDefinition() )
80 printf("weak ");
81 if ( atom->isCoalesableByName() )
82 printf("coalesce-by-name ");
83 if ( atom->isCoalesableByValue() )
84 printf("coalesce-by-value ");
85 if ( atom->dontDeadStrip() )
86 printf("dont-dead-strip ");
87 if ( atom->isZeroFill() )
88 printf("zero-fill ");
89 printf("\n");
90
91 // size
92 printf("size: 0x%012llX\n", atom->getSize());
93
94 // content
95 uint8_t content[atom->getSize()];
96 atom->copyRawContent(content);
97 printf("content: ");
98 if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
99 printf("\"%s\"", content);
100 }
101 else {
102 for (unsigned int i=0; i < sizeof(content); ++i)
103 printf("%02X ", content[i]);
104 }
105 printf("\n");
106
107 // references
108 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
109 const int refCount = references.size();
110 printf("references: (%u)\n", refCount);
111 for (int i=0; i < refCount; ++i) {
112 ObjectFile::Reference* ref = references[i];
113 printf(" %s\n", ref->getDescription());
114 }
115
116 // attributes
117
118 }
119
120 #endif
121
122 class CStringComparor
123 {
124 public:
125 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
126 };
127
128 class CStringEquals
129 {
130 public:
131 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
132 };
133
134 class Section : public ObjectFile::Section
135 {
136 public:
137 static Section* find(const char* sectionName, const char* segmentName, bool zeroFill);
138 static void assignIndexes();
139
140 private:
141 Section(const char* sectionName, const char* segmentName, bool zeroFill);
142
143 struct Sorter {
144 static int segmentOrdinal(const char* segName);
145 bool operator()(Section* left, Section* right);
146 };
147
148 typedef __gnu_cxx::hash_map<const char*, class Section*, __gnu_cxx::hash<const char*>, CStringEquals> NameToSection;
149 //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
150
151 const char* fSectionName;
152 const char* fSegmentName;
153 bool fZeroFill;
154
155 static NameToSection fgMapping;
156 static std::vector<Section*> fgSections;
157 };
158
159 Section::NameToSection Section::fgMapping;
160 std::vector<Section*> Section::fgSections;
161
162 Section::Section(const char* sectionName, const char* segmentName, bool zeroFill)
163 : fSectionName(sectionName), fSegmentName(segmentName), fZeroFill(zeroFill)
164 {
165 //fprintf(stderr, "new Section(%s, %s)\n", sectionName, segmentName);
166 }
167
168 Section* Section::find(const char* sectionName, const char* segmentName, bool zeroFill)
169 {
170 #if 0
171 std::pair<NameToSection::iterator, NameToSection::iterator> range = fgMapping.equal_range(sectionName);
172 for (NameToSection::iterator it=range.first; it != range.second; it++) {
173 if ( strcmp(it->second->fSegmentName, segmentName) == 0 )
174 return it->second;
175 }
176 #endif
177 NameToSection::iterator pos = fgMapping.find(sectionName);
178 if ( pos != fgMapping.end() ) {
179 if ( strcmp(pos->second->fSegmentName, segmentName) == 0 )
180 return pos->second;
181 // otherwise same section name is used in different segments, look slow way
182 for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
183 if ( (strcmp((*it)->fSectionName, sectionName) == 0) && (strcmp((*it)->fSegmentName, segmentName) == 0) )
184 return *it;
185 }
186 }
187
188 // does not exist, so make a new one
189 Section* sect = new Section(sectionName, segmentName, zeroFill);
190 sect->fIndex = fgMapping.size();
191 fgMapping[sectionName] = sect;
192 fgSections.push_back(sect);
193 return sect;
194 }
195
196 int Section::Sorter::segmentOrdinal(const char* segName)
197 {
198 if ( strcmp(segName, "__PAGEZERO") == 0 )
199 return 1;
200 if ( strcmp(segName, "__TEXT") == 0 )
201 return 2;
202 if ( strcmp(segName, "__DATA") == 0 )
203 return 3;
204 if ( strcmp(segName, "__OBJC") == 0 )
205 return 4;
206 if ( strcmp(segName, "__LINKEDIT") == 0 )
207 return INT_MAX; // linkedit segment should always sort last
208 else
209 return 5;
210 }
211
212
213 bool Section::Sorter::operator()(Section* left, Section* right)
214 {
215 // Segment is primary sort key
216 const char* leftSegName = left->fSegmentName;
217 const char* rightSegName = right->fSegmentName;
218 int segNameCmp = strcmp(leftSegName, rightSegName);
219 if ( segNameCmp != 0 )
220 {
221 int leftSegOrdinal = segmentOrdinal(leftSegName);
222 int rightSegOrdinal = segmentOrdinal(rightSegName);
223 if ( leftSegOrdinal < rightSegOrdinal )
224 return true;
225 if ( leftSegOrdinal == rightSegOrdinal )
226 return segNameCmp < 0;
227 return false;
228 }
229
230 // zerofill section sort to the end
231 if ( !left->fZeroFill && right->fZeroFill )
232 return true;
233 if ( left->fZeroFill && !right->fZeroFill )
234 return false;
235
236 // section discovery order is last sort key
237 return left->fIndex < right->fIndex;
238 }
239
240 void Section::assignIndexes()
241 {
242 //printf("unsorted:\n");
243 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
244 // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
245 //}
246
247 // sort it
248 std::sort(fgSections.begin(), fgSections.end(), Section::Sorter());
249
250 // assign correct section ordering to each Section object
251 unsigned int newOrder = 1;
252 for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++)
253 (*it)->fIndex = newOrder++;
254
255 //printf("sorted:\n");
256 //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
257 // printf("section: name=%s\n", (*it)->fSectionName);
258 //}
259 }
260
261 class Linker {
262 public:
263 Linker(int argc, const char* argv[]);
264
265 void createReaders();
266 void createWriter();
267 void addInputFile(ObjectFile::Reader* reader);
268 void setOutputFile(ExecutableFile::Writer* writer);
269 void link();
270
271
272 private:
273 ObjectFile::Reader* createReader(const Options::FileInfo&);
274 void addAtom(ObjectFile::Atom& atom);
275 void addAtoms(std::vector<class ObjectFile::Atom*>& atoms);
276 void buildAtomList();
277 void loadUndefines();
278 void addWeakAtomOverrides();
279 void resolveReferences();
280 void deadStrip();
281 void sortAtoms();
282 void tweakLayout();
283 void writeOutput();
284
285 void resolve(ObjectFile::Reference* reference);
286 void addJustInTimeAtoms(const char* name);
287
288 void addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info);
289 void addIndirectLibraries(ObjectFile::Reader* reader);
290 bool haveIndirectLibrary(const char* path, ObjectFile::Reader* reader);
291 bool haveDirectLibrary(const char* path);
292
293 struct SegmentAndItsAtoms
294 {
295 class Segment* fSegment;
296 uint64_t fSegmentSize;
297 uint64_t fSegmentBaseAddress;
298 std::vector<class ObjectFile::Atom*> fAtoms;
299 };
300
301
302 class SymbolTable
303 {
304 public:
305 SymbolTable(Linker&);
306 void require(const char* name);
307 bool add(ObjectFile::Atom& atom);
308 ObjectFile::Atom* find(const char* name);
309 unsigned int getRequireCount() { return fRequireCount; }
310 void getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines);
311 private:
312 typedef std::map<const char*, ObjectFile::Atom*, CStringComparor> Mapper;
313 Linker& fOwner;
314 Mapper fTable;
315 unsigned int fRequireCount;
316 };
317
318 struct AtomSorter
319 {
320 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right);
321 };
322
323 typedef std::map<const char*, uint32_t, CStringComparor> SectionOrder;
324
325 struct IndirectLibrary {
326 const char* path;
327 uint64_t fileLen;
328 ObjectFile::Reader* reader;
329 std::set<ObjectFile::Reader*> parents;
330 ObjectFile::Reader* reExportParent;
331 };
332
333 Options fOptions;
334 SymbolTable fGlobalSymbolTable;
335 unsigned int fWeakSymbolsAddedCount;
336 std::vector<class ObjectFile::Reader*> fInputFiles;
337 ExecutableFile::Writer* fOutputFile;
338 std::vector<ExecutableFile::DyLibUsed> fDynamicLibraries;
339 std::list<IndirectLibrary> fIndirectDynamicLibraries;
340 std::vector<class ObjectFile::Atom*> fAllAtoms;
341 std::vector< SegmentAndItsAtoms > fAllAtomsBySegment;
342 std::set<class ObjectFile::Atom*> fDeadAtoms;
343 SectionOrder fSectionOrder;
344 unsigned int fNextSortOrder;
345 bool fDirectLibrariesComplete;
346 };
347
348
349
350 Linker::Linker(int argc, const char* argv[])
351 : fOptions(argc, argv), fGlobalSymbolTable(*this), fOutputFile(NULL), fNextSortOrder(1), fDirectLibrariesComplete(false)
352 {
353 }
354
355 void Linker::addInputFile(ObjectFile::Reader* reader)
356 {
357 fInputFiles.push_back(reader);
358 }
359
360 void Linker::setOutputFile(ExecutableFile::Writer* writer)
361 {
362 fOutputFile = writer;
363 }
364
365 void Linker::link()
366 {
367 this->buildAtomList();
368 this->loadUndefines();
369 this->resolveReferences();
370 this->deadStrip();
371 this->sortAtoms();
372 this->tweakLayout();
373 this->writeOutput();
374 }
375
376 inline void Linker::addAtom(ObjectFile::Atom& atom)
377 {
378 // add to list of all atoms
379 fAllAtoms.push_back(&atom);
380
381 // add atom's references's names to symbol table as to-be-resolved-later
382 std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
383 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
384 ObjectFile::Reference* reference = *it;
385 if ( reference->isUnbound() ) {
386 fGlobalSymbolTable.require(reference->getTargetName());
387 }
388 }
389
390 // if in global namespace, add atom itself to symbol table
391 ObjectFile::Atom::Scope scope = atom.getScope();
392 const char* name = atom.getName();
393 if ( (scope != ObjectFile::Atom::scopeTranslationUnit) && (name != NULL) ) {
394 fGlobalSymbolTable.add(atom);
395
396 // update scope based on export list (possible that globals are downgraded to private_extern)
397 if ( (scope == ObjectFile::Atom::scopeGlobal) && fOptions.hasExportRestrictList() ) {
398 bool doExport = fOptions.shouldExport(name);
399 if ( !doExport ) {
400 atom.setScope(ObjectFile::Atom::scopeLinkageUnit);
401 }
402 }
403 }
404
405 // record section orders so output file can have same order
406 atom.setSection(Section::find(atom.getSectionName(), atom.getSegment().getName(), atom.isZeroFill()));
407
408 // assign order in which this atom was originally seen
409 if ( atom.getSortOrder() == 0 )
410 fNextSortOrder = atom.setSortOrder(fNextSortOrder);
411 }
412
413 inline void Linker::addAtoms(std::vector<class ObjectFile::Atom*>& atoms)
414 {
415 for (std::vector<ObjectFile::Atom*>::iterator it=atoms.begin(); it != atoms.end(); it++) {
416 this->addAtom(**it);
417 }
418 }
419
420 void Linker::buildAtomList()
421 {
422 // add initial undefines from -u option
423 std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
424 for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++) {
425 fGlobalSymbolTable.require(*it);
426 }
427
428 // writer can contribute atoms
429 this->addAtoms(fOutputFile->getAtoms());
430
431 // each reader contributes atoms
432 const int readerCount = fInputFiles.size();
433 for (int i=0; i < readerCount; ++i) {
434 this->addAtoms(fInputFiles[i]->getAtoms());
435 }
436
437 // extra command line section always at end
438 std::vector<Options::ExtraSection>& extraSections = fOptions.extraSections();
439 for( std::vector<Options::ExtraSection>::iterator it=extraSections.begin(); it != extraSections.end(); ++it) {
440 this->addAtoms(SectCreate::MakeReader(it->segmentName, it->sectionName, it->path, it->data, it->dataLen)->getAtoms());
441 }
442 }
443
444 void Linker::loadUndefines()
445 {
446 // keep looping until no more undefines were added in last loop
447 unsigned int undefineCount = 0xFFFFFFFF;
448 while ( undefineCount != fGlobalSymbolTable.getRequireCount() ) {
449 undefineCount = fGlobalSymbolTable.getRequireCount();
450 std::vector<const char*> undefineNames;
451 fGlobalSymbolTable.getNeededNames(true, undefineNames);
452 const int undefineCount = undefineNames.size();
453 for (int i=0; i < undefineCount; ++i) {
454 const char* name = undefineNames[i];
455 ObjectFile::Atom* possibleAtom = fGlobalSymbolTable.find(name);
456 if ( (possibleAtom == NULL) || (possibleAtom->isWeakDefinition() && (fOptions.outputKind() != Options::kObjectFile)) )
457 this->addJustInTimeAtoms(name);
458 }
459 }
460
461 if ( fOptions.outputKind() != Options::kObjectFile ) {
462 // error out on any remaining undefines
463 bool doPrint = true;
464 bool doError = true;
465 switch ( fOptions.undefinedTreatment() ) {
466 case Options::kUndefinedError:
467 break;
468 case Options::kUndefinedDynamicLookup:
469 doError = false;
470 break;
471 case Options::kUndefinedWarning:
472 doError = false;
473 break;
474 case Options::kUndefinedSuppress:
475 doError = false;
476 doPrint = false;
477 break;
478 }
479 std::vector<const char*> unresolvableUndefines;
480 fGlobalSymbolTable.getNeededNames(false, unresolvableUndefines);
481 const int unresolvableCount = unresolvableUndefines.size();
482 if ( unresolvableCount != 0 ) {
483 if ( doPrint ) {
484 fprintf(stderr, "can't resolve symbols:\n");
485 for (int i=0; i < unresolvableCount; ++i) {
486 const char* name = unresolvableUndefines[i];
487 const unsigned int nameLen = strlen(name);
488 fprintf(stderr, " %s, referenced from:\n", name);
489 char stubName[nameLen+6];
490 strcpy(stubName, name);
491 strcat(stubName, "$stub");
492 char nonLazyName[nameLen+16];
493 strcpy(nonLazyName, name);
494 strcat(nonLazyName, "$non_lazy_ptr");
495 ObjectFile::Atom* lastStubAtomWithUnresolved = NULL;
496 ObjectFile::Atom* lastNonLazyAtomWithUnresolved = NULL;
497 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
498 ObjectFile::Atom* atom = *it;
499 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
500 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
501 ObjectFile::Reference* reference = *rit;
502 if ( reference->isUnbound() ) {
503 if ( (atom != lastStubAtomWithUnresolved) && (strcmp(reference->getTargetName(), stubName) == 0) ) {
504 const char* path = atom->getFile()->getPath();
505 const char* shortPath = strrchr(path, '/');
506 if ( shortPath == NULL )
507 shortPath = path;
508 else
509 shortPath = &shortPath[1];
510 fprintf(stderr, " %s in %s\n", atom->getDisplayName(), shortPath);
511 lastStubAtomWithUnresolved = atom;
512 }
513 else if ( (atom != lastNonLazyAtomWithUnresolved) && (strcmp(reference->getTargetName(), nonLazyName) == 0) ) {
514 const char* path = atom->getFile()->getPath();
515 const char* shortPath = strrchr(path, '/');
516 if ( shortPath == NULL )
517 shortPath = path;
518 else
519 shortPath = &shortPath[1];
520 fprintf(stderr, " %s in %s\n", atom->getDisplayName(), shortPath);
521 lastNonLazyAtomWithUnresolved = atom;
522 }
523 }
524 }
525 }
526 }
527 }
528 if ( doError )
529 throw "symbol(s) not found";
530 }
531
532 // now verify that -init routine exists
533 if ( fOptions.initFunctionName() != NULL ) {
534 if ( fGlobalSymbolTable.find(fOptions.initFunctionName()) == NULL )
535 throwf("symbol %s not found for -init", fOptions.initFunctionName());
536 }
537 }
538 }
539
540
541
542 void Linker::addJustInTimeAtoms(const char* name)
543 {
544 // give writer a crack at it
545 ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
546 if ( atom != NULL ) {
547 this->addAtom(*atom);
548 }
549 else {
550 // give direct readers a chance
551 const int readerCount = fInputFiles.size();
552 for (int i=0; i < readerCount; ++i) {
553 // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
554 // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
555 std::vector<class ObjectFile::Atom*>* atoms = fInputFiles[i]->getJustInTimeAtomsFor(name);
556 if ( atoms != NULL ) {
557 this->addAtoms(*atoms);
558 delete atoms;
559 return; // found a definition, no need to search anymore
560 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
561 }
562 }
563
564 // give indirect readers a chance
565 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
566 ObjectFile::Reader* reader = it->reader;
567 if ( reader != NULL ) {
568 std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
569 if ( atoms != NULL ) {
570 this->addAtoms(*atoms);
571 delete atoms;
572 break;
573 //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
574 }
575 }
576 }
577 }
578 }
579
580 void Linker::resolve(ObjectFile::Reference* reference)
581 {
582 ObjectFile::Atom* target = NULL;
583 const char* targetName = reference->getTargetName();
584 const int targetNameLen = strlen(targetName);
585 if ( (targetNameLen > 5) && (strcmp(&targetName[targetNameLen-5], "$stub") == 0) ) {
586 // when looking up "_foo$stub", first look for "_foo"
587 char nonStubTarget[targetNameLen+1];
588 strcpy(nonStubTarget, targetName);
589 nonStubTarget[targetNameLen-5] = '\0';
590 // unless interposing and the symbol is exported
591 if ( !fOptions.interposable() || !fOptions.shouldExport(nonStubTarget) ) {
592 target = fGlobalSymbolTable.find(nonStubTarget);
593 // also need indirection to all exported weak symbols for C++ support
594 if ( (target != NULL) && !target->isImportProxy() && (!target->isWeakDefinition() || (target->getScope() != ObjectFile::Atom::scopeGlobal)) ) {
595 reference->setTarget(*target);
596 // mark stub as no longer being needed
597 ObjectFile::Atom* stub = fGlobalSymbolTable.find(targetName);
598 if ( stub != NULL ) {
599 char lazySymbol[targetNameLen+8];
600 strcpy(lazySymbol, nonStubTarget);
601 strcat(lazySymbol, "$lazy_ptr");
602 ObjectFile::Atom* lazyPtr = fGlobalSymbolTable.find(lazySymbol);
603 fDeadAtoms.insert(stub);
604 if ( lazyPtr != NULL )
605 fDeadAtoms.insert(lazyPtr);
606 }
607 return;
608 }
609 }
610 }
611
612 // look in global symbol table
613 target = fGlobalSymbolTable.find(targetName);
614 if ( target == NULL ) {
615 fprintf(stderr, "can't resolve: %s\n", targetName);
616 }
617 reference->setTarget(*target);
618
619 // handle weak-imports
620 if ( target->isImportProxy() ) {
621 bool mismatch = false;
622 if ( reference->isWeakReference() ) {
623 switch(target->getImportWeakness()) {
624 case ObjectFile::Atom::kWeakUnset:
625 target->setImportWeakness(true);
626 break;
627 case ObjectFile::Atom::kWeakImport:
628 break;
629 case ObjectFile::Atom::kNonWeakImport:
630 mismatch = true;
631 break;
632 }
633 }
634 else {
635 switch(target->getImportWeakness()) {
636 case ObjectFile::Atom::kWeakUnset:
637 target->setImportWeakness(false);
638 break;
639 case ObjectFile::Atom::kWeakImport:
640 mismatch = true;
641 break;
642 case ObjectFile::Atom::kNonWeakImport:
643 break;
644 }
645 }
646 if ( mismatch ) {
647 switch ( fOptions.weakReferenceMismatchTreatment() ) {
648 case Options::kWeakReferenceMismatchError:
649 throwf("mismatching weak references for symbol: %s", target->getName());
650 case Options::kWeakReferenceMismatchWeak:
651 target->setImportWeakness(true);
652 break;
653 case Options::kWeakReferenceMismatchNonWeak:
654 target->setImportWeakness(false);
655 break;
656 }
657 }
658 }
659
660 // handle references that have two (from and to) targets
661 if ( reference->isUnbound() ) {
662 const char* fromTargetName = reference->getFromTargetName();
663 ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName);
664 if ( target == NULL ) {
665 fprintf(stderr, "can't resolve: %s\n", fromTargetName);
666 }
667 reference->setFromTarget(*fromTarget);
668 }
669 }
670
671
672 void Linker::resolveReferences()
673 {
674 // note: the atom list may grow during this loop as libraries supply needed atoms
675 for (unsigned int j=0; j < fAllAtoms.size(); ++j) {
676 ObjectFile::Atom* atom = fAllAtoms[j];
677 std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
678 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
679 ObjectFile::Reference* reference = *it;
680 if ( reference->isUnbound() ) {
681 this->resolve(reference);
682 }
683 }
684 }
685 }
686
687 class InSet
688 {
689 public:
690 InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
691
692 bool operator()(ObjectFile::Atom*& atom) const {
693 return ( fDeadAtoms.count(atom) != 0 );
694 }
695
696 private:
697 std::set<ObjectFile::Atom*>& fDeadAtoms;
698 };
699
700
701 void Linker::deadStrip()
702 {
703 //printf("Stripping atoms:\n");
704 //for (std::set<ObjectFile::Atom*>::iterator it=fDeadAtoms.begin(); it != fDeadAtoms.end(); it++) {
705 // printf("\t%s\n", (*it)->getDisplayName());
706 //}
707
708 // for now, just remove atoms weak atoms that have been overridden
709 fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
710 }
711
712
713
714 void Linker::sortAtoms()
715 {
716 Section::assignIndexes();
717 std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter());
718 }
719
720
721
722 // make sure given addresses are within reach of branches, etc
723 void Linker::tweakLayout()
724 {
725
726
727
728 }
729
730
731 void Linker::writeOutput()
732 {
733 // if main executable, find entry point atom
734 ObjectFile::Atom* entryPoint;
735 switch ( fOptions.outputKind() ) {
736 case Options::kDynamicExecutable:
737 case Options::kStaticExecutable:
738 case Options::kDyld:
739 entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
740 if ( entryPoint == NULL ) {
741 throwf("could not find entry point: %s", fOptions.entryName());
742 }
743 break;
744 case Options::kDynamicLibrary:
745 if ( fOptions.initFunctionName() != NULL ) {
746 entryPoint = fGlobalSymbolTable.find(fOptions.initFunctionName());
747 if ( entryPoint == NULL ) {
748 throwf("could not find -init function: %s", fOptions.initFunctionName());
749 }
750 }
751 break;
752 default:
753 entryPoint = NULL;
754 }
755
756 // tell writer about each segment's atoms
757 fOutputFile->write(fAllAtoms, entryPoint);
758 }
759
760
761
762
763 ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
764 {
765 // map in whole file
766 uint64_t len = info.fileLen;
767 int fd = ::open(info.path, O_RDONLY, 0);
768 if ( fd == -1 )
769 throw "can't open file";
770 if ( info.fileLen < 20 )
771 throw "file too small";
772 char* p = (char*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE, fd, 0);
773 if ( p == (char*)(-1) )
774 throw "can't map file";
775 ::close(fd);
776
777 // if fat file, skip to architecture we want
778 const mach_header* mh = (mach_header*)p;
779 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
780 // Fat header is always big-endian
781 const struct fat_header* fh = (struct fat_header*)p;
782 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
783 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
784 if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fOptions.architecture() ) {
785 mh = (struct mach_header*)((char*)p + OSSwapBigToHostInt32(archs[i].offset));
786 len = OSSwapBigToHostInt32(archs[i].size);
787 break;
788 }
789 }
790 }
791
792 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
793 const char* archName = "unknown";
794 switch (fOptions.architecture()) {
795 case CPU_TYPE_POWERPC:
796 archName = "ppc";
797 break;
798 case CPU_TYPE_POWERPC64:
799 archName = "ppc64";
800 break;
801 case CPU_TYPE_I386:
802 archName = "i386";
803 break;
804 }
805 throwf("missing required architecture %s in fat file", archName);
806 }
807
808 // pull out cpu-type and file-type in endian-safe way
809 cpu_type_t cpuType = 0;
810 uint32_t fileType = 0;
811 if ( mh->magic == MH_MAGIC ) {
812 fileType = mh->filetype;
813 cpuType = mh->cputype;
814 }
815 else if ( mh->magic == OSSwapInt32(MH_MAGIC) ) {
816 fileType = OSSwapInt32(mh->filetype);
817 cpuType = OSSwapInt32(mh->cputype);
818 }
819 else if ( mh->magic == MH_MAGIC_64 ) {
820 fileType = ((mach_header_64*)mh)->filetype;
821 cpuType = ((mach_header_64*)mh)->cputype;
822 }
823 else if ( mh->magic == OSSwapInt32(MH_MAGIC_64) ) {
824 fileType = OSSwapInt32(((mach_header_64*)mh)->filetype);
825 cpuType = OSSwapInt32(((mach_header_64*)mh)->cputype);
826 }
827 else if ( strncmp((const char*)mh, "!<arch>\n", 8) == 0 ) {
828 // is static archive
829 switch ( fOptions.architecture() ) {
830 case CPU_TYPE_POWERPC:
831 return ppc::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
832 case CPU_TYPE_POWERPC64:
833 return ppc64::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
834 case CPU_TYPE_I386:
835 return i386::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
836 }
837 throw "no matching archive reader";
838 }
839 else {
840 throw "unknown file type";
841 }
842
843 // bail out if cpu-type does not match requrired architecture
844 if ( fOptions.architecture() == cpuType ) {
845 // make appropriate reader object
846 if ( fileType == MH_OBJECT ) {
847 switch ( cpuType ) {
848 case CPU_TYPE_POWERPC:
849 return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, info.path, fOptions.readerOptions());
850 case CPU_TYPE_POWERPC64:
851 return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, info.path, fOptions.readerOptions());
852 case CPU_TYPE_I386:
853 return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, info.path, fOptions.readerOptions());
854 default:
855 throw "wrong architecture in object file";
856 }
857 }
858 else if ( fileType == MH_DYLIB ) {
859 ObjectFile::Reader* dylibReader = NULL;
860 switch ( cpuType ) {
861 case CPU_TYPE_POWERPC:
862 dylibReader = ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, info.path, fOptions.readerOptions());
863 break;
864 case CPU_TYPE_POWERPC64:
865 dylibReader = ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, info.path, fOptions.readerOptions());
866 break;
867 case CPU_TYPE_I386:
868 dylibReader = i386::ObjectFileDylibMachO::MakeReader((class i386::macho_header*)mh, info.path, fOptions.readerOptions());
869 break;
870 default:
871 throw "wrong architecture in dylib";
872 }
873 this->addDylib(dylibReader, info);
874 return dylibReader;
875 }
876 throw "unknown mach-o file type";
877 }
878 else {
879 throw "file does not contain requested architecture";
880 }
881
882 }
883
884
885 void Linker::createReaders()
886 {
887 std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
888 const int count = files.size();
889 if ( count == 0 )
890 throw "no object files specified";
891 // add all direct object, archives, and dylibs
892 for (int i=0; i < count; ++i) {
893 Options::FileInfo& entry = files[i];
894 // ignore /usr/lib/dyld on command line in crt.o build
895 if ( strcmp(entry.path, "/usr/lib/dyld") != 0 ) {
896 try {
897 this->addInputFile(this->createReader(entry));
898 }
899 catch (const char* msg) {
900 if ( strstr(msg, "architecture") != NULL ) {
901 if ( fOptions.ignoreOtherArchInputFiles() ) {
902 // ignore, because this is about an architecture not in use
903 }
904 else {
905 fprintf(stderr, "ld64 warning: in %s, %s\n", entry.path, msg);
906 }
907 }
908 else {
909 throwf("in %s, %s", entry.path, msg);
910 }
911 }
912 }
913 }
914
915 // add first level of indirect dylibs
916 fDirectLibrariesComplete = true;
917 for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
918 this->addIndirectLibraries(it->reader);
919 }
920
921 // indirect handling depends on namespace
922 switch ( fOptions.nameSpace() ) {
923 case Options::kFlatNameSpace:
924 case Options::kForceFlatNameSpace:
925 // with flat namespace, blindly load all indirect libraries
926 // the indirect list will grow as indirect libraries are loaded
927 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
928 struct stat statBuffer;
929 if ( stat(it->path, &statBuffer) == 0 ) {
930 Options::FileInfo info;
931 info.path = it->path;
932 info.fileLen = statBuffer.st_size;
933 info.options.fWeakImport = false;
934 info.options.fReExport = false;
935 info.options.fInstallPathOverride = NULL;
936 it->reader = this->createReader(info);
937 }
938 else {
939 fprintf(stderr, "ld64 warning: indirect library not found: %s\n", it->path);
940 }
941 }
942 break;
943
944 case Options::kTwoLevelNameSpace:
945 // with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
946 {
947 bool indirectAdded = true;
948 while ( indirectAdded ) {
949 indirectAdded = false;
950 // instantiate a reader for each indirect library and try to find parent that re-exports it
951 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
952 if ( it->reader == NULL ) {
953 try {
954 struct stat statBuffer;
955 if ( stat(it->path, &statBuffer) != 0 )
956 throw "file not found";
957
958 Options::FileInfo info;
959 info.path = it->path;
960 info.fileLen = statBuffer.st_size;
961 info.options.fWeakImport = false;
962 info.options.fReExport = false;
963 info.options.fInstallPathOverride = NULL;
964 it->reader = this->createReader(info);
965 indirectAdded = true;
966 }
967 catch (const char* msg) {
968 fprintf(stderr, "ld64 warning: indirect library %s could not be loaded: %s\n", it->path, msg);
969 }
970 }
971 // if an indirect library does not have an assigned parent, look for one
972 if ( (it->reader != NULL) && (it->reExportParent == NULL) ) {
973 // ask each parent if they re-export this dylib
974 for (std::set<ObjectFile::Reader*>::iterator pit=it->parents.begin(); pit != it->parents.end(); pit++) {
975 if ( (*pit)->reExports(it->reader) ) {
976 it->reExportParent = *pit;
977 break;
978 }
979 }
980 }
981 }
982 }
983 }
984 break;
985 }
986
987 // add relevant indirect libraries to the end of fDynamicLibraries
988 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
989 if ( (it->reExportParent != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace) ) {
990 ExecutableFile::DyLibUsed dylibInfo;
991 dylibInfo.reader = it->reader;
992 dylibInfo.options.fWeakImport = false;
993 dylibInfo.options.fReExport = false;
994 dylibInfo.options.fInstallPathOverride = NULL;
995 dylibInfo.indirect = true;
996 dylibInfo.directReader = it->reExportParent;
997 fDynamicLibraries.push_back(dylibInfo);
998 if ( fOptions.readerOptions().fTraceIndirectDylibs )
999 printf("[Logging for Build & Integration] Used indirect dynamic library: %s\n", it->path);
1000 }
1001 }
1002 }
1003
1004
1005
1006 void Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info)
1007 {
1008 if ( fDirectLibrariesComplete ) {
1009 this->addIndirectLibraries(reader);
1010 }
1011 else {
1012 if ( fOptions.readerOptions().fTraceDylibs )
1013 printf("[Logging for Build & Integration] Used dynamic library: %s\n", reader->getPath());
1014 ExecutableFile::DyLibUsed dylibInfo;
1015 dylibInfo.reader = reader;
1016 dylibInfo.options = info.options;
1017 dylibInfo.indirect = false;
1018 dylibInfo.directReader = NULL;
1019 fDynamicLibraries.push_back(dylibInfo);
1020 }
1021 }
1022
1023
1024 void Linker::addIndirectLibraries(ObjectFile::Reader* reader)
1025 {
1026 std::vector<const char*>* dependentLibs = reader->getDependentLibraryPaths();
1027 if ( dependentLibs != NULL ) {
1028 for (std::vector<const char*>::iterator it=dependentLibs->begin(); it != dependentLibs->end(); it++) {
1029 if ( this->haveDirectLibrary(*it) ) {
1030 // do nothing, direct library already exists
1031 }
1032 else if ( this->haveIndirectLibrary(*it, reader) ) {
1033 // side effect of haveIndirectLibrary() added reader to parent list
1034 }
1035 else {
1036 // add to list of indirect libraries
1037 IndirectLibrary indirectLib;
1038 indirectLib.path = *it;
1039 indirectLib.fileLen = 0;
1040 indirectLib.reader = NULL;
1041 indirectLib.parents.insert(reader);
1042 indirectLib.reExportParent = NULL;
1043 fIndirectDynamicLibraries.push_back(indirectLib);
1044 //fprintf(stderr, "add indirect library: %s\n", *it);
1045 }
1046 }
1047 }
1048 }
1049
1050 bool Linker::haveIndirectLibrary(const char* path, ObjectFile::Reader* parentReader)
1051 {
1052 for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
1053 if ( strcmp(path, it->path) == 0 ) {
1054 it->parents.insert(parentReader);
1055 return true;
1056 }
1057 if ( it->reader != NULL ) {
1058 const char* installPath = it->reader->getInstallPath();
1059 if ( (installPath != NULL) && (strcmp(path, installPath) == 0) )
1060 return true;
1061 }
1062 }
1063 return false;
1064 }
1065
1066 bool Linker::haveDirectLibrary(const char* path)
1067 {
1068 for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
1069 if ( strcmp(path, it->reader->getPath()) == 0 )
1070 return true;
1071 const char* installPath = it->reader->getInstallPath();
1072 if ( (installPath != NULL) && (strcmp(path, installPath) == 0) )
1073 return true;
1074 }
1075 return false;
1076 }
1077
1078
1079
1080
1081 void Linker::createWriter()
1082 {
1083 const char* path = fOptions.getOutputFilePath();
1084 switch ( fOptions.architecture() ) {
1085 case CPU_TYPE_POWERPC:
1086 this->setOutputFile(ppc::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
1087 break;
1088 case CPU_TYPE_POWERPC64:
1089 this->setOutputFile(ppc64::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
1090 break;
1091 case CPU_TYPE_I386:
1092 this->setOutputFile(i386::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
1093 break;
1094 default:
1095 throw "unknown architecture";
1096 }
1097 }
1098
1099
1100 Linker::SymbolTable::SymbolTable(Linker& owner)
1101 : fOwner(owner), fRequireCount(0)
1102 {
1103 }
1104
1105 void Linker::SymbolTable::require(const char* name)
1106 {
1107 //fprintf(stderr, "require(%s)\n", name);
1108 Mapper::iterator pos = fTable.find(name);
1109 if ( pos == fTable.end() ) {
1110 fTable[name] = NULL;
1111 ++fRequireCount;
1112 }
1113 }
1114
1115 bool Linker::SymbolTable::add(ObjectFile::Atom& atom)
1116 {
1117 const bool log = false;
1118 const char* name = atom.getName();
1119 //fprintf(stderr, "map.add(%p: %s => %p)\n", &fTable, name, &atom);
1120 Mapper::iterator pos = fTable.find(name);
1121 if ( pos != fTable.end() ) {
1122 ObjectFile::Atom* existingAtom = pos->second;
1123 if ( existingAtom != NULL ) {
1124 if ( existingAtom->isTentativeDefinition() ) {
1125 if ( atom.isTentativeDefinition() ) {
1126 if ( atom.getSize() > existingAtom->getSize() ) {
1127 // replace common-symbol atom with another larger common-symbol
1128 if ( fOwner.fOptions.warnCommons() )
1129 fprintf(stderr, "ld64: replacing common symbol %s size %lld from %s with larger symbol size %lld from %s\n",
1130 existingAtom->getName(), existingAtom->getSize(), existingAtom->getFile()->getPath(), atom.getSize(), atom.getFile()->getPath());
1131 fOwner.fDeadAtoms.insert(existingAtom);
1132 fTable[name] = &atom;
1133 return true;
1134 }
1135 else {
1136 // keep existing common-symbol atom
1137 if ( fOwner.fOptions.warnCommons() ) {
1138 if ( atom.getSize() == existingAtom->getSize() )
1139 fprintf(stderr, "ld64: ignoring common symbol %s from %s because already have common from %s with same size\n",
1140 atom.getName(), atom.getFile()->getPath(), existingAtom->getFile()->getPath());
1141 else
1142 fprintf(stderr, "ld64: ignoring common symbol %s size %lld from %s because already have larger symbol size %lld from %s\n",
1143 atom.getName(), atom.getSize(), atom.getFile()->getPath(), existingAtom->getSize(), existingAtom->getFile()->getPath());
1144 }
1145 fOwner.fDeadAtoms.insert(&atom);
1146 return false;
1147 }
1148 }
1149 else {
1150 // have common symbol, now found true defintion
1151 if ( atom.isImportProxy() ) {
1152 // definition is in a dylib, so commons-mode decides how to handle
1153 switch ( fOwner.fOptions.commonsMode() ) {
1154 case Options::kCommonsIgnoreDylibs:
1155 if ( fOwner.fOptions.warnCommons() )
1156 fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
1157 existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
1158 fOwner.fDeadAtoms.insert(&atom);
1159 return false;
1160 case Options::kCommonsOverriddenByDylibs:
1161 if ( fOwner.fOptions.warnCommons() )
1162 fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from %s\n",
1163 existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
1164 fOwner.fDeadAtoms.insert(existingAtom);
1165 fTable[name] = &atom;
1166 return true;
1167 case Options::kCommonsConflictsDylibsError:
1168 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
1169 existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
1170 }
1171 }
1172 else {
1173 // replace common-symbol atom with true definition from .o file
1174 if ( fOwner.fOptions.warnCommons() ) {
1175 if ( atom.getSize() < existingAtom->getSize() )
1176 fprintf(stderr, "ld64: warning: replacing common symbol %s size %lld from %s with smaller true definition size %lld from %s\n",
1177 existingAtom->getName(), existingAtom->getSize(), existingAtom->getFile()->getPath(), atom.getSize(), atom.getFile()->getPath());
1178 else
1179 fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from %s\n",
1180 existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
1181 }
1182 fOwner.fDeadAtoms.insert(existingAtom);
1183 fTable[name] = &atom;
1184 return true;
1185 }
1186 }
1187 }
1188 else if ( atom.isTentativeDefinition() ) {
1189 // keep existing true definition, ignore new tentative definition
1190 if ( fOwner.fOptions.warnCommons() ) {
1191 if ( atom.getSize() > existingAtom->getSize() )
1192 fprintf(stderr, "ld64: warning: ignoring common symbol %s size %lld from %s because already have definition from %s size %lld, even though definition is smaller\n",
1193 atom.getName(), atom.getSize(), atom.getFile()->getPath(), existingAtom->getFile()->getPath(), existingAtom->getSize());
1194 else
1195 fprintf(stderr, "ld64: ignoring common symbol %s from %s because already have definition from %s\n",
1196 atom.getName(), atom.getFile()->getPath(), existingAtom->getFile()->getPath());
1197 }
1198 fOwner.fDeadAtoms.insert(&atom);
1199 return false;
1200 }
1201 else {
1202 // neither existing nor new atom are tentative definitions
1203 // if existing is weak, we may replace it
1204 if ( existingAtom->isWeakDefinition() ) {
1205 if ( atom.isImportProxy() ) {
1206 // keep weak definition even though one exists in a dylib, because coalescing means dylib's copy may not be used
1207 if ( log ) fprintf(stderr, "keep weak atom even though also in a dylib: %s\n", atom.getName());
1208 fOwner.fDeadAtoms.insert(&atom);
1209 return false;
1210 }
1211 else if ( atom.isWeakDefinition() ) {
1212 // have another weak atom, use existing, mark new as dead
1213 if ( log ) fprintf(stderr, "already have weak atom: %s\n", atom.getName());
1214 fOwner.fDeadAtoms.insert(&atom);
1215 return false;
1216 }
1217 else {
1218 // replace weak atom with non-weak atom
1219 if ( log ) fprintf(stderr, "replacing weak atom %p from %s with %p from %s: %s\n", existingAtom, existingAtom->getFile()->getPath(), &atom, atom.getFile()->getPath(), atom.getName());
1220 fOwner.fDeadAtoms.insert(existingAtom);
1221 fTable[name] = &atom;
1222 return true;
1223 }
1224 }
1225 }
1226 if ( atom.isWeakDefinition() ) {
1227 // ignore new weak atom, because we already have a non-weak one
1228 return false;
1229 }
1230 if ( atom.isCoalesableByName() && existingAtom->isCoalesableByName() ) {
1231 // both coalesable, so ignore duplicate
1232 return false;
1233 }
1234 fprintf(stderr, "duplicate symbol %s in %s and %s\n", name, atom.getFile()->getPath(), existingAtom->getFile()->getPath());
1235 }
1236 }
1237 fTable[name] = &atom;
1238 return true;
1239 }
1240
1241 ObjectFile::Atom* Linker::SymbolTable::find(const char* name)
1242 {
1243 Mapper::iterator pos = fTable.find(name);
1244 if ( pos != fTable.end() ) {
1245 return pos->second;
1246 }
1247 return NULL;
1248 }
1249
1250
1251 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines)
1252 {
1253 for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) {
1254 if ( (it->second == NULL) || (andWeakDefintions && it->second->isWeakDefinition()) ) {
1255 undefines.push_back(it->first);
1256 }
1257 }
1258 }
1259
1260
1261
1262
1263 bool Linker::AtomSorter::operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
1264 {
1265 // first sort by section order (which is already sorted by segment)
1266 unsigned int leftSectionIndex = left->getSection()->getIndex();
1267 unsigned int rightSectionIndex = right->getSection()->getIndex();
1268 if ( leftSectionIndex != rightSectionIndex)
1269 return (leftSectionIndex < rightSectionIndex);
1270
1271 // with a section, sort by original atom order (.o file order and atom order in .o files)
1272 return left->getSortOrder() < right->getSortOrder();
1273 }
1274
1275
1276 int main(int argc, const char* argv[])
1277 {
1278 try {
1279 // create linker object given command line arguments
1280 Linker ld(argc, argv);
1281
1282 // open all input files
1283 ld.createReaders();
1284
1285 // open output file
1286 ld.createWriter();
1287
1288 // do linking
1289 ld.link();
1290 }
1291 catch (const char* msg) {
1292 fprintf(stderr, "ld64 failed: %s\n", msg);
1293 return 1;
1294 }
1295
1296 return 0;
1297 }
1298
1299
1300
1301
1302
1303
1304