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