]> git.saurik.com Git - apple/ld64.git/blame - ld64-134.9/src/ld/ld.cpp
ld64-134.9.tar.gz
[apple/ld64.git] / ld64-134.9 / src / ld / ld.cpp
CommitLineData
b1f7435d
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
2 *
3 * Copyright (c) 2005-2011 Apple 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
25// start temp HACK for cross builds
26extern "C" double log2 ( double );
27//#define __MATH__
28// end temp HACK for cross builds
29
30
31#include <stdlib.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/mman.h>
35#include <sys/sysctl.h>
36#include <fcntl.h>
37#include <errno.h>
38#include <limits.h>
39#include <unistd.h>
40#include <execinfo.h>
41#include <mach/mach_time.h>
42#include <mach/vm_statistics.h>
43#include <mach/mach_init.h>
44#include <mach/mach_host.h>
45#include <dlfcn.h>
46#include <mach-o/dyld.h>
47#include <dlfcn.h>
48#include <AvailabilityMacros.h>
49
50#include <string>
51#include <map>
52#include <set>
53#include <string>
54#include <vector>
55#include <list>
56#include <algorithm>
57#include <ext/hash_map>
58#include <ext/hash_set>
59#include <cxxabi.h>
60
61#include "Options.h"
62
63#include "MachOFileAbstraction.hpp"
64#include "Architectures.hpp"
65#include "ld.hpp"
66
67#include "InputFiles.h"
68#include "Resolver.h"
69#include "OutputFile.h"
70#include "Snapshot.h"
71
72#include "passes/stubs/make_stubs.h"
73#include "passes/dtrace_dof.h"
74#include "passes/got.h"
75#include "passes/tlvp.h"
76#include "passes/huge.h"
77#include "passes/compact_unwind.h"
78#include "passes/order.h"
79#include "passes/branch_island.h"
80#include "passes/branch_shim.h"
81#include "passes/objc.h"
82#include "passes/dylibs.h"
83
84#include "parsers/archive_file.h"
85#include "parsers/macho_relocatable_file.h"
86#include "parsers/macho_dylib_file.h"
87#include "parsers/lto_file.h"
88#include "parsers/opaque_section_file.h"
89
90
91struct PerformanceStatistics {
92 uint64_t startTool;
93 uint64_t startInputFileProcessing;
94 uint64_t startResolver;
95 uint64_t startDylibs;
96 uint64_t startPasses;
97 uint64_t startOutput;
98 uint64_t startDone;
99 vm_statistics_data_t vmStart;
100 vm_statistics_data_t vmEnd;
101};
102
103
104
105
106
107class InternalState : public ld::Internal
108{
109public:
110 InternalState(const Options& opts) : _options(opts), _atomsOrderedInSections(false) { }
111 virtual ld::Internal::FinalSection* addAtom(const ld::Atom& atom);
112 virtual ld::Internal::FinalSection* getFinalSection(const ld::Section&);
113
114 void sortSections();
115 void markAtomsOrdered() { _atomsOrderedInSections = true; }
116 virtual ~InternalState() {}
117private:
118
119 class FinalSection : public ld::Internal::FinalSection
120 {
121 public:
122 FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile);
123 static int sectionComparer(const void* l, const void* r);
124 static const ld::Section& outputSection(const ld::Section& sect, bool mergeZeroFill);
125 static const ld::Section& objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal);
126 private:
127 friend class InternalState;
128 static uint32_t sectionOrder(const ld::Section& sect, uint32_t sectionsSeen);
129 static uint32_t segmentOrder(const ld::Section& sect, bool objFile);
130 uint32_t _segmentOrder;
131 uint32_t _sectionOrder;
132
133 static std::vector<const char*> _s_segmentsSeen;
134 static ld::Section _s_DATA_data;
135 static ld::Section _s_DATA_const;
136 static ld::Section _s_TEXT_text;
137 static ld::Section _s_TEXT_const;
138 static ld::Section _s_DATA_nl_symbol_ptr;
139 static ld::Section _s_DATA_common;
140 static ld::Section _s_DATA_zerofill;
141 };
142
143
144 struct SectionHash {
145 size_t operator()(const ld::Section*) const;
146 };
147 struct SectionEquals {
148 bool operator()(const ld::Section* left, const ld::Section* right) const;
149 };
150 typedef __gnu_cxx::hash_map<const ld::Section*, FinalSection*, SectionHash, SectionEquals> SectionInToOut;
151
152
153 SectionInToOut _sectionInToFinalMap;
154 const Options& _options;
155 bool _atomsOrderedInSections;
156};
157
158ld::Section InternalState::FinalSection::_s_DATA_data( "__DATA", "__data", ld::Section::typeUnclassified);
159ld::Section InternalState::FinalSection::_s_DATA_const("__DATA", "__const", ld::Section::typeUnclassified);
160ld::Section InternalState::FinalSection::_s_TEXT_text( "__TEXT", "__text", ld::Section::typeCode);
161ld::Section InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::Section::typeUnclassified);
162ld::Section InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
163ld::Section InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill);
164ld::Section InternalState::FinalSection::_s_DATA_zerofill("__DATA", "__zerofill", ld::Section::typeZeroFill);
165std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen;
166
167
168size_t InternalState::SectionHash::operator()(const ld::Section* sect) const
169{
170 size_t hash = 0;
171 __gnu_cxx::hash<const char*> temp;
172 hash += temp.operator()(sect->segmentName());
173 hash += temp.operator()(sect->sectionName());
174 return hash;
175}
176
177bool InternalState::SectionEquals::operator()(const ld::Section* left, const ld::Section* right) const
178{
179 return (*left == *right);
180}
181
182
183InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile)
184 : ld::Internal::FinalSection(sect),
185 _segmentOrder(segmentOrder(sect, objFile)),
186 _sectionOrder(sectionOrder(sect, sectionsSeen))
187{
188 //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n",
189 // this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
190}
191
192const ld::Section& InternalState::FinalSection::outputSection(const ld::Section& sect, bool mergeZeroFill)
193{
194 // merge sections in final linked image
195 switch ( sect.type() ) {
196 case ld::Section::typeLiteral4:
197 case ld::Section::typeLiteral8:
198 case ld::Section::typeLiteral16:
199 return _s_TEXT_const;
200 case ld::Section::typeUnclassified:
201 if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
202 if ( strcmp(sect.sectionName(), "__datacoal_nt") == 0 )
203 return _s_DATA_data;
204 if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
205 return _s_DATA_const;
206 }
207 else if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
208 if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
209 return _s_TEXT_const;
210 }
211 break;
212 case ld::Section::typeZeroFill:
213 if ( mergeZeroFill )
214 return _s_DATA_zerofill;
215 break;
216 case ld::Section::typeCode:
217 if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
218 if ( strcmp(sect.sectionName(), "__textcoal_nt") == 0 )
219 return _s_TEXT_text;
220 else if ( strcmp(sect.sectionName(), "__StaticInit") == 0 )
221 return _s_TEXT_text;
222 }
223 break;
224 case ld::Section::typeNonLazyPointer:
225 if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
226 if ( strcmp(sect.sectionName(), "__nl_symbol_ptr") == 0 )
227 return _s_DATA_nl_symbol_ptr;
228 }
229 else if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) {
230 if ( strcmp(sect.sectionName(), "__pointers") == 0 )
231 return _s_DATA_nl_symbol_ptr;
232 }
233 break;
234 case ld::Section::typeTentativeDefs:
235 if ( mergeZeroFill )
236 return _s_DATA_zerofill;
237 else
238 return _s_DATA_common;
239 break;
240 // FIX ME: more
241 default:
242 break;
243 }
244 return sect;
245}
246
247const ld::Section& InternalState::FinalSection::objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal)
248{
249 // in -r mode the only section that ever changes is __tenative -> __common with -d option
250 if ( (sect.type() == ld::Section::typeTentativeDefs) && makeTentativeDefsReal)
251 return _s_DATA_common;
252 return sect;
253}
254
255uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, bool objFile)
256{
257 if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 )
258 return 0;
259 if ( strcmp(sect.segmentName(), "__HEADER") == 0 ) // only used with -preload
260 return 0;
261 if ( strcmp(sect.segmentName(), "__TEXT") == 0 )
262 return 1;
263 // in -r mode, want __DATA last so zerofill sections are at end
264 if ( strcmp(sect.segmentName(), "__DATA") == 0 )
265 return (objFile ? 5 : 2);
266 if ( strcmp(sect.segmentName(), "__OBJC") == 0 )
267 return 3;
268 if ( strcmp(sect.segmentName(), "__IMPORT") == 0 )
269 return 4;
270
271 // layout non-standard segments in order seen (+10 to shift beyond standard segments)
272 for (uint32_t i=0; i < _s_segmentsSeen.size(); ++i) {
273 if ( strcmp(_s_segmentsSeen[i], sect.segmentName()) == 0 )
274 return i+10;
275 }
276 _s_segmentsSeen.push_back(sect.segmentName());
277 return _s_segmentsSeen.size()-1+10;
278}
279
280uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint32_t sectionsSeen)
281{
282 if ( sect.type() == ld::Section::typeFirstSection )
283 return 0;
284 if ( sect.type() == ld::Section::typeMachHeader )
285 return 1;
286 if ( sect.type() == ld::Section::typeLastSection )
287 return INT_MAX;
288 if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
289 switch ( sect.type() ) {
290 case ld::Section::typeCode:
291 // <rdar://problem/8346444> make __text always be first "code" section
292 if ( strcmp(sect.sectionName(), "__text") == 0 )
293 return 10;
294 else
295 return 11;
296 case ld::Section::typeStub:
297 return 12;
298 case ld::Section::typeStubHelper:
299 return 13;
300 case ld::Section::typeLSDA:
301 return INT_MAX-3;
302 case ld::Section::typeUnwindInfo:
303 return INT_MAX-2;
304 case ld::Section::typeCFI:
305 return INT_MAX-1;
306 case ld::Section::typeStubClose:
307 return INT_MAX;
308 default:
309 return sectionsSeen+20;
310 }
311 }
312 else if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
313 switch ( sect.type() ) {
314 case ld::Section::typeLazyPointerClose:
315 return 8;
316 case ld::Section::typeDyldInfo:
317 return 9;
318 case ld::Section::typeNonLazyPointer:
319 return 10;
320 case ld::Section::typeLazyPointer:
321 return 11;
322 case ld::Section::typeInitializerPointers:
323 return 12;
324 case ld::Section::typeTerminatorPointers:
325 return 13;
326 case ld::Section::typeTLVInitialValues:
327 return INT_MAX-4; // need TLV zero-fill to follow TLV init values
328 case ld::Section::typeTLVZeroFill:
329 return INT_MAX-3;
330 case ld::Section::typeZeroFill:
331 // make sure __huge is always last zerofill section
332 if ( strcmp(sect.sectionName(), "__huge") == 0 )
333 return INT_MAX-1;
334 else
335 return INT_MAX-2;
336 default:
337 // <rdar://problem/7435296> Reorder sections to reduce page faults in object files
338 if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 )
339 return 20;
340 else if ( strcmp(sect.sectionName(), "__objc_nlclslist") == 0 )
341 return 21;
342 else if ( strcmp(sect.sectionName(), "__objc_catlist") == 0 )
343 return 22;
344 else if ( strcmp(sect.sectionName(), "__objc_protolist") == 0 )
345 return 23;
346 else if ( strcmp(sect.sectionName(), "__objc_imageinfo") == 0 )
347 return 24;
348 else if ( strcmp(sect.sectionName(), "__objc_const") == 0 )
349 return 25;
350 else if ( strcmp(sect.sectionName(), "__objc_selrefs") == 0 )
351 return 26;
352 else if ( strcmp(sect.sectionName(), "__objc_msgrefs") == 0 )
353 return 27;
354 else if ( strcmp(sect.sectionName(), "__objc_protorefs") == 0 )
355 return 28;
356 else if ( strcmp(sect.sectionName(), "__objc_classrefs") == 0 )
357 return 29;
358 else if ( strcmp(sect.sectionName(), "__objc_superrefs") == 0 )
359 return 30;
360 else if ( strcmp(sect.sectionName(), "__objc_data") == 0 )
361 return 31;
362 else
363 return sectionsSeen+40;
364 }
365 }
366 // make sure zerofill in any other section is at end of segment
367 if ( sect.type() == ld::Section::typeZeroFill )
368 return INT_MAX-1;
369 return sectionsSeen+20;
370}
371
372#ifndef NDEBUG
373static void validateFixups(const ld::Atom& atom)
374{
375 //fprintf(stderr, "validateFixups %s\n", atom.name());
376 bool lastWasClusterEnd = true;
377 ld::Fixup::Cluster lastClusterSize = ld::Fixup::k1of1;
378 uint32_t curClusterOffsetInAtom = 0;
379 for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
380 //fprintf(stderr, " fixup offset=%d, cluster=%d\n", fit->offsetInAtom, fit->clusterSize);
381 assert((fit->offsetInAtom <= atom.size()) || (fit->offsetInAtom == 0));
382 if ( fit->firstInCluster() ) {
383 assert(lastWasClusterEnd);
384 curClusterOffsetInAtom = fit->offsetInAtom;
385 lastWasClusterEnd = (fit->clusterSize == ld::Fixup::k1of1);
386 }
387 else {
388 assert(!lastWasClusterEnd);
389 assert(fit->offsetInAtom == curClusterOffsetInAtom);
390 switch ((ld::Fixup::Cluster)fit->clusterSize) {
391 case ld::Fixup::k1of1:
392 case ld::Fixup::k1of2:
393 case ld::Fixup::k1of3:
394 case ld::Fixup::k1of4:
395 case ld::Fixup::k1of5:
396 lastWasClusterEnd = false;
397 break;
398 case ld::Fixup::k2of2:
399 assert(lastClusterSize = ld::Fixup::k1of2);
400 lastWasClusterEnd = true;
401 break;
402 case ld::Fixup::k2of3:
403 assert(lastClusterSize = ld::Fixup::k1of3);
404 lastWasClusterEnd = false;
405 break;
406 case ld::Fixup::k2of4:
407 assert(lastClusterSize = ld::Fixup::k1of4);
408 lastWasClusterEnd = false;
409 break;
410 case ld::Fixup::k2of5:
411 assert(lastClusterSize = ld::Fixup::k1of5);
412 lastWasClusterEnd = false;
413 break;
414 case ld::Fixup::k3of3:
415 assert(lastClusterSize = ld::Fixup::k2of3);
416 lastWasClusterEnd = true;
417 break;
418 case ld::Fixup::k3of4:
419 assert(lastClusterSize = ld::Fixup::k2of4);
420 lastWasClusterEnd = false;
421 break;
422 case ld::Fixup::k3of5:
423 assert(lastClusterSize = ld::Fixup::k2of5);
424 lastWasClusterEnd = false;
425 break;
426 case ld::Fixup::k4of4:
427 assert(lastClusterSize = ld::Fixup::k3of4);
428 lastWasClusterEnd = true;
429 break;
430 case ld::Fixup::k4of5:
431 assert(lastClusterSize = ld::Fixup::k3of5);
432 lastWasClusterEnd = false;
433 break;
434 case ld::Fixup::k5of5:
435 assert(lastClusterSize = ld::Fixup::k4of5);
436 lastWasClusterEnd = true;
437 break;
438 }
439 }
440 lastClusterSize = fit->clusterSize;
441 if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
442 assert(fit->u.target != NULL);
443 }
444 }
445 switch (lastClusterSize) {
446 case ld::Fixup::k1of1:
447 case ld::Fixup::k2of2:
448 case ld::Fixup::k3of3:
449 case ld::Fixup::k4of4:
450 case ld::Fixup::k5of5:
451 break;
452 default:
453 assert(0 && "last fixup was not end of cluster");
454 break;
455 }
456}
457#endif
458
459ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
460{
461 ld::Internal::FinalSection* fs = this->getFinalSection(atom.section());
462 //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs);
463#ifndef NDEBUG
464 validateFixups(atom);
465#endif
466 if ( _atomsOrderedInSections ) {
467 // make sure this atom is placed before any trailing section$end$ atom
468 if ( (fs->atoms.size() > 1) && (fs->atoms.back()->contentType() == ld::Atom::typeSectionEnd) ) {
469 // last atom in section$end$ atom, insert before it
470 const ld::Atom* endAtom = fs->atoms.back();
471 fs->atoms.pop_back();
472 fs->atoms.push_back(&atom);
473 fs->atoms.push_back(endAtom);
474 }
475 else {
476 // not end atom, just append new atom
477 fs->atoms.push_back(&atom);
478 }
479 }
480 else {
481 // normal case
482 fs->atoms.push_back(&atom);
483 }
484 return fs;
485}
486
487ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& inputSection)
488{
489 const ld::Section* baseForFinalSection = &inputSection;
490
491 // see if input section already has a FinalSection
492 SectionInToOut::iterator pos = _sectionInToFinalMap.find(&inputSection);
493 if ( pos != _sectionInToFinalMap.end() ) {
494 return pos->second;
495 }
496
497 // otherwise, create a new final section
498 bool objFile = false;
499 switch ( _options.outputKind() ) {
500 case Options::kStaticExecutable:
501 case Options::kDynamicExecutable:
502 case Options::kDynamicLibrary:
503 case Options::kDynamicBundle:
504 case Options::kDyld:
505 case Options::kKextBundle:
506 case Options::kPreload:
507 {
508 // coalesce some sections
509 const ld::Section& outSect = FinalSection::outputSection(inputSection, _options.mergeZeroFill());
510 pos = _sectionInToFinalMap.find(&outSect);
511 if ( pos != _sectionInToFinalMap.end() ) {
512 _sectionInToFinalMap[&inputSection] = pos->second;
513 //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
514 return pos->second;
515 }
516 else if ( outSect != inputSection ) {
517 // new output section created, but not in map
518 baseForFinalSection = &outSect;
519 }
520 }
521 break;
522 case Options::kObjectFile:
523 baseForFinalSection = &FinalSection::objectOutputSection(inputSection, _options.makeTentativeDefinitionsReal());
524 pos = _sectionInToFinalMap.find(baseForFinalSection);
525 if ( pos != _sectionInToFinalMap.end() ) {
526 _sectionInToFinalMap[&inputSection] = pos->second;
527 //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
528 return pos->second;
529 }
530 objFile = true;
531 break;
532 }
533
534 InternalState::FinalSection* result = new InternalState::FinalSection(*baseForFinalSection,
535 _sectionInToFinalMap.size(), objFile);
536 _sectionInToFinalMap[baseForFinalSection] = result;
537 //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", baseForFinalSection, result);
538 sections.push_back(result);
539 return result;
540}
541
542
543int InternalState::FinalSection::sectionComparer(const void* l, const void* r)
544{
545 const FinalSection* left = *(FinalSection**)l;
546 const FinalSection* right = *(FinalSection**)r;
547 if ( left->_segmentOrder != right->_segmentOrder )
548 return (left->_segmentOrder - right->_segmentOrder);
549 return (left->_sectionOrder - right->_sectionOrder);
550}
551
552void InternalState::sortSections()
553{
554 //fprintf(stderr, "UNSORTED final sections:\n");
555 //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
556 // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
557 //}
558 qsort(&sections[0], sections.size(), sizeof(FinalSection*), &InternalState::FinalSection::sectionComparer);
559 //fprintf(stderr, "SORTED final sections:\n");
560 //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
561 // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
562 //}
563 assert((sections[0]->type() == ld::Section::typeMachHeader)
564 || ((sections[0]->type() == ld::Section::typeFirstSection) && (sections[1]->type() == ld::Section::typeMachHeader))
565 || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeMachHeader))
566 || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeFirstSection) && (sections[2]->type() == ld::Section::typeMachHeader)) );
567
568}
569
570static char* commatize(uint64_t in, char* out)
571{
572 char* result = out;
573 char rawNum[30];
574 sprintf(rawNum, "%llu", in);
575 const int rawNumLen = strlen(rawNum);
576 for(int i=0; i < rawNumLen-1; ++i) {
577 *out++ = rawNum[i];
578 if ( ((rawNumLen-i) % 3) == 1 )
579 *out++ = ',';
580 }
581 *out++ = rawNum[rawNumLen-1];
582 *out = '\0';
583 return result;
584}
585
586static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
587{
588 static uint64_t sUnitsPerSecond = 0;
589 if ( sUnitsPerSecond == 0 ) {
590 struct mach_timebase_info timeBaseInfo;
591 if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
592 sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
593 //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
594 }
595 }
596 if ( partTime < sUnitsPerSecond ) {
597 uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
598 uint32_t milliSeconds = milliSecondsTimeTen/10;
599 uint32_t percentTimesTen = (partTime*1000)/totalTime;
600 uint32_t percent = percentTimesTen/10;
601 fprintf(stderr, "%24s: % 4d.%d milliseconds (% 4d.%d%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
602 }
603 else {
604 uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
605 uint32_t seconds = secondsTimeTen/10;
606 uint32_t percentTimesTen = (partTime*1000)/totalTime;
607 uint32_t percent = percentTimesTen/10;
608 fprintf(stderr, "%24s: % 4d.%d seconds (% 4d.%d%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
609 }
610}
611
612
613static void getVMInfo(vm_statistics_data_t& info)
614{
615 mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t);
616 kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO,
617 (host_info_t)&info, &count);
618 if (error != KERN_SUCCESS) {
619 bzero(&info, sizeof(vm_statistics_data_t));
620 }
621}
622
623
624
625static const char* sOverridePathlibLTO = NULL;
626
627//
628// This is magic glue that overrides the default behaviour
629// of lazydylib1.o which is used to lazily load libLTO.dylib.
630//
631extern "C" const char* dyld_lazy_dylib_path_fix(const char* path);
632const char* dyld_lazy_dylib_path_fix(const char* path)
633{
634 if ( sOverridePathlibLTO != NULL )
635 return sOverridePathlibLTO;
636 else
637 return path;
638}
639
640
641
642int main(int argc, const char* argv[])
643{
644 const char* archName = NULL;
645 bool showArch = false;
646 bool archInferred = false;
647 try {
648 PerformanceStatistics statistics;
649 statistics.startTool = mach_absolute_time();
650
651 // create object to track command line arguments
652 Options options(argc, argv);
653 InternalState state(options);
654
655 // allow libLTO to be overridden by command line -lto_library
656 sOverridePathlibLTO = options.overridePathlibLTO();
657
658 // gather vm stats
659 if ( options.printStatistics() )
660 getVMInfo(statistics.vmStart);
661
662 // update strings for error messages
663 showArch = options.printArchPrefix();
664 archName = options.architectureName();
665 archInferred = (options.architecture() == 0);
666
667 // open and parse input files
668 statistics.startInputFileProcessing = mach_absolute_time();
669 ld::tool::InputFiles inputFiles(options, &archName);
670
671 // load and resolve all references
672 statistics.startResolver = mach_absolute_time();
673 ld::tool::Resolver resolver(options, inputFiles, state);
674 resolver.resolve();
675
676 // add dylibs used
677 statistics.startDylibs = mach_absolute_time();
678 inputFiles.dylibs(state);
679
680 // do initial section sorting so passes have rough idea of the layout
681 state.sortSections();
682
683 // run passes
684 statistics.startPasses = mach_absolute_time();
685 ld::passes::objc::doPass(options, state);
686 ld::passes::stubs::doPass(options, state);
687 ld::passes::huge::doPass(options, state);
688 ld::passes::got::doPass(options, state);
689 ld::passes::tlvp::doPass(options, state);
690 ld::passes::dylibs::doPass(options, state); // must be after stubs and GOT passes
691 ld::passes::order::doPass(options, state);
692 state.markAtomsOrdered();
693 ld::passes::branch_shim::doPass(options, state); // must be after stubs
694 ld::passes::branch_island::doPass(options, state); // must be after stubs and order pass
695 ld::passes::dtrace::doPass(options, state);
696 ld::passes::compact_unwind::doPass(options, state); // must be after order pass
697
698 // sort final sections
699 state.sortSections();
700
701 // write output file
702 statistics.startOutput = mach_absolute_time();
703 ld::tool::OutputFile out(options);
704 out.write(state);
705 statistics.startDone = mach_absolute_time();
706
707 // print statistics
708 //mach_o::relocatable::printCounts();
709 if ( options.printStatistics() ) {
710 getVMInfo(statistics.vmEnd);
711 uint64_t totalTime = statistics.startDone - statistics.startTool;
712 printTime("ld total time", totalTime, totalTime);
713 printTime(" option parsing time", statistics.startInputFileProcessing - statistics.startTool, totalTime);
714 printTime(" object file processing", statistics.startResolver - statistics.startInputFileProcessing,totalTime);
715 printTime(" resolve symbols", statistics.startDylibs - statistics.startResolver, totalTime);
716 printTime(" build atom list", statistics.startPasses - statistics.startDylibs, totalTime);
717 printTime(" passess", statistics.startOutput - statistics.startPasses, totalTime);
718 printTime(" write output", statistics.startDone - statistics.startOutput, totalTime);
719 fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n",
720 statistics.vmEnd.pageins-statistics.vmStart.pageins,
721 statistics.vmEnd.pageouts-statistics.vmStart.pageouts,
722 statistics.vmEnd.faults-statistics.vmStart.faults);
723 char temp[40];
724 fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", inputFiles._totalObjectLoaded, commatize(inputFiles._totalObjectSize, temp));
725 fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", inputFiles._totalArchivesLoaded, commatize(inputFiles._totalArchiveSize, temp));
726 fprintf(stderr, "processed %3u dylib files\n", inputFiles._totalDylibsLoaded);
727 fprintf(stderr, "wrote output file totaling %15s bytes\n", commatize(out.fileSize(), temp));
728 }
729 // <rdar://problem/6780050> Would like linker warning to be build error.
730 if ( options.errorBecauseOfWarnings() ) {
731 fprintf(stderr, "ld: fatal warning(s) induced error (-fatal_warnings)\n");
732 return 1;
733 }
734 }
735 catch (const char* msg) {
736 if ( archInferred )
737 fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName);
738 else if ( showArch )
739 fprintf(stderr, "ld: %s for architecture %s\n", msg, archName);
740 else
741 fprintf(stderr, "ld: %s\n", msg);
742 return 1;
743 }
744
745 return 0;
746}
747
748
749#ifndef NDEBUG
750// implement assert() function to print out a backtrace before aborting
751void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
752{
753 Snapshot *snapshot = Snapshot::globalSnapshot;
754
755 snapshot->setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
756 snapshot->createSnapshot();
757 snapshot->recordAssertionMessage("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
758
759 void* callStack[128];
760 int depth = ::backtrace(callStack, 128);
761 char* buffer = (char*)malloc(1024);
762 for(int i=0; i < depth-1; ++i) {
763 Dl_info info;
764 dladdr(callStack[i], &info);
765 const char* symboName = info.dli_sname;
766 if ( (symboName != NULL) && (strncmp(symboName, "_Z", 2) == 0) ) {
767 size_t bufLen = 1024;
768 int result;
769 char* unmangled = abi::__cxa_demangle(symboName, buffer, &bufLen, &result);
770 if ( unmangled != NULL )
771 symboName = unmangled;
772 }
773 long offset = (uintptr_t)callStack[i] - (uintptr_t)info.dli_saddr;
774 fprintf(stderr, "%d %p %s + %ld\n", i, callStack[i], symboName, offset);
775 snapshot->recordAssertionMessage("%d %p %s + %ld\n", i, callStack[i], symboName, offset);
776 }
777 fprintf(stderr, "A linker snapshot was created at:\n\t%s\n", snapshot->rootDir());
778 fprintf(stderr, "ld: Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
779 exit(1);
780}
781#endif
782
783