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