123.2
[darwin-xtools.git] / ld64 / src / ld / ld.cpp
blobd9d66a679ab86b4e0ea3df0ec2c3e08b88a37cda
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
3 * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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.
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.
22 * @APPLE_LICENSE_HEADER_END@
25 // start temp HACK for cross builds
26 extern "C" double log2 ( double );
27 //#define __MATH__
28 // end temp HACK for cross builds
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>
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>
61 #include "Options.h"
63 #include "MachOFileAbstraction.hpp"
64 #include "Architectures.hpp"
65 #include "ld.hpp"
67 #include "InputFiles.h"
68 #include "Resolver.h"
69 #include "OutputFile.h"
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"
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"
90 class InternalState : public ld::Internal
92 public:
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&);
97 void sortSections();
98 virtual ~InternalState() {}
99 private:
101 class FinalSection : public ld::Internal::FinalSection
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;
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;
125 struct SectionHash {
126 size_t operator()(const ld::Section*) const;
128 struct SectionEquals {
129 bool operator()(const ld::Section* left, const ld::Section* right) const;
131 typedef __gnu_cxx::hash_map<const ld::Section*, FinalSection*, SectionHash, SectionEquals> SectionInToOut;
134 SectionInToOut _sectionInToFinalMap;
135 const Options& _options;
138 ld::Section InternalState::FinalSection::_s_DATA_data( "__DATA", "__data", ld::Section::typeUnclassified);
139 ld::Section InternalState::FinalSection::_s_DATA_const("__DATA", "__const", ld::Section::typeUnclassified);
140 ld::Section InternalState::FinalSection::_s_TEXT_text( "__TEXT", "__text", ld::Section::typeCode);
141 ld::Section InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::Section::typeUnclassified);
142 ld::Section InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
143 ld::Section InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill);
144 std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen;
147 size_t InternalState::SectionHash::operator()(const ld::Section* sect) const
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;
156 bool InternalState::SectionEquals::operator()(const ld::Section* left, const ld::Section* right) const
158 return (*left == *right);
162 InternalState::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))
167 //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n",
168 // this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
171 const ld::Section& InternalState::FinalSection::outputSection(const ld::Section& sect)
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;
186 else if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
187 if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
188 return _s_TEXT_const;
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;
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;
204 else if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) {
205 if ( strcmp(sect.sectionName(), "__pointers") == 0 )
206 return _s_DATA_nl_symbol_ptr;
208 break;
209 case ld::Section::typeTentativeDefs:
210 return _s_DATA_common;
211 break;
212 // FIX ME: more
213 default:
214 break;
216 return sect;
219 const ld::Section& InternalState::FinalSection::objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal)
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;
227 uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, bool objFile)
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;
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;
248 _s_segmentsSeen.push_back(sect.segmentName());
249 return _s_segmentsSeen.size()-1+10;
252 uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint32_t sectionsSeen)
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;
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;
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;
344 #ifndef NDEBUG
345 static void validateFixups(const ld::Atom& atom)
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);
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;
412 lastClusterSize = fit->clusterSize;
413 if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
414 assert(fit->u.target != NULL);
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;
429 #endif
431 ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
433 ld::Internal::FinalSection* fs = this->getFinalSection(atom.section());
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;
450 break;
451 default:
452 break;
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;
463 ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& inputSection)
465 const ld::Section* baseForFinalSection = &inputSection;
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;
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:
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;
492 else if ( outSect != inputSection ) {
493 // new output section created, but not in map
494 baseForFinalSection = &outSect;
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;
506 objFile = true;
507 break;
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;
519 int InternalState::FinalSection::sectionComparer(const void* l, const void* r)
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);
528 void InternalState::sortSections()
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());
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());
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)) );
546 static void getVMInfo(vm_statistics_data_t& info)
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));
556 int main(int argc, const char* argv[])
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);
569 // create object to track command line arguments
570 Options options(argc, argv);
572 // gather stats
573 if ( options.printStatistics() )
574 getVMInfo(vmStart);
576 // update strings for error messages
577 showArch = options.printArchPrefix();
578 archName = options.architectureName();
579 archInferred = (options.architecture() == 0);
581 // open and parse input files
582 ld::tool::InputFiles inputFiles(options, &archName);
584 // load and resolve all references
585 InternalState state(options);
586 ld::tool::Resolver resolver(options, inputFiles, state);
587 resolver.resolve();
589 // add dylibs used
590 inputFiles.dylibs(state);
592 // do initial section sorting so passes have rough idea of the layout
593 state.sortSections();
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
608 // sort final sections
609 state.sortSections();
611 // write output file
612 ld::tool::OutputFile out(options);
613 out.write(state);
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);
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;
634 return 0;
638 #ifndef NDEBUG
639 // implement assert() function to print out a backtrace before aborting
640 void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
642 fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
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;
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);
661 exit(1);
663 #endif