]> git.saurik.com Git - apple/dyld.git/blob - launch-cache/MachOBinder.hpp
332478fa19112648dc9185bfe16b1755e5237026
[apple/dyld.git] / launch-cache / MachOBinder.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #ifndef __MACHO_BINDER__
26 #define __MACHO_BINDER__
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31 #include <mach/mach.h>
32 #include <limits.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #include <mach-o/loader.h>
39 #include <mach-o/fat.h>
40
41 #include <vector>
42 #include <set>
43 #include <ext/hash_map>
44 #include <ext/hash_set>
45
46 #include "MachOFileAbstraction.hpp"
47 #include "Architectures.hpp"
48 #include "MachOLayout.hpp"
49 #include "MachORebaser.hpp"
50 #include "MachOTrie.hpp"
51
52 #ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
53 #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
54 #endif
55
56
57
58 template <typename A>
59 class Binder : public Rebaser<A>
60 {
61 public:
62 struct CStringEquals {
63 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
64 };
65 typedef __gnu_cxx::hash_map<const char*, class Binder<A>*, __gnu_cxx::hash<const char*>, CStringEquals> Map;
66
67
68 Binder(const MachOLayoutAbstraction&, uint64_t dyldBaseAddress);
69 virtual ~Binder() {}
70
71 const char* getDylibID() const;
72 void setDependentBinders(const Map& map);
73 void bind(std::vector<void*>&);
74 void optimize();
75 void addResolverClient(Binder<A>* clientDylib, const char* symbolName);
76 void addResolverLazyPointerMappedAddress(const char* symbolName,
77 typename A::P::uint_t lpVMAddr);
78 private:
79 typedef typename A::P P;
80 typedef typename A::P::E E;
81 typedef typename A::P::uint_t pint_t;
82 struct BinderAndReExportFlag { Binder<A>* binder; bool reExport; };
83 struct SymbolReExport { const char* exportName; int dylibOrdinal; const char* importName; };
84 typedef __gnu_cxx::hash_map<const char*, pint_t, __gnu_cxx::hash<const char*>, CStringEquals> NameToAddrMap;
85 typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> NameSet;
86 struct ClientAndSymbol { Binder<A>* client; const char* symbolName; };
87 struct SymbolAndLazyPointer { const char* symbolName; pint_t lpVMAddr; };
88
89 static bool isPublicLocation(const char* pth);
90 void doBindExternalRelocations();
91 void doBindIndirectSymbols();
92 void doSetUpDyldSection();
93 void doSetPreboundUndefines();
94 void hoistPrivateRexports();
95 int ordinalOfDependentBinder(Binder<A>* dep);
96 void doBindDyldInfo(std::vector<void*>& pointersInData);
97 void doBindDyldLazyInfo(std::vector<void*>& pointersInData);
98 void bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type,
99 int libraryOrdinal, int64_t addend,
100 const char* symbolName, bool lazyPointer, bool weakImport,
101 std::vector<void*>& pointersInData);
102 pint_t resolveUndefined(const macho_nlist<P>* undefinedSymbol);
103 bool findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol);
104 void bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value);
105 const char* parentUmbrella();
106 pint_t runtimeAddressFromNList(const macho_nlist<P>* sym);
107 void optimizeStub(const char* symbolName, pint_t lpVMAddr);
108 void optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddr);
109 pint_t findLazyPointerFor(const char* symbolName);
110
111
112 static uint8_t pointerRelocSize();
113 static uint8_t pointerRelocType();
114
115 std::vector<BinderAndReExportFlag> fDependentDylibs;
116 NameToAddrMap fHashTable;
117 NameSet fSymbolResolvers;
118 std::vector<SymbolReExport> fReExportedSymbols;
119 uint64_t fDyldBaseAddress;
120 const macho_nlist<P>* fSymbolTable;
121 const char* fStrings;
122 const macho_dysymtab_command<P>* fDynamicInfo;
123 const macho_segment_command<P>* fFristWritableSegment;
124 const macho_dylib_command<P>* fDylibID;
125 const macho_dylib_command<P>* fParentUmbrella;
126 const macho_dyld_info_command<P>* fDyldInfo;
127 bool fOriginallyPrebound;
128 bool fReExportedSymbolsResolved;
129 std::vector<ClientAndSymbol> fClientAndSymbols;
130 std::vector<SymbolAndLazyPointer> fSymbolAndLazyPointers;
131 };
132
133 template <>
134 uint32_t Binder<arm>::runtimeAddressFromNList(const macho_nlist<Pointer32<LittleEndian> >* sym)
135 {
136 if (sym->n_desc() & N_ARM_THUMB_DEF)
137 return sym->n_value() + 1;
138 else
139 return sym->n_value();
140 }
141
142 template <typename A>
143 typename A::P::uint_t Binder<A>::runtimeAddressFromNList(const macho_nlist<P>* sym)
144 {
145 return sym->n_value();
146 }
147
148
149 template <typename A>
150 Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress)
151 : Rebaser<A>(layout), fDyldBaseAddress(dyldBaseAddress),
152 fSymbolTable(NULL), fStrings(NULL), fDynamicInfo(NULL),
153 fFristWritableSegment(NULL), fDylibID(NULL), fDyldInfo(NULL),
154 fParentUmbrella(NULL), fReExportedSymbolsResolved(false)
155 {
156 fOriginallyPrebound = ((this->fHeader->flags() & MH_PREBOUND) != 0);
157 // update header flags so the cache looks prebound split-seg (0x80000000 is in-shared-cache bit)
158 ((macho_header<P>*)this->fHeader)->set_flags(this->fHeader->flags() | MH_PREBOUND | MH_SPLIT_SEGS | 0x80000000);
159
160 // calculate fDynamicInfo, fStrings, fSymbolTable
161 const macho_symtab_command<P>* symtab;
162 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
163 const uint32_t cmd_count = this->fHeader->ncmds();
164 const macho_load_command<P>* cmd = cmds;
165 for (uint32_t i = 0; i < cmd_count; ++i) {
166 switch (cmd->cmd()) {
167 case LC_SYMTAB:
168 symtab = (macho_symtab_command<P>*)cmd;
169 fSymbolTable = (macho_nlist<P>*)(&this->fLinkEditBase[symtab->symoff()]);
170 fStrings = (const char*)&this->fLinkEditBase[symtab->stroff()];
171 break;
172 case LC_DYSYMTAB:
173 fDynamicInfo = (macho_dysymtab_command<P>*)cmd;
174 break;
175 case LC_ID_DYLIB:
176 ((macho_dylib_command<P>*)cmd)->set_timestamp(0);
177 fDylibID = (macho_dylib_command<P>*)cmd;
178 break;
179 case LC_LOAD_DYLIB:
180 case LC_LOAD_WEAK_DYLIB:
181 case LC_REEXPORT_DYLIB:
182 case LC_LOAD_UPWARD_DYLIB:
183 ((macho_dylib_command<P>*)cmd)->set_timestamp(0);
184 break;
185 case LC_SUB_FRAMEWORK:
186 fParentUmbrella = (macho_dylib_command<P>*)cmd;
187 break;
188 case LC_DYLD_INFO:
189 case LC_DYLD_INFO_ONLY:
190 fDyldInfo = (macho_dyld_info_command<P>*)cmd;
191 break;
192 case LC_RPATH:
193 throwf("dyld shared cache does not support LC_RPATH found in %s", layout.getFilePath());
194 break;
195 default:
196 if ( cmd->cmd() & LC_REQ_DYLD )
197 throwf("unknown required load command 0x%08X", cmd->cmd());
198 }
199 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
200 }
201 if ( fDynamicInfo == NULL )
202 throw "no LC_DYSYMTAB";
203 if ( fSymbolTable == NULL )
204 throw "no LC_SYMTAB";
205 // build hash table
206 // fprintf(stderr, "exports for %s\n", layout.getFilePath());
207 if ( fDyldInfo != NULL ) {
208 std::vector<mach_o::trie::Entry> exports;
209 const uint8_t* exportsStart = layout.getDyldInfoExports();
210 const uint8_t* exportsEnd = &exportsStart[fDyldInfo->export_size()];
211 mach_o::trie::parseTrie(exportsStart, exportsEnd, exports);
212 pint_t baseAddress = layout.getSegments()[0].newAddress();
213 for(std::vector<mach_o::trie::Entry>::iterator it = exports.begin(); it != exports.end(); ++it) {
214 if ( (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR ) {
215 if ( (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
216 fSymbolResolvers.insert(it->name);
217 }
218 if ( it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
219 //fprintf(stderr, "found re-export %s in %s\n", sym.exportName, this->getDylibID());
220 SymbolReExport sym;
221 sym.exportName = it->name;
222 sym.dylibOrdinal = it->other;
223 sym.importName = it->importName;
224 if ( (sym.importName == NULL) || (sym.importName[0] == '\0') )
225 sym.importName = sym.exportName;
226 fReExportedSymbols.push_back(sym);
227 // fHashTable entry will be added in first call to findExportedSymbolAddress()
228 }
229 else {
230 fHashTable[it->name] = it->address + baseAddress;
231 }
232 }
233 else {
234 throwf("non-regular symbol binding not supported for %s in %s", it->name, layout.getFilePath());
235 }
236 //fprintf(stderr, "0x%08llX %s\n", it->address + baseAddress, it->name);
237 }
238 }
239 else {
240 if ( fDynamicInfo->tocoff() == 0 ) {
241 const macho_nlist<P>* start = &fSymbolTable[fDynamicInfo->iextdefsym()];
242 const macho_nlist<P>* end = &start[fDynamicInfo->nextdefsym()];
243 fHashTable.resize(fDynamicInfo->nextdefsym()); // set initial bucket count
244 for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
245 const char* name = &fStrings[sym->n_strx()];
246 fHashTable[name] = runtimeAddressFromNList(sym);
247 //fprintf(stderr, " 0x%08llX %s\n", sym->n_value(), name);
248 }
249 }
250 else {
251 int32_t count = fDynamicInfo->ntoc();
252 fHashTable.resize(count); // set initial bucket count
253 const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)&this->fLinkEditBase[fDynamicInfo->tocoff()];
254 for (int32_t i = 0; i < count; ++i) {
255 const uint32_t index = E::get32(toc[i].symbol_index);
256 const macho_nlist<P>* sym = &fSymbolTable[index];
257 const char* name = &fStrings[sym->n_strx()];
258 fHashTable[name] = runtimeAddressFromNList(sym);
259 //fprintf(stderr, "- 0x%08llX %s\n", sym->n_value(), name);
260 }
261 }
262 }
263 }
264
265 template <> uint8_t Binder<x86>::pointerRelocSize() { return 2; }
266 template <> uint8_t Binder<x86_64>::pointerRelocSize() { return 3; }
267 template <> uint8_t Binder<arm>::pointerRelocSize() { return 2; }
268
269 template <> uint8_t Binder<x86>::pointerRelocType() { return GENERIC_RELOC_VANILLA; }
270 template <> uint8_t Binder<x86_64>::pointerRelocType() { return X86_64_RELOC_UNSIGNED; }
271 template <> uint8_t Binder<arm>::pointerRelocType() { return ARM_RELOC_VANILLA; }
272
273
274 template <typename A>
275 const char* Binder<A>::getDylibID() const
276 {
277 if ( fDylibID != NULL )
278 return fDylibID->name();
279 else
280 return NULL;
281 }
282
283 template <typename A>
284 const char* Binder<A>::parentUmbrella()
285 {
286 if ( fParentUmbrella != NULL )
287 return fParentUmbrella->name();
288 else
289 return NULL;
290 }
291
292
293 template <typename A>
294 bool Binder<A>::isPublicLocation(const char* pth)
295 {
296 // /usr/lib is a public location
297 if ( (strncmp(pth, "/usr/lib/", 9) == 0) && (strchr(&pth[9], '/') == NULL) )
298 return true;
299
300 // /System/Library/Frameworks/ is a public location
301 if ( strncmp(pth, "/System/Library/Frameworks/", 27) == 0 ) {
302 const char* frameworkDot = strchr(&pth[27], '.');
303 // but only top level framework
304 // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true
305 // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false
306 // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar ==> false
307 // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
308 if ( frameworkDot != NULL ) {
309 int frameworkNameLen = frameworkDot - &pth[27];
310 if ( strncmp(&pth[strlen(pth)-frameworkNameLen-1], &pth[26], frameworkNameLen+1) == 0 )
311 return true;
312 }
313 }
314
315 return false;
316 }
317
318 template <typename A>
319 void Binder<A>::setDependentBinders(const Map& map)
320 {
321 // first pass to build vector of dylibs
322 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
323 const uint32_t cmd_count = this->fHeader->ncmds();
324 const macho_load_command<P>* cmd = cmds;
325 for (uint32_t i = 0; i < cmd_count; ++i) {
326 switch (cmd->cmd()) {
327 case LC_LOAD_DYLIB:
328 case LC_LOAD_WEAK_DYLIB:
329 case LC_REEXPORT_DYLIB:
330 case LC_LOAD_UPWARD_DYLIB:
331 const char* path = ((struct macho_dylib_command<P>*)cmd)->name();
332 typename Map::const_iterator pos = map.find(path);
333 if ( pos != map.end() ) {
334 BinderAndReExportFlag entry;
335 entry.binder = pos->second;
336 entry.reExport = ( cmd->cmd() == LC_REEXPORT_DYLIB );
337 fDependentDylibs.push_back(entry);
338 }
339 else {
340 // the load command string does not match the install name of any loaded dylib
341 // this could happen if there was not a world build and some dylib changed its
342 // install path to be some symlinked path
343
344 // use realpath() and walk map looking for a realpath match
345 bool found = false;
346 char targetPath[PATH_MAX];
347 if ( realpath(path, targetPath) != NULL ) {
348 for(typename Map::const_iterator it=map.begin(); it != map.end(); ++it) {
349 char aPath[PATH_MAX];
350 if ( realpath(it->first, aPath) != NULL ) {
351 if ( strcmp(targetPath, aPath) == 0 ) {
352 BinderAndReExportFlag entry;
353 entry.binder = it->second;
354 entry.reExport = ( cmd->cmd() == LC_REEXPORT_DYLIB );
355 fDependentDylibs.push_back(entry);
356 found = true;
357 fprintf(stderr, "update_dyld_shared_cache: warning mismatched install path in %s for %s\n",
358 this->getDylibID(), path);
359 break;
360 }
361 }
362 }
363 }
364 if ( ! found ) {
365 if ( cmd->cmd() == LC_LOAD_WEAK_DYLIB ) {
366 BinderAndReExportFlag entry;
367 entry.binder = NULL;
368 entry.reExport = false;
369 fDependentDylibs.push_back(entry);
370 break;
371 }
372 else {
373 throwf("in %s can't find dylib %s", this->getDylibID(), path);
374 }
375 }
376 }
377 break;
378 }
379 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
380 }
381 // handle pre-10.5 re-exports
382 if ( (this->fHeader->flags() & MH_NO_REEXPORTED_DYLIBS) == 0 ) {
383 cmd = cmds;
384 // LC_SUB_LIBRARY means re-export one with matching leaf name
385 const char* dylibBaseName;
386 const char* frameworkLeafName;
387 for (uint32_t i = 0; i < cmd_count; ++i) {
388 switch ( cmd->cmd() ) {
389 case LC_SUB_LIBRARY:
390 dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
391 for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
392 const char* dylibName = it->binder->getDylibID();
393 const char* lastSlash = strrchr(dylibName, '/');
394 const char* leafStart = &lastSlash[1];
395 if ( lastSlash == NULL )
396 leafStart = dylibName;
397 const char* firstDot = strchr(leafStart, '.');
398 int len = strlen(leafStart);
399 if ( firstDot != NULL )
400 len = firstDot - leafStart;
401 if ( strncmp(leafStart, dylibBaseName, len) == 0 )
402 it->reExport = true;
403 }
404 break;
405 case LC_SUB_UMBRELLA:
406 frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
407 for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
408 const char* dylibName = it->binder->getDylibID();
409 const char* lastSlash = strrchr(dylibName, '/');
410 if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
411 it->reExport = true;
412 }
413 break;
414 }
415 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
416 }
417 // ask dependents if they re-export through me
418 const char* thisName = this->getDylibID();
419 if ( thisName != NULL ) {
420 const char* thisLeafName = strrchr(thisName, '/');
421 if ( thisLeafName != NULL )
422 ++thisLeafName;
423 for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
424 if ( ! it->reExport ) {
425 const char* parentUmbrellaName = it->binder->parentUmbrella();
426 if ( parentUmbrellaName != NULL ) {
427 if ( strcmp(parentUmbrellaName, thisLeafName) == 0 )
428 it->reExport = true;
429 }
430 }
431 }
432 }
433 }
434
435 }
436
437 template <typename A>
438 int Binder<A>::ordinalOfDependentBinder(Binder<A>* dep)
439 {
440 for (int i=0; i < fDependentDylibs.size(); ++i) {
441 if ( fDependentDylibs[i].binder == dep )
442 return i+1;
443 }
444 throw "dependend dylib not found";
445 }
446
447 template <typename A>
448 void Binder<A>::hoistPrivateRexports()
449 {
450 std::vector<Binder<A>*> privateReExportedDylibs;
451 for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
452 if ( it->reExport && ! isPublicLocation(it->binder->getDylibID()) )
453 privateReExportedDylibs.push_back(it->binder);
454 }
455 if ( privateReExportedDylibs.size() != 0 ) {
456 // parse export info into vector of exports
457 const uint8_t* exportsStart = this->fLayout.getDyldInfoExports();
458 const uint8_t* exportsEnd = &exportsStart[fDyldInfo->export_size()];
459 std::vector<mach_o::trie::Entry> exports;
460 mach_o::trie::parseTrie(exportsStart, exportsEnd, exports);
461 //fprintf(stderr, "%s exports %lu symbols from trie of size %u \n", this->fLayout.getFilePath(), exports.size(), fDyldInfo->export_size());
462
463 // add re-exports for each export from an re-exported dylib
464 for(typename std::vector<Binder<A>*>::iterator it = privateReExportedDylibs.begin(); it != privateReExportedDylibs.end(); ++it) {
465 Binder<A>* binder = *it;
466 int ordinal = ordinalOfDependentBinder(binder);
467 const uint8_t* aDylibsExportsStart = binder->fLayout.getDyldInfoExports();
468 const uint8_t* aDylibsExportsEnd = &aDylibsExportsStart[binder->fDyldInfo->export_size()];
469 std::vector<mach_o::trie::Entry> aDylibsExports;
470 mach_o::trie::parseTrie(aDylibsExportsStart, aDylibsExportsEnd, aDylibsExports);
471 //fprintf(stderr, "%s re-exports %lu symbols from %s\n", this->fLayout.getFilePath(), aDylibsExports.size(), binder->getDylibID());
472 for(std::vector<mach_o::trie::Entry>::iterator eit = aDylibsExports.begin(); eit != aDylibsExports.end(); ++eit) {
473 mach_o::trie::Entry entry = *eit;
474 entry.flags |= EXPORT_SYMBOL_FLAGS_REEXPORT;
475 entry.other = ordinal;
476 entry.importName = NULL;
477 exports.push_back(entry);
478 }
479 }
480 // rebuild new combined trie
481 std::vector<uint8_t> newExportTrieBytes;
482 newExportTrieBytes.reserve(fDyldInfo->export_size());
483 mach_o::trie::makeTrie(exports, newExportTrieBytes);
484 //fprintf(stderr, "%s now exports %lu symbols from trie of size %lu\n", this->fLayout.getFilePath(), exports.size(), newExportTrieBytes.size());
485
486 // allocate new buffer and set export_off to use new buffer instead
487 uint32_t newExportsSize = newExportTrieBytes.size();
488 uint8_t* sideTrie = new uint8_t[newExportsSize];
489 memcpy(sideTrie, &newExportTrieBytes[0], newExportsSize);
490 this->fLayout.setDyldInfoExports(sideTrie);
491 ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_off(0); // invalidate old trie
492 ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_size(newExportsSize);
493 }
494 }
495
496
497 template <typename A>
498 void Binder<A>::bind(std::vector<void*>& pointersInData)
499 {
500 this->doSetUpDyldSection();
501 if ( fDyldInfo != NULL ) {
502 this->doBindDyldInfo(pointersInData);
503 this->doBindDyldLazyInfo(pointersInData);
504 this->hoistPrivateRexports();
505 // weak bind info is processed at launch time
506 }
507 else {
508 this->doBindExternalRelocations();
509 this->doBindIndirectSymbols();
510 this->doSetPreboundUndefines();
511 }
512 }
513
514
515 template <typename A>
516 void Binder<A>::doSetUpDyldSection()
517 {
518 // find __DATA __dyld section
519 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
520 const uint32_t cmd_count = this->fHeader->ncmds();
521 const macho_load_command<P>* cmd = cmds;
522 for (uint32_t i = 0; i < cmd_count; ++i) {
523 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
524 const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
525 if ( strcmp(seg->segname(), "__DATA") == 0 ) {
526 const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
527 const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
528 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
529 if ( (strcmp(sect->sectname(), "__dyld") == 0) && (sect->size() >= 2*sizeof(pint_t)) ) {
530 // set two values in __dyld section to point into dyld
531 pint_t* lazyBinder = this->mappedAddressForNewAddress(sect->addr());
532 pint_t* dyldFuncLookup = this->mappedAddressForNewAddress(sect->addr()+sizeof(pint_t));
533 A::P::setP(*lazyBinder, fDyldBaseAddress + 0x1000);
534 A::P::setP(*dyldFuncLookup, fDyldBaseAddress + 0x1008);
535 }
536 }
537 }
538 }
539 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
540 }
541 }
542
543 template <typename A>
544 void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, int libraryOrdinal,
545 int64_t addend, const char* symbolName, bool lazyPointer, bool weakImport, std::vector<void*>& pointersInData)
546 {
547 //printf("%d 0x%08llX type=%d, lib=%d, addend=%lld, symbol=%s\n", segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
548 const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
549 if ( segmentIndex > segments.size() )
550 throw "bad segment index in rebase info";
551
552 if ( libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
553 throw "dynamic lookup linkage not allowed in dyld shared cache";
554
555 if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE )
556 throw "linkage to main executable not allowed in dyld shared cache";
557
558 if ( libraryOrdinal < 0 )
559 throw "bad mach-o binary, special library ordinal not allowd in dyld shared cache";
560
561 if ( (unsigned)libraryOrdinal > fDependentDylibs.size() )
562 throw "bad mach-o binary, library ordinal too big";
563
564 Binder<A>* binder;
565 if ( libraryOrdinal == BIND_SPECIAL_DYLIB_SELF )
566 binder = this;
567 else
568 binder = fDependentDylibs[libraryOrdinal-1].binder;
569 pint_t targetSymbolAddress;
570 bool isResolverSymbol;
571 Binder<A>* foundIn;
572 if ( weakImport && (binder == NULL) ) {
573 targetSymbolAddress = 0;
574 foundIn = NULL;
575 isResolverSymbol = false;
576 }
577 else {
578 if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress, &foundIn, &isResolverSymbol) )
579 throwf("could not bind symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
580 }
581
582 // don't bind lazy pointers to resolver stubs in shared cache
583 if ( lazyPointer && isResolverSymbol ) {
584 if ( foundIn == this ) {
585 // record location of lazy pointer for other dylibs to re-use
586 pint_t lpVMAddr = segments[segmentIndex].newAddress() + segmentOffset;
587 foundIn->addResolverLazyPointerMappedAddress(symbolName, lpVMAddr);
588 //fprintf(stderr, "resolver %s in %s has lazy pointer with segmentOffset=0x%08llX\n", symbolName, this->getDylibID(), segmentOffset);
589 }
590 else {
591 // record that this dylib has a lazy pointer to a resolver function
592 foundIn->addResolverClient(this, symbolName);
593 // fprintf(stderr, "have lazy pointer to resolver %s in %s\n", symbolName, this->getDylibID());
594 }
595 return;
596 }
597
598 // do actual update
599 const MachOLayoutAbstraction::Segment& seg = segments[segmentIndex];
600 uint8_t* mappedAddr = (uint8_t*)seg.mappedAddress() + segmentOffset;
601 pint_t* mappedAddrP = (pint_t*)mappedAddr;
602 uint32_t* mappedAddr32 = (uint32_t*)mappedAddr;
603 int32_t svalue32new;
604 switch ( type ) {
605 case BIND_TYPE_POINTER:
606 P::setP(*mappedAddrP, targetSymbolAddress + addend);
607 break;
608
609 case BIND_TYPE_TEXT_ABSOLUTE32:
610 E::set32(*mappedAddr32, targetSymbolAddress + addend);
611 break;
612
613 case BIND_TYPE_TEXT_PCREL32:
614 svalue32new = seg.address() + segmentOffset + 4 - (targetSymbolAddress + addend);
615 E::set32(*mappedAddr32, svalue32new);
616 break;
617
618 default:
619 throw "bad bind type";
620 }
621 pointersInData.push_back(mappedAddr);
622 }
623
624
625
626 template <typename A>
627 void Binder<A>::doBindDyldLazyInfo(std::vector<void*>& pointersInData)
628 {
629 const uint8_t* p = &this->fLinkEditBase[fDyldInfo->lazy_bind_off()];
630 const uint8_t* end = &p[fDyldInfo->lazy_bind_size()];
631
632 uint8_t type = BIND_TYPE_POINTER;
633 uint64_t segmentOffset = 0;
634 uint8_t segmentIndex = 0;
635 const char* symbolName = NULL;
636 int libraryOrdinal = 0;
637 int64_t addend = 0;
638 bool weakImport = false;
639 while ( p < end ) {
640 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
641 uint8_t opcode = *p & BIND_OPCODE_MASK;
642 ++p;
643 switch (opcode) {
644 case BIND_OPCODE_DONE:
645 // this opcode marks the end of each lazy pointer binding
646 break;
647 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
648 libraryOrdinal = immediate;
649 break;
650 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
651 libraryOrdinal = read_uleb128(p, end);
652 break;
653 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
654 // the special ordinals are negative numbers
655 if ( immediate == 0 )
656 libraryOrdinal = 0;
657 else {
658 int8_t signExtended = BIND_OPCODE_MASK | immediate;
659 libraryOrdinal = signExtended;
660 }
661 break;
662 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
663 weakImport = ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 );
664 symbolName = (char*)p;
665 while (*p != '\0')
666 ++p;
667 ++p;
668 break;
669 case BIND_OPCODE_SET_ADDEND_SLEB:
670 addend = read_sleb128(p, end);
671 break;
672 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
673 segmentIndex = immediate;
674 segmentOffset = read_uleb128(p, end);
675 break;
676 case BIND_OPCODE_DO_BIND:
677 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, true, weakImport, pointersInData);
678 segmentOffset += sizeof(pint_t);
679 break;
680 case BIND_OPCODE_SET_TYPE_IMM:
681 case BIND_OPCODE_ADD_ADDR_ULEB:
682 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
683 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
684 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
685 default:
686 throwf("bad lazy bind opcode %d", *p);
687 }
688 }
689
690
691 }
692
693 template <typename A>
694 void Binder<A>::doBindDyldInfo(std::vector<void*>& pointersInData)
695 {
696 const uint8_t* p = &this->fLinkEditBase[fDyldInfo->bind_off()];
697 const uint8_t* end = &p[fDyldInfo->bind_size()];
698
699 uint8_t type = 0;
700 uint64_t segmentOffset = 0;
701 uint8_t segmentIndex = 0;
702 const char* symbolName = NULL;
703 int libraryOrdinal = 0;
704 int64_t addend = 0;
705 uint32_t count;
706 uint32_t skip;
707 bool weakImport = false;
708 bool done = false;
709 while ( !done && (p < end) ) {
710 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
711 uint8_t opcode = *p & BIND_OPCODE_MASK;
712 ++p;
713 switch (opcode) {
714 case BIND_OPCODE_DONE:
715 done = true;
716 break;
717 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
718 libraryOrdinal = immediate;
719 break;
720 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
721 libraryOrdinal = read_uleb128(p, end);
722 break;
723 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
724 // the special ordinals are negative numbers
725 if ( immediate == 0 )
726 libraryOrdinal = 0;
727 else {
728 int8_t signExtended = BIND_OPCODE_MASK | immediate;
729 libraryOrdinal = signExtended;
730 }
731 break;
732 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
733 weakImport = ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 );
734 symbolName = (char*)p;
735 while (*p != '\0')
736 ++p;
737 ++p;
738 break;
739 case BIND_OPCODE_SET_TYPE_IMM:
740 type = immediate;
741 break;
742 case BIND_OPCODE_SET_ADDEND_SLEB:
743 addend = read_sleb128(p, end);
744 break;
745 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
746 segmentIndex = immediate;
747 segmentOffset = read_uleb128(p, end);
748 break;
749 case BIND_OPCODE_ADD_ADDR_ULEB:
750 segmentOffset += read_uleb128(p, end);
751 break;
752 case BIND_OPCODE_DO_BIND:
753 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
754 segmentOffset += sizeof(pint_t);
755 break;
756 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
757 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
758 segmentOffset += read_uleb128(p, end) + sizeof(pint_t);
759 break;
760 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
761 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
762 segmentOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
763 break;
764 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
765 count = read_uleb128(p, end);
766 skip = read_uleb128(p, end);
767 for (uint32_t i=0; i < count; ++i) {
768 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
769 segmentOffset += skip + sizeof(pint_t);
770 }
771 break;
772 default:
773 throwf("bad bind opcode %d", *p);
774 }
775 }
776
777
778
779 }
780
781
782 template <typename A>
783 void Binder<A>::doSetPreboundUndefines()
784 {
785 const macho_dysymtab_command<P>* dysymtab = NULL;
786 macho_nlist<P>* symbolTable = NULL;
787
788 // get symbol table info
789 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
790 const uint32_t cmd_count = this->fHeader->ncmds();
791 const macho_load_command<P>* cmd = cmds;
792 for (uint32_t i = 0; i < cmd_count; ++i) {
793 switch (cmd->cmd()) {
794 case LC_SYMTAB:
795 {
796 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
797 symbolTable = (macho_nlist<P>*)(&this->fLinkEditBase[symtab->symoff()]);
798 }
799 break;
800 case LC_DYSYMTAB:
801 dysymtab = (macho_dysymtab_command<P>*)cmd;
802 break;
803 }
804 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
805 }
806
807 // walk all undefines and set their prebound n_value
808 macho_nlist<P>* const lastUndefine = &symbolTable[dysymtab->iundefsym()+dysymtab->nundefsym()];
809 for (macho_nlist<P>* entry = &symbolTable[dysymtab->iundefsym()]; entry < lastUndefine; ++entry) {
810 if ( entry->n_type() & N_EXT ) {
811 //fprintf(stderr, "doSetPreboundUndefines: r_sym=%s, pbaddr=0x%08X, in %s\n",
812 // &fStrings[entry->n_strx()], pbaddr, this->getDylibID());
813 pint_t pbaddr = this->resolveUndefined(entry);
814 entry->set_n_value(pbaddr);
815 }
816 }
817 }
818
819
820 template <typename A>
821 void Binder<A>::doBindExternalRelocations()
822 {
823 // get where reloc addresses start
824 // these address are always relative to first writable segment because they are in cache which always
825 // has writable segments far from read-only segments
826 pint_t firstWritableSegmentBaseAddress = 0;
827 const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
828 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
829 const MachOLayoutAbstraction::Segment& seg = *it;
830 if ( seg.writable() ) {
831 firstWritableSegmentBaseAddress = seg.newAddress();
832 break;
833 }
834 }
835
836 // loop through all external relocation records and bind each
837 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&this->fLinkEditBase[fDynamicInfo->extreloff()]);
838 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicInfo->nextrel()];
839 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
840 if ( reloc->r_length() != pointerRelocSize() )
841 throw "bad external relocation length";
842 if ( reloc->r_type() != pointerRelocType() )
843 throw "unknown external relocation type";
844 if ( reloc->r_pcrel() )
845 throw "r_pcrel external relocaiton not supported";
846
847 const macho_nlist<P>* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum()];
848 pint_t* location;
849 try {
850 location = this->mappedAddressForNewAddress(reloc->r_address() + firstWritableSegmentBaseAddress);
851 }
852 catch (const char* msg) {
853 throwf("%s processesing external relocation r_address 0x%08X", msg, reloc->r_address());
854 }
855 pint_t addend = P::getP(*location);
856 if ( fOriginallyPrebound ) {
857 // in a prebound binary, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
858 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
859 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
860 addend -= undefinedSymbol->n_value();
861 // To further complicate things, if this is defined symbol, then its n_value has already been adjust to the
862 // new base address, so we need to back off the slide too..
863 if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
864 addend += this->getSlideForNewAddress(undefinedSymbol->n_value());
865 }
866 }
867 pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
868 //fprintf(stderr, "external reloc: r_address=0x%08X, r_sym=%s, symAddr=0x%08llX, addend=0x%08llX in %s\n",
869 // reloc->r_address(), &fStrings[undefinedSymbol->n_strx()], (uint64_t)symbolAddr, (uint64_t)addend, this->getDylibID());
870 P::setP(*location, symbolAddr + addend);
871 }
872 }
873
874
875 // most architectures use pure code, unmodifiable stubs
876 template <typename A>
877 void Binder<A>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
878 {
879 // do nothing
880 }
881
882 // x86 supports fast stubs
883 template <>
884 void Binder<x86>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
885 {
886 // if the stub is not 5-bytes, it is an old slow stub
887 if ( elementSize == 5 ) {
888 uint32_t rel32 = value - (vmlocation + 5);
889 location[0] = 0xE9; // JMP rel32
890 location[1] = rel32 & 0xFF;
891 location[2] = (rel32 >> 8) & 0xFF;
892 location[3] = (rel32 >> 16) & 0xFF;
893 location[4] = (rel32 >> 24) & 0xFF;
894 }
895 }
896
897 template <typename A>
898 void Binder<A>::doBindIndirectSymbols()
899 {
900 const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicInfo->indirectsymoff()];
901 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
902 const uint32_t cmd_count = this->fHeader->ncmds();
903 const macho_load_command<P>* cmd = cmds;
904 //fprintf(stderr, "doBindIndirectSymbols() %s\n", this->fLayout.getFilePath());
905 for (uint32_t i = 0; i < cmd_count; ++i) {
906 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
907 const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
908 const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
909 const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
910 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
911 uint8_t elementSize = 0;
912 uint8_t sectionType = sect->flags() & SECTION_TYPE;
913 switch ( sectionType ) {
914 case S_SYMBOL_STUBS:
915 elementSize = sect->reserved2();
916 break;
917 case S_NON_LAZY_SYMBOL_POINTERS:
918 case S_LAZY_SYMBOL_POINTERS:
919 elementSize = sizeof(pint_t);
920 break;
921 }
922 if ( elementSize != 0 ) {
923 uint32_t elementCount = sect->size() / elementSize;
924 const uint32_t indirectTableOffset = sect->reserved1();
925 uint8_t* location = NULL;
926 if ( sect->size() != 0 )
927 location = (uint8_t*)this->mappedAddressForNewAddress(sect->addr());
928 pint_t vmlocation = sect->addr();
929 for (uint32_t j=0; j < elementCount; ++j, location += elementSize, vmlocation += elementSize) {
930 uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]);
931 switch ( symbolIndex ) {
932 case INDIRECT_SYMBOL_ABS:
933 case INDIRECT_SYMBOL_LOCAL:
934 break;
935 default:
936 const macho_nlist<P>* undefinedSymbol = &fSymbolTable[symbolIndex];
937 //fprintf(stderr, " sect=%s, index=%d, symbolIndex=%d, sym=%s\n", sect->sectname(), j, symbolIndex, &fStrings[undefinedSymbol->n_strx()]);
938 pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
939 switch ( sectionType ) {
940 case S_NON_LAZY_SYMBOL_POINTERS:
941 case S_LAZY_SYMBOL_POINTERS:
942 P::setP(*((pint_t*)location), symbolAddr);
943 break;
944 case S_SYMBOL_STUBS:
945 this->bindStub(elementSize, location, vmlocation, symbolAddr);
946 break;
947 }
948 break;
949 }
950 }
951 }
952 }
953 }
954 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
955 }
956 }
957
958
959
960
961 template <typename A>
962 typename A::P::uint_t Binder<A>::resolveUndefined(const macho_nlist<P>* undefinedSymbol)
963 {
964 if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
965 if ( (undefinedSymbol->n_type() & N_PEXT) != 0 ) {
966 // is a multi-module private_extern internal reference that the linker did not optimize away
967 return runtimeAddressFromNList(undefinedSymbol);
968 }
969 if ( (undefinedSymbol->n_desc() & N_WEAK_DEF) != 0 ) {
970 // is a weak definition, we should prebind to this one in the same linkage unit
971 return runtimeAddressFromNList(undefinedSymbol);
972 }
973 }
974 const char* symbolName = &fStrings[undefinedSymbol->n_strx()];
975 if ( (this->fHeader->flags() & MH_TWOLEVEL) == 0 ) {
976 // flat namespace binding
977 throw "flat namespace not supported";
978 }
979 else {
980 uint8_t ordinal = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc());
981 Binder<A>* binder = NULL;
982 switch ( ordinal ) {
983 case EXECUTABLE_ORDINAL:
984 case DYNAMIC_LOOKUP_ORDINAL:
985 throw "magic ordineal not supported";
986 case SELF_LIBRARY_ORDINAL:
987 binder = this;
988 break;
989 default:
990 if ( ordinal > fDependentDylibs.size() )
991 throw "two-level ordinal out of range";
992 binder = fDependentDylibs[ordinal-1].binder;
993 }
994 pint_t addr;
995 bool isResolver;
996 Binder<A>* foundIn;
997 if ( ! binder->findExportedSymbolAddress(symbolName, &addr, &foundIn, &isResolver) )
998 throwf("could not resolve undefined symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
999 return addr;
1000 }
1001 }
1002
1003 template <typename A>
1004 bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol)
1005 {
1006 *foundIn = NULL;
1007 // since re-export chains can be any length, re-exports cannot be resolved in setDependencies()
1008 // instead we lazily, recursively update
1009 if ( !fReExportedSymbolsResolved ) {
1010
1011 // update fHashTable with any individual symbol re-exports
1012 for (typename std::vector<SymbolReExport>::iterator it=fReExportedSymbols.begin(); it != fReExportedSymbols.end(); ++it) {
1013 pint_t targetSymbolAddress;
1014 bool isResolver;
1015
1016 if ( it->dylibOrdinal <= 0 )
1017 throw "bad mach-o binary, special library ordinal not allowed in re-exported symbols in dyld shared cache";
1018
1019 Binder<A>* binder = fDependentDylibs[it->dylibOrdinal-1].binder;
1020
1021 if ( ! binder->findExportedSymbolAddress(it->importName, &targetSymbolAddress, foundIn, &isResolver) )
1022 throwf("could not bind symbol %s in %s expected in %s", it->importName, this->getDylibID(), binder->getDylibID());
1023
1024 if ( isResolver )
1025 throw "bad mach-o binary, re-export of resolvers symbols not supported in dyld shared cache";
1026
1027 fHashTable[it->exportName] = targetSymbolAddress;
1028 }
1029 // mark as done
1030 fReExportedSymbolsResolved = true;
1031 }
1032
1033 *isResolverSymbol = false;
1034 if ( !fSymbolResolvers.empty() && fSymbolResolvers.count(name) ) {
1035 // lazy pointers should be left unbound, rather than bind to resolver stub
1036 *isResolverSymbol = true;
1037 }
1038
1039 typename NameToAddrMap::iterator pos = fHashTable.find(name);
1040 if ( pos != fHashTable.end() ) {
1041 *result = pos->second;
1042 //fprintf(stderr, "findExportedSymbolAddress(%s) => 0x%08llX in %s\n", name, (uint64_t)*result, this->getDylibID());
1043 *foundIn = this;
1044 return true;
1045 }
1046
1047 // search re-exports
1048 for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
1049 if ( it->reExport ) {
1050 if ( it->binder->findExportedSymbolAddress(name, result, foundIn, isResolverSymbol) )
1051 return true;
1052 }
1053 }
1054 //fprintf(stderr, "findExportedSymbolAddress(%s) => not found in %s\n", name, this->getDylibID());
1055 return false;
1056 }
1057
1058 // record which dylibs will be using this dylibs lazy pointer
1059 template <typename A>
1060 void Binder<A>::addResolverClient(Binder<A>* clientDylib, const char* symbolName)
1061 {
1062 ClientAndSymbol x;
1063 x.client = clientDylib;
1064 x.symbolName = symbolName;
1065 fClientAndSymbols.push_back(x);
1066 }
1067
1068 // Record that this dylib has an lazy pointer that points within itself for use
1069 // with a resolver function.
1070 template <typename A>
1071 void Binder<A>::addResolverLazyPointerMappedAddress(const char* symbolName, pint_t lpVMAddr)
1072 {
1073 SymbolAndLazyPointer x;
1074 x.symbolName = symbolName;
1075 x.lpVMAddr = lpVMAddr;
1076 fSymbolAndLazyPointers.push_back(x);
1077 }
1078
1079 template <typename A>
1080 typename A::P::uint_t Binder<A>::findLazyPointerFor(const char* symbolName)
1081 {
1082 for (typename std::vector<SymbolAndLazyPointer>::iterator it = fSymbolAndLazyPointers.begin(); it != fSymbolAndLazyPointers.end(); ++it) {
1083 if ( strcmp(it->symbolName, symbolName) == 0 )
1084 return it->lpVMAddr;
1085 }
1086 return 0;
1087 }
1088
1089 // called after all binding is done to optimize lazy pointers
1090 template <typename A>
1091 void Binder<A>::optimize()
1092 {
1093 for (typename std::vector<ClientAndSymbol>::iterator it = fClientAndSymbols.begin(); it != fClientAndSymbols.end(); ++it) {
1094 pint_t lpVMAddr = findLazyPointerFor(it->symbolName);
1095 if ( lpVMAddr != 0 ) {
1096 it->client->optimizeStub(it->symbolName, lpVMAddr);
1097 }
1098 else {
1099 fprintf(stderr, "not able to optimize lazy pointer for %s in %s\n", it->symbolName, it->client->getDylibID());
1100 }
1101
1102 }
1103 }
1104
1105 template <>
1106 void Binder<arm>::optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddr)
1107 {
1108 if ( stubSize != 16 ) {
1109 fprintf(stderr, "could not optimize ARM stub to resolver function in %s because it is wrong size\n", this->getDylibID());
1110 return;
1111 }
1112 uint32_t* instructions = (uint32_t*)stubMappedAddress;
1113 if ( (E::get32(instructions[0]) != 0xe59fc004)
1114 || (E::get32(instructions[1]) != 0xe08fc00c)
1115 || (E::get32(instructions[2]) != 0xe59cf000)
1116 ) {
1117 fprintf(stderr, "could not optimize ARM stub to resolver function in %s because instructions are not as expected\n", this->getDylibID());
1118 return;
1119 }
1120 // last .long in stub is: lazyPtr - (stub+8)
1121 // alter to point to more optimal lazy pointer
1122 uint32_t betterOffset = lpVMAddr - (stubVMAddress + 12);
1123 E::set32(instructions[3], betterOffset);
1124 }
1125
1126
1127 template <>
1128 void Binder<x86_64>::optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddr)
1129 {
1130 if ( stubSize != 6 ) {
1131 fprintf(stderr, "could not optimize x86_64 stub to resolver function in %s because it is wrong size\n", this->getDylibID());
1132 return;
1133 }
1134 if ( (stubMappedAddress[0] != 0xFF) || (stubMappedAddress[1] != 0x25) ) {
1135 fprintf(stderr, "could not optimize stub to resolver function in %s because instructions are not as expected\n", this->getDylibID());
1136 return;
1137 }
1138 // last four bytes in stub is RIP relative offset to lazy pointer
1139 // alter to point to more optimal lazy pointer
1140 uint32_t betterOffset = lpVMAddr - (stubVMAddress + 6);
1141 E::set32(*((uint32_t*)(&stubMappedAddress[2])), betterOffset);
1142 }
1143
1144 template <typename A>
1145 void Binder<A>::optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddress)
1146 {
1147 // Remaining architectures are not optimized
1148 //fprintf(stderr, "optimize stub at %p in %s to use lazyPointer at 0x%llX\n", stubMappedAddress, this->getDylibID(), (uint64_t)lpVMAddress);
1149 }
1150
1151 // search for stub in this image that call target symbol name and then optimize its lazy pointer
1152 template <typename A>
1153 void Binder<A>::optimizeStub(const char* stubName, pint_t lpVMAddr)
1154 {
1155 // find named stub
1156 const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicInfo->indirectsymoff()];
1157 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
1158 const uint32_t cmd_count = this->fHeader->ncmds();
1159 const macho_load_command<P>* cmd = cmds;
1160 for (uint32_t i = 0; i < cmd_count; ++i) {
1161 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1162 macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
1163 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
1164 macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
1165 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
1166 if ( ((sect->flags() & SECTION_TYPE) == S_SYMBOL_STUBS) && (sect->size() != 0) ) {
1167 pint_t stubsVMStart = sect->addr();
1168 uint8_t* stubsMappingStart = (uint8_t*)this->mappedAddressForNewAddress(stubsVMStart);
1169 const uint32_t indirectTableOffset = sect->reserved1();
1170 const uint32_t stubSize = sect->reserved2();
1171 uint32_t elementCount = sect->size() / stubSize;
1172 pint_t stubVMAddr = stubsVMStart;
1173 uint8_t* stubMappedAddr = stubsMappingStart;
1174 for (uint32_t j=0; j < elementCount; ++j, stubMappedAddr += stubSize, stubVMAddr += stubSize) {
1175 uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]);
1176 switch ( symbolIndex ) {
1177 case INDIRECT_SYMBOL_ABS:
1178 case INDIRECT_SYMBOL_LOCAL:
1179 break;
1180 default:
1181 {
1182 const macho_nlist<P>* sym = &this->fSymbolTable[symbolIndex];
1183 const char* symName = &fStrings[sym->n_strx()];
1184 if ( strcmp(symName, stubName) == 0 )
1185 this->optimizeStub(stubMappedAddr, stubVMAddr, stubSize, lpVMAddr);
1186 }
1187 break;
1188 }
1189 }
1190 }
1191 }
1192 }
1193 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
1194 }
1195 }
1196
1197
1198 #endif // __MACHO_BINDER__
1199
1200
1201
1202