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