]> git.saurik.com Git - apple/ld64.git/blobdiff - ld64-134.9/src/ld/ld.cpp
ld64-136.tar.gz
[apple/ld64.git] / ld64-134.9 / src / ld / ld.cpp
diff --git a/ld64-134.9/src/ld/ld.cpp b/ld64-134.9/src/ld/ld.cpp
deleted file mode 100644 (file)
index 1a234db..0000000
+++ /dev/null
@@ -1,783 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
- *
- * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-// start temp HACK for cross builds
-extern "C" double log2 ( double );
-//#define __MATH__
-// end temp HACK for cross builds
-
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/sysctl.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <unistd.h>
-#include <execinfo.h>
-#include <mach/mach_time.h>
-#include <mach/vm_statistics.h>
-#include <mach/mach_init.h>
-#include <mach/mach_host.h>
-#include <dlfcn.h>
-#include <mach-o/dyld.h>
-#include <dlfcn.h>
-#include <AvailabilityMacros.h>
-
-#include <string>
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-#include <list>
-#include <algorithm>
-#include <ext/hash_map>
-#include <ext/hash_set>
-#include <cxxabi.h>
-
-#include "Options.h"
-
-#include "MachOFileAbstraction.hpp"
-#include "Architectures.hpp"
-#include "ld.hpp"
-
-#include "InputFiles.h"
-#include "Resolver.h"
-#include "OutputFile.h"
-#include "Snapshot.h"
-
-#include "passes/stubs/make_stubs.h"
-#include "passes/dtrace_dof.h"
-#include "passes/got.h"
-#include "passes/tlvp.h"
-#include "passes/huge.h"
-#include "passes/compact_unwind.h"
-#include "passes/order.h"
-#include "passes/branch_island.h"
-#include "passes/branch_shim.h"
-#include "passes/objc.h"
-#include "passes/dylibs.h"
-
-#include "parsers/archive_file.h"
-#include "parsers/macho_relocatable_file.h"
-#include "parsers/macho_dylib_file.h"
-#include "parsers/lto_file.h"
-#include "parsers/opaque_section_file.h"
-
-
-struct PerformanceStatistics {
-       uint64_t                                                startTool;
-       uint64_t                                                startInputFileProcessing;
-       uint64_t                                                startResolver;
-       uint64_t                                                startDylibs;
-       uint64_t                                                startPasses;
-       uint64_t                                                startOutput;
-       uint64_t                                                startDone;
-       vm_statistics_data_t                    vmStart;
-       vm_statistics_data_t                    vmEnd;
-};
-
-
-
-
-
-class InternalState : public ld::Internal
-{
-public:
-                                                                                       InternalState(const Options& opts) : _options(opts), _atomsOrderedInSections(false) { }
-       virtual ld::Internal::FinalSection*             addAtom(const ld::Atom& atom);
-       virtual ld::Internal::FinalSection*             getFinalSection(const ld::Section&);
-       
-       void                                                                    sortSections();
-       void                                                                    markAtomsOrdered() { _atomsOrderedInSections = true; }
-       virtual                                                                 ~InternalState() {}
-private:
-
-       class FinalSection : public ld::Internal::FinalSection 
-       {
-       public:
-                                                       FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile);
-               static int                                      sectionComparer(const void* l, const void* r);
-               static const ld::Section&       outputSection(const ld::Section& sect, bool mergeZeroFill);
-               static const ld::Section&       objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal);
-       private:
-               friend class InternalState;
-               static uint32_t         sectionOrder(const ld::Section& sect, uint32_t sectionsSeen);
-               static uint32_t         segmentOrder(const ld::Section& sect, bool objFile);
-               uint32_t                        _segmentOrder;
-               uint32_t                        _sectionOrder;
-
-               static std::vector<const char*> _s_segmentsSeen;
-               static ld::Section              _s_DATA_data;
-               static ld::Section              _s_DATA_const;
-               static ld::Section              _s_TEXT_text;
-               static ld::Section              _s_TEXT_const;
-               static ld::Section              _s_DATA_nl_symbol_ptr;
-               static ld::Section              _s_DATA_common;
-               static ld::Section              _s_DATA_zerofill;
-       };
-       
-       
-       struct SectionHash {
-               size_t operator()(const ld::Section*) const;
-       };
-       struct SectionEquals {
-               bool operator()(const ld::Section* left, const ld::Section* right) const;
-       };
-       typedef __gnu_cxx::hash_map<const ld::Section*, FinalSection*, SectionHash, SectionEquals> SectionInToOut;
-       
-
-       SectionInToOut                  _sectionInToFinalMap;
-       const Options&                  _options;
-       bool                                    _atomsOrderedInSections;
-};
-
-ld::Section    InternalState::FinalSection::_s_DATA_data( "__DATA", "__data",  ld::Section::typeUnclassified);
-ld::Section    InternalState::FinalSection::_s_DATA_const("__DATA", "__const", ld::Section::typeUnclassified);
-ld::Section    InternalState::FinalSection::_s_TEXT_text( "__TEXT", "__text",  ld::Section::typeCode);
-ld::Section    InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::Section::typeUnclassified);
-ld::Section    InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
-ld::Section    InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill);
-ld::Section    InternalState::FinalSection::_s_DATA_zerofill("__DATA", "__zerofill", ld::Section::typeZeroFill);
-std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen;
-
-
-size_t InternalState::SectionHash::operator()(const ld::Section* sect) const
-{
-       size_t hash = 0;        
-       __gnu_cxx::hash<const char*> temp;
-       hash += temp.operator()(sect->segmentName());
-       hash += temp.operator()(sect->sectionName());
-       return hash;
-}
-
-bool InternalState::SectionEquals::operator()(const ld::Section* left, const ld::Section* right) const
-{
-       return (*left == *right);
-}
-
-
-InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile)
-       : ld::Internal::FinalSection(sect), 
-         _segmentOrder(segmentOrder(sect, objFile)),
-         _sectionOrder(sectionOrder(sect, sectionsSeen))
-{
-       //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n", 
-       //              this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
-}
-
-const ld::Section& InternalState::FinalSection::outputSection(const ld::Section& sect, bool mergeZeroFill)
-{
-       // merge sections in final linked image
-       switch ( sect.type() ) {
-               case ld::Section::typeLiteral4:
-               case ld::Section::typeLiteral8:
-               case ld::Section::typeLiteral16:
-                       return _s_TEXT_const;
-               case ld::Section::typeUnclassified:
-                       if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
-                               if ( strcmp(sect.sectionName(), "__datacoal_nt") == 0 )
-                                       return _s_DATA_data;
-                               if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
-                                       return _s_DATA_const;
-                       }
-                       else if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
-                               if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
-                                       return _s_TEXT_const;
-                       }
-                       break;
-               case ld::Section::typeZeroFill:
-                       if ( mergeZeroFill )
-                               return _s_DATA_zerofill;
-                       break;
-               case ld::Section::typeCode:
-                       if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
-                               if ( strcmp(sect.sectionName(), "__textcoal_nt") == 0 )
-                                       return _s_TEXT_text;
-                               else if ( strcmp(sect.sectionName(), "__StaticInit") == 0 )
-                                       return _s_TEXT_text;
-                       }
-                       break;
-               case ld::Section::typeNonLazyPointer:
-                       if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
-                               if ( strcmp(sect.sectionName(), "__nl_symbol_ptr") == 0 )
-                                       return _s_DATA_nl_symbol_ptr;
-                       }
-                       else if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) {
-                               if ( strcmp(sect.sectionName(), "__pointers") == 0 )
-                                       return _s_DATA_nl_symbol_ptr; 
-                       }
-                       break;
-               case ld::Section::typeTentativeDefs:
-                       if ( mergeZeroFill )
-                               return _s_DATA_zerofill;
-                       else
-                               return _s_DATA_common;
-                       break;
-                       // FIX ME: more 
-               default:
-                       break;
-       }
-       return sect;
-}
-
-const ld::Section& InternalState::FinalSection::objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal)
-{
-       // in -r mode the only section that ever changes is __tenative -> __common with -d option
-       if ( (sect.type() == ld::Section::typeTentativeDefs) && makeTentativeDefsReal)
-               return _s_DATA_common;
-       return sect;
-}
-
-uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, bool objFile)
-{
-       if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 ) 
-               return 0;
-       if ( strcmp(sect.segmentName(), "__HEADER") == 0 ) // only used with -preload
-               return 0;
-       if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) 
-               return 1;
-       // in -r mode, want __DATA  last so zerofill sections are at end
-       if ( strcmp(sect.segmentName(), "__DATA") == 0 ) 
-               return (objFile ? 5 : 2);
-       if ( strcmp(sect.segmentName(), "__OBJC") == 0 ) 
-               return 3;
-       if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) 
-               return 4;
-       
-       // layout non-standard segments in order seen (+10 to shift beyond standard segments)
-       for (uint32_t i=0; i < _s_segmentsSeen.size(); ++i) {
-               if ( strcmp(_s_segmentsSeen[i], sect.segmentName()) == 0 )
-                       return i+10;
-       }
-       _s_segmentsSeen.push_back(sect.segmentName());
-       return _s_segmentsSeen.size()-1+10;
-}
-
-uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint32_t sectionsSeen)
-{
-       if ( sect.type() == ld::Section::typeFirstSection )
-               return 0;
-       if ( sect.type() == ld::Section::typeMachHeader )
-               return 1;
-       if ( sect.type() == ld::Section::typeLastSection )
-               return INT_MAX;
-       if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
-               switch ( sect.type() ) {
-                       case ld::Section::typeCode:
-                               // <rdar://problem/8346444> make __text always be first "code" section
-                               if ( strcmp(sect.sectionName(), "__text") == 0 )
-                                       return 10;
-                               else
-                                       return 11;
-                       case ld::Section::typeStub:
-                               return 12;
-                       case ld::Section::typeStubHelper:
-                               return 13;
-                       case ld::Section::typeLSDA:
-                               return INT_MAX-3;
-                       case ld::Section::typeUnwindInfo:
-                               return INT_MAX-2;
-                       case ld::Section::typeCFI:
-                               return INT_MAX-1;
-                       case ld::Section::typeStubClose:
-                               return INT_MAX;
-                       default:
-                               return sectionsSeen+20;
-               }
-       }
-       else if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
-               switch ( sect.type() ) {
-                       case ld::Section::typeLazyPointerClose:
-                               return 8;
-                       case ld::Section::typeDyldInfo:
-                               return 9;
-                       case ld::Section::typeNonLazyPointer:
-                               return 10;
-                       case ld::Section::typeLazyPointer:
-                               return 11;
-                       case ld::Section::typeInitializerPointers:
-                               return 12;
-                       case ld::Section::typeTerminatorPointers:
-                               return 13;
-                       case ld::Section::typeTLVInitialValues:
-                               return INT_MAX-4; // need TLV zero-fill to follow TLV init values
-                       case ld::Section::typeTLVZeroFill:
-                               return INT_MAX-3;
-                       case ld::Section::typeZeroFill:
-                               // make sure __huge is always last zerofill section
-                               if ( strcmp(sect.sectionName(), "__huge") == 0 )
-                                       return INT_MAX-1;
-                               else
-                                       return INT_MAX-2;
-                       default:
-                               // <rdar://problem/7435296> Reorder sections to reduce page faults in object files
-                               if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 ) 
-                                       return 20;
-                               else if ( strcmp(sect.sectionName(), "__objc_nlclslist") == 0 ) 
-                                       return 21;
-                               else if ( strcmp(sect.sectionName(), "__objc_catlist") == 0 ) 
-                                       return 22;
-                               else if ( strcmp(sect.sectionName(), "__objc_protolist") == 0 ) 
-                                       return 23;
-                               else if ( strcmp(sect.sectionName(), "__objc_imageinfo") == 0 ) 
-                                       return 24;
-                               else if ( strcmp(sect.sectionName(), "__objc_const") == 0 ) 
-                                       return 25;
-                               else if ( strcmp(sect.sectionName(), "__objc_selrefs") == 0 ) 
-                                       return 26;
-                               else if ( strcmp(sect.sectionName(), "__objc_msgrefs") == 0 ) 
-                                       return 27;
-                               else if ( strcmp(sect.sectionName(), "__objc_protorefs") == 0 ) 
-                                       return 28;
-                               else if ( strcmp(sect.sectionName(), "__objc_classrefs") == 0 ) 
-                                       return 29;
-                               else if ( strcmp(sect.sectionName(), "__objc_superrefs") == 0 ) 
-                                       return 30;
-                               else if ( strcmp(sect.sectionName(), "__objc_data") == 0 ) 
-                                       return 31;
-                               else
-                                       return sectionsSeen+40;
-               }
-       }
-       // make sure zerofill in any other section is at end of segment
-       if ( sect.type() == ld::Section::typeZeroFill )
-               return INT_MAX-1;
-       return sectionsSeen+20;
-}
-
-#ifndef NDEBUG
-static void validateFixups(const ld::Atom& atom)
-{
-       //fprintf(stderr, "validateFixups %s\n", atom.name());
-       bool lastWasClusterEnd = true;
-       ld::Fixup::Cluster lastClusterSize = ld::Fixup::k1of1;
-       uint32_t curClusterOffsetInAtom = 0;
-       for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
-               //fprintf(stderr, "  fixup offset=%d, cluster=%d\n", fit->offsetInAtom, fit->clusterSize);
-               assert((fit->offsetInAtom <= atom.size()) || (fit->offsetInAtom == 0));
-               if ( fit->firstInCluster() ) {
-                       assert(lastWasClusterEnd);
-                       curClusterOffsetInAtom = fit->offsetInAtom;
-                       lastWasClusterEnd = (fit->clusterSize == ld::Fixup::k1of1);
-               }
-               else {
-                       assert(!lastWasClusterEnd);
-                       assert(fit->offsetInAtom == curClusterOffsetInAtom);
-                       switch ((ld::Fixup::Cluster)fit->clusterSize) {
-                               case ld::Fixup::k1of1:
-                               case ld::Fixup::k1of2:
-                               case ld::Fixup::k1of3:
-                               case ld::Fixup::k1of4:
-                               case ld::Fixup::k1of5:
-                                       lastWasClusterEnd = false;
-                                       break;
-                               case ld::Fixup::k2of2:
-                                       assert(lastClusterSize = ld::Fixup::k1of2);
-                                       lastWasClusterEnd = true;
-                                       break;
-                               case ld::Fixup::k2of3:
-                                       assert(lastClusterSize = ld::Fixup::k1of3);
-                                       lastWasClusterEnd = false;
-                                       break;
-                               case ld::Fixup::k2of4:
-                                       assert(lastClusterSize = ld::Fixup::k1of4);
-                                       lastWasClusterEnd = false;
-                                       break;
-                               case ld::Fixup::k2of5:
-                                       assert(lastClusterSize = ld::Fixup::k1of5);
-                                       lastWasClusterEnd = false;
-                                       break;
-                               case ld::Fixup::k3of3:
-                                       assert(lastClusterSize = ld::Fixup::k2of3);
-                                       lastWasClusterEnd = true;
-                                       break;
-                               case ld::Fixup::k3of4:
-                                       assert(lastClusterSize = ld::Fixup::k2of4);
-                                       lastWasClusterEnd = false;
-                                       break;
-                               case ld::Fixup::k3of5:
-                                       assert(lastClusterSize = ld::Fixup::k2of5);
-                                       lastWasClusterEnd = false;
-                                       break;
-                               case ld::Fixup::k4of4:
-                                       assert(lastClusterSize = ld::Fixup::k3of4);
-                                       lastWasClusterEnd = true;
-                                       break;
-                               case ld::Fixup::k4of5:
-                                       assert(lastClusterSize = ld::Fixup::k3of5);
-                                       lastWasClusterEnd = false;
-                                       break;
-                               case ld::Fixup::k5of5:
-                                       assert(lastClusterSize = ld::Fixup::k4of5);
-                                       lastWasClusterEnd = true;
-                                       break;
-                       }
-               }
-               lastClusterSize = fit->clusterSize;
-               if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
-                       assert(fit->u.target != NULL);
-               }
-       }
-       switch (lastClusterSize) {
-               case ld::Fixup::k1of1:
-               case ld::Fixup::k2of2:
-               case ld::Fixup::k3of3:
-               case ld::Fixup::k4of4:
-               case ld::Fixup::k5of5:
-                       break;
-               default:
-                       assert(0 && "last fixup was not end of cluster");
-                       break;
-       }
-}
-#endif
-
-ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
-{
-       ld::Internal::FinalSection* fs = this->getFinalSection(atom.section());
-       //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs);
-#ifndef NDEBUG
-       validateFixups(atom);
-#endif
-       if ( _atomsOrderedInSections ) {
-               // make sure this atom is placed before any trailing section$end$ atom
-               if ( (fs->atoms.size() > 1) && (fs->atoms.back()->contentType() == ld::Atom::typeSectionEnd) ) {
-                       // last atom in section$end$ atom, insert before it
-                       const ld::Atom* endAtom = fs->atoms.back();
-                       fs->atoms.pop_back();
-                       fs->atoms.push_back(&atom);
-                       fs->atoms.push_back(endAtom);
-               }
-               else {
-                       // not end atom, just append new atom
-                       fs->atoms.push_back(&atom);
-               }
-       }
-       else {
-               // normal case
-               fs->atoms.push_back(&atom);
-       }
-       return fs;
-}
-
-ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& inputSection)
-{      
-       const ld::Section* baseForFinalSection = &inputSection;
-       
-       // see if input section already has a FinalSection
-       SectionInToOut::iterator pos = _sectionInToFinalMap.find(&inputSection);
-       if ( pos != _sectionInToFinalMap.end() ) {
-               return pos->second;
-       }
-
-       // otherwise, create a new final section
-       bool objFile = false;
-       switch ( _options.outputKind() ) {
-               case Options::kStaticExecutable:
-               case Options::kDynamicExecutable:
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kDyld:
-               case Options::kKextBundle:
-               case Options::kPreload:
-                       {
-                               // coalesce some sections
-                               const ld::Section& outSect = FinalSection::outputSection(inputSection, _options.mergeZeroFill());
-                               pos = _sectionInToFinalMap.find(&outSect);
-                               if ( pos != _sectionInToFinalMap.end() ) {
-                                       _sectionInToFinalMap[&inputSection] = pos->second;
-                                       //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
-                                       return pos->second;
-                               }
-                               else if ( outSect != inputSection ) {
-                                       // new output section created, but not in map
-                                       baseForFinalSection = &outSect;
-                               }
-                       }
-                       break;
-               case Options::kObjectFile:
-                       baseForFinalSection = &FinalSection::objectOutputSection(inputSection, _options.makeTentativeDefinitionsReal());
-                       pos = _sectionInToFinalMap.find(baseForFinalSection);
-                       if ( pos != _sectionInToFinalMap.end() ) {
-                               _sectionInToFinalMap[&inputSection] = pos->second;
-                               //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
-                               return pos->second;
-                       }
-                       objFile = true;
-                       break;
-       }
-
-       InternalState::FinalSection* result = new InternalState::FinalSection(*baseForFinalSection, 
-                                                                                                                                       _sectionInToFinalMap.size(), objFile);
-       _sectionInToFinalMap[baseForFinalSection] = result;
-       //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", baseForFinalSection, result);
-       sections.push_back(result);
-       return result;
-}
-
-
-int InternalState::FinalSection::sectionComparer(const void* l, const void* r)
-{
-       const FinalSection* left  = *(FinalSection**)l;
-       const FinalSection* right = *(FinalSection**)r;
-       if ( left->_segmentOrder != right->_segmentOrder )
-               return (left->_segmentOrder - right->_segmentOrder);
-       return (left->_sectionOrder - right->_sectionOrder);
-}
-
-void InternalState::sortSections()
-{
-       //fprintf(stderr, "UNSORTED final sections:\n");
-       //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
-       //      fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
-       //}
-       qsort(&sections[0], sections.size(), sizeof(FinalSection*), &InternalState::FinalSection::sectionComparer);
-       //fprintf(stderr, "SORTED final sections:\n");
-       //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
-       //      fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
-       //}
-       assert((sections[0]->type() == ld::Section::typeMachHeader) 
-               || ((sections[0]->type() == ld::Section::typeFirstSection) && (sections[1]->type() == ld::Section::typeMachHeader))
-               || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeMachHeader))
-               || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeFirstSection) && (sections[2]->type() == ld::Section::typeMachHeader)) );
-       
-}
-
-static char* commatize(uint64_t in, char* out)
-{
-       char* result = out;
-       char rawNum[30];
-       sprintf(rawNum, "%llu", in);
-       const int rawNumLen = strlen(rawNum);
-       for(int i=0; i < rawNumLen-1; ++i) {
-               *out++ = rawNum[i];
-               if ( ((rawNumLen-i) % 3) == 1 )
-                       *out++ = ',';
-       }
-       *out++ = rawNum[rawNumLen-1];
-       *out = '\0';
-       return result;
-}
-
-static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
-{
-       static uint64_t sUnitsPerSecond = 0;
-       if ( sUnitsPerSecond == 0 ) {
-               struct mach_timebase_info timeBaseInfo;
-               if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
-                       sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
-                       //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
-               }
-       }
-       if ( partTime < sUnitsPerSecond ) {
-               uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
-               uint32_t milliSeconds = milliSecondsTimeTen/10;
-               uint32_t percentTimesTen = (partTime*1000)/totalTime;
-               uint32_t percent = percentTimesTen/10;
-               fprintf(stderr, "%24s: % 4d.%d milliseconds (% 4d.%d%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
-       }
-       else {
-               uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
-               uint32_t seconds = secondsTimeTen/10;
-               uint32_t percentTimesTen = (partTime*1000)/totalTime;
-               uint32_t percent = percentTimesTen/10;
-               fprintf(stderr, "%24s: % 4d.%d seconds (% 4d.%d%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
-       }
-}
-
-
-static void getVMInfo(vm_statistics_data_t& info)
-{
-       mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t);
-       kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO,
-                                                       (host_info_t)&info, &count);
-       if (error != KERN_SUCCESS) {
-               bzero(&info, sizeof(vm_statistics_data_t));
-       }
-}
-
-
-
-static const char* sOverridePathlibLTO = NULL;
-
-//
-// This is magic glue that overrides the default behaviour 
-// of lazydylib1.o which is used to lazily load libLTO.dylib.
-//
-extern "C" const char* dyld_lazy_dylib_path_fix(const char* path);
-const char* dyld_lazy_dylib_path_fix(const char* path)
-{
-       if ( sOverridePathlibLTO != NULL )
-               return sOverridePathlibLTO;
-       else
-               return path;
-}
-
-
-
-int main(int argc, const char* argv[])
-{
-       const char* archName = NULL;
-       bool showArch = false;
-       bool archInferred = false;
-       try {
-               PerformanceStatistics statistics;
-               statistics.startTool = mach_absolute_time();
-               
-               // create object to track command line arguments
-               Options options(argc, argv);
-               InternalState state(options);
-               
-               // allow libLTO to be overridden by command line -lto_library
-               sOverridePathlibLTO = options.overridePathlibLTO();
-               
-               // gather vm stats
-               if ( options.printStatistics() )
-                       getVMInfo(statistics.vmStart);
-
-               // update strings for error messages
-               showArch = options.printArchPrefix();
-               archName = options.architectureName();
-               archInferred = (options.architecture() == 0);
-               
-               // open and parse input files
-               statistics.startInputFileProcessing = mach_absolute_time();
-               ld::tool::InputFiles inputFiles(options, &archName);
-               
-               // load and resolve all references
-               statistics.startResolver = mach_absolute_time();
-               ld::tool::Resolver resolver(options, inputFiles, state);
-               resolver.resolve();
-        
-               // add dylibs used
-               statistics.startDylibs = mach_absolute_time();
-               inputFiles.dylibs(state);
-       
-               // do initial section sorting so passes have rough idea of the layout
-               state.sortSections();
-
-               // run passes
-               statistics.startPasses = mach_absolute_time();
-               ld::passes::objc::doPass(options, state);
-               ld::passes::stubs::doPass(options, state);
-               ld::passes::huge::doPass(options, state);
-               ld::passes::got::doPass(options, state);
-               ld::passes::tlvp::doPass(options, state);
-               ld::passes::dylibs::doPass(options, state);     // must be after stubs and GOT passes
-               ld::passes::order::doPass(options, state);
-               state.markAtomsOrdered();
-               ld::passes::branch_shim::doPass(options, state);        // must be after stubs 
-               ld::passes::branch_island::doPass(options, state);      // must be after stubs and order pass
-               ld::passes::dtrace::doPass(options, state);
-               ld::passes::compact_unwind::doPass(options, state);  // must be after order pass
-               
-               // sort final sections
-               state.sortSections();
-
-               // write output file
-               statistics.startOutput = mach_absolute_time();
-               ld::tool::OutputFile out(options);
-               out.write(state);
-               statistics.startDone = mach_absolute_time();
-               
-               // print statistics
-               //mach_o::relocatable::printCounts();
-               if ( options.printStatistics() ) {
-                       getVMInfo(statistics.vmEnd);
-                       uint64_t totalTime = statistics.startDone - statistics.startTool;
-                       printTime("ld total time", totalTime, totalTime);
-                       printTime(" option parsing time", statistics.startInputFileProcessing  -        statistics.startTool,                           totalTime);
-                       printTime(" object file processing", statistics.startResolver                    -      statistics.startInputFileProcessing,totalTime);
-                       printTime(" resolve symbols", statistics.startDylibs                             -      statistics.startResolver,                       totalTime);
-                       printTime(" build atom list", statistics.startPasses                             -      statistics.startDylibs,                         totalTime);
-                       printTime(" passess", statistics.startOutput                             -      statistics.startPasses,                         totalTime);
-                       printTime(" write output", statistics.startDone                          -      statistics.startOutput,                         totalTime);
-                       fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", 
-                                                               statistics.vmEnd.pageins-statistics.vmStart.pageins,
-                                                               statistics.vmEnd.pageouts-statistics.vmStart.pageouts, 
-                                                               statistics.vmEnd.faults-statistics.vmStart.faults);
-                       char temp[40];
-                       fprintf(stderr, "processed %3u object files,  totaling %15s bytes\n", inputFiles._totalObjectLoaded, commatize(inputFiles._totalObjectSize, temp));
-                       fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", inputFiles._totalArchivesLoaded, commatize(inputFiles._totalArchiveSize, temp));
-                       fprintf(stderr, "processed %3u dylib files\n", inputFiles._totalDylibsLoaded);
-                       fprintf(stderr, "wrote output file            totaling %15s bytes\n", commatize(out.fileSize(), temp));
-               }
-               // <rdar://problem/6780050> Would like linker warning to be build error.
-               if ( options.errorBecauseOfWarnings() ) {
-                       fprintf(stderr, "ld: fatal warning(s) induced error (-fatal_warnings)\n");
-                       return 1;
-               }
-       }
-       catch (const char* msg) {
-               if ( archInferred )
-                       fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName);
-               else if ( showArch )
-                       fprintf(stderr, "ld: %s for architecture %s\n", msg, archName);
-               else
-                       fprintf(stderr, "ld: %s\n", msg);
-               return 1;
-       }
-
-       return 0;
-}
-
-
-#ifndef NDEBUG
-// implement assert() function to print out a backtrace before aborting
-void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
-{
-    Snapshot *snapshot = Snapshot::globalSnapshot;
-    
-    snapshot->setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
-    snapshot->createSnapshot();
-       snapshot->recordAssertionMessage("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
-
-       void* callStack[128];
-       int depth = ::backtrace(callStack, 128);
-       char* buffer = (char*)malloc(1024);
-       for(int i=0; i < depth-1; ++i) {
-               Dl_info info;
-               dladdr(callStack[i], &info);
-               const char* symboName = info.dli_sname;
-               if ( (symboName != NULL) && (strncmp(symboName, "_Z", 2) == 0) ) {
-                       size_t bufLen = 1024;
-                       int result;
-                       char* unmangled = abi::__cxa_demangle(symboName, buffer, &bufLen, &result);
-                       if ( unmangled != NULL )
-                               symboName = unmangled;
-               }
-               long offset = (uintptr_t)callStack[i] - (uintptr_t)info.dli_saddr;
-               fprintf(stderr, "%d  %p  %s + %ld\n", i, callStack[i], symboName, offset);
-               snapshot->recordAssertionMessage("%d  %p  %s + %ld\n", i, callStack[i], symboName, offset);
-       }
-    fprintf(stderr, "A linker snapshot was created at:\n\t%s\n", snapshot->rootDir());
-       fprintf(stderr, "ld: Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
-       exit(1);
-}
-#endif
-
-