1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
3 * Copyright (c) 2005-2011 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
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 );
28 // end temp HACK for cross builds
32 #include <sys/types.h>
35 #include <sys/sysctl.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>
46 #include <mach-o/dyld.h>
48 #include <AvailabilityMacros.h>
57 #include <unordered_map>
62 #include "MachOFileAbstraction.hpp"
63 #include "Architectures.hpp"
66 #include "InputFiles.h"
68 #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.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 struct PerformanceStatistics
{
92 uint64_t startInputFileProcessing
;
93 uint64_t startResolver
;
98 vm_statistics_data_t vmStart
;
99 vm_statistics_data_t vmEnd
;
103 class InternalState
: public ld::Internal
106 InternalState(const Options
& opts
) : _options(opts
), _atomsOrderedInSections(false) { }
107 virtual ld::Internal::FinalSection
* addAtom(const ld::Atom
& atom
);
108 virtual ld::Internal::FinalSection
* getFinalSection(const ld::Section
&);
109 ld::Internal::FinalSection
* getFinalSection(const char* seg
, const char* sect
, ld::Section::Type type
);
111 uint64_t assignFileOffsets();
112 void setSectionSizesAndAlignments();
114 void markAtomsOrdered() { _atomsOrderedInSections
= true; }
115 virtual ~InternalState() {}
118 class FinalSection
: public ld::Internal::FinalSection
121 FinalSection(const ld::Section
& sect
, uint32_t sectionsSeen
, const Options
&);
122 static int sectionComparer(const void* l
, const void* r
);
123 static const ld::Section
& outputSection(const ld::Section
& sect
, bool mergeZeroFill
);
124 static const ld::Section
& objectOutputSection(const ld::Section
& sect
, const Options
&);
126 friend class InternalState
;
127 static uint32_t sectionOrder(const ld::Section
& sect
, uint32_t sectionsSeen
, const Options
& options
);
128 static uint32_t segmentOrder(const ld::Section
& sect
, const Options
& options
);
129 uint32_t _segmentOrder
;
130 uint32_t _sectionOrder
;
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
;
139 static ld::Section _s_DATA_zerofill
;
142 bool hasZeroForFileOffset(const ld::Section
* sect
);
143 uint64_t pageAlign(uint64_t addr
);
144 uint64_t pageAlign(uint64_t addr
, uint64_t pageSize
);
147 size_t operator()(const ld::Section
*) const;
149 struct SectionEquals
{
150 bool operator()(const ld::Section
* left
, const ld::Section
* right
) const;
152 typedef std::unordered_map
<const ld::Section
*, FinalSection
*, SectionHash
, SectionEquals
> SectionInToOut
;
155 SectionInToOut _sectionInToFinalMap
;
156 const Options
& _options
;
157 bool _atomsOrderedInSections
;
160 ld::Section
InternalState::FinalSection::_s_DATA_data( "__DATA", "__data", ld::Section::typeUnclassified
);
161 ld::Section
InternalState::FinalSection::_s_DATA_const("__DATA", "__const", ld::Section::typeUnclassified
);
162 ld::Section
InternalState::FinalSection::_s_TEXT_text( "__TEXT", "__text", ld::Section::typeCode
);
163 ld::Section
InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::Section::typeUnclassified
);
164 ld::Section
InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer
);
165 ld::Section
InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill
);
166 ld::Section
InternalState::FinalSection::_s_DATA_zerofill("__DATA", "__zerofill", ld::Section::typeZeroFill
);
167 std::vector
<const char*> InternalState::FinalSection::_s_segmentsSeen
;
170 size_t InternalState::SectionHash::operator()(const ld::Section
* sect
) const
173 ld::CStringHash temp
;
174 hash
+= temp
.operator()(sect
->segmentName());
175 hash
+= temp
.operator()(sect
->sectionName());
179 bool InternalState::SectionEquals::operator()(const ld::Section
* left
, const ld::Section
* right
) const
181 return (*left
== *right
);
185 InternalState::FinalSection::FinalSection(const ld::Section
& sect
, uint32_t sectionsSeen
, const Options
& opts
)
186 : ld::Internal::FinalSection(sect
),
187 _segmentOrder(segmentOrder(sect
, opts
)),
188 _sectionOrder(sectionOrder(sect
, sectionsSeen
, opts
))
190 //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n",
191 // this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
194 const ld::Section
& InternalState::FinalSection::outputSection(const ld::Section
& sect
, bool mergeZeroFill
)
196 // merge sections in final linked image
197 switch ( sect
.type() ) {
198 case ld::Section::typeLiteral4
:
199 case ld::Section::typeLiteral8
:
200 case ld::Section::typeLiteral16
:
201 if ( strcmp(sect
.segmentName(), "__TEXT") == 0 )
202 return _s_TEXT_const
;
204 case ld::Section::typeUnclassified
:
205 if ( strcmp(sect
.segmentName(), "__DATA") == 0 ) {
206 if ( strcmp(sect
.sectionName(), "__datacoal_nt") == 0 )
208 if ( strcmp(sect
.sectionName(), "__const_coal") == 0 )
209 return _s_DATA_const
;
211 else if ( strcmp(sect
.segmentName(), "__TEXT") == 0 ) {
212 if ( strcmp(sect
.sectionName(), "__const_coal") == 0 )
213 return _s_TEXT_const
;
216 case ld::Section::typeZeroFill
:
218 return _s_DATA_zerofill
;
220 case ld::Section::typeCode
:
221 if ( strcmp(sect
.segmentName(), "__TEXT") == 0 ) {
222 if ( strcmp(sect
.sectionName(), "__textcoal_nt") == 0 )
224 else if ( strcmp(sect
.sectionName(), "__StaticInit") == 0 )
228 case ld::Section::typeNonLazyPointer
:
229 if ( strcmp(sect
.segmentName(), "__DATA") == 0 ) {
230 if ( strcmp(sect
.sectionName(), "__nl_symbol_ptr") == 0 )
231 return _s_DATA_nl_symbol_ptr
;
233 else if ( strcmp(sect
.segmentName(), "__IMPORT") == 0 ) {
234 if ( strcmp(sect
.sectionName(), "__pointers") == 0 )
235 return _s_DATA_nl_symbol_ptr
;
238 case ld::Section::typeTentativeDefs
:
239 if ( (strcmp(sect
.segmentName(), "__DATA") == 0) && (strcmp(sect
.sectionName(), "__comm/tent") == 0) ) {
241 return _s_DATA_zerofill
;
243 return _s_DATA_common
;
253 const ld::Section
& InternalState::FinalSection::objectOutputSection(const ld::Section
& sect
, const Options
& options
)
255 // in -r mode the only section that ever changes is __tenative -> __common with -d option
256 if ( (sect
.type() == ld::Section::typeTentativeDefs
) && options
.makeTentativeDefinitionsReal())
257 return _s_DATA_common
;
261 uint32_t InternalState::FinalSection::segmentOrder(const ld::Section
& sect
, const Options
& options
)
263 if ( options
.outputKind() == Options::kPreload
) {
264 if ( strcmp(sect
.segmentName(), "__HEADER") == 0 )
266 const std::vector
<const char*>& order
= options
.segmentOrder();
267 for (size_t i
=0; i
!= order
.size(); ++i
) {
268 if ( strcmp(sect
.segmentName(), order
[i
]) == 0 )
271 if ( strcmp(sect
.segmentName(), "__TEXT") == 0 )
272 return order
.size()+1;
273 if ( strcmp(sect
.segmentName(), "__DATA") == 0 )
274 return order
.size()+2;
277 if ( strcmp(sect
.segmentName(), "__PAGEZERO") == 0 )
279 if ( strcmp(sect
.segmentName(), "__TEXT") == 0 )
281 // in -r mode, want __DATA last so zerofill sections are at end
282 if ( strcmp(sect
.segmentName(), "__DATA") == 0 )
283 return (options
.outputKind() == Options::kObjectFile
) ? 5 : 2;
284 if ( strcmp(sect
.segmentName(), "__OBJC") == 0 )
286 if ( strcmp(sect
.segmentName(), "__IMPORT") == 0 )
289 // layout non-standard segments in order seen (+100 to shift beyond standard segments)
290 for (uint32_t i
=0; i
< _s_segmentsSeen
.size(); ++i
) {
291 if ( strcmp(_s_segmentsSeen
[i
], sect
.segmentName()) == 0 )
294 _s_segmentsSeen
.push_back(sect
.segmentName());
295 return _s_segmentsSeen
.size()-1+100;
298 uint32_t InternalState::FinalSection::sectionOrder(const ld::Section
& sect
, uint32_t sectionsSeen
, const Options
& options
)
300 if ( sect
.type() == ld::Section::typeFirstSection
)
302 if ( sect
.type() == ld::Section::typeMachHeader
)
304 if ( sect
.type() == ld::Section::typeLastSection
)
306 const std::vector
<const char*>* sectionList
= options
.sectionOrder(sect
.segmentName());
307 if ( (options
.outputKind() == Options::kPreload
) && (sectionList
!= NULL
) ) {
309 for (std::vector
<const char*>::const_iterator it
=sectionList
->begin(); it
!= sectionList
->end(); ++it
, ++count
) {
310 if ( strcmp(*it
, sect
.sectionName()) == 0 )
314 if ( strcmp(sect
.segmentName(), "__TEXT") == 0 ) {
315 switch ( sect
.type() ) {
316 case ld::Section::typeCode
:
317 // <rdar://problem/8346444> make __text always be first "code" section
318 if ( strcmp(sect
.sectionName(), "__text") == 0 )
322 case ld::Section::typeStub
:
324 case ld::Section::typeStubHelper
:
326 case ld::Section::typeLSDA
:
328 case ld::Section::typeUnwindInfo
:
330 case ld::Section::typeCFI
:
332 case ld::Section::typeStubClose
:
335 return sectionsSeen
+20;
338 else if ( strcmp(sect
.segmentName(), "__DATA") == 0 ) {
339 switch ( sect
.type() ) {
340 case ld::Section::typeLazyPointerClose
:
342 case ld::Section::typeDyldInfo
:
344 case ld::Section::typeNonLazyPointer
:
346 case ld::Section::typeLazyPointer
:
348 case ld::Section::typeInitializerPointers
:
350 case ld::Section::typeTerminatorPointers
:
352 case ld::Section::typeTLVInitialValues
:
353 return INT_MAX
-4; // need TLV zero-fill to follow TLV init values
354 case ld::Section::typeTLVZeroFill
:
356 case ld::Section::typeZeroFill
:
357 // make sure __huge is always last zerofill section
358 if ( strcmp(sect
.sectionName(), "__huge") == 0 )
363 // <rdar://problem/14348664> __DATA,__const section should be near __mod_init_func not __data
364 if ( strcmp(sect
.sectionName(), "__const") == 0 )
366 // <rdar://problem/17125893> Linker should put __cfstring near __const
367 if ( strcmp(sect
.sectionName(), "__cfstring") == 0 )
369 // <rdar://problem/7435296> Reorder sections to reduce page faults in object files
370 else if ( strcmp(sect
.sectionName(), "__objc_classlist") == 0 )
372 else if ( strcmp(sect
.sectionName(), "__objc_nlclslist") == 0 )
374 else if ( strcmp(sect
.sectionName(), "__objc_catlist") == 0 )
376 else if ( strcmp(sect
.sectionName(), "__objc_nlcatlist") == 0 )
378 else if ( strcmp(sect
.sectionName(), "__objc_protolist") == 0 )
380 else if ( strcmp(sect
.sectionName(), "__objc_imageinfo") == 0 )
382 else if ( strcmp(sect
.sectionName(), "__objc_const") == 0 )
384 else if ( strcmp(sect
.sectionName(), "__objc_selrefs") == 0 )
386 else if ( strcmp(sect
.sectionName(), "__objc_msgrefs") == 0 )
388 else if ( strcmp(sect
.sectionName(), "__objc_protorefs") == 0 )
390 else if ( strcmp(sect
.sectionName(), "__objc_classrefs") == 0 )
392 else if ( strcmp(sect
.sectionName(), "__objc_superrefs") == 0 )
394 else if ( strcmp(sect
.sectionName(), "__objc_ivar") == 0 )
396 else if ( strcmp(sect
.sectionName(), "__objc_data") == 0 )
399 return sectionsSeen
+40;
402 // make sure zerofill in any other section is at end of segment
403 if ( sect
.type() == ld::Section::typeZeroFill
)
405 return sectionsSeen
+20;
409 static void validateFixups(const ld::Atom
& atom
)
411 //fprintf(stderr, "validateFixups %s\n", atom.name());
412 bool lastWasClusterEnd
= true;
413 ld::Fixup::Cluster lastClusterSize
= ld::Fixup::k1of1
;
414 uint32_t curClusterOffsetInAtom
= 0;
415 for (ld::Fixup::iterator fit
=atom
.fixupsBegin(); fit
!= atom
.fixupsEnd(); ++fit
) {
416 //fprintf(stderr, " fixup offset=%d, cluster=%d\n", fit->offsetInAtom, fit->clusterSize);
417 assert((fit
->offsetInAtom
<= atom
.size()) || (fit
->offsetInAtom
== 0));
418 if ( fit
->firstInCluster() ) {
419 assert(lastWasClusterEnd
);
420 curClusterOffsetInAtom
= fit
->offsetInAtom
;
421 lastWasClusterEnd
= (fit
->clusterSize
== ld::Fixup::k1of1
);
424 assert(!lastWasClusterEnd
);
425 assert(fit
->offsetInAtom
== curClusterOffsetInAtom
);
426 switch ((ld::Fixup::Cluster
)fit
->clusterSize
) {
427 case ld::Fixup::k1of1
:
428 case ld::Fixup::k1of2
:
429 case ld::Fixup::k1of3
:
430 case ld::Fixup::k1of4
:
431 case ld::Fixup::k1of5
:
432 lastWasClusterEnd
= false;
434 case ld::Fixup::k2of2
:
435 assert(lastClusterSize
= ld::Fixup::k1of2
);
436 lastWasClusterEnd
= true;
438 case ld::Fixup::k2of3
:
439 assert(lastClusterSize
= ld::Fixup::k1of3
);
440 lastWasClusterEnd
= false;
442 case ld::Fixup::k2of4
:
443 assert(lastClusterSize
= ld::Fixup::k1of4
);
444 lastWasClusterEnd
= false;
446 case ld::Fixup::k2of5
:
447 assert(lastClusterSize
= ld::Fixup::k1of5
);
448 lastWasClusterEnd
= false;
450 case ld::Fixup::k3of3
:
451 assert(lastClusterSize
= ld::Fixup::k2of3
);
452 lastWasClusterEnd
= true;
454 case ld::Fixup::k3of4
:
455 assert(lastClusterSize
= ld::Fixup::k2of4
);
456 lastWasClusterEnd
= false;
458 case ld::Fixup::k3of5
:
459 assert(lastClusterSize
= ld::Fixup::k2of5
);
460 lastWasClusterEnd
= false;
462 case ld::Fixup::k4of4
:
463 assert(lastClusterSize
= ld::Fixup::k3of4
);
464 lastWasClusterEnd
= true;
466 case ld::Fixup::k4of5
:
467 assert(lastClusterSize
= ld::Fixup::k3of5
);
468 lastWasClusterEnd
= false;
470 case ld::Fixup::k5of5
:
471 assert(lastClusterSize
= ld::Fixup::k4of5
);
472 lastWasClusterEnd
= true;
476 lastClusterSize
= fit
->clusterSize
;
477 if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
478 assert(fit
->u
.target
!= NULL
);
481 switch (lastClusterSize
) {
482 case ld::Fixup::k1of1
:
483 case ld::Fixup::k2of2
:
484 case ld::Fixup::k3of3
:
485 case ld::Fixup::k4of4
:
486 case ld::Fixup::k5of5
:
489 assert(0 && "last fixup was not end of cluster");
495 ld::Internal::FinalSection
* InternalState::addAtom(const ld::Atom
& atom
)
497 ld::Internal::FinalSection
* fs
= NULL
;
498 const char* sectName
= atom
.section().sectionName();
499 ld::Section::Type sectType
= atom
.section().type();
500 const ld::File
* f
= atom
.file();
501 const char* path
= (f
!= NULL
) ? f
->path() : NULL
;
502 if ( atom
.section().type() == ld::Section::typeTentativeDefs
) {
503 // tentative defintions don't have a real section name yet
504 sectType
= ld::Section::typeZeroFill
;
505 if ( _options
.mergeZeroFill() )
506 sectName
= FinalSection::_s_DATA_zerofill
.sectionName();
508 sectName
= FinalSection::_s_DATA_common
.sectionName();
510 // Support for -move_to_r._segment
511 if ( atom
.symbolTableInclusion() == ld::Atom::symbolTableIn
) {
513 //fprintf(stderr, "%s\n", atom.name());
515 if ( _options
.moveRwSymbol(atom
.name(), path
, dstSeg
, wildCardMatch
) ) {
516 if ( (sectType
!= ld::Section::typeZeroFill
)
517 && (sectType
!= ld::Section::typeUnclassified
)
518 && (sectType
!= ld::Section::typeTentativeDefs
) ) {
519 if ( !wildCardMatch
)
520 warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not data (is %d)", atom
.name(), path
, dstSeg
, sectType
);
523 if ( _options
.traceSymbolLayout() )
524 printf("symbol '%s', -move_to_rw_segment mapped it to %s/%s\n", atom
.name(), dstSeg
, sectName
);
525 fs
= this->getFinalSection(dstSeg
, sectName
, sectType
);
528 if ( (fs
== NULL
) && _options
.moveRoSymbol(atom
.name(), path
, dstSeg
, wildCardMatch
) ) {
529 if ( atom
.section().type() != ld::Section::typeCode
) {
530 if ( !wildCardMatch
)
531 warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not code (is %d)", atom
.name(), path
, dstSeg
, sectType
);
534 if ( _options
.traceSymbolLayout() )
535 printf("symbol '%s', -move_to_ro_segment mapped it to %s/%s\n", atom
.name(), dstSeg
, sectName
);
536 fs
= this->getFinalSection(dstSeg
, sectName
, ld::Section::typeCode
);
540 // support for -rename_section and -rename_segment
542 const std::vector
<Options::SectionRename
>& sectRenames
= _options
.sectionRenames();
543 const std::vector
<Options::SegmentRename
>& segRenames
= _options
.segmentRenames();
544 for ( std::vector
<Options::SectionRename
>::const_iterator it
=sectRenames
.begin(); it
!= sectRenames
.end(); ++it
) {
545 if ( (strcmp(sectName
, it
->fromSection
) == 0) && (strcmp(atom
.section().segmentName(), it
->fromSegment
) == 0) ) {
546 if ( _options
.traceSymbolLayout() )
547 printf("symbol '%s', -rename_section mapped it to %s/%s\n", atom
.name(), it
->toSegment
, it
->toSection
);
548 fs
= this->getFinalSection(it
->toSegment
, it
->toSection
, sectType
);
552 for ( std::vector
<Options::SegmentRename
>::const_iterator it
=segRenames
.begin(); it
!= segRenames
.end(); ++it
) {
553 if ( strcmp(atom
.section().segmentName(), it
->fromSegment
) == 0 ) {
554 if ( _options
.traceSymbolLayout() )
555 printf("symbol '%s', -rename_segment mapped it to %s/%s\n", atom
.name(), it
->toSegment
, sectName
);
556 fs
= this->getFinalSection(it
->toSegment
, sectName
, sectType
);
563 // if no override, use default location
565 fs
= this->getFinalSection(atom
.section());
566 if ( _options
.traceSymbolLayout() && (atom
.symbolTableInclusion() == ld::Atom::symbolTableIn
) )
567 printf("symbol '%s', use default mapping to %s/%s\n", atom
.name(), fs
->segmentName(), fs
->sectionName());
570 //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs);
572 validateFixups(atom
);
574 if ( _atomsOrderedInSections
) {
575 // make sure this atom is placed before any trailing section$end$ atom
576 if ( (fs
->atoms
.size() > 1) && (fs
->atoms
.back()->contentType() == ld::Atom::typeSectionEnd
) ) {
577 // last atom in section$end$ atom, insert before it
578 const ld::Atom
* endAtom
= fs
->atoms
.back();
579 fs
->atoms
.pop_back();
580 fs
->atoms
.push_back(&atom
);
581 fs
->atoms
.push_back(endAtom
);
584 // not end atom, just append new atom
585 fs
->atoms
.push_back(&atom
);
590 fs
->atoms
.push_back(&atom
);
597 ld::Internal::FinalSection
* InternalState::getFinalSection(const char* seg
, const char* sect
, ld::Section::Type type
)
599 for (std::vector
<ld::Internal::FinalSection
*>::iterator it
=sections
.begin(); it
!= sections
.end(); ++it
) {
600 if ( (strcmp((*it
)->segmentName(),seg
) == 0) && (strcmp((*it
)->sectionName(),sect
) == 0) )
603 return this->getFinalSection(*new ld::Section(seg
, sect
, type
, false));
606 ld::Internal::FinalSection
* InternalState::getFinalSection(const ld::Section
& inputSection
)
608 const ld::Section
* baseForFinalSection
= &inputSection
;
610 // see if input section already has a FinalSection
611 SectionInToOut::iterator pos
= _sectionInToFinalMap
.find(&inputSection
);
612 if ( pos
!= _sectionInToFinalMap
.end() ) {
616 // otherwise, create a new final section
617 switch ( _options
.outputKind() ) {
618 case Options::kStaticExecutable
:
619 case Options::kDynamicExecutable
:
620 case Options::kDynamicLibrary
:
621 case Options::kDynamicBundle
:
623 case Options::kKextBundle
:
624 case Options::kPreload
:
626 // coalesce some sections
627 const ld::Section
& outSect
= FinalSection::outputSection(inputSection
, _options
.mergeZeroFill());
628 pos
= _sectionInToFinalMap
.find(&outSect
);
629 if ( pos
!= _sectionInToFinalMap
.end() ) {
630 _sectionInToFinalMap
[&inputSection
] = pos
->second
;
631 //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
634 else if ( outSect
!= inputSection
) {
635 // new output section created, but not in map
636 baseForFinalSection
= &outSect
;
640 case Options::kObjectFile
:
641 baseForFinalSection
= &FinalSection::objectOutputSection(inputSection
, _options
);
642 pos
= _sectionInToFinalMap
.find(baseForFinalSection
);
643 if ( pos
!= _sectionInToFinalMap
.end() ) {
644 _sectionInToFinalMap
[&inputSection
] = pos
->second
;
645 //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
651 InternalState::FinalSection
* result
= new InternalState::FinalSection(*baseForFinalSection
,
652 _sectionInToFinalMap
.size(), _options
);
653 _sectionInToFinalMap
[baseForFinalSection
] = result
;
654 //fprintf(stderr, "_sectionInToFinalMap[%p(%s)] = %p\n", baseForFinalSection, baseForFinalSection->sectionName(), result);
655 sections
.push_back(result
);
660 int InternalState::FinalSection::sectionComparer(const void* l
, const void* r
)
662 const FinalSection
* left
= *(FinalSection
**)l
;
663 const FinalSection
* right
= *(FinalSection
**)r
;
664 if ( left
->_segmentOrder
!= right
->_segmentOrder
)
665 return (left
->_segmentOrder
- right
->_segmentOrder
);
666 return (left
->_sectionOrder
- right
->_sectionOrder
);
669 void InternalState::sortSections()
671 //fprintf(stderr, "UNSORTED final sections:\n");
672 //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
673 // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
675 qsort(§ions
[0], sections
.size(), sizeof(FinalSection
*), &InternalState::FinalSection::sectionComparer
);
676 //fprintf(stderr, "SORTED final sections:\n");
677 //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
678 // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
680 assert((sections
[0]->type() == ld::Section::typeMachHeader
)
681 || ((sections
[0]->type() == ld::Section::typeFirstSection
) && (sections
[1]->type() == ld::Section::typeMachHeader
))
682 || ((sections
[0]->type() == ld::Section::typePageZero
) && (sections
[1]->type() == ld::Section::typeMachHeader
))
683 || ((sections
[0]->type() == ld::Section::typePageZero
) && (sections
[1]->type() == ld::Section::typeFirstSection
) && (sections
[2]->type() == ld::Section::typeMachHeader
)) );
688 bool InternalState::hasZeroForFileOffset(const ld::Section
* sect
)
690 switch ( sect
->type() ) {
691 case ld::Section::typeZeroFill
:
692 case ld::Section::typeTLVZeroFill
:
693 return _options
.optimizeZeroFill();
694 case ld::Section::typePageZero
:
695 case ld::Section::typeStack
:
696 case ld::Section::typeTentativeDefs
:
704 uint64_t InternalState::pageAlign(uint64_t addr
)
706 const uint64_t alignment
= _options
.segmentAlignment();
707 return ((addr
+alignment
-1) & (-alignment
));
710 uint64_t InternalState::pageAlign(uint64_t addr
, uint64_t pageSize
)
712 return ((addr
+pageSize
-1) & (-pageSize
));
715 void InternalState::setSectionSizesAndAlignments()
717 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= sections
.begin(); sit
!= sections
.end(); ++sit
) {
718 ld::Internal::FinalSection
* sect
= *sit
;
719 if ( sect
->type() == ld::Section::typeAbsoluteSymbols
) {
720 // absolute symbols need their finalAddress() to their value
721 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
722 const ld::Atom
* atom
= *ait
;
723 (const_cast<ld::Atom
*>(atom
))->setSectionOffset(atom
->objectAddress());
727 uint16_t maxAlignment
= 0;
729 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
730 const ld::Atom
* atom
= *ait
;
731 bool pagePerAtom
= false;
732 uint32_t atomAlignmentPowerOf2
= atom
->alignment().powerOf2
;
733 uint32_t atomModulus
= atom
->alignment().modulus
;
734 if ( _options
.pageAlignDataAtoms() && ( strcmp(atom
->section().segmentName(), "__DATA") == 0) ) {
735 // most objc sections cannot be padded
736 bool contiguousObjCSection
= ( strncmp(atom
->section().sectionName(), "__objc_", 7) == 0 );
737 if ( strcmp(atom
->section().sectionName(), "__objc_const") == 0 )
738 contiguousObjCSection
= false;
739 if ( strcmp(atom
->section().sectionName(), "__objc_data") == 0 )
740 contiguousObjCSection
= false;
741 switch ( atom
->section().type() ) {
742 case ld::Section::typeUnclassified
:
743 case ld::Section::typeTentativeDefs
:
744 case ld::Section::typeZeroFill
:
745 if ( contiguousObjCSection
)
748 if ( atomAlignmentPowerOf2
< 12 ) {
749 atomAlignmentPowerOf2
= 12;
757 if ( atomAlignmentPowerOf2
> maxAlignment
)
758 maxAlignment
= atomAlignmentPowerOf2
;
759 // calculate section offset for this atom
760 uint64_t alignment
= 1 << atomAlignmentPowerOf2
;
761 uint64_t currentModulus
= (offset
% alignment
);
762 uint64_t requiredModulus
= atomModulus
;
763 if ( currentModulus
!= requiredModulus
) {
764 if ( requiredModulus
> currentModulus
)
765 offset
+= requiredModulus
-currentModulus
;
767 offset
+= requiredModulus
+alignment
-currentModulus
;
769 // LINKEDIT atoms are laid out later
770 if ( sect
->type() != ld::Section::typeLinkEdit
) {
771 (const_cast<ld::Atom
*>(atom
))->setSectionOffset(offset
);
772 offset
+= atom
->size();
774 offset
= (offset
+ 4095) & (-4096); // round up to end of page
777 if ( (atom
->scope() == ld::Atom::scopeGlobal
)
778 && (atom
->definition() == ld::Atom::definitionRegular
)
779 && (atom
->combine() == ld::Atom::combineByName
)
780 && ((atom
->symbolTableInclusion() == ld::Atom::symbolTableIn
)
781 || (atom
->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip
)) ) {
782 this->hasWeakExternalSymbols
= true;
783 if ( _options
.warnWeakExports() )
784 warning("weak external symbol: %s", atom
->name());
788 // section alignment is that of a contained atom with the greatest alignment
789 sect
->alignment
= maxAlignment
;
790 // unless -sectalign command line option overrides
791 if ( _options
.hasCustomSectionAlignment(sect
->segmentName(), sect
->sectionName()) )
792 sect
->alignment
= _options
.customSectionAlignment(sect
->segmentName(), sect
->sectionName());
793 // each atom in __eh_frame has zero alignment to assure they pack together,
794 // but compilers usually make the CFIs pointer sized, so we want whole section
795 // to start on pointer sized boundary.
796 if ( sect
->type() == ld::Section::typeCFI
)
798 if ( sect
->type() == ld::Section::typeTLVDefs
)
799 this->hasThreadLocalVariableDefinitions
= true;
804 uint64_t InternalState::assignFileOffsets()
806 const bool log
= false;
807 const bool hiddenSectionsOccupyAddressSpace
= ((_options
.outputKind() != Options::kObjectFile
)
808 && (_options
.outputKind() != Options::kPreload
));
809 const bool segmentsArePageAligned
= (_options
.outputKind() != Options::kObjectFile
);
811 uint64_t address
= 0;
812 const char* lastSegName
= "";
813 uint64_t floatingAddressStart
= _options
.baseAddress();
815 // first pass, assign addresses to sections in segments with fixed start addresses
816 if ( log
) fprintf(stderr
, "Fixed address segments:\n");
817 for (std::vector
<ld::Internal::FinalSection
*>::iterator it
= sections
.begin(); it
!= sections
.end(); ++it
) {
818 ld::Internal::FinalSection
* sect
= *it
;
819 if ( ! _options
.hasCustomSegmentAddress(sect
->segmentName()) )
821 if ( segmentsArePageAligned
) {
822 if ( strcmp(lastSegName
, sect
->segmentName()) != 0 ) {
823 address
= _options
.customSegmentAddress(sect
->segmentName());
824 lastSegName
= sect
->segmentName();
827 // adjust section address based on alignment
828 uint64_t unalignedAddress
= address
;
829 uint64_t alignment
= (1 << sect
->alignment
);
830 address
= ( (unalignedAddress
+alignment
-1) & (-alignment
) );
832 // update section info
833 sect
->address
= address
;
834 sect
->alignmentPaddingBytes
= (address
- unalignedAddress
);
837 if ( ((address
+ sect
->size
) > _options
.maxAddress()) && (_options
.outputKind() != Options::kObjectFile
)
838 && (_options
.outputKind() != Options::kStaticExecutable
) )
839 throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range",
840 sect
->sectionName(), address
, sect
->size
);
842 if ( log
) fprintf(stderr
, " address=0x%08llX, hidden=%d, alignment=%02d, section=%s,%s\n",
843 sect
->address
, sect
->isSectionHidden(), sect
->alignment
, sect
->segmentName(), sect
->sectionName());
844 // update running totals
845 if ( !sect
->isSectionHidden() || hiddenSectionsOccupyAddressSpace
)
846 address
+= sect
->size
;
848 // if TEXT segment address is fixed, then flow other segments after it
849 if ( strcmp(sect
->segmentName(), "__TEXT") == 0 ) {
850 floatingAddressStart
= address
;
854 // second pass, assign section address to sections in segments that are contiguous with previous segment
855 address
= floatingAddressStart
;
857 ld::Internal::FinalSection
* overlappingFixedSection
= NULL
;
858 ld::Internal::FinalSection
* overlappingFlowSection
= NULL
;
859 if ( log
) fprintf(stderr
, "Regular layout segments:\n");
860 for (std::vector
<ld::Internal::FinalSection
*>::iterator it
= sections
.begin(); it
!= sections
.end(); ++it
) {
861 ld::Internal::FinalSection
* sect
= *it
;
862 if ( _options
.hasCustomSegmentAddress(sect
->segmentName()) )
864 if ( (_options
.outputKind() == Options::kPreload
) && (sect
->type() == ld::Section::typeMachHeader
) ) {
865 sect
->alignmentPaddingBytes
= 0;
868 if ( segmentsArePageAligned
) {
869 if ( strcmp(lastSegName
, sect
->segmentName()) != 0 ) {
870 // round up size of last segment if needed
871 if ( *lastSegName
!= '\0' ) {
872 address
= pageAlign(address
, _options
.segPageSize(lastSegName
));
874 // set segment address based on end of last segment
875 address
= pageAlign(address
);
876 lastSegName
= sect
->segmentName();
879 // adjust section address based on alignment
880 uint64_t unalignedAddress
= address
;
881 uint64_t alignment
= (1 << sect
->alignment
);
882 address
= ( (unalignedAddress
+alignment
-1) & (-alignment
) );
884 // update section info
885 sect
->address
= address
;
886 sect
->alignmentPaddingBytes
= (address
- unalignedAddress
);
889 if ( ((address
+ sect
->size
) > _options
.maxAddress()) && (_options
.outputKind() != Options::kObjectFile
)
890 && (_options
.outputKind() != Options::kStaticExecutable
) )
891 throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range",
892 sect
->sectionName(), address
, sect
->size
);
894 // sanity check it does not overlap a fixed address segment
895 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= sections
.begin(); sit
!= sections
.end(); ++sit
) {
896 ld::Internal::FinalSection
* otherSect
= *sit
;
897 if ( ! _options
.hasCustomSegmentAddress(otherSect
->segmentName()) )
899 if ( otherSect
->size
== 0 )
901 if ( sect
->size
== 0 )
903 if ( sect
->address
> otherSect
->address
) {
904 if ( (otherSect
->address
+otherSect
->size
) > sect
->address
) {
905 overlappingFixedSection
= otherSect
;
906 overlappingFlowSection
= sect
;
910 if ( (sect
->address
+sect
->size
) > otherSect
->address
) {
911 overlappingFixedSection
= otherSect
;
912 overlappingFlowSection
= sect
;
917 if ( log
) fprintf(stderr
, " address=0x%08llX, size=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
918 sect
->address
, sect
->size
, sect
->isSectionHidden(), sect
->alignment
, sect
->alignmentPaddingBytes
,
919 sect
->segmentName(), sect
->sectionName());
920 // update running totals
921 if ( !sect
->isSectionHidden() || hiddenSectionsOccupyAddressSpace
)
922 address
+= sect
->size
;
924 if ( overlappingFixedSection
!= NULL
) {
925 fprintf(stderr
, "Section layout:\n");
926 for (std::vector
<ld::Internal::FinalSection
*>::iterator it
= sections
.begin(); it
!= sections
.end(); ++it
) {
927 ld::Internal::FinalSection
* sect
= *it
;
928 //if ( sect->isSectionHidden() )
930 fprintf(stderr
, " address:0x%08llX, alignment:2^%d, size:0x%08llX, padBytes:%d, section:%s/%s\n",
931 sect
->address
, sect
->alignment
, sect
->size
, sect
->alignmentPaddingBytes
,
932 sect
->segmentName(), sect
->sectionName());
935 throwf("Section (%s/%s) overlaps fixed address section (%s/%s)",
936 overlappingFlowSection
->segmentName(), overlappingFlowSection
->sectionName(),
937 overlappingFixedSection
->segmentName(), overlappingFixedSection
->sectionName());
941 // third pass, assign section file offsets
942 uint64_t fileOffset
= 0;
944 if ( log
) fprintf(stderr
, "All segments with file offsets:\n");
945 for (std::vector
<ld::Internal::FinalSection
*>::iterator it
= sections
.begin(); it
!= sections
.end(); ++it
) {
946 ld::Internal::FinalSection
* sect
= *it
;
947 if ( hasZeroForFileOffset(sect
) ) {
948 // fileoff of zerofill sections is moot, but historically it is set to zero
949 sect
->fileOffset
= 0;
951 // <rdar://problem/10445047> align file offset with address layout
952 fileOffset
+= sect
->alignmentPaddingBytes
;
955 // page align file offset at start of each segment
956 if ( segmentsArePageAligned
&& (*lastSegName
!= '\0') && (strcmp(lastSegName
, sect
->segmentName()) != 0) ) {
957 fileOffset
= pageAlign(fileOffset
, _options
.segPageSize(lastSegName
));
959 lastSegName
= sect
->segmentName();
961 // align file offset with address layout
962 fileOffset
+= sect
->alignmentPaddingBytes
;
964 // update section info
965 sect
->fileOffset
= fileOffset
;
967 // update running total
968 fileOffset
+= sect
->size
;
971 if ( log
) fprintf(stderr
, " fileoffset=0x%08llX, address=0x%08llX, hidden=%d, size=%lld, alignment=%02d, section=%s,%s\n",
972 sect
->fileOffset
, sect
->address
, sect
->isSectionHidden(), sect
->size
, sect
->alignment
,
973 sect
->segmentName(), sect
->sectionName());
977 // for encrypted iPhoneOS apps
978 if ( _options
.makeEncryptable() ) {
979 // remember end of __TEXT for later use by load command
980 for (std::vector
<ld::Internal::FinalSection
*>::iterator it
= state
.sections
.begin(); it
!= state
.sections
.end(); ++it
) {
981 ld::Internal::FinalSection
* sect
= *it
;
982 if ( strcmp(sect
->segmentName(), "__TEXT") == 0 ) {
983 _encryptedTEXTendOffset
= pageAlign(sect
->fileOffset
+ sect
->size
);
989 // return total file size
993 static char* commatize(uint64_t in
, char* out
)
997 sprintf(rawNum
, "%llu", in
);
998 const int rawNumLen
= strlen(rawNum
);
999 for(int i
=0; i
< rawNumLen
-1; ++i
) {
1001 if ( ((rawNumLen
-i
) % 3) == 1 )
1004 *out
++ = rawNum
[rawNumLen
-1];
1009 static void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
)
1011 static uint64_t sUnitsPerSecond
= 0;
1012 if ( sUnitsPerSecond
== 0 ) {
1013 struct mach_timebase_info timeBaseInfo
;
1014 if ( mach_timebase_info(&timeBaseInfo
) != KERN_SUCCESS
)
1016 sUnitsPerSecond
= 1000000000ULL * timeBaseInfo
.denom
/ timeBaseInfo
.numer
;
1018 if ( partTime
< sUnitsPerSecond
) {
1019 uint32_t milliSecondsTimeTen
= (partTime
*10000)/sUnitsPerSecond
;
1020 uint32_t milliSeconds
= milliSecondsTimeTen
/10;
1021 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
1022 uint32_t percent
= percentTimesTen
/10;
1023 fprintf(stderr
, "%24s: % 4d.%d milliseconds (% 4d.%d%%)\n", msg
, milliSeconds
, milliSecondsTimeTen
-milliSeconds
*10, percent
, percentTimesTen
-percent
*10);
1026 uint32_t secondsTimeTen
= (partTime
*10)/sUnitsPerSecond
;
1027 uint32_t seconds
= secondsTimeTen
/10;
1028 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
1029 uint32_t percent
= percentTimesTen
/10;
1030 fprintf(stderr
, "%24s: % 4d.%d seconds (% 4d.%d%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10);
1035 static void getVMInfo(vm_statistics_data_t
& info
)
1037 mach_msg_type_number_t count
= sizeof(vm_statistics_data_t
) / sizeof(natural_t
);
1038 kern_return_t error
= host_statistics(mach_host_self(), HOST_VM_INFO
,
1039 (host_info_t
)&info
, &count
);
1040 if (error
!= KERN_SUCCESS
) {
1041 bzero(&info
, sizeof(vm_statistics_data_t
));
1047 static const char* sOverridePathlibLTO
= NULL
;
1050 // This is magic glue that overrides the default behaviour
1051 // of lazydylib1.o which is used to lazily load libLTO.dylib.
1053 extern "C" const char* dyld_lazy_dylib_path_fix(const char* path
);
1054 const char* dyld_lazy_dylib_path_fix(const char* path
)
1056 if ( sOverridePathlibLTO
!= NULL
)
1057 return sOverridePathlibLTO
;
1064 int main(int argc
, const char* argv
[])
1066 const char* archName
= NULL
;
1067 bool showArch
= false;
1068 bool archInferred
= false;
1070 PerformanceStatistics statistics
;
1071 statistics
.startTool
= mach_absolute_time();
1073 // create object to track command line arguments
1074 Options
options(argc
, argv
);
1075 InternalState
state(options
);
1077 // allow libLTO to be overridden by command line -lto_library
1078 sOverridePathlibLTO
= options
.overridePathlibLTO();
1081 if ( options
.printStatistics() )
1082 getVMInfo(statistics
.vmStart
);
1084 // update strings for error messages
1085 showArch
= options
.printArchPrefix();
1086 archName
= options
.architectureName();
1087 archInferred
= (options
.architecture() == 0);
1089 // open and parse input files
1090 statistics
.startInputFileProcessing
= mach_absolute_time();
1091 ld::tool::InputFiles
inputFiles(options
, &archName
);
1093 // load and resolve all references
1094 statistics
.startResolver
= mach_absolute_time();
1095 ld::tool::Resolver
resolver(options
, inputFiles
, state
);
1099 statistics
.startDylibs
= mach_absolute_time();
1100 inputFiles
.dylibs(state
);
1102 // do initial section sorting so passes have rough idea of the layout
1103 state
.sortSections();
1106 statistics
.startPasses
= mach_absolute_time();
1107 ld::passes::objc::doPass(options
, state
);
1108 ld::passes::stubs::doPass(options
, state
);
1109 ld::passes::huge::doPass(options
, state
);
1110 ld::passes::got::doPass(options
, state
);
1111 ld::passes::tlvp::doPass(options
, state
);
1112 ld::passes::dylibs::doPass(options
, state
); // must be after stubs and GOT passes
1113 ld::passes::order::doPass(options
, state
);
1114 state
.markAtomsOrdered();
1115 ld::passes::branch_shim::doPass(options
, state
); // must be after stubs
1116 ld::passes::branch_island::doPass(options
, state
); // must be after stubs and order pass
1117 ld::passes::dtrace::doPass(options
, state
);
1118 ld::passes::compact_unwind::doPass(options
, state
); // must be after order pass
1120 // sort final sections
1121 state
.sortSections();
1123 // write output file
1124 statistics
.startOutput
= mach_absolute_time();
1125 ld::tool::OutputFile
out(options
);
1127 statistics
.startDone
= mach_absolute_time();
1130 //mach_o::relocatable::printCounts();
1131 if ( options
.printStatistics() ) {
1132 getVMInfo(statistics
.vmEnd
);
1133 uint64_t totalTime
= statistics
.startDone
- statistics
.startTool
;
1134 printTime("ld total time", totalTime
, totalTime
);
1135 printTime(" option parsing time", statistics
.startInputFileProcessing
- statistics
.startTool
, totalTime
);
1136 printTime(" object file processing", statistics
.startResolver
- statistics
.startInputFileProcessing
,totalTime
);
1137 printTime(" resolve symbols", statistics
.startDylibs
- statistics
.startResolver
, totalTime
);
1138 printTime(" build atom list", statistics
.startPasses
- statistics
.startDylibs
, totalTime
);
1139 printTime(" passess", statistics
.startOutput
- statistics
.startPasses
, totalTime
);
1140 printTime(" write output", statistics
.startDone
- statistics
.startOutput
, totalTime
);
1141 fprintf(stderr
, "pageins=%u, pageouts=%u, faults=%u\n",
1142 statistics
.vmEnd
.pageins
-statistics
.vmStart
.pageins
,
1143 statistics
.vmEnd
.pageouts
-statistics
.vmStart
.pageouts
,
1144 statistics
.vmEnd
.faults
-statistics
.vmStart
.faults
);
1146 fprintf(stderr
, "processed %3u object files, totaling %15s bytes\n", inputFiles
._totalObjectLoaded
, commatize(inputFiles
._totalObjectSize
, temp
));
1147 fprintf(stderr
, "processed %3u archive files, totaling %15s bytes\n", inputFiles
._totalArchivesLoaded
, commatize(inputFiles
._totalArchiveSize
, temp
));
1148 fprintf(stderr
, "processed %3u dylib files\n", inputFiles
._totalDylibsLoaded
);
1149 fprintf(stderr
, "wrote output file totaling %15s bytes\n", commatize(out
.fileSize(), temp
));
1151 // <rdar://problem/6780050> Would like linker warning to be build error.
1152 if ( options
.errorBecauseOfWarnings() ) {
1153 fprintf(stderr
, "ld: fatal warning(s) induced error (-fatal_warnings)\n");
1157 catch (const char* msg
) {
1159 fprintf(stderr
, "ld: %s for inferred architecture %s\n", msg
, archName
);
1160 else if ( showArch
)
1161 fprintf(stderr
, "ld: %s for architecture %s\n", msg
, archName
);
1163 fprintf(stderr
, "ld: %s\n", msg
);
1172 // implement assert() function to print out a backtrace before aborting
1173 void __assert_rtn(const char* func
, const char* file
, int line
, const char* failedexpr
)
1175 Snapshot
*snapshot
= Snapshot::globalSnapshot
;
1177 snapshot
->setSnapshotMode(Snapshot::SNAPSHOT_DEBUG
);
1178 snapshot
->createSnapshot();
1179 snapshot
->recordAssertionMessage("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr
, func
, file
, line
);
1181 void* callStack
[128];
1182 int depth
= ::backtrace(callStack
, 128);
1183 char* buffer
= (char*)malloc(1024);
1184 for(int i
=0; i
< depth
-1; ++i
) {
1186 dladdr(callStack
[i
], &info
);
1187 const char* symboName
= info
.dli_sname
;
1188 if ( (symboName
!= NULL
) && (strncmp(symboName
, "_Z", 2) == 0) ) {
1189 size_t bufLen
= 1024;
1191 char* unmangled
= abi::__cxa_demangle(symboName
, buffer
, &bufLen
, &result
);
1192 if ( unmangled
!= NULL
)
1193 symboName
= unmangled
;
1195 long offset
= (uintptr_t)callStack
[i
] - (uintptr_t)info
.dli_saddr
;
1196 fprintf(stderr
, "%d %p %s + %ld\n", i
, callStack
[i
], symboName
, offset
);
1197 snapshot
->recordAssertionMessage("%d %p %s + %ld\n", i
, callStack
[i
], symboName
, offset
);
1199 fprintf(stderr
, "A linker snapshot was created at:\n\t%s\n", snapshot
->rootDir());
1200 fprintf(stderr
, "ld: Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr
, func
, file
, line
);