]> git.saurik.com Git - apple/ld64.git/blame_incremental - src/ld/ld.cpp
ld64-123.2.1.tar.gz
[apple/ld64.git] / src / ld / ld.cpp
... / ...
CommitLineData
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
2 *
3 * Copyright (c) 2005-2010 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
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"
77#include "passes/order_file.h"
78#include "passes/branch_island.h"
79#include "passes/branch_shim.h"
80#include "passes/objc.h"
81#include "passes/dylibs.h"
82
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"
88
89
90class InternalState : public ld::Internal
91{
92public:
93 InternalState(const Options& opts) : _options(opts) { }
94 virtual ld::Internal::FinalSection* addAtom(const ld::Atom& atom);
95 virtual ld::Internal::FinalSection* getFinalSection(const ld::Section&);
96
97 void sortSections();
98 virtual ~InternalState() {}
99private:
100
101 class FinalSection : public ld::Internal::FinalSection
102 {
103 public:
104 FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile);
105 static int sectionComparer(const void* l, const void* r);
106 static const ld::Section& outputSection(const ld::Section& sect);
107 static const ld::Section& objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal);
108 private:
109 friend class InternalState;
110 static uint32_t sectionOrder(const ld::Section& sect, uint32_t sectionsSeen);
111 static uint32_t segmentOrder(const ld::Section& sect, bool objFile);
112 uint32_t _segmentOrder;
113 uint32_t _sectionOrder;
114
115 static std::vector<const char*> _s_segmentsSeen;
116 static ld::Section _s_DATA_data;
117 static ld::Section _s_DATA_const;
118 static ld::Section _s_TEXT_text;
119 static ld::Section _s_TEXT_const;
120 static ld::Section _s_DATA_nl_symbol_ptr;
121 static ld::Section _s_DATA_common;
122 };
123
124
125 struct SectionHash {
126 size_t operator()(const ld::Section*) const;
127 };
128 struct SectionEquals {
129 bool operator()(const ld::Section* left, const ld::Section* right) const;
130 };
131 typedef __gnu_cxx::hash_map<const ld::Section*, FinalSection*, SectionHash, SectionEquals> SectionInToOut;
132
133
134 SectionInToOut _sectionInToFinalMap;
135 const Options& _options;
136};
137
138ld::Section InternalState::FinalSection::_s_DATA_data( "__DATA", "__data", ld::Section::typeUnclassified);
139ld::Section InternalState::FinalSection::_s_DATA_const("__DATA", "__const", ld::Section::typeUnclassified);
140ld::Section InternalState::FinalSection::_s_TEXT_text( "__TEXT", "__text", ld::Section::typeCode);
141ld::Section InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::Section::typeUnclassified);
142ld::Section InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
143ld::Section InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill);
144std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen;
145
146
147size_t InternalState::SectionHash::operator()(const ld::Section* sect) const
148{
149 size_t hash = 0;
150 __gnu_cxx::hash<const char*> temp;
151 hash += temp.operator()(sect->segmentName());
152 hash += temp.operator()(sect->sectionName());
153 return hash;
154}
155
156bool InternalState::SectionEquals::operator()(const ld::Section* left, const ld::Section* right) const
157{
158 return (*left == *right);
159}
160
161
162InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile)
163 : ld::Internal::FinalSection(sect),
164 _segmentOrder(segmentOrder(sect, objFile)),
165 _sectionOrder(sectionOrder(sect, sectionsSeen))
166{
167 //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n",
168 // this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
169}
170
171const ld::Section& InternalState::FinalSection::outputSection(const ld::Section& sect)
172{
173 // merge sections in final linked image
174 switch ( sect.type() ) {
175 case ld::Section::typeLiteral4:
176 case ld::Section::typeLiteral8:
177 case ld::Section::typeLiteral16:
178 return _s_TEXT_const;
179 case ld::Section::typeUnclassified:
180 if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
181 if ( strcmp(sect.sectionName(), "__datacoal_nt") == 0 )
182 return _s_DATA_data;
183 if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
184 return _s_DATA_const;
185 }
186 else if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
187 if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
188 return _s_TEXT_const;
189 }
190 break;
191 case ld::Section::typeCode:
192 if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
193 if ( strcmp(sect.sectionName(), "__textcoal_nt") == 0 )
194 return _s_TEXT_text;
195 else if ( strcmp(sect.sectionName(), "__StaticInit") == 0 )
196 return _s_TEXT_text;
197 }
198 break;
199 case ld::Section::typeNonLazyPointer:
200 if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
201 if ( strcmp(sect.sectionName(), "__nl_symbol_ptr") == 0 )
202 return _s_DATA_nl_symbol_ptr;
203 }
204 else if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) {
205 if ( strcmp(sect.sectionName(), "__pointers") == 0 )
206 return _s_DATA_nl_symbol_ptr;
207 }
208 break;
209 case ld::Section::typeTentativeDefs:
210 return _s_DATA_common;
211 break;
212 // FIX ME: more
213 default:
214 break;
215 }
216 return sect;
217}
218
219const ld::Section& InternalState::FinalSection::objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal)
220{
221 // in -r mode the only section that ever changes is __tenative -> __common with -d option
222 if ( (sect.type() == ld::Section::typeTentativeDefs) && makeTentativeDefsReal)
223 return _s_DATA_common;
224 return sect;
225}
226
227uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, bool objFile)
228{
229 if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 )
230 return 0;
231 if ( strcmp(sect.segmentName(), "__HEADER") == 0 ) // only used with -preload
232 return 0;
233 if ( strcmp(sect.segmentName(), "__TEXT") == 0 )
234 return 1;
235 // in -r mode, want __DATA last so zerofill sections are at end
236 if ( strcmp(sect.segmentName(), "__DATA") == 0 )
237 return (objFile ? 5 : 2);
238 if ( strcmp(sect.segmentName(), "__OBJC") == 0 )
239 return 3;
240 if ( strcmp(sect.segmentName(), "__IMPORT") == 0 )
241 return 4;
242
243 // layout non-standard segments in order seen (+10 to shift beyond standard segments)
244 for (uint32_t i=0; i < _s_segmentsSeen.size(); ++i) {
245 if ( strcmp(_s_segmentsSeen[i], sect.segmentName()) == 0 )
246 return i+10;
247 }
248 _s_segmentsSeen.push_back(sect.segmentName());
249 return _s_segmentsSeen.size()-1+10;
250}
251
252uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint32_t sectionsSeen)
253{
254 if ( sect.type() == ld::Section::typeFirstSection )
255 return 0;
256 if ( sect.type() == ld::Section::typeMachHeader )
257 return 1;
258 if ( sect.type() == ld::Section::typeLastSection )
259 return INT_MAX;
260 if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
261 switch ( sect.type() ) {
262 case ld::Section::typeCode:
263 // <rdar://problem/8346444> make __text always be first "code" section
264 if ( strcmp(sect.sectionName(), "__text") == 0 )
265 return 10;
266 else
267 return 11;
268 case ld::Section::typeStub:
269 return 12;
270 case ld::Section::typeStubHelper:
271 return 13;
272 case ld::Section::typeLSDA:
273 return INT_MAX-3;
274 case ld::Section::typeUnwindInfo:
275 return INT_MAX-2;
276 case ld::Section::typeCFI:
277 return INT_MAX-1;
278 case ld::Section::typeStubClose:
279 return INT_MAX;
280 default:
281 return sectionsSeen+20;
282 }
283 }
284 else if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
285 switch ( sect.type() ) {
286 case ld::Section::typeLazyPointerClose:
287 return 8;
288 case ld::Section::typeDyldInfo:
289 return 9;
290 case ld::Section::typeNonLazyPointer:
291 return 10;
292 case ld::Section::typeLazyPointer:
293 return 11;
294 case ld::Section::typeInitializerPointers:
295 return 12;
296 case ld::Section::typeTerminatorPointers:
297 return 13;
298 case ld::Section::typeTLVInitialValues:
299 return INT_MAX-4; // need TLV zero-fill to follow TLV init values
300 case ld::Section::typeTLVZeroFill:
301 return INT_MAX-3;
302 case ld::Section::typeZeroFill:
303 // make sure __huge is always last zerofill section
304 if ( strcmp(sect.sectionName(), "__huge") == 0 )
305 return INT_MAX-1;
306 else
307 return INT_MAX-2;
308 default:
309 // <rdar://problem/7435296> Reorder sections to reduce page faults in object files
310 if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 )
311 return 20;
312 else if ( strcmp(sect.sectionName(), "__objc_nlclslist") == 0 )
313 return 21;
314 else if ( strcmp(sect.sectionName(), "__objc_catlist") == 0 )
315 return 22;
316 else if ( strcmp(sect.sectionName(), "__objc_protolist") == 0 )
317 return 23;
318 else if ( strcmp(sect.sectionName(), "__objc_imageinfo") == 0 )
319 return 24;
320 else if ( strcmp(sect.sectionName(), "__objc_const") == 0 )
321 return 25;
322 else if ( strcmp(sect.sectionName(), "__objc_selrefs") == 0 )
323 return 26;
324 else if ( strcmp(sect.sectionName(), "__objc_msgrefs") == 0 )
325 return 27;
326 else if ( strcmp(sect.sectionName(), "__objc_protorefs") == 0 )
327 return 28;
328 else if ( strcmp(sect.sectionName(), "__objc_classrefs") == 0 )
329 return 29;
330 else if ( strcmp(sect.sectionName(), "__objc_superrefs") == 0 )
331 return 30;
332 else if ( strcmp(sect.sectionName(), "__objc_data") == 0 )
333 return 31;
334 else
335 return sectionsSeen+40;
336 }
337 }
338 // make sure zerofill in any other section is at end of segment
339 if ( sect.type() == ld::Section::typeZeroFill )
340 return INT_MAX-1;
341 return sectionsSeen+20;
342}
343
344#ifndef NDEBUG
345static void validateFixups(const ld::Atom& atom)
346{
347 //fprintf(stderr, "validateFixups %s\n", atom.name());
348 bool lastWasClusterEnd = true;
349 ld::Fixup::Cluster lastClusterSize = ld::Fixup::k1of1;
350 uint32_t curClusterOffsetInAtom = 0;
351 for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
352 //fprintf(stderr, " fixup offset=%d, cluster=%d\n", fit->offsetInAtom, fit->clusterSize);
353 assert((fit->offsetInAtom < atom.size()) || (fit->offsetInAtom == 0));
354 if ( fit->firstInCluster() ) {
355 assert(lastWasClusterEnd);
356 curClusterOffsetInAtom = fit->offsetInAtom;
357 lastWasClusterEnd = (fit->clusterSize == ld::Fixup::k1of1);
358 }
359 else {
360 assert(!lastWasClusterEnd);
361 assert(fit->offsetInAtom == curClusterOffsetInAtom);
362 switch ((ld::Fixup::Cluster)fit->clusterSize) {
363 case ld::Fixup::k1of1:
364 case ld::Fixup::k1of2:
365 case ld::Fixup::k1of3:
366 case ld::Fixup::k1of4:
367 case ld::Fixup::k1of5:
368 lastWasClusterEnd = false;
369 break;
370 case ld::Fixup::k2of2:
371 assert(lastClusterSize = ld::Fixup::k1of2);
372 lastWasClusterEnd = true;
373 break;
374 case ld::Fixup::k2of3:
375 assert(lastClusterSize = ld::Fixup::k1of3);
376 lastWasClusterEnd = false;
377 break;
378 case ld::Fixup::k2of4:
379 assert(lastClusterSize = ld::Fixup::k1of4);
380 lastWasClusterEnd = false;
381 break;
382 case ld::Fixup::k2of5:
383 assert(lastClusterSize = ld::Fixup::k1of5);
384 lastWasClusterEnd = false;
385 break;
386 case ld::Fixup::k3of3:
387 assert(lastClusterSize = ld::Fixup::k2of3);
388 lastWasClusterEnd = true;
389 break;
390 case ld::Fixup::k3of4:
391 assert(lastClusterSize = ld::Fixup::k2of4);
392 lastWasClusterEnd = false;
393 break;
394 case ld::Fixup::k3of5:
395 assert(lastClusterSize = ld::Fixup::k2of5);
396 lastWasClusterEnd = false;
397 break;
398 case ld::Fixup::k4of4:
399 assert(lastClusterSize = ld::Fixup::k3of4);
400 lastWasClusterEnd = true;
401 break;
402 case ld::Fixup::k4of5:
403 assert(lastClusterSize = ld::Fixup::k3of5);
404 lastWasClusterEnd = false;
405 break;
406 case ld::Fixup::k5of5:
407 assert(lastClusterSize = ld::Fixup::k4of5);
408 lastWasClusterEnd = true;
409 break;
410 }
411 }
412 lastClusterSize = fit->clusterSize;
413 if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
414 assert(fit->u.target != NULL);
415 }
416 }
417 switch (lastClusterSize) {
418 case ld::Fixup::k1of1:
419 case ld::Fixup::k2of2:
420 case ld::Fixup::k3of3:
421 case ld::Fixup::k4of4:
422 case ld::Fixup::k5of5:
423 break;
424 default:
425 assert(0 && "last fixup was not end of cluster");
426 break;
427 }
428}
429#endif
430
431ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
432{
433 ld::Internal::FinalSection* fs = this->getFinalSection(atom.section());
434
435 // <rdar://problem/8612550> When order file used on data, turn ordered zero fill symbols into zero data
436 switch ( atom.section().type() ) {
437 case ld::Section::typeZeroFill:
438 case ld::Section::typeTentativeDefs:
439 if ( (_options.outputKind() == Options::kDyld) && (atom.symbolTableInclusion() == ld::Atom::symbolTableIn)
440 && (atom.size() <= 512) && (_options.orderedSymbolsCount() != 0) ) {
441 for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) {
442 if ( (it->objectFileName == NULL) && (strcmp(it->symbolName, atom.name()) == 0) ) {
443 // found in order file, move to __data section
444 fs = getFinalSection(InternalState::FinalSection::_s_DATA_data);\
445 //fprintf(stderr, "moved %s to __data section\n", atom.name());
446 break;
447 }
448 }
449 }
450 break;
451 default:
452 break;
453 }
454
455 //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs);
456#ifndef NDEBUG
457 validateFixups(atom);
458#endif
459 fs->atoms.push_back(&atom);
460 return fs;
461}
462
463ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& inputSection)
464{
465 const ld::Section* baseForFinalSection = &inputSection;
466
467 // see if input section already has a FinalSection
468 SectionInToOut::iterator pos = _sectionInToFinalMap.find(&inputSection);
469 if ( pos != _sectionInToFinalMap.end() ) {
470 return pos->second;
471 }
472
473 // otherwise, create a new final section
474 bool objFile = false;
475 switch ( _options.outputKind() ) {
476 case Options::kStaticExecutable:
477 case Options::kDynamicExecutable:
478 case Options::kDynamicLibrary:
479 case Options::kDynamicBundle:
480 case Options::kDyld:
481 case Options::kKextBundle:
482 case Options::kPreload:
483 {
484 // coalesce some sections
485 const ld::Section& outSect = FinalSection::outputSection(inputSection);
486 pos = _sectionInToFinalMap.find(&outSect);
487 if ( pos != _sectionInToFinalMap.end() ) {
488 _sectionInToFinalMap[&inputSection] = pos->second;
489 //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
490 return pos->second;
491 }
492 else if ( outSect != inputSection ) {
493 // new output section created, but not in map
494 baseForFinalSection = &outSect;
495 }
496 }
497 break;
498 case Options::kObjectFile:
499 baseForFinalSection = &FinalSection::objectOutputSection(inputSection, _options.makeTentativeDefinitionsReal());
500 pos = _sectionInToFinalMap.find(baseForFinalSection);
501 if ( pos != _sectionInToFinalMap.end() ) {
502 _sectionInToFinalMap[&inputSection] = pos->second;
503 //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
504 return pos->second;
505 }
506 objFile = true;
507 break;
508 }
509
510 InternalState::FinalSection* result = new InternalState::FinalSection(*baseForFinalSection,
511 _sectionInToFinalMap.size(), objFile);
512 _sectionInToFinalMap[baseForFinalSection] = result;
513 //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", baseForFinalSection, result);
514 sections.push_back(result);
515 return result;
516}
517
518
519int InternalState::FinalSection::sectionComparer(const void* l, const void* r)
520{
521 const FinalSection* left = *(FinalSection**)l;
522 const FinalSection* right = *(FinalSection**)r;
523 if ( left->_segmentOrder != right->_segmentOrder )
524 return (left->_segmentOrder - right->_segmentOrder);
525 return (left->_sectionOrder - right->_sectionOrder);
526}
527
528void InternalState::sortSections()
529{
530 //fprintf(stderr, "UNSORTED final sections:\n");
531 //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
532 // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
533 //}
534 qsort(&sections[0], sections.size(), sizeof(FinalSection*), &InternalState::FinalSection::sectionComparer);
535 //fprintf(stderr, "SORTED final sections:\n");
536 //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
537 // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
538 //}
539 assert((sections[0]->type() == ld::Section::typeMachHeader)
540 || ((sections[0]->type() == ld::Section::typeFirstSection) && (sections[1]->type() == ld::Section::typeMachHeader))
541 || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeMachHeader))
542 || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeFirstSection) && (sections[2]->type() == ld::Section::typeMachHeader)) );
543
544}
545
546static void getVMInfo(vm_statistics_data_t& info)
547{
548 mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t);
549 kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO,
550 (host_info_t)&info, &count);
551 if (error != KERN_SUCCESS) {
552 bzero(&info, sizeof(vm_statistics_data_t));
553 }
554}
555
556int main(int argc, const char* argv[])
557{
558#if DEBUG
559 usleep(1000000);
560#endif
561 const char* archName = NULL;
562 bool showArch = false;
563 bool archInferred = false;
564 try {
565 vm_statistics_data_t vmStart;
566 vm_statistics_data_t vmEnd;
567 getVMInfo(vmStart);
568
569 // create object to track command line arguments
570 Options options(argc, argv);
571
572 // gather stats
573 if ( options.printStatistics() )
574 getVMInfo(vmStart);
575
576 // update strings for error messages
577 showArch = options.printArchPrefix();
578 archName = options.architectureName();
579 archInferred = (options.architecture() == 0);
580
581 // open and parse input files
582 ld::tool::InputFiles inputFiles(options, &archName);
583
584 // load and resolve all references
585 InternalState state(options);
586 ld::tool::Resolver resolver(options, inputFiles, state);
587 resolver.resolve();
588
589 // add dylibs used
590 inputFiles.dylibs(state);
591
592 // do initial section sorting so passes have rough idea of the layout
593 state.sortSections();
594
595 // run passes
596 ld::passes::objc::doPass(options, state);
597 ld::passes::stubs::doPass(options, state);
598 ld::passes::huge::doPass(options, state);
599 ld::passes::got::doPass(options, state);
600 ld::passes::tlvp::doPass(options, state);
601 ld::passes::dylibs::doPass(options, state); // must be after stubs and GOT passes
602 ld::passes::order_file::doPass(options, state);
603 ld::passes::branch_shim::doPass(options, state); // must be after stubs
604 ld::passes::branch_island::doPass(options, state); // must be after stubs and order_file pass
605 ld::passes::dtrace::doPass(options, state);
606 ld::passes::compact_unwind::doPass(options, state); // must be after order-file pass
607
608 // sort final sections
609 state.sortSections();
610
611 // write output file
612 ld::tool::OutputFile out(options);
613 out.write(state);
614
615 // print statistics
616 //mach_o::relocatable::printCounts();
617 if ( options.printStatistics() ) {
618 getVMInfo(vmEnd);
619 fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", vmEnd.pageins-vmStart.pageins,
620 vmEnd.pageouts-vmStart.pageouts, vmEnd.faults-vmStart.faults);
621
622 }
623 }
624 catch (const char* msg) {
625 if ( archInferred )
626 fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName);
627 else if ( showArch )
628 fprintf(stderr, "ld: %s for architecture %s\n", msg, archName);
629 else
630 fprintf(stderr, "ld: %s\n", msg);
631 return 1;
632 }
633
634 return 0;
635}
636
637
638#ifndef NDEBUG
639// implement assert() function to print out a backtrace before aborting
640void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
641{
642 fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
643
644 void* callStack[128];
645 int depth = ::backtrace(callStack, 128);
646 char* buffer = (char*)malloc(1024);
647 for(int i=0; i < depth-1; ++i) {
648 Dl_info info;
649 dladdr(callStack[i], &info);
650 const char* symboName = info.dli_sname;
651 if ( (symboName != NULL) && (strncmp(symboName, "_Z", 2) == 0) ) {
652 size_t bufLen = 1024;
653 int result;
654 char* unmangled = abi::__cxa_demangle(symboName, buffer, &bufLen, &result);
655 if ( unmangled != NULL )
656 symboName = unmangled;
657 }
658 long offset = (uintptr_t)callStack[i] - (uintptr_t)info.dli_saddr;
659 fprintf(stderr, "%d %p %s + %ld\n", i, callStack[i], symboName, offset);
660 }
661 exit(1);
662}
663#endif
664
665