]>
Commit | Line | Data |
---|---|---|
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 | ||
58 | template <typename A> | |
59 | class Binder : public Rebaser<A> | |
60 | { | |
61 | public: | |
62 | struct CStringEquals { | |
63 | bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } | |
64 | }; | |
65 | typedef __gnu_cxx::hash_map<const char*, class Binder<A>*, __gnu_cxx::hash<const char*>, CStringEquals> Map; | |
66 | ||
67 | ||
68 | Binder(const MachOLayoutAbstraction&, uint64_t dyldBaseAddress); | |
69 | virtual ~Binder() {} | |
70 | ||
71 | const char* getDylibID() const; | |
72 | void setDependentBinders(const Map& map); | |
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 |
78 | private: |
79 | typedef typename A::P P; | |
80 | typedef typename A::P::E E; | |
81 | typedef typename A::P::uint_t pint_t; | |
82 | struct BinderAndReExportFlag { Binder<A>* binder; bool reExport; }; | |
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 |
133 | template <> |
134 | uint32_t Binder<arm>::runtimeAddressFromNList(const macho_nlist<Pointer32<LittleEndian> >* sym) | |
135 | { | |
136 | if (sym->n_desc() & N_ARM_THUMB_DEF) | |
137 | return sym->n_value() + 1; | |
138 | else | |
139 | return sym->n_value(); | |
140 | } | |
141 | ||
142 | template <typename A> | |
143 | typename A::P::uint_t Binder<A>::runtimeAddressFromNList(const macho_nlist<P>* sym) | |
144 | { | |
145 | return sym->n_value(); | |
146 | } | |
147 | ||
bac542e6 A |
148 | |
149 | template <typename A> | |
150 | Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress) | |
151 | : Rebaser<A>(layout), fDyldBaseAddress(dyldBaseAddress), | |
152 | fSymbolTable(NULL), fStrings(NULL), fDynamicInfo(NULL), | |
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 | ||
265 | template <> uint8_t Binder<ppc>::pointerRelocSize() { return 2; } | |
bac542e6 A |
266 | template <> uint8_t Binder<x86>::pointerRelocSize() { return 2; } |
267 | template <> uint8_t Binder<x86_64>::pointerRelocSize() { return 3; } | |
39a8cd10 | 268 | template <> uint8_t Binder<arm>::pointerRelocSize() { return 2; } |
bac542e6 A |
269 | |
270 | template <> uint8_t Binder<ppc>::pointerRelocType() { return GENERIC_RELOC_VANILLA; } | |
bac542e6 A |
271 | template <> uint8_t Binder<x86>::pointerRelocType() { return GENERIC_RELOC_VANILLA; } |
272 | template <> uint8_t Binder<x86_64>::pointerRelocType() { return X86_64_RELOC_UNSIGNED; } | |
39a8cd10 | 273 | template <> uint8_t Binder<arm>::pointerRelocType() { return ARM_RELOC_VANILLA; } |
bac542e6 A |
274 | |
275 | ||
276 | template <typename A> | |
277 | const char* Binder<A>::getDylibID() const | |
278 | { | |
279 | if ( fDylibID != NULL ) | |
280 | return fDylibID->name(); | |
281 | else | |
282 | return NULL; | |
283 | } | |
284 | ||
285 | template <typename A> | |
286 | const char* Binder<A>::parentUmbrella() | |
287 | { | |
288 | if ( fParentUmbrella != NULL ) | |
289 | return fParentUmbrella->name(); | |
290 | else | |
291 | return NULL; | |
292 | } | |
293 | ||
294 | ||
412ebb8e A |
295 | template <typename A> |
296 | bool 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 | |
320 | template <typename A> | |
321 | void 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 | ||
429 | template <typename A> | |
430 | int 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 | ||
439 | template <typename A> | |
440 | void 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 | 489 | template <typename A> |
412ebb8e | 490 | void 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 | ||
507 | template <typename A> | |
508 | void 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 = §ionsStart[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 | 535 | template <typename A> |
412ebb8e A |
536 | void 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 | ||
611 | template <typename A> | |
412ebb8e | 612 | void 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 | ||
676 | template <typename A> | |
412ebb8e | 677 | void 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 | |
763 | template <typename A> | |
764 | void 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 | ||
801 | template <typename A> | |
802 | void 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 | |
857 | template <typename A> | |
858 | void 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 | |
864 | template <> | |
865 | void 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 | ||
878 | template <typename A> | |
879 | void 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 = §ionsStart[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 | ||
942 | template <typename A> | |
943 | typename 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 | ||
984 | template <typename A> | |
412ebb8e | 985 | bool 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 |
1040 | template <typename A> | |
1041 | void 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. | |
1051 | template <typename A> | |
1052 | void 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 | ||
1060 | template <typename A> | |
1061 | typename 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 | |
1071 | template <typename A> | |
1072 | void 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 | ||
1086 | template <> | |
1087 | void 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 | ||
1108 | template <> | |
1109 | void 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 | ||
1125 | template <typename A> | |
1126 | void 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 | |
1133 | template <typename A> | |
1134 | void 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 = §ionsStart[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 |