1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2006-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 #ifndef __MACHO_BINDER__
26 #define __MACHO_BINDER__
28 #include <sys/types.h>
31 #include <mach/mach.h>
38 #include <mach-o/loader.h>
39 #include <mach-o/fat.h>
43 #include <unordered_map>
44 #include <unordered_set>
46 #include "MachOFileAbstraction.hpp"
47 #include "Architectures.hpp"
48 #include "MachOLayout.hpp"
49 #include "MachORebaser.hpp"
50 #include "MachOTrie.hpp"
52 #ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
53 #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
56 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
57 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
62 class Binder
: public Rebaser
<A
>
67 size_t operator()(const char* __s
) const {
74 struct CStringEquals
{
75 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
77 typedef std::unordered_map
<const char*, class Binder
<A
>*, CStringHash
, CStringEquals
> Map
;
80 Binder(const MachOLayoutAbstraction
&, uint64_t dyldBaseAddress
);
83 const char* getDylibID() const;
84 void setDependentBinders(const Map
& map
);
85 void bind(std::vector
<void*>&);
87 void addResolverClient(Binder
<A
>* clientDylib
, const char* symbolName
);
89 typedef typename
A::P P
;
90 typedef typename
A::P::E E
;
91 typedef typename
A::P::uint_t pint_t
;
92 struct BinderAndReExportFlag
{ Binder
<A
>* binder
; bool reExport
; };
93 struct SymbolReExport
{ const char* exportName
; int dylibOrdinal
; const char* importName
; };
94 typedef std::unordered_map
<const char*, pint_t
, CStringHash
, CStringEquals
> NameToAddrMap
;
95 typedef std::unordered_set
<const char*, CStringHash
, CStringEquals
> NameSet
;
96 struct ClientAndSymbol
{ Binder
<A
>* client
; const char* symbolName
; };
97 struct SymbolAndLazyPointer
{ const char* symbolName
; pint_t lpVMAddr
; };
99 static bool isPublicLocation(const char* pth
);
100 void doBindExternalRelocations();
101 void doBindIndirectSymbols();
102 void doSetUpDyldSection();
103 void doSetPreboundUndefines();
104 void hoistPrivateRexports();
105 int ordinalOfDependentBinder(Binder
<A
>* dep
);
106 void doBindDyldInfo(std::vector
<void*>& pointersInData
);
107 void doBindDyldLazyInfo(std::vector
<void*>& pointersInData
);
108 void bindDyldInfoAt(uint8_t segmentIndex
, uint64_t segmentOffset
, uint8_t type
,
109 int libraryOrdinal
, int64_t addend
,
110 const char* symbolName
, bool lazyPointer
, bool weakImport
,
111 std::vector
<void*>& pointersInData
);
112 pint_t
resolveUndefined(const macho_nlist
<P
>* undefinedSymbol
);
113 bool findExportedSymbolAddress(const char* name
, pint_t
* result
, Binder
<A
>** foundIn
,
114 bool* isResolverSymbol
, bool* isAbsolute
);
115 void bindStub(uint8_t elementSize
, uint8_t* location
, pint_t vmlocation
, pint_t value
);
116 const char* parentUmbrella();
117 pint_t
runtimeAddressFromNList(const macho_nlist
<P
>* sym
);
118 void optimizeStub(const char* symbolName
, pint_t lpVMAddr
);
119 void optimizeStub(uint8_t* stubMappedAddress
, pint_t stubVMAddress
, uint32_t stubSize
, pint_t lpVMAddr
);
120 pint_t
findLazyPointerFor(const char* symbolName
);
123 static uint8_t pointerRelocSize();
124 static uint8_t pointerRelocType();
126 std::vector
<BinderAndReExportFlag
> fDependentDylibs
;
127 NameToAddrMap fHashTable
;
128 NameSet fSymbolResolvers
;
129 NameSet fAbsoluteSymbols
;
130 std::vector
<SymbolReExport
> fReExportedSymbols
;
131 uint64_t fDyldBaseAddress
;
132 const macho_nlist
<P
>* fSymbolTable
;
133 const char* fStrings
;
134 const macho_dysymtab_command
<P
>* fDynamicInfo
;
135 const macho_segment_command
<P
>* fFristWritableSegment
;
136 const macho_dylib_command
<P
>* fDylibID
;
137 const macho_dylib_command
<P
>* fParentUmbrella
;
138 const macho_dyld_info_command
<P
>* fDyldInfo
;
139 bool fOriginallyPrebound
;
140 bool fReExportedSymbolsResolved
;
141 std::vector
<ClientAndSymbol
> fClientAndSymbols
;
142 NameToAddrMap fResolverLazyPointers
;
146 uint32_t Binder
<arm
>::runtimeAddressFromNList(const macho_nlist
<Pointer32
<LittleEndian
> >* sym
)
148 if (sym
->n_desc() & N_ARM_THUMB_DEF
)
149 return sym
->n_value() + 1;
151 return sym
->n_value();
154 template <typename A
>
155 typename
A::P::uint_t Binder
<A
>::runtimeAddressFromNList(const macho_nlist
<P
>* sym
)
157 return sym
->n_value();
161 template <typename A
>
162 Binder
<A
>::Binder(const MachOLayoutAbstraction
& layout
, uint64_t dyldBaseAddress
)
163 : Rebaser
<A
>(layout
), fDyldBaseAddress(dyldBaseAddress
),
164 fSymbolTable(NULL
), fStrings(NULL
), fDynamicInfo(NULL
),
165 fFristWritableSegment(NULL
), fDylibID(NULL
), fDyldInfo(NULL
),
166 fParentUmbrella(NULL
), fReExportedSymbolsResolved(false)
168 fOriginallyPrebound
= ((this->fHeader
->flags() & MH_PREBOUND
) != 0);
169 // update header flags so the cache looks prebound split-seg (0x80000000 is in-shared-cache bit)
170 ((macho_header
<P
>*)this->fHeader
)->set_flags(this->fHeader
->flags() | MH_PREBOUND
| MH_SPLIT_SEGS
| 0x80000000);
172 // calculate fDynamicInfo, fStrings, fSymbolTable
173 const macho_symtab_command
<P
>* symtab
;
174 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)this->fHeader
+ sizeof(macho_header
<P
>));
175 const uint32_t cmd_count
= this->fHeader
->ncmds();
176 const macho_load_command
<P
>* cmd
= cmds
;
177 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
178 switch (cmd
->cmd()) {
180 symtab
= (macho_symtab_command
<P
>*)cmd
;
181 fSymbolTable
= (macho_nlist
<P
>*)(&this->fLinkEditBase
[symtab
->symoff()]);
182 fStrings
= (const char*)&this->fLinkEditBase
[symtab
->stroff()];
185 fDynamicInfo
= (macho_dysymtab_command
<P
>*)cmd
;
188 ((macho_dylib_command
<P
>*)cmd
)->set_timestamp(0);
189 fDylibID
= (macho_dylib_command
<P
>*)cmd
;
192 case LC_LOAD_WEAK_DYLIB
:
193 case LC_REEXPORT_DYLIB
:
194 case LC_LOAD_UPWARD_DYLIB
:
195 ((macho_dylib_command
<P
>*)cmd
)->set_timestamp(0);
197 case LC_SUB_FRAMEWORK
:
198 fParentUmbrella
= (macho_dylib_command
<P
>*)cmd
;
201 case LC_DYLD_INFO_ONLY
:
202 fDyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
205 throwf("dyld shared cache does not support LC_RPATH found in %s", layout
.getFilePath());
208 if ( cmd
->cmd() & LC_REQ_DYLD
)
209 throwf("unknown required load command 0x%08X", cmd
->cmd());
211 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
213 if ( fDynamicInfo
== NULL
)
214 throw "no LC_DYSYMTAB";
215 if ( fSymbolTable
== NULL
)
216 throw "no LC_SYMTAB";
218 // fprintf(stderr, "exports for %s\n", layout.getFilePath());
219 if ( fDyldInfo
!= NULL
) {
220 std::vector
<mach_o::trie::Entry
> exports
;
221 const uint8_t* exportsStart
= layout
.getDyldInfoExports();
222 const uint8_t* exportsEnd
= &exportsStart
[fDyldInfo
->export_size()];
223 mach_o::trie::parseTrie(exportsStart
, exportsEnd
, exports
);
224 pint_t baseAddress
= layout
.getSegments()[0].newAddress();
225 for(std::vector
<mach_o::trie::Entry
>::iterator it
= exports
.begin(); it
!= exports
.end(); ++it
) {
226 switch ( it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) {
227 case EXPORT_SYMBOL_FLAGS_KIND_REGULAR
:
228 if ( (it
->flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) ) {
229 fSymbolResolvers
.insert(it
->name
);
231 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
232 //fprintf(stderr, "found re-export %s in %s\n", sym.exportName, this->getDylibID());
234 sym
.exportName
= it
->name
;
235 sym
.dylibOrdinal
= it
->other
;
236 sym
.importName
= it
->importName
;
237 if ( (sym
.importName
== NULL
) || (sym
.importName
[0] == '\0') )
238 sym
.importName
= sym
.exportName
;
239 fReExportedSymbols
.push_back(sym
);
240 // fHashTable entry will be added in first call to findExportedSymbolAddress()
243 fHashTable
[it
->name
] = it
->address
+ baseAddress
;
246 case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
:
247 fHashTable
[it
->name
] = it
->address
+ baseAddress
;
249 case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
:
250 fHashTable
[it
->name
] = it
->address
;
251 fAbsoluteSymbols
.insert(it
->name
);
254 throwf("non-regular symbol binding not supported for %s in %s", it
->name
, layout
.getFilePath());
257 //fprintf(stderr, "0x%08llX %s\n", it->address + baseAddress, it->name);
261 if ( fDynamicInfo
->tocoff() == 0 ) {
262 const macho_nlist
<P
>* start
= &fSymbolTable
[fDynamicInfo
->iextdefsym()];
263 const macho_nlist
<P
>* end
= &start
[fDynamicInfo
->nextdefsym()];
264 fHashTable
.reserve(fDynamicInfo
->nextdefsym()); // set initial bucket count
265 for (const macho_nlist
<P
>* sym
=start
; sym
< end
; ++sym
) {
266 const char* name
= &fStrings
[sym
->n_strx()];
267 fHashTable
[name
] = runtimeAddressFromNList(sym
);
268 //fprintf(stderr, " 0x%08llX %s\n", sym->n_value(), name);
272 int32_t count
= fDynamicInfo
->ntoc();
273 fHashTable
.reserve(count
); // set initial bucket count
274 const struct dylib_table_of_contents
* toc
= (dylib_table_of_contents
*)&this->fLinkEditBase
[fDynamicInfo
->tocoff()];
275 for (int32_t i
= 0; i
< count
; ++i
) {
276 const uint32_t index
= E::get32(toc
[i
].symbol_index
);
277 const macho_nlist
<P
>* sym
= &fSymbolTable
[index
];
278 const char* name
= &fStrings
[sym
->n_strx()];
279 fHashTable
[name
] = runtimeAddressFromNList(sym
);
280 //fprintf(stderr, "- 0x%08llX %s\n", sym->n_value(), name);
286 template <> uint8_t Binder
<x86
>::pointerRelocSize() { return 2; }
287 template <> uint8_t Binder
<x86_64
>::pointerRelocSize() { return 3; }
288 template <> uint8_t Binder
<arm
>::pointerRelocSize() { return 2; }
289 template <> uint8_t Binder
<arm64
>::pointerRelocSize() { return 3; }
291 template <> uint8_t Binder
<x86
>::pointerRelocType() { return GENERIC_RELOC_VANILLA
; }
292 template <> uint8_t Binder
<x86_64
>::pointerRelocType() { return X86_64_RELOC_UNSIGNED
; }
293 template <> uint8_t Binder
<arm
>::pointerRelocType() { return ARM_RELOC_VANILLA
; }
294 template <> uint8_t Binder
<arm64
>::pointerRelocType() { return ARM64_RELOC_UNSIGNED
; }
297 template <typename A
>
298 const char* Binder
<A
>::getDylibID() const
300 if ( fDylibID
!= NULL
)
301 return fDylibID
->name();
306 template <typename A
>
307 const char* Binder
<A
>::parentUmbrella()
309 if ( fParentUmbrella
!= NULL
)
310 return fParentUmbrella
->name();
316 template <typename A
>
317 bool Binder
<A
>::isPublicLocation(const char* pth
)
319 // /usr/lib is a public location
320 if ( (strncmp(pth
, "/usr/lib/", 9) == 0) && (strchr(&pth
[9], '/') == NULL
) )
323 // /System/Library/Frameworks/ is a public location
324 if ( strncmp(pth
, "/System/Library/Frameworks/", 27) == 0 ) {
325 const char* frameworkDot
= strchr(&pth
[27], '.');
326 // but only top level framework
327 // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true
328 // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false
329 // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar ==> false
330 // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
331 if ( frameworkDot
!= NULL
) {
332 int frameworkNameLen
= frameworkDot
- &pth
[27];
333 if ( strncmp(&pth
[strlen(pth
)-frameworkNameLen
-1], &pth
[26], frameworkNameLen
+1) == 0 )
341 template <typename A
>
342 void Binder
<A
>::setDependentBinders(const Map
& map
)
344 // first pass to build vector of dylibs
345 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)this->fHeader
+ sizeof(macho_header
<P
>));
346 const uint32_t cmd_count
= this->fHeader
->ncmds();
347 const macho_load_command
<P
>* cmd
= cmds
;
348 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
349 switch (cmd
->cmd()) {
351 case LC_LOAD_WEAK_DYLIB
:
352 case LC_REEXPORT_DYLIB
:
353 case LC_LOAD_UPWARD_DYLIB
:
354 const char* path
= ((struct macho_dylib_command
<P
>*)cmd
)->name();
355 typename
Map::const_iterator pos
= map
.find(path
);
356 if ( pos
!= map
.end() ) {
357 BinderAndReExportFlag entry
;
358 entry
.binder
= pos
->second
;
359 entry
.reExport
= ( cmd
->cmd() == LC_REEXPORT_DYLIB
);
360 fDependentDylibs
.push_back(entry
);
363 // the load command string does not match the install name of any loaded dylib
364 // this could happen if there was not a world build and some dylib changed its
365 // install path to be some symlinked path
367 // use realpath() and walk map looking for a realpath match
369 char targetPath
[PATH_MAX
];
370 if ( realpath(path
, targetPath
) != NULL
) {
371 for(typename
Map::const_iterator it
=map
.begin(); it
!= map
.end(); ++it
) {
372 char aPath
[PATH_MAX
];
373 if ( realpath(it
->first
, aPath
) != NULL
) {
374 if ( strcmp(targetPath
, aPath
) == 0 ) {
375 BinderAndReExportFlag entry
;
376 entry
.binder
= it
->second
;
377 entry
.reExport
= ( cmd
->cmd() == LC_REEXPORT_DYLIB
);
378 fDependentDylibs
.push_back(entry
);
380 fprintf(stderr
, "update_dyld_shared_cache: warning mismatched install path in %s for %s\n",
381 this->getDylibID(), path
);
388 if ( cmd
->cmd() == LC_LOAD_WEAK_DYLIB
) {
389 BinderAndReExportFlag entry
;
391 entry
.reExport
= false;
392 fDependentDylibs
.push_back(entry
);
396 throwf("in %s can't find dylib %s", this->getDylibID(), path
);
402 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
404 // handle pre-10.5 re-exports
405 if ( (this->fHeader
->flags() & MH_NO_REEXPORTED_DYLIBS
) == 0 ) {
407 // LC_SUB_LIBRARY means re-export one with matching leaf name
408 const char* dylibBaseName
;
409 const char* frameworkLeafName
;
410 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
411 switch ( cmd
->cmd() ) {
413 dylibBaseName
= ((macho_sub_library_command
<P
>*)cmd
)->sub_library();
414 for (typename
std::vector
<BinderAndReExportFlag
>::iterator it
= fDependentDylibs
.begin(); it
!= fDependentDylibs
.end(); ++it
) {
415 const char* dylibName
= it
->binder
->getDylibID();
416 const char* lastSlash
= strrchr(dylibName
, '/');
417 const char* leafStart
= &lastSlash
[1];
418 if ( lastSlash
== NULL
)
419 leafStart
= dylibName
;
420 const char* firstDot
= strchr(leafStart
, '.');
421 int len
= strlen(leafStart
);
422 if ( firstDot
!= NULL
)
423 len
= firstDot
- leafStart
;
424 if ( strncmp(leafStart
, dylibBaseName
, len
) == 0 )
428 case LC_SUB_UMBRELLA
:
429 frameworkLeafName
= ((macho_sub_umbrella_command
<P
>*)cmd
)->sub_umbrella();
430 for (typename
std::vector
<BinderAndReExportFlag
>::iterator it
= fDependentDylibs
.begin(); it
!= fDependentDylibs
.end(); ++it
) {
431 const char* dylibName
= it
->binder
->getDylibID();
432 const char* lastSlash
= strrchr(dylibName
, '/');
433 if ( (lastSlash
!= NULL
) && (strcmp(&lastSlash
[1], frameworkLeafName
) == 0) )
438 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
440 // ask dependents if they re-export through me
441 const char* thisName
= this->getDylibID();
442 if ( thisName
!= NULL
) {
443 const char* thisLeafName
= strrchr(thisName
, '/');
444 if ( thisLeafName
!= NULL
)
446 for (typename
std::vector
<BinderAndReExportFlag
>::iterator it
= fDependentDylibs
.begin(); it
!= fDependentDylibs
.end(); ++it
) {
447 if ( ! it
->reExport
) {
448 Binder
<A
>* dep
= it
->binder
;
450 const char* parentUmbrellaName
= dep
->parentUmbrella();
451 if ( parentUmbrellaName
!= NULL
) {
452 if ( strcmp(parentUmbrellaName
, thisLeafName
) == 0 )
463 template <typename A
>
464 int Binder
<A
>::ordinalOfDependentBinder(Binder
<A
>* dep
)
466 for (int i
=0; i
< fDependentDylibs
.size(); ++i
) {
467 if ( fDependentDylibs
[i
].binder
== dep
)
470 throw "dependend dylib not found";
473 template <typename A
>
474 void Binder
<A
>::hoistPrivateRexports()
476 std::vector
<Binder
<A
>*> privateReExportedDylibs
;
477 for (typename
std::vector
<BinderAndReExportFlag
>::iterator it
= fDependentDylibs
.begin(); it
!= fDependentDylibs
.end(); ++it
) {
478 if ( it
->reExport
&& ! isPublicLocation(it
->binder
->getDylibID()) )
479 privateReExportedDylibs
.push_back(it
->binder
);
481 if ( privateReExportedDylibs
.size() != 0 ) {
482 // parse export info into vector of exports
483 const uint8_t* exportsStart
= this->fLayout
.getDyldInfoExports();
484 const uint8_t* exportsEnd
= &exportsStart
[fDyldInfo
->export_size()];
485 std::vector
<mach_o::trie::Entry
> exports
;
486 mach_o::trie::parseTrie(exportsStart
, exportsEnd
, exports
);
487 //fprintf(stderr, "%s exports %lu symbols from trie of size %u \n", this->fLayout.getFilePath(), exports.size(), fDyldInfo->export_size());
489 // add re-exports for each export from an re-exported dylib
490 for(typename
std::vector
<Binder
<A
>*>::iterator it
= privateReExportedDylibs
.begin(); it
!= privateReExportedDylibs
.end(); ++it
) {
491 Binder
<A
>* binder
= *it
;
492 int ordinal
= ordinalOfDependentBinder(binder
);
493 const uint8_t* aDylibsExportsStart
= binder
->fLayout
.getDyldInfoExports();
494 const uint8_t* aDylibsExportsEnd
= &aDylibsExportsStart
[binder
->fDyldInfo
->export_size()];
495 std::vector
<mach_o::trie::Entry
> aDylibsExports
;
496 mach_o::trie::parseTrie(aDylibsExportsStart
, aDylibsExportsEnd
, aDylibsExports
);
497 //fprintf(stderr, "%s re-exports %lu symbols from %s\n", this->fLayout.getFilePath(), aDylibsExports.size(), binder->getDylibID());
498 for(std::vector
<mach_o::trie::Entry
>::iterator eit
= aDylibsExports
.begin(); eit
!= aDylibsExports
.end(); ++eit
) {
499 mach_o::trie::Entry entry
= *eit
;
500 entry
.flags
|= EXPORT_SYMBOL_FLAGS_REEXPORT
;
501 entry
.other
= ordinal
;
502 entry
.importName
= NULL
;
503 exports
.push_back(entry
);
506 // rebuild new combined trie
507 std::vector
<uint8_t> newExportTrieBytes
;
508 newExportTrieBytes
.reserve(fDyldInfo
->export_size());
509 mach_o::trie::makeTrie(exports
, newExportTrieBytes
);
510 //fprintf(stderr, "%s now exports %lu symbols from trie of size %lu\n", this->fLayout.getFilePath(), exports.size(), newExportTrieBytes.size());
512 // allocate new buffer and set export_off to use new buffer instead
513 uint32_t newExportsSize
= newExportTrieBytes
.size();
514 uint8_t* sideTrie
= new uint8_t[newExportsSize
];
515 memcpy(sideTrie
, &newExportTrieBytes
[0], newExportsSize
);
516 this->fLayout
.setDyldInfoExports(sideTrie
);
517 ((macho_dyld_info_command
<P
>*)fDyldInfo
)->set_export_off(0); // invalidate old trie
518 ((macho_dyld_info_command
<P
>*)fDyldInfo
)->set_export_size(newExportsSize
);
523 template <typename A
>
524 void Binder
<A
>::bind(std::vector
<void*>& pointersInData
)
526 this->doSetUpDyldSection();
527 if ( fDyldInfo
!= NULL
) {
528 this->doBindDyldInfo(pointersInData
);
529 this->doBindDyldLazyInfo(pointersInData
);
530 this->hoistPrivateRexports();
531 // weak bind info is processed at launch time
534 this->doBindExternalRelocations();
535 this->doBindIndirectSymbols();
536 this->doSetPreboundUndefines();
541 template <typename A
>
542 void Binder
<A
>::doSetUpDyldSection()
544 // find __DATA __dyld section
545 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)this->fHeader
+ sizeof(macho_header
<P
>));
546 const uint32_t cmd_count
= this->fHeader
->ncmds();
547 const macho_load_command
<P
>* cmd
= cmds
;
548 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
549 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
550 const macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
551 if ( strcmp(seg
->segname(), "__DATA") == 0 ) {
552 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((uint8_t*)seg
+ sizeof(macho_segment_command
<P
>));
553 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
554 for (const macho_section
<P
>* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
555 if ( (strcmp(sect
->sectname(), "__dyld") == 0) && (sect
->size() >= 2*sizeof(pint_t
)) ) {
556 // set two values in __dyld section to point into dyld
557 pint_t
* lazyBinder
= this->mappedAddressForNewAddress(sect
->addr());
558 pint_t
* dyldFuncLookup
= this->mappedAddressForNewAddress(sect
->addr()+sizeof(pint_t
));
559 A::P::setP(*lazyBinder
, fDyldBaseAddress
+ 0x1000);
560 A::P::setP(*dyldFuncLookup
, fDyldBaseAddress
+ 0x1008);
565 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
569 template <typename A
>
570 void Binder
<A
>::bindDyldInfoAt(uint8_t segmentIndex
, uint64_t segmentOffset
, uint8_t type
, int libraryOrdinal
,
571 int64_t addend
, const char* symbolName
, bool lazyPointer
, bool weakImport
, std::vector
<void*>& pointersInData
)
573 //printf("%d 0x%08llX type=%d, lib=%d, addend=%lld, symbol=%s\n", segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
574 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= this->fLayout
.getSegments();
575 if ( segmentIndex
> segments
.size() )
576 throw "bad segment index in rebase info";
578 if ( libraryOrdinal
== BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
579 throw "dynamic lookup linkage not allowed in dyld shared cache";
581 if ( libraryOrdinal
== BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
)
582 throw "linkage to main executable not allowed in dyld shared cache";
584 if ( libraryOrdinal
< 0 )
585 throw "bad mach-o binary, special library ordinal not allowd in dyld shared cache";
587 if ( (unsigned)libraryOrdinal
> fDependentDylibs
.size() )
588 throw "bad mach-o binary, library ordinal too big";
591 if ( libraryOrdinal
== BIND_SPECIAL_DYLIB_SELF
)
594 binder
= fDependentDylibs
[libraryOrdinal
-1].binder
;
595 pint_t targetSymbolAddress
;
596 bool isResolverSymbol
= false;
597 bool isAbsolute
= false;
599 if ( weakImport
&& (binder
== NULL
) ) {
600 targetSymbolAddress
= 0;
604 if ( ! binder
->findExportedSymbolAddress(symbolName
, &targetSymbolAddress
, &foundIn
, &isResolverSymbol
, &isAbsolute
) )
605 throwf("could not bind symbol %s in %s expected in %s", symbolName
, this->getDylibID(), binder
->getDylibID());
608 // don't bind lazy pointers to resolver stubs in shared cache
609 if ( lazyPointer
&& isResolverSymbol
) {
610 if ( foundIn
!= this ) {
611 // record that this dylib has a lazy pointer to a resolver function
612 foundIn
->addResolverClient(this, symbolName
);
613 // fprintf(stderr, "have lazy pointer to resolver %s in %s\n", symbolName, this->getDylibID());
619 const MachOLayoutAbstraction::Segment
& seg
= segments
[segmentIndex
];
620 uint8_t* mappedAddr
= (uint8_t*)seg
.mappedAddress() + segmentOffset
;
621 pint_t
* mappedAddrP
= (pint_t
*)mappedAddr
;
622 uint32_t* mappedAddr32
= (uint32_t*)mappedAddr
;
625 case BIND_TYPE_POINTER
:
626 P::setP(*mappedAddrP
, targetSymbolAddress
+ addend
);
629 case BIND_TYPE_TEXT_ABSOLUTE32
:
630 E::set32(*mappedAddr32
, targetSymbolAddress
+ addend
);
633 case BIND_TYPE_TEXT_PCREL32
:
634 svalue32new
= seg
.address() + segmentOffset
+ 4 - (targetSymbolAddress
+ addend
);
635 E::set32(*mappedAddr32
, svalue32new
);
639 throw "bad bind type";
642 pointersInData
.push_back(mappedAddr
);
647 template <typename A
>
648 void Binder
<A
>::doBindDyldLazyInfo(std::vector
<void*>& pointersInData
)
650 const uint8_t* p
= &this->fLinkEditBase
[fDyldInfo
->lazy_bind_off()];
651 const uint8_t* end
= &p
[fDyldInfo
->lazy_bind_size()];
653 uint8_t type
= BIND_TYPE_POINTER
;
654 uint64_t segmentOffset
= 0;
655 uint8_t segmentIndex
= 0;
656 const char* symbolName
= NULL
;
657 int libraryOrdinal
= 0;
659 bool weakImport
= false;
661 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
662 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
665 case BIND_OPCODE_DONE
:
666 // this opcode marks the end of each lazy pointer binding
668 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
669 libraryOrdinal
= immediate
;
671 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
672 libraryOrdinal
= read_uleb128(p
, end
);
674 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
675 // the special ordinals are negative numbers
676 if ( immediate
== 0 )
679 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
680 libraryOrdinal
= signExtended
;
683 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
684 weakImport
= ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 );
685 symbolName
= (char*)p
;
690 case BIND_OPCODE_SET_ADDEND_SLEB
:
691 addend
= read_sleb128(p
, end
);
693 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
694 segmentIndex
= immediate
;
695 segmentOffset
= read_uleb128(p
, end
);
697 case BIND_OPCODE_DO_BIND
:
698 bindDyldInfoAt(segmentIndex
, segmentOffset
, type
, libraryOrdinal
, addend
, symbolName
, true, weakImport
, pointersInData
);
699 segmentOffset
+= sizeof(pint_t
);
701 case BIND_OPCODE_SET_TYPE_IMM
:
702 case BIND_OPCODE_ADD_ADDR_ULEB
:
703 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
704 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
705 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
707 throwf("bad lazy bind opcode %d", *p
);
714 template <typename A
>
715 void Binder
<A
>::doBindDyldInfo(std::vector
<void*>& pointersInData
)
717 const uint8_t* p
= &this->fLinkEditBase
[fDyldInfo
->bind_off()];
718 const uint8_t* end
= &p
[fDyldInfo
->bind_size()];
721 uint64_t segmentOffset
= 0;
722 uint8_t segmentIndex
= 0;
723 const char* symbolName
= NULL
;
724 int libraryOrdinal
= 0;
728 bool weakImport
= false;
730 while ( !done
&& (p
< end
) ) {
731 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
732 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
735 case BIND_OPCODE_DONE
:
738 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
739 libraryOrdinal
= immediate
;
741 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
742 libraryOrdinal
= read_uleb128(p
, end
);
744 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
745 // the special ordinals are negative numbers
746 if ( immediate
== 0 )
749 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
750 libraryOrdinal
= signExtended
;
753 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
754 weakImport
= ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 );
755 symbolName
= (char*)p
;
760 case BIND_OPCODE_SET_TYPE_IMM
:
763 case BIND_OPCODE_SET_ADDEND_SLEB
:
764 addend
= read_sleb128(p
, end
);
766 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
767 segmentIndex
= immediate
;
768 segmentOffset
= read_uleb128(p
, end
);
770 case BIND_OPCODE_ADD_ADDR_ULEB
:
771 segmentOffset
+= read_uleb128(p
, end
);
773 case BIND_OPCODE_DO_BIND
:
774 bindDyldInfoAt(segmentIndex
, segmentOffset
, type
, libraryOrdinal
, addend
, symbolName
, false, weakImport
, pointersInData
);
775 segmentOffset
+= sizeof(pint_t
);
777 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
778 bindDyldInfoAt(segmentIndex
, segmentOffset
, type
, libraryOrdinal
, addend
, symbolName
, false, weakImport
, pointersInData
);
779 segmentOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
781 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
782 bindDyldInfoAt(segmentIndex
, segmentOffset
, type
, libraryOrdinal
, addend
, symbolName
, false, weakImport
, pointersInData
);
783 segmentOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
785 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
786 count
= read_uleb128(p
, end
);
787 skip
= read_uleb128(p
, end
);
788 for (uint32_t i
=0; i
< count
; ++i
) {
789 bindDyldInfoAt(segmentIndex
, segmentOffset
, type
, libraryOrdinal
, addend
, symbolName
, false, weakImport
, pointersInData
);
790 segmentOffset
+= skip
+ sizeof(pint_t
);
794 throwf("bad bind opcode %d", *p
);
803 template <typename A
>
804 void Binder
<A
>::doSetPreboundUndefines()
806 const macho_dysymtab_command
<P
>* dysymtab
= NULL
;
807 macho_nlist
<P
>* symbolTable
= NULL
;
809 // get symbol table info
810 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)this->fHeader
+ sizeof(macho_header
<P
>));
811 const uint32_t cmd_count
= this->fHeader
->ncmds();
812 const macho_load_command
<P
>* cmd
= cmds
;
813 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
814 switch (cmd
->cmd()) {
817 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
818 symbolTable
= (macho_nlist
<P
>*)(&this->fLinkEditBase
[symtab
->symoff()]);
822 dysymtab
= (macho_dysymtab_command
<P
>*)cmd
;
825 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
828 // walk all undefines and set their prebound n_value
829 macho_nlist
<P
>* const lastUndefine
= &symbolTable
[dysymtab
->iundefsym()+dysymtab
->nundefsym()];
830 for (macho_nlist
<P
>* entry
= &symbolTable
[dysymtab
->iundefsym()]; entry
< lastUndefine
; ++entry
) {
831 if ( entry
->n_type() & N_EXT
) {
832 //fprintf(stderr, "doSetPreboundUndefines: r_sym=%s, pbaddr=0x%08X, in %s\n",
833 // &fStrings[entry->n_strx()], pbaddr, this->getDylibID());
834 pint_t pbaddr
= this->resolveUndefined(entry
);
835 entry
->set_n_value(pbaddr
);
841 template <typename A
>
842 void Binder
<A
>::doBindExternalRelocations()
844 // get where reloc addresses start
845 // these address are always relative to first writable segment because they are in cache which always
846 // has writable segments far from read-only segments
847 pint_t firstWritableSegmentBaseAddress
= 0;
848 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= this->fLayout
.getSegments();
849 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator it
= segments
.begin(); it
!= segments
.end(); ++it
) {
850 const MachOLayoutAbstraction::Segment
& seg
= *it
;
851 if ( seg
.writable() ) {
852 firstWritableSegmentBaseAddress
= seg
.newAddress();
857 // loop through all external relocation records and bind each
858 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(&this->fLinkEditBase
[fDynamicInfo
->extreloff()]);
859 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicInfo
->nextrel()];
860 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
861 if ( reloc
->r_length() != pointerRelocSize() )
862 throw "bad external relocation length";
863 if ( reloc
->r_type() != pointerRelocType() )
864 throw "unknown external relocation type";
865 if ( reloc
->r_pcrel() )
866 throw "r_pcrel external relocaiton not supported";
868 const macho_nlist
<P
>* undefinedSymbol
= &fSymbolTable
[reloc
->r_symbolnum()];
871 location
= this->mappedAddressForNewAddress(reloc
->r_address() + firstWritableSegmentBaseAddress
);
873 catch (const char* msg
) {
874 throwf("%s processesing external relocation r_address 0x%08X", msg
, reloc
->r_address());
876 pint_t addend
= P::getP(*location
);
877 if ( fOriginallyPrebound
) {
878 // in a prebound binary, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
879 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
880 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
881 addend
-= undefinedSymbol
->n_value();
882 // To further complicate things, if this is defined symbol, then its n_value has already been adjust to the
883 // new base address, so we need to back off the slide too..
884 if ( (undefinedSymbol
->n_type() & N_TYPE
) == N_SECT
) {
885 addend
+= this->getSlideForNewAddress(undefinedSymbol
->n_value());
888 pint_t symbolAddr
= this->resolveUndefined(undefinedSymbol
);
889 //fprintf(stderr, "external reloc: r_address=0x%08X, r_sym=%s, symAddr=0x%08llX, addend=0x%08llX in %s\n",
890 // reloc->r_address(), &fStrings[undefinedSymbol->n_strx()], (uint64_t)symbolAddr, (uint64_t)addend, this->getDylibID());
891 P::setP(*location
, symbolAddr
+ addend
);
896 // most architectures use pure code, unmodifiable stubs
897 template <typename A
>
898 void Binder
<A
>::bindStub(uint8_t elementSize
, uint8_t* location
, pint_t vmlocation
, pint_t value
)
903 // x86 supports fast stubs
905 void Binder
<x86
>::bindStub(uint8_t elementSize
, uint8_t* location
, pint_t vmlocation
, pint_t value
)
907 // if the stub is not 5-bytes, it is an old slow stub
908 if ( elementSize
== 5 ) {
909 uint32_t rel32
= value
- (vmlocation
+ 5);
910 location
[0] = 0xE9; // JMP rel32
911 location
[1] = rel32
& 0xFF;
912 location
[2] = (rel32
>> 8) & 0xFF;
913 location
[3] = (rel32
>> 16) & 0xFF;
914 location
[4] = (rel32
>> 24) & 0xFF;
918 template <typename A
>
919 void Binder
<A
>::doBindIndirectSymbols()
921 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicInfo
->indirectsymoff()];
922 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)this->fHeader
+ sizeof(macho_header
<P
>));
923 const uint32_t cmd_count
= this->fHeader
->ncmds();
924 const macho_load_command
<P
>* cmd
= cmds
;
925 //fprintf(stderr, "doBindIndirectSymbols() %s\n", this->fLayout.getFilePath());
926 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
927 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
928 const macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
929 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((uint8_t*)seg
+ sizeof(macho_segment_command
<P
>));
930 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
931 for (const macho_section
<P
>* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
932 uint8_t elementSize
= 0;
933 uint8_t sectionType
= sect
->flags() & SECTION_TYPE
;
934 switch ( sectionType
) {
936 elementSize
= sect
->reserved2();
938 case S_NON_LAZY_SYMBOL_POINTERS
:
939 case S_LAZY_SYMBOL_POINTERS
:
940 elementSize
= sizeof(pint_t
);
943 if ( elementSize
!= 0 ) {
944 uint32_t elementCount
= sect
->size() / elementSize
;
945 const uint32_t indirectTableOffset
= sect
->reserved1();
946 uint8_t* location
= NULL
;
947 if ( sect
->size() != 0 )
948 location
= (uint8_t*)this->mappedAddressForNewAddress(sect
->addr());
949 pint_t vmlocation
= sect
->addr();
950 for (uint32_t j
=0; j
< elementCount
; ++j
, location
+= elementSize
, vmlocation
+= elementSize
) {
951 uint32_t symbolIndex
= E::get32(indirectTable
[indirectTableOffset
+ j
]);
952 switch ( symbolIndex
) {
953 case INDIRECT_SYMBOL_ABS
:
954 case INDIRECT_SYMBOL_LOCAL
:
957 const macho_nlist
<P
>* undefinedSymbol
= &fSymbolTable
[symbolIndex
];
958 //fprintf(stderr, " sect=%s, index=%d, symbolIndex=%d, sym=%s\n", sect->sectname(), j, symbolIndex, &fStrings[undefinedSymbol->n_strx()]);
959 pint_t symbolAddr
= this->resolveUndefined(undefinedSymbol
);
960 switch ( sectionType
) {
961 case S_NON_LAZY_SYMBOL_POINTERS
:
962 case S_LAZY_SYMBOL_POINTERS
:
963 P::setP(*((pint_t
*)location
), symbolAddr
);
966 this->bindStub(elementSize
, location
, vmlocation
, symbolAddr
);
975 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
982 template <typename A
>
983 typename
A::P::uint_t Binder
<A
>::resolveUndefined(const macho_nlist
<P
>* undefinedSymbol
)
985 if ( (undefinedSymbol
->n_type() & N_TYPE
) == N_SECT
) {
986 if ( (undefinedSymbol
->n_type() & N_PEXT
) != 0 ) {
987 // is a multi-module private_extern internal reference that the linker did not optimize away
988 return runtimeAddressFromNList(undefinedSymbol
);
990 if ( (undefinedSymbol
->n_desc() & N_WEAK_DEF
) != 0 ) {
991 // is a weak definition, we should prebind to this one in the same linkage unit
992 return runtimeAddressFromNList(undefinedSymbol
);
995 const char* symbolName
= &fStrings
[undefinedSymbol
->n_strx()];
996 if ( (this->fHeader
->flags() & MH_TWOLEVEL
) == 0 ) {
997 // flat namespace binding
998 throw "flat namespace not supported";
1001 uint8_t ordinal
= GET_LIBRARY_ORDINAL(undefinedSymbol
->n_desc());
1002 Binder
<A
>* binder
= NULL
;
1003 switch ( ordinal
) {
1004 case EXECUTABLE_ORDINAL
:
1005 case DYNAMIC_LOOKUP_ORDINAL
:
1006 throw "magic ordineal not supported";
1007 case SELF_LIBRARY_ORDINAL
:
1011 if ( ordinal
> fDependentDylibs
.size() )
1012 throw "two-level ordinal out of range";
1013 binder
= fDependentDylibs
[ordinal
-1].binder
;
1019 if ( ! binder
->findExportedSymbolAddress(symbolName
, &addr
, &foundIn
, &isResolver
, &isAbsolute
) )
1020 throwf("could not resolve undefined symbol %s in %s expected in %s", symbolName
, this->getDylibID(), binder
->getDylibID());
1025 template <typename A
>
1026 bool Binder
<A
>::findExportedSymbolAddress(const char* name
, pint_t
* result
, Binder
<A
>** foundIn
, bool* isResolverSymbol
, bool* isAbsolute
)
1029 // since re-export chains can be any length, re-exports cannot be resolved in setDependencies()
1030 // instead we lazily, recursively update
1031 if ( !fReExportedSymbolsResolved
) {
1033 // update fHashTable with any individual symbol re-exports
1034 for (typename
std::vector
<SymbolReExport
>::iterator it
=fReExportedSymbols
.begin(); it
!= fReExportedSymbols
.end(); ++it
) {
1035 pint_t targetSymbolAddress
;
1039 if ( it
->dylibOrdinal
<= 0 )
1040 throw "bad mach-o binary, special library ordinal not allowed in re-exported symbols in dyld shared cache";
1042 Binder
<A
>* binder
= fDependentDylibs
[it
->dylibOrdinal
-1].binder
;
1044 if ( ! binder
->findExportedSymbolAddress(it
->importName
, &targetSymbolAddress
, foundIn
, &isResolver
, &isAb
) )
1045 throwf("could not bind symbol %s in %s expected in %s", it
->importName
, this->getDylibID(), binder
->getDylibID());
1048 fSymbolResolvers
.insert(name
);
1050 fHashTable
[it
->exportName
] = targetSymbolAddress
;
1053 fReExportedSymbolsResolved
= true;
1056 *isResolverSymbol
= false;
1057 if ( !fSymbolResolvers
.empty() && fSymbolResolvers
.count(name
) ) {
1058 // lazy pointers should be left unbound, rather than bind to resolver stub
1059 *isResolverSymbol
= true;
1062 // search this dylib
1063 typename
NameToAddrMap::iterator pos
= fHashTable
.find(name
);
1064 if ( pos
!= fHashTable
.end() ) {
1065 *result
= pos
->second
;
1066 //fprintf(stderr, "findExportedSymbolAddress(%s) => 0x%08llX in %s\n", name, (uint64_t)*result, this->getDylibID());
1068 *isAbsolute
= (fAbsoluteSymbols
.count(name
) != 0);
1072 // search re-exported dylibs
1073 for (typename
std::vector
<BinderAndReExportFlag
>::iterator it
= fDependentDylibs
.begin(); it
!= fDependentDylibs
.end(); ++it
) {
1074 if ( it
->reExport
) {
1075 if ( it
->binder
->findExportedSymbolAddress(name
, result
, foundIn
, isResolverSymbol
, isAbsolute
) )
1079 //fprintf(stderr, "findExportedSymbolAddress(%s) => not found in %s\n", name, this->getDylibID());
1083 // record which dylibs will be using this dylibs lazy pointer
1084 template <typename A
>
1085 void Binder
<A
>::addResolverClient(Binder
<A
>* clientDylib
, const char* symbolName
)
1088 x
.client
= clientDylib
;
1089 x
.symbolName
= symbolName
;
1090 fClientAndSymbols
.push_back(x
);
1094 template <typename A
>
1095 typename
A::P::uint_t Binder
<A
>::findLazyPointerFor(const char* symbolName
)
1097 static const bool log
= false;
1099 // first check cache
1100 typename
NameToAddrMap::iterator pos
= fResolverLazyPointers
.find(symbolName
);
1101 if ( pos
!= fResolverLazyPointers
.end() ) {
1102 if ( log
) fprintf(stderr
, "found cached shared lazy pointer at 0x%llX for %s in %s\n", (uint64_t)(pos
->second
), symbolName
, this->getDylibID());
1106 // do slow lookup in lazy pointer section
1107 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicInfo
->indirectsymoff()];
1108 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)this->fHeader
+ sizeof(macho_header
<P
>));
1109 const uint32_t cmd_count
= this->fHeader
->ncmds();
1110 const macho_load_command
<P
>* cmd
= cmds
;
1111 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1112 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1113 const macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1114 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((uint8_t*)seg
+ sizeof(macho_segment_command
<P
>));
1115 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
1116 for (const macho_section
<P
>* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1117 uint8_t sectionType
= sect
->flags() & SECTION_TYPE
;
1118 if ( sectionType
== S_LAZY_SYMBOL_POINTERS
) {
1119 uint32_t elementCount
= sect
->size() / sizeof(pint_t
);
1120 const uint32_t indirectTableOffset
= sect
->reserved1();
1121 pint_t vmlocation
= sect
->addr();
1122 for (uint32_t j
=0; j
< elementCount
; ++j
, vmlocation
+= sizeof(pint_t
)) {
1123 uint32_t symbolIndex
= E::get32(indirectTable
[indirectTableOffset
+ j
]);
1124 switch ( symbolIndex
) {
1125 case INDIRECT_SYMBOL_ABS
:
1126 case INDIRECT_SYMBOL_LOCAL
:
1129 const macho_nlist
<P
>* aSymbol
= &fSymbolTable
[symbolIndex
];
1130 const char* aName
= &fStrings
[aSymbol
->n_strx()];
1131 //fprintf(stderr, " sect=%s, index=%d, symbolIndex=%d, sym=%s\n", sect->sectname(), j, symbolIndex, &fStrings[undefinedSymbol->n_strx()]);
1132 if ( strcmp(aName
, symbolName
) == 0 ) {
1133 fResolverLazyPointers
[symbolName
] = vmlocation
;
1134 if ( log
) fprintf(stderr
, "found slow-path shared lazy pointer at 0x%llX for %s in %s\n", (uint64_t)vmlocation
, symbolName
, this->getDylibID());
1143 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1146 if ( log
) fprintf(stderr
, "not found shared lazy pointer for %s in %s, checking for re-export symbol\n", symbolName
, this->getDylibID());
1147 for (typename
std::vector
<SymbolReExport
>::iterator it
=fReExportedSymbols
.begin(); it
!= fReExportedSymbols
.end(); ++it
) {
1148 if ( strcmp(it
->exportName
, symbolName
) != 0 )
1151 if ( it
->dylibOrdinal
<= 0 )
1152 throw "bad mach-o binary, special library ordinal not allowed in re-exported symbols in dyld shared cache";
1154 Binder
<A
>* binder
= fDependentDylibs
[it
->dylibOrdinal
-1].binder
;
1155 return binder
->findLazyPointerFor(it
->importName
);
1158 if ( log
) fprintf(stderr
, "not found shared lazy pointer for %s in %s, checking re-export dylibs\n", symbolName
, this->getDylibID());
1159 for (typename
std::vector
<BinderAndReExportFlag
>::iterator it
= fDependentDylibs
.begin(); it
!= fDependentDylibs
.end(); ++it
) {
1160 if ( it
->reExport
) {
1161 pint_t result
= it
->binder
->findLazyPointerFor(symbolName
);
1167 if ( log
) fprintf(stderr
, "NOT found shared lazy pointer for %s in %s\n", symbolName
, this->getDylibID());
1171 // called after all binding is done to optimize lazy pointers
1172 template <typename A
>
1173 void Binder
<A
>::optimize()
1175 for (typename
std::vector
<ClientAndSymbol
>::iterator it
= fClientAndSymbols
.begin(); it
!= fClientAndSymbols
.end(); ++it
) {
1176 pint_t lpVMAddr
= findLazyPointerFor(it
->symbolName
);
1177 if ( lpVMAddr
!= 0 ) {
1178 it
->client
->optimizeStub(it
->symbolName
, lpVMAddr
);
1181 fprintf(stderr
, "not able to optimize lazy pointer for %s in %s\n", it
->symbolName
, it
->client
->getDylibID());
1188 void Binder
<arm
>::optimizeStub(uint8_t* stubMappedAddress
, pint_t stubVMAddress
, uint32_t stubSize
, pint_t lpVMAddr
)
1190 if ( stubSize
!= 16 ) {
1191 fprintf(stderr
, "could not optimize ARM stub to resolver function in %s because it is wrong size\n", this->getDylibID());
1194 uint32_t* instructions
= (uint32_t*)stubMappedAddress
;
1195 if ( (E::get32(instructions
[0]) != 0xe59fc004)
1196 || (E::get32(instructions
[1]) != 0xe08fc00c)
1197 || (E::get32(instructions
[2]) != 0xe59cf000)
1199 fprintf(stderr
, "could not optimize ARM stub to resolver function in %s because instructions are not as expected\n", this->getDylibID());
1202 // last .long in stub is: lazyPtr - (stub+8)
1203 // alter to point to more optimal lazy pointer
1204 uint32_t betterOffset
= lpVMAddr
- (stubVMAddress
+ 12);
1205 E::set32(instructions
[3], betterOffset
);
1210 void Binder
<x86_64
>::optimizeStub(uint8_t* stubMappedAddress
, pint_t stubVMAddress
, uint32_t stubSize
, pint_t lpVMAddr
)
1212 if ( stubSize
!= 6 ) {
1213 fprintf(stderr
, "could not optimize x86_64 stub to resolver function in %s because it is wrong size\n", this->getDylibID());
1216 if ( (stubMappedAddress
[0] != 0xFF) || (stubMappedAddress
[1] != 0x25) ) {
1217 fprintf(stderr
, "could not optimize stub to resolver function in %s because instructions are not as expected\n", this->getDylibID());
1220 // last four bytes in stub is RIP relative offset to lazy pointer
1221 // alter to point to more optimal lazy pointer
1222 uint32_t betterOffset
= lpVMAddr
- (stubVMAddress
+ 6);
1223 E::set32(*((uint32_t*)(&stubMappedAddress
[2])), betterOffset
);
1226 template <typename A
>
1227 void Binder
<A
>::optimizeStub(uint8_t* stubMappedAddress
, pint_t stubVMAddress
, uint32_t stubSize
, pint_t lpVMAddress
)
1229 // Remaining architectures are not optimized
1230 //fprintf(stderr, "optimize stub at %p in %s to use lazyPointer at 0x%llX\n", stubMappedAddress, this->getDylibID(), (uint64_t)lpVMAddress);
1233 // search for stub in this image that call target symbol name and then optimize its lazy pointer
1234 template <typename A
>
1235 void Binder
<A
>::optimizeStub(const char* stubName
, pint_t lpVMAddr
)
1238 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicInfo
->indirectsymoff()];
1239 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)this->fHeader
+ sizeof(macho_header
<P
>));
1240 const uint32_t cmd_count
= this->fHeader
->ncmds();
1241 const macho_load_command
<P
>* cmd
= cmds
;
1242 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1243 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1244 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1245 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)seg
+ sizeof(macho_segment_command
<P
>));
1246 macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
1247 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1248 if ( ((sect
->flags() & SECTION_TYPE
) == S_SYMBOL_STUBS
) && (sect
->size() != 0) ) {
1249 pint_t stubsVMStart
= sect
->addr();
1250 uint8_t* stubsMappingStart
= (uint8_t*)this->mappedAddressForNewAddress(stubsVMStart
);
1251 const uint32_t indirectTableOffset
= sect
->reserved1();
1252 const uint32_t stubSize
= sect
->reserved2();
1253 uint32_t elementCount
= sect
->size() / stubSize
;
1254 pint_t stubVMAddr
= stubsVMStart
;
1255 uint8_t* stubMappedAddr
= stubsMappingStart
;
1256 for (uint32_t j
=0; j
< elementCount
; ++j
, stubMappedAddr
+= stubSize
, stubVMAddr
+= stubSize
) {
1257 uint32_t symbolIndex
= E::get32(indirectTable
[indirectTableOffset
+ j
]);
1258 switch ( symbolIndex
) {
1259 case INDIRECT_SYMBOL_ABS
:
1260 case INDIRECT_SYMBOL_LOCAL
:
1264 const macho_nlist
<P
>* sym
= &this->fSymbolTable
[symbolIndex
];
1265 const char* symName
= &fStrings
[sym
->n_strx()];
1266 if ( strcmp(symName
, stubName
) == 0 )
1267 this->optimizeStub(stubMappedAddr
, stubVMAddr
, stubSize
, lpVMAddr
);
1275 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1280 #endif // __MACHO_BINDER__