1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2009-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 
  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@ 
  31 #include <libkern/OSByteOrder.h> 
  40 #include "make_stubs.h" 
  49                                                                 Pass(const Options
& opts
); 
  50         void                                            process(ld::Internal
& internal
); 
  51         void                                            addAtom(const ld::Atom
& atom
)   { _internal
->addAtom(atom
); } 
  52         bool                                            usingCompressedLINKEDIT() const { return _compressedLINKEDIT
; } 
  53         ld::Internal
*                           internal() { return _internal
; } 
  55         Atom
*                                           compressedHelperHelper
; 
  56         Atom
*                                           compressedImageCache
; 
  57         Atom
*                                           compressedFastBinderPointer
; 
  61         struct AtomByNameSorter
 
  63                  bool operator()(const ld::Atom
* left
, const ld::Atom
* right
) 
  65                           return (strcmp(left
->name(), right
->name()) < 0); 
  69         const ld::Atom
*                         stubableFixup(const ld::Fixup
* fixup
, ld::Internal
&); 
  70         ld::Atom
*                                       makeStub(const ld::Atom
& target
, bool weakImport
); 
  71         void                                            verifyNoResolverFunctions(ld::Internal
& state
); 
  73         const Options
&                          _options
; 
  74         const cpu_type_t                        _architecture
; 
  75         const bool                                      _lazyDylibsInUuse
; 
  76         const bool                                      _compressedLINKEDIT
; 
  78         const bool                                      _mightBeInSharedRegion
; 
  80         const bool                                      _flatNamespace
; 
  81         ld::Internal
*                           _internal
; 
  86 #include "stub_x86_64.hpp" 
  87 #include "stub_x86_64_classic.hpp" 
  88 #include "stub_x86.hpp" 
  89 #include "stub_x86_classic.hpp" 
  90 #include "stub_arm.hpp" 
  91 #include "stub_arm_classic.hpp" 
  95 Pass::Pass(const Options
& opts
)  
  96         :       compressedHelperHelper(NULL
),  
  97                 compressedImageCache(NULL
), 
  98                 compressedFastBinderPointer(NULL
), 
 100                 _architecture(opts
.architecture()), 
 101                 _lazyDylibsInUuse(opts
.usingLazyDylibLinking()), 
 102                 _compressedLINKEDIT(opts
.makeCompressedDyldInfo()), 
 103                 _prebind(opts
.prebind()), 
 104                 _mightBeInSharedRegion(opts
.sharedRegionEligible()),  
 105                 _pic(opts
.outputSlidable()), 
 106                 _flatNamespace(opts
.nameSpace() != Options::kTwoLevelNameSpace
), 
 107                 _internal(NULL
), _stubCount(0), _largeText(false) 
 113 const ld::Atom
* Pass::stubableFixup(const ld::Fixup
* fixup
, ld::Internal
& state
) 
 115         if ( fixup
->binding 
== ld::Fixup::bindingsIndirectlyBound 
) { 
 116                 const ld::Atom
* target 
= state
.indirectBindingTable
[fixup
->u
.bindingIndex
]; 
 117                 switch ( fixup
->kind 
) { 
 118                         case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32
: 
 119                         case ld::Fixup::kindStoreTargetAddressARMBranch24
: 
 120                         case ld::Fixup::kindStoreTargetAddressThumbBranch22
: 
 121                                 // create stub if target is in a dylib 
 122                                 if ( target
->definition() == ld::Atom::definitionProxy 
)  
 124                                 // use stub if target is a resolver function in same linkage unit 
 125                                 if ( target
->contentType() == ld::Atom::typeResolver 
)  
 127                                 if ( target
->scope() == ld::Atom::scopeGlobal 
) {        
 128                                         // create stub if target is global weak definition in symbol table 
 129                                         if ( (target
->definition() == ld::Atom::definitionRegular
)  
 130                                                 && (target
->combine() == ld::Atom::combineByName
)  
 131                                                 && ((target
->symbolTableInclusion() == ld::Atom::symbolTableIn
)  
 132                                                  || (target
->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip
)) ) 
 134                                         // create stub if target is interposable 
 135                                         if ( _options
.interposable(target
->name()) )  
 137                                         if ( _flatNamespace 
) { 
 138                                                 // flat namespace does not indirect calls within main exectuables 
 139                                                 if ( _options
.outputKind() == Options::kDynamicExecutable 
)  
 141                                                 // create stub if target is global and building -flat dylib or bundle 
 147                                 if ( target
->contentType() == ld::Atom::typeResolver 
) { 
 148                                         // any pointer to a resolver needs to change to pointer to stub 
 159 ld::Atom
* Pass::makeStub(const ld::Atom
& target
, bool weakImport
) 
 161         //fprintf(stderr, "makeStub(target=%p %s in sect %s)\n", &target, target.name(), target.section().sectionName()); 
 162         bool stubToGlobalWeakDef 
= ( (target
.scope() == ld::Atom::scopeGlobal
) 
 163                                                                 && (target
.definition() == ld::Atom::definitionRegular
)  
 164                                                                 && (target
.combine() == ld::Atom::combineByName
) ); 
 166         bool forLazyDylib 
= false; 
 167         const ld::dylib::File
* dylib 
= dynamic_cast<const ld::dylib::File
*>(target
.file()); 
 168         if ( (dylib 
!= NULL
) && dylib
->willBeLazyLoadedDylib() )  
 170         bool stubToResolver 
= (target
.contentType() == ld::Atom::typeResolver
); 
 172         if ( usingCompressedLINKEDIT() && !forLazyDylib 
) { 
 173                 if ( _internal
->compressedFastBinderProxy 
== NULL 
) 
 174                         throwf("symbol dyld_stub_binder not found (normally in libSystem.dylib).  Needed to perform lazy binding to function %s", target
.name()); 
 177         switch ( _architecture 
) { 
 179                         if ( usingCompressedLINKEDIT() && !forLazyDylib 
) 
 180                                 return new ld::passes::stubs::x86::StubAtom(*this, target
, stubToGlobalWeakDef
, stubToResolver
, weakImport
); 
 182                                 return new ld::passes::stubs::x86::classic::StubAtom(*this, target
, forLazyDylib
, weakImport
); 
 184                 case CPU_TYPE_X86_64
: 
 185                         if ( usingCompressedLINKEDIT() && !forLazyDylib 
) 
 186                                 return new ld::passes::stubs::x86_64::StubAtom(*this, target
, stubToGlobalWeakDef
, stubToResolver
, weakImport
); 
 188                                 return new ld::passes::stubs::x86_64::classic::StubAtom(*this, target
, forLazyDylib
, weakImport
); 
 191                         if ( usingCompressedLINKEDIT() && !forLazyDylib 
) { 
 192                                 if ( (_stubCount 
< 900) && !_mightBeInSharedRegion 
&& !_largeText 
) 
 193                                         return new ld::passes::stubs::arm::StubCloseAtom(*this, target
, stubToGlobalWeakDef
, stubToResolver
, weakImport
); 
 195                                         return new ld::passes::stubs::arm::StubPICAtom(*this, target
, stubToGlobalWeakDef
, stubToResolver
, weakImport
); 
 197                                         return new ld::passes::stubs::arm::StubNoPICAtom(*this, target
, stubToGlobalWeakDef
, stubToResolver
, weakImport
); 
 201                                         return new ld::passes::stubs::arm::classic::StubPICAtom(*this, target
, forLazyDylib
, weakImport
); 
 203                                         return new ld::passes::stubs::arm::classic::StubNoPICAtom(*this, target
, forLazyDylib
, weakImport
); 
 207         throw "unsupported arch for stub"; 
 211 void Pass::verifyNoResolverFunctions(ld::Internal
& state
) 
 213         for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit 
!= state
.sections
.end(); ++sit
) { 
 214                 ld::Internal::FinalSection
* sect 
= *sit
; 
 215                 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin();  ait 
!= sect
->atoms
.end(); ++ait
) { 
 216                         const ld::Atom
* atom 
= *ait
; 
 217                         if ( atom
->contentType() == ld::Atom::typeResolver 
)  
 218                                 throwf("resolver function '%s' not supported in type of output", atom
->name()); 
 223 void Pass::process(ld::Internal
& state
) 
 225         switch ( _options
.outputKind() ) { 
 226                 case Options::kObjectFile
: 
 227                         // these kinds don't use stubs and can have resolver functions 
 229                 case Options::kKextBundle
: 
 230                 case Options::kStaticExecutable
: 
 231                 case Options::kPreload
: 
 233                         // these kinds don't use stubs and cannot have resolver functions 
 234                         verifyNoResolverFunctions(state
); 
 236                 case Options::kDynamicLibrary
: 
 237                         // uses stubs and can have resolver functions 
 239                 case Options::kDynamicExecutable
: 
 240                 case Options::kDynamicBundle
: 
 241                         // these kinds do use stubs and cannot have resolver functions 
 242                         verifyNoResolverFunctions(state
); 
 246         // walk all atoms and fixups looking for stubable references 
 247         // don't create stubs inline because that could invalidate the sections iterator 
 248         std::vector
<const ld::Atom
*> atomsCallingStubs
; 
 249         std::map
<const ld::Atom
*,ld::Atom
*> stubFor
; 
 250         std::map
<const ld::Atom
*,bool>          weakImportMap
; 
 251         atomsCallingStubs
.reserve(128); 
 252         uint64_t codeSize 
= 0; 
 253         for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit 
!= state
.sections
.end(); ++sit
) { 
 254                 ld::Internal::FinalSection
* sect 
= *sit
; 
 255                 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin();  ait 
!= sect
->atoms
.end(); ++ait
) { 
 256                         const ld::Atom
* atom 
= *ait
; 
 257                         codeSize 
+= atom
->size(); 
 258                         bool atomNeedsStub 
= false; 
 259                         for (ld::Fixup::iterator fit 
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit 
!= end
; ++fit
) { 
 260                                 const ld::Atom
* stubableTargetOfFixup 
= stubableFixup(fit
, state
); 
 261                                 if ( stubableTargetOfFixup 
!= NULL 
) { 
 262                                         if ( !atomNeedsStub 
) { 
 263                                                 atomsCallingStubs
.push_back(atom
); 
 264                                                 atomNeedsStub 
= true; 
 266                                         stubFor
[stubableTargetOfFixup
] = NULL
;   
 267                                         // record weak_import attribute 
 268                                         std::map
<const ld::Atom
*,bool>::iterator pos 
= weakImportMap
.find(stubableTargetOfFixup
); 
 269                                         if ( pos 
== weakImportMap
.end() ) { 
 270                                                 // target not in weakImportMap, so add 
 271                                                 weakImportMap
[stubableTargetOfFixup
] = fit
->weakImport
; 
 274                                                 // target in weakImportMap, check for weakness mismatch 
 275                                                 if ( pos
->second 
!= fit
->weakImport 
) { 
 277                                                         switch ( _options
.weakReferenceMismatchTreatment() ) { 
 278                                                                 case Options::kWeakReferenceMismatchError
: 
 279                                                                         throwf("mismatching weak references for symbol: %s", stubableTargetOfFixup
->name()); 
 280                                                                 case Options::kWeakReferenceMismatchWeak
: 
 283                                                                 case Options::kWeakReferenceMismatchNonWeak
: 
 291                         // all resolver functions must have a corresponding stub 
 292                         if ( atom
->contentType() == ld::Atom::typeResolver 
) { 
 293                                 if ( _options
.outputKind() != Options::kDynamicLibrary 
)  
 294                                         throwf("resolver functions (%s) can only be used in dylibs", atom
->name()); 
 295                                 if ( !_options
.makeCompressedDyldInfo() ) { 
 296                                         if ( _options
.architecture() == CPU_TYPE_ARM 
) 
 297                                                 throwf("resolver functions (%s) can only be used when targeting iOS 4.2 or later", atom
->name()); 
 299                                                 throwf("resolver functions (%s) can only be used when targeting Mac OS X 10.6 or later", atom
->name()); 
 301                                 stubFor
[atom
] = NULL
;    
 306         // short circuit if no stubs needed 
 308         _stubCount 
= stubFor
.size(); 
 309         if ( _stubCount 
== 0 ) 
 312         // <rdar://problem/8553283> lazily check for helper 
 313         if ( !_options
.makeCompressedDyldInfo() && (state
.classicBindingHelper 
== NULL
) )  
 314                 throw "symbol dyld_stub_binding_helper not found, normally in crt1.o/dylib1.o/bundle1.o"; 
 316         // disable arm close stubs in some cases 
 317         if ( _architecture 
== CPU_TYPE_ARM 
) { 
 318         if ( codeSize 
> 4*1024*1024 ) 
 321             for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit 
!= state
.sections
.end(); ++sit
) { 
 322                 ld::Internal::FinalSection
* sect 
= *sit
; 
 323                 if ( sect
->type() == ld::Section::typeMachHeader 
) 
 325                 if ( strcmp(sect
->segmentName(), "__TEXT") == 0) { 
 326                     for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin();  ait 
!= sect
->atoms
.end(); ++ait
) { 
 327                         const ld::Atom
* atom 
= *ait
; 
 328                         if ( atom
->alignment().powerOf2 
> 10 ) { 
 329                             // overaligned section means might not be able to keep closestubs sect pushed to end of __TEXT 
 330                             //warning("alignment 1<<%d in atom %s in section %s disables close stubs optimization",  
 331                             //        atom->alignment().powerOf2, atom->name(), sect->segmentName()); 
 342         for (std::map
<const ld::Atom
*,ld::Atom
*>::iterator it 
= stubFor
.begin(); it 
!= stubFor
.end(); ++it
) { 
 343                 it
->second 
= makeStub(*it
->first
, weakImportMap
[it
->first
]); 
 346         // updated atoms to use stubs 
 347         for (std::vector
<const ld::Atom
*>::iterator it
=atomsCallingStubs
.begin(); it 
!= atomsCallingStubs
.end(); ++it
) { 
 348                 const ld::Atom
* atom 
= *it
; 
 349                 for (ld::Fixup::iterator fit 
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit 
!= end
; ++fit
) { 
 350                         const ld::Atom
* stubableTargetOfFixup 
= stubableFixup(fit
, state
); 
 351                         if ( stubableTargetOfFixup 
!= NULL 
) { 
 352                                 ld::Atom
* stub 
= stubFor
[stubableTargetOfFixup
]; 
 353                                 assert(stub 
!= NULL 
&& "stub not created"); 
 354                                 fit
->binding 
= ld::Fixup::bindingDirectlyBound
; 
 355                                 fit
->u
.target 
= stub
; 
 360         // sort new atoms so links are consistent 
 361         for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit 
!= state
.sections
.end(); ++sit
) { 
 362                 ld::Internal::FinalSection
* sect 
= *sit
; 
 363                 switch ( sect
->type() ) { 
 364                         case ld::Section::typeStubHelper
: 
 365                         case ld::Section::typeStub
: 
 366                         case ld::Section::typeStubClose
: 
 367                         case ld::Section::typeLazyPointer
: 
 368                         case ld::Section::typeLazyPointerClose
: 
 369                                 std::sort(sect
->atoms
.begin(), sect
->atoms
.end(), AtomByNameSorter()); 
 379 void doPass(const Options
& opts
, ld::Internal
& internal
) 
 382         pass
.process(internal
); 
 388 } // namespace passes