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 61template <typename A> 62class Binder : public Rebaser<A> 63{ 64public: 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); 88private: 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 145template <> 146uint32_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 154template <typename A> 155typename A::P::uint_t Binder<A>::runtimeAddressFromNList(const macho_nlist<P>* sym) 156{ 157 return sym->n_value(); 158} 159 160 161template <typename A> 162Binder<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 286template <> uint8_t Binder<x86>::pointerRelocSize() { return 2; } 287template <> uint8_t Binder<x86_64>::pointerRelocSize() { return 3; } 288template <> uint8_t Binder<arm>::pointerRelocSize() { return 2; } 289 290template <> uint8_t Binder<x86>::pointerRelocType() { return GENERIC_RELOC_VANILLA; } 291template <> uint8_t Binder<x86_64>::pointerRelocType() { return X86_64_RELOC_UNSIGNED; } 292template <> uint8_t Binder<arm>::pointerRelocType() { return ARM_RELOC_VANILLA; } 293 294 295template <typename A> 296const char* Binder<A>::getDylibID() const 297{ 298 if ( fDylibID != NULL ) 299 return fDylibID->name(); 300 else 301 return NULL; 302} 303 304template <typename A> 305const char* Binder<A>::parentUmbrella() 306{ 307 if ( fParentUmbrella != NULL ) 308 return fParentUmbrella->name(); 309 else 310 return NULL; 311} 312 313 314template <typename A> 315bool 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 339template <typename A> 340void 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 461template <typename A> 462int 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 471template <typename A> 472void 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 521template <typename A> 522void 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 539template <typename A> 540void 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 = §ionsStart[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 567template <typename A> 568void 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 645template <typename A> 646void 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 712template <typename A> 713void 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 801template <typename A> 802void 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 839template <typename A> 840void 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 895template <typename A> 896void 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 902template <> 903void 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 916template <typename A> 917void 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 = §ionsStart[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 980template <typename A> 981typename 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 1023template <typename A> 1024bool 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 1082template <typename A> 1083void 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 1092template <typename A> 1093typename 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 = §ionsStart[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 1149template <typename A> 1150void 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 1164template <> 1165void 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 1186template <> 1187void 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 1203template <typename A> 1204void 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 1211template <typename A> 1212void 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 = §ionsStart[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 1262