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