]> git.saurik.com Git - apple/dyld.git/blob - launch-cache/MachOBinder.hpp
dyld-132.13.tar.gz
[apple/dyld.git] / launch-cache / MachOBinder.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #ifndef __MACHO_BINDER__
26 #define __MACHO_BINDER__
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31 #include <mach/mach.h>
32 #include <limits.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #include <mach-o/loader.h>
39 #include <mach-o/fat.h>
40
41 #include <vector>
42 #include <set>
43
44 #include "MachOFileAbstraction.hpp"
45 #include "Architectures.hpp"
46 #include "MachOLayout.hpp"
47 #include "MachORebaser.hpp"
48 #include "MachOTrie.hpp"
49
50
51
52
53 template <typename A>
54 class Binder : public Rebaser<A>
55 {
56 public:
57 struct CStringEquals {
58 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
59 };
60 typedef __gnu_cxx::hash_map<const char*, class Binder<A>*, __gnu_cxx::hash<const char*>, CStringEquals> Map;
61
62
63 Binder(const MachOLayoutAbstraction&, uint64_t dyldBaseAddress);
64 virtual ~Binder() {}
65
66 const char* getDylibID() const;
67 void setDependentBinders(const Map& map);
68 void bind();
69
70 private:
71 typedef typename A::P P;
72 typedef typename A::P::E E;
73 typedef typename A::P::uint_t pint_t;
74 struct BinderAndReExportFlag { Binder<A>* binder; bool reExport; };
75 typedef __gnu_cxx::hash_map<const char*, pint_t, __gnu_cxx::hash<const char*>, CStringEquals> NameToAddrMap;
76
77 void doBindExternalRelocations();
78 void doBindIndirectSymbols();
79 void doSetUpDyldSection();
80 void doSetPreboundUndefines();
81 void doBindDyldInfo();
82 void doBindDyldLazyInfo();
83 void bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type,
84 int libraryOrdinal, int64_t addend, const char* symbolName);
85 pint_t resolveUndefined(const macho_nlist<P>* undefinedSymbol);
86 bool findExportedSymbolAddress(const char* name, pint_t* result);
87 void bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value);
88 const char* parentUmbrella();
89
90 static uint8_t pointerRelocSize();
91 static uint8_t pointerRelocType();
92
93 std::vector<BinderAndReExportFlag> fDependentDylibs;
94 NameToAddrMap fHashTable;
95 uint64_t fDyldBaseAddress;
96 const macho_nlist<P>* fSymbolTable;
97 const char* fStrings;
98 const macho_dysymtab_command<P>* fDynamicInfo;
99 const macho_segment_command<P>* fFristWritableSegment;
100 const macho_dylib_command<P>* fDylibID;
101 const macho_dylib_command<P>* fParentUmbrella;
102 const macho_dyld_info_command<P>* fDyldInfo;
103 bool fOriginallyPrebound;
104 };
105
106
107 template <typename A>
108 Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress)
109 : Rebaser<A>(layout), fDyldBaseAddress(dyldBaseAddress),
110 fSymbolTable(NULL), fStrings(NULL), fDynamicInfo(NULL),
111 fFristWritableSegment(NULL), fDylibID(NULL), fDyldInfo(NULL),
112 fParentUmbrella(NULL)
113 {
114 fOriginallyPrebound = ((this->fHeader->flags() & MH_PREBOUND) != 0);
115 // update header flags so the cache looks prebound split-seg (0x80000000 is in-shared-cache bit)
116 ((macho_header<P>*)this->fHeader)->set_flags(this->fHeader->flags() | MH_PREBOUND | MH_SPLIT_SEGS | 0x80000000);
117
118 // calculate fDynamicInfo, fStrings, fSymbolTable
119 const macho_symtab_command<P>* symtab;
120 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
121 const uint32_t cmd_count = this->fHeader->ncmds();
122 const macho_load_command<P>* cmd = cmds;
123 for (uint32_t i = 0; i < cmd_count; ++i) {
124 switch (cmd->cmd()) {
125 case LC_SYMTAB:
126 symtab = (macho_symtab_command<P>*)cmd;
127 fSymbolTable = (macho_nlist<P>*)(&this->fLinkEditBase[symtab->symoff()]);
128 fStrings = (const char*)&this->fLinkEditBase[symtab->stroff()];
129 break;
130 case LC_DYSYMTAB:
131 fDynamicInfo = (macho_dysymtab_command<P>*)cmd;
132 break;
133 case LC_ID_DYLIB:
134 ((macho_dylib_command<P>*)cmd)->set_timestamp(0);
135 fDylibID = (macho_dylib_command<P>*)cmd;
136 break;
137 case LC_LOAD_DYLIB:
138 case LC_LOAD_WEAK_DYLIB:
139 case LC_REEXPORT_DYLIB:
140 ((macho_dylib_command<P>*)cmd)->set_timestamp(0);
141 break;
142 case LC_SUB_FRAMEWORK:
143 fParentUmbrella = (macho_dylib_command<P>*)cmd;
144 break;
145 case LC_DYLD_INFO:
146 case LC_DYLD_INFO_ONLY:
147 fDyldInfo = (macho_dyld_info_command<P>*)cmd;
148 break;
149 case LC_RPATH:
150 throwf("LC_RPATH not supported in dylibs in dyld shared cache");
151 break;
152 default:
153 if ( cmd->cmd() & LC_REQ_DYLD )
154 throwf("unknown required load command 0x%08X", cmd->cmd());
155 }
156 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
157 }
158 if ( fDynamicInfo == NULL )
159 throw "no LC_DYSYMTAB";
160 if ( fSymbolTable == NULL )
161 throw "no LC_SYMTAB";
162 // build hash table
163 // fprintf(stderr, "exports for %s\n", layout.getFilePath());
164 if ( fDyldInfo != NULL ) {
165 std::vector<mach_o::trie::Entry> exports;
166 const uint8_t* exportsStart = &this->fLinkEditBase[fDyldInfo->export_off()];
167 const uint8_t* exportsEnd = &exportsStart[fDyldInfo->export_size()];
168 mach_o::trie::parseTrie(exportsStart, exportsEnd, exports);
169 pint_t baseAddress = layout.getSegments()[0].newAddress();
170 for(std::vector<mach_o::trie::Entry>::iterator it = exports.begin(); it != exports.end(); ++it) {
171 fHashTable[it->name] = it->address + baseAddress;
172 //fprintf(stderr, "0x%08llX %s\n", it->address + baseAddress, it->name);
173 }
174 }
175 else {
176 if ( fDynamicInfo->tocoff() == 0 ) {
177 const macho_nlist<P>* start = &fSymbolTable[fDynamicInfo->iextdefsym()];
178 const macho_nlist<P>* end = &start[fDynamicInfo->nextdefsym()];
179 fHashTable.resize(fDynamicInfo->nextdefsym()); // set initial bucket count
180 for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
181 const char* name = &fStrings[sym->n_strx()];
182 fHashTable[name] = sym->n_value();
183 //fprintf(stderr, " 0x%08llX %s\n", sym->n_value(), name);
184 }
185 }
186 else {
187 int32_t count = fDynamicInfo->ntoc();
188 fHashTable.resize(count); // set initial bucket count
189 const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)&this->fLinkEditBase[fDynamicInfo->tocoff()];
190 for (int32_t i = 0; i < count; ++i) {
191 const uint32_t index = E::get32(toc[i].symbol_index);
192 const macho_nlist<P>* sym = &fSymbolTable[index];
193 const char* name = &fStrings[sym->n_strx()];
194 fHashTable[name] = sym->n_value();
195 //fprintf(stderr, "- 0x%08llX %s\n", sym->n_value(), name);
196 }
197 }
198 }
199 }
200
201 template <> uint8_t Binder<ppc>::pointerRelocSize() { return 2; }
202 template <> uint8_t Binder<x86>::pointerRelocSize() { return 2; }
203 template <> uint8_t Binder<x86_64>::pointerRelocSize() { return 3; }
204 template <> uint8_t Binder<arm>::pointerRelocSize() { return 2; }
205
206 template <> uint8_t Binder<ppc>::pointerRelocType() { return GENERIC_RELOC_VANILLA; }
207 template <> uint8_t Binder<x86>::pointerRelocType() { return GENERIC_RELOC_VANILLA; }
208 template <> uint8_t Binder<x86_64>::pointerRelocType() { return X86_64_RELOC_UNSIGNED; }
209 template <> uint8_t Binder<arm>::pointerRelocType() { return ARM_RELOC_VANILLA; }
210
211
212 template <typename A>
213 const char* Binder<A>::getDylibID() const
214 {
215 if ( fDylibID != NULL )
216 return fDylibID->name();
217 else
218 return NULL;
219 }
220
221 template <typename A>
222 const char* Binder<A>::parentUmbrella()
223 {
224 if ( fParentUmbrella != NULL )
225 return fParentUmbrella->name();
226 else
227 return NULL;
228 }
229
230
231
232 template <typename A>
233 void Binder<A>::setDependentBinders(const Map& map)
234 {
235 // first pass to build vector of dylibs
236 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
237 const uint32_t cmd_count = this->fHeader->ncmds();
238 const macho_load_command<P>* cmd = cmds;
239 for (uint32_t i = 0; i < cmd_count; ++i) {
240 switch (cmd->cmd()) {
241 case LC_LOAD_DYLIB:
242 case LC_LOAD_WEAK_DYLIB:
243 case LC_REEXPORT_DYLIB:
244 const char* path = ((struct macho_dylib_command<P>*)cmd)->name();
245 typename Map::const_iterator pos = map.find(path);
246 if ( pos != map.end() ) {
247 BinderAndReExportFlag entry;
248 entry.binder = pos->second;
249 entry.reExport = ( cmd->cmd() == LC_REEXPORT_DYLIB );
250 fDependentDylibs.push_back(entry);
251 }
252 else {
253 // the load command string does not match the install name of any loaded dylib
254 // this could happen if there was not a world build and some dylib changed its
255 // install path to be some symlinked path
256
257 // use realpath() and walk map looking for a realpath match
258 bool found = false;
259 char targetPath[PATH_MAX];
260 if ( realpath(path, targetPath) != NULL ) {
261 for(typename Map::const_iterator it=map.begin(); it != map.end(); ++it) {
262 char aPath[PATH_MAX];
263 if ( realpath(it->first, aPath) != NULL ) {
264 if ( strcmp(targetPath, aPath) == 0 ) {
265 BinderAndReExportFlag entry;
266 entry.binder = it->second;
267 entry.reExport = ( cmd->cmd() == LC_REEXPORT_DYLIB );
268 fDependentDylibs.push_back(entry);
269 found = true;
270 fprintf(stderr, "update_dyld_shared_cache: warning mismatched install path in %s for %s\n",
271 this->getDylibID(), path);
272 break;
273 }
274 }
275 }
276 }
277 if ( ! found )
278 throwf("in %s can't find dylib %s", this->getDylibID(), path);
279 }
280 break;
281 }
282 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
283 }
284 // handle pre-10.5 re-exports
285 if ( (this->fHeader->flags() & MH_NO_REEXPORTED_DYLIBS) == 0 ) {
286 cmd = cmds;
287 // LC_SUB_LIBRARY means re-export one with matching leaf name
288 const char* dylibBaseName;
289 const char* frameworkLeafName;
290 for (uint32_t i = 0; i < cmd_count; ++i) {
291 switch ( cmd->cmd() ) {
292 case LC_SUB_LIBRARY:
293 dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
294 for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
295 const char* dylibName = it->binder->getDylibID();
296 const char* lastSlash = strrchr(dylibName, '/');
297 const char* leafStart = &lastSlash[1];
298 if ( lastSlash == NULL )
299 leafStart = dylibName;
300 const char* firstDot = strchr(leafStart, '.');
301 int len = strlen(leafStart);
302 if ( firstDot != NULL )
303 len = firstDot - leafStart;
304 if ( strncmp(leafStart, dylibBaseName, len) == 0 )
305 it->reExport = true;
306 }
307 break;
308 case LC_SUB_UMBRELLA:
309 frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
310 for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
311 const char* dylibName = it->binder->getDylibID();
312 const char* lastSlash = strrchr(dylibName, '/');
313 if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
314 it->reExport = true;
315 }
316 break;
317 }
318 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
319 }
320 // ask dependents if they re-export through me
321 const char* thisName = this->getDylibID();
322 if ( thisName != NULL ) {
323 const char* thisLeafName = strrchr(thisName, '/');
324 if ( thisLeafName != NULL )
325 ++thisLeafName;
326 for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
327 if ( ! it->reExport ) {
328 const char* parentUmbrellaName = it->binder->parentUmbrella();
329 if ( parentUmbrellaName != NULL ) {
330 if ( strcmp(parentUmbrellaName, thisLeafName) == 0 )
331 it->reExport = true;
332 }
333 }
334 }
335 }
336 }
337 }
338
339 template <typename A>
340 void Binder<A>::bind()
341 {
342 this->doSetUpDyldSection();
343 if ( fDyldInfo != NULL ) {
344 this->doBindDyldInfo();
345 this->doBindDyldLazyInfo();
346 // weak bind info is processed at launch time
347 }
348 else {
349 this->doBindExternalRelocations();
350 this->doBindIndirectSymbols();
351 this->doSetPreboundUndefines();
352 }
353 }
354
355
356 template <typename A>
357 void Binder<A>::doSetUpDyldSection()
358 {
359 // find __DATA __dyld section
360 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
361 const uint32_t cmd_count = this->fHeader->ncmds();
362 const macho_load_command<P>* cmd = cmds;
363 for (uint32_t i = 0; i < cmd_count; ++i) {
364 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
365 const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
366 if ( strcmp(seg->segname(), "__DATA") == 0 ) {
367 const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
368 const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
369 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
370 if ( (strcmp(sect->sectname(), "__dyld") == 0) && (sect->size() >= 2*sizeof(pint_t)) ) {
371 // set two values in __dyld section to point into dyld
372 pint_t* lazyBinder = this->mappedAddressForNewAddress(sect->addr());
373 pint_t* dyldFuncLookup = this->mappedAddressForNewAddress(sect->addr()+sizeof(pint_t));
374 A::P::setP(*lazyBinder, fDyldBaseAddress + 0x1000);
375 A::P::setP(*dyldFuncLookup, fDyldBaseAddress + 0x1008);
376 }
377 }
378 }
379 }
380 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
381 }
382 }
383
384 template <typename A>
385 void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, int libraryOrdinal, int64_t addend, const char* symbolName)
386 {
387 //printf("%d 0x%08llX type=%d, lib=%d, addend=%lld, symbol=%s\n", segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
388 const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
389 if ( segmentIndex > segments.size() )
390 throw "bad segment index in rebase info";
391
392 if ( libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
393 throw "flat_namespace linkage not allowed in dyld shared cache";
394
395 if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE )
396 throw "linkage to main executable not allowed in dyld shared cache";
397
398 if ( libraryOrdinal < 0 )
399 throw "bad mach-o binary, special library ordinal not allowd in dyld shared cache";
400
401 if ( (unsigned)libraryOrdinal > fDependentDylibs.size() )
402 throw "bad mach-o binary, library ordinal too big";
403
404 Binder<A>* binder;
405 if ( libraryOrdinal == BIND_SPECIAL_DYLIB_SELF )
406 binder = this;
407 else
408 binder = fDependentDylibs[libraryOrdinal-1].binder;
409 pint_t targetSymbolAddress;
410 if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress) )
411 throwf("could not resolve %s expected in %s", symbolName, binder->getDylibID());
412
413 // do actual update
414 const MachOLayoutAbstraction::Segment& seg = segments[segmentIndex];
415 uint8_t* mappedAddr = (uint8_t*)seg.mappedAddress() + segmentOffset;
416 pint_t* mappedAddrP = (pint_t*)mappedAddr;
417 uint32_t* mappedAddr32 = (uint32_t*)mappedAddr;
418 int32_t svalue32new;
419 switch ( type ) {
420 case BIND_TYPE_POINTER:
421 P::setP(*mappedAddrP, targetSymbolAddress + addend);
422 break;
423
424 case BIND_TYPE_TEXT_ABSOLUTE32:
425 E::set32(*mappedAddr32, targetSymbolAddress + addend);
426 break;
427
428 case BIND_TYPE_TEXT_PCREL32:
429 svalue32new = seg.address() + segmentOffset + 4 - (targetSymbolAddress + addend);
430 E::set32(*mappedAddr32, svalue32new);
431 break;
432
433 default:
434 throw "bad bind type";
435 }
436 }
437
438
439
440 template <typename A>
441 void Binder<A>::doBindDyldLazyInfo()
442 {
443 const uint8_t* p = &this->fLinkEditBase[fDyldInfo->lazy_bind_off()];
444 const uint8_t* end = &p[fDyldInfo->lazy_bind_size()];
445
446 uint8_t type = BIND_TYPE_POINTER;
447 uint64_t segmentOffset = 0;
448 uint8_t segmentIndex = 0;
449 const char* symbolName = NULL;
450 int libraryOrdinal = 0;
451 int64_t addend = 0;
452 while ( p < end ) {
453 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
454 uint8_t opcode = *p & BIND_OPCODE_MASK;
455 ++p;
456 switch (opcode) {
457 case BIND_OPCODE_DONE:
458 // this opcode marks the end of each lazy pointer binding
459 break;
460 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
461 libraryOrdinal = immediate;
462 break;
463 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
464 libraryOrdinal = read_uleb128(p, end);
465 break;
466 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
467 // the special ordinals are negative numbers
468 if ( immediate == 0 )
469 libraryOrdinal = 0;
470 else {
471 int8_t signExtended = BIND_OPCODE_MASK | immediate;
472 libraryOrdinal = signExtended;
473 }
474 break;
475 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
476 symbolName = (char*)p;
477 while (*p != '\0')
478 ++p;
479 ++p;
480 break;
481 case BIND_OPCODE_SET_ADDEND_SLEB:
482 addend = read_sleb128(p, end);
483 break;
484 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
485 segmentIndex = immediate;
486 segmentOffset = read_uleb128(p, end);
487 break;
488 case BIND_OPCODE_DO_BIND:
489 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
490 segmentOffset += sizeof(pint_t);
491 break;
492 case BIND_OPCODE_SET_TYPE_IMM:
493 case BIND_OPCODE_ADD_ADDR_ULEB:
494 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
495 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
496 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
497 default:
498 throwf("bad lazy bind opcode %d", *p);
499 }
500 }
501
502
503 }
504
505 template <typename A>
506 void Binder<A>::doBindDyldInfo()
507 {
508 const uint8_t* p = &this->fLinkEditBase[fDyldInfo->bind_off()];
509 const uint8_t* end = &p[fDyldInfo->bind_size()];
510
511 uint8_t type = 0;
512 uint64_t segmentOffset = 0;
513 uint8_t segmentIndex = 0;
514 const char* symbolName = NULL;
515 int libraryOrdinal = 0;
516 int64_t addend = 0;
517 uint32_t count;
518 uint32_t skip;
519 bool done = false;
520 while ( !done && (p < end) ) {
521 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
522 uint8_t opcode = *p & BIND_OPCODE_MASK;
523 ++p;
524 switch (opcode) {
525 case BIND_OPCODE_DONE:
526 done = true;
527 break;
528 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
529 libraryOrdinal = immediate;
530 break;
531 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
532 libraryOrdinal = read_uleb128(p, end);
533 break;
534 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
535 // the special ordinals are negative numbers
536 if ( immediate == 0 )
537 libraryOrdinal = 0;
538 else {
539 int8_t signExtended = BIND_OPCODE_MASK | immediate;
540 libraryOrdinal = signExtended;
541 }
542 break;
543 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
544 symbolName = (char*)p;
545 while (*p != '\0')
546 ++p;
547 ++p;
548 break;
549 case BIND_OPCODE_SET_TYPE_IMM:
550 type = immediate;
551 break;
552 case BIND_OPCODE_SET_ADDEND_SLEB:
553 addend = read_sleb128(p, end);
554 break;
555 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
556 segmentIndex = immediate;
557 segmentOffset = read_uleb128(p, end);
558 break;
559 case BIND_OPCODE_ADD_ADDR_ULEB:
560 segmentOffset += read_uleb128(p, end);
561 break;
562 case BIND_OPCODE_DO_BIND:
563 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
564 segmentOffset += sizeof(pint_t);
565 break;
566 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
567 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
568 segmentOffset += read_uleb128(p, end) + sizeof(pint_t);
569 break;
570 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
571 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
572 segmentOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
573 break;
574 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
575 count = read_uleb128(p, end);
576 skip = read_uleb128(p, end);
577 for (uint32_t i=0; i < count; ++i) {
578 bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
579 segmentOffset += skip + sizeof(pint_t);
580 }
581 break;
582 default:
583 throwf("bad bind opcode %d", *p);
584 }
585 }
586
587
588
589 }
590
591
592 template <typename A>
593 void Binder<A>::doSetPreboundUndefines()
594 {
595 const macho_dysymtab_command<P>* dysymtab = NULL;
596 macho_nlist<P>* symbolTable = NULL;
597
598 // get symbol table info
599 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
600 const uint32_t cmd_count = this->fHeader->ncmds();
601 const macho_load_command<P>* cmd = cmds;
602 for (uint32_t i = 0; i < cmd_count; ++i) {
603 switch (cmd->cmd()) {
604 case LC_SYMTAB:
605 {
606 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
607 symbolTable = (macho_nlist<P>*)(&this->fLinkEditBase[symtab->symoff()]);
608 }
609 break;
610 case LC_DYSYMTAB:
611 dysymtab = (macho_dysymtab_command<P>*)cmd;
612 break;
613 }
614 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
615 }
616
617 // walk all undefines and set their prebound n_value
618 macho_nlist<P>* const lastUndefine = &symbolTable[dysymtab->iundefsym()+dysymtab->nundefsym()];
619 for (macho_nlist<P>* entry = &symbolTable[dysymtab->iundefsym()]; entry < lastUndefine; ++entry) {
620 if ( entry->n_type() & N_EXT ) {
621 //fprintf(stderr, "doSetPreboundUndefines: r_sym=%s, pbaddr=0x%08X, in %s\n",
622 // &fStrings[entry->n_strx()], pbaddr, this->getDylibID());
623 pint_t pbaddr = this->resolveUndefined(entry);
624 entry->set_n_value(pbaddr);
625 }
626 }
627 }
628
629
630 template <typename A>
631 void Binder<A>::doBindExternalRelocations()
632 {
633 // get where reloc addresses start
634 // these address are always relative to first writable segment because they are in cache which always
635 // has writable segments far from read-only segments
636 pint_t firstWritableSegmentBaseAddress = 0;
637 const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
638 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
639 const MachOLayoutAbstraction::Segment& seg = *it;
640 if ( seg.writable() ) {
641 firstWritableSegmentBaseAddress = seg.newAddress();
642 break;
643 }
644 }
645
646 // loop through all external relocation records and bind each
647 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&this->fLinkEditBase[fDynamicInfo->extreloff()]);
648 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicInfo->nextrel()];
649 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
650 if ( reloc->r_length() != pointerRelocSize() )
651 throw "bad external relocation length";
652 if ( reloc->r_type() != pointerRelocType() )
653 throw "unknown external relocation type";
654 if ( reloc->r_pcrel() )
655 throw "r_pcrel external relocaiton not supported";
656
657 const macho_nlist<P>* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum()];
658 pint_t* location;
659 try {
660 location = mappedAddressForNewAddress(reloc->r_address() + firstWritableSegmentBaseAddress);
661 }
662 catch (const char* msg) {
663 throwf("%s processesing external relocation r_address 0x%08X", msg, reloc->r_address());
664 }
665 pint_t addend = P::getP(*location);
666 if ( fOriginallyPrebound ) {
667 // in a prebound binary, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
668 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
669 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
670 addend -= undefinedSymbol->n_value();
671 // To further complicate things, if this is defined symbol, then its n_value has already been adjust to the
672 // new base address, so we need to back off the slide too..
673 if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
674 addend += this->getSlideForNewAddress(undefinedSymbol->n_value());
675 }
676 }
677 pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
678 //fprintf(stderr, "external reloc: r_address=0x%08X, r_sym=%s, symAddr=0x%08llX, addend=0x%08llX in %s\n",
679 // reloc->r_address(), &fStrings[undefinedSymbol->n_strx()], (uint64_t)symbolAddr, (uint64_t)addend, this->getDylibID());
680 P::setP(*location, symbolAddr + addend);
681 }
682 }
683
684
685 // most architectures use pure code, unmodifiable stubs
686 template <typename A>
687 void Binder<A>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
688 {
689 // do nothing
690 }
691
692 // x86 supports fast stubs
693 template <>
694 void Binder<x86>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
695 {
696 // if the stub is not 5-bytes, it is an old slow stub
697 if ( elementSize == 5 ) {
698 uint32_t rel32 = value - (vmlocation + 5);
699 location[0] = 0xE9; // JMP rel32
700 location[1] = rel32 & 0xFF;
701 location[2] = (rel32 >> 8) & 0xFF;
702 location[3] = (rel32 >> 16) & 0xFF;
703 location[4] = (rel32 >> 24) & 0xFF;
704 }
705 }
706
707 template <typename A>
708 void Binder<A>::doBindIndirectSymbols()
709 {
710 const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicInfo->indirectsymoff()];
711 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
712 const uint32_t cmd_count = this->fHeader->ncmds();
713 const macho_load_command<P>* cmd = cmds;
714 //fprintf(stderr, "doBindIndirectSymbols() %s\n", this->fLayout.getFilePath());
715 for (uint32_t i = 0; i < cmd_count; ++i) {
716 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
717 const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
718 const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
719 const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
720 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
721 uint8_t elementSize = 0;
722 uint8_t sectionType = sect->flags() & SECTION_TYPE;
723 switch ( sectionType ) {
724 case S_SYMBOL_STUBS:
725 elementSize = sect->reserved2();
726 break;
727 case S_NON_LAZY_SYMBOL_POINTERS:
728 case S_LAZY_SYMBOL_POINTERS:
729 elementSize = sizeof(pint_t);
730 break;
731 }
732 if ( elementSize != 0 ) {
733 uint32_t elementCount = sect->size() / elementSize;
734 const uint32_t indirectTableOffset = sect->reserved1();
735 uint8_t* location = NULL;
736 if ( sect->size() != 0 )
737 location = (uint8_t*)this->mappedAddressForNewAddress(sect->addr());
738 pint_t vmlocation = sect->addr();
739 for (uint32_t j=0; j < elementCount; ++j, location += elementSize, vmlocation += elementSize) {
740 uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]);
741 switch ( symbolIndex ) {
742 case INDIRECT_SYMBOL_ABS:
743 case INDIRECT_SYMBOL_LOCAL:
744 break;
745 default:
746 const macho_nlist<P>* undefinedSymbol = &fSymbolTable[symbolIndex];
747 //fprintf(stderr, " sect=%s, index=%d, symbolIndex=%d, sym=%s\n", sect->sectname(), j, symbolIndex, &fStrings[undefinedSymbol->n_strx()]);
748 pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
749 switch ( sectionType ) {
750 case S_NON_LAZY_SYMBOL_POINTERS:
751 case S_LAZY_SYMBOL_POINTERS:
752 P::setP(*((pint_t*)location), symbolAddr);
753 break;
754 case S_SYMBOL_STUBS:
755 this->bindStub(elementSize, location, vmlocation, symbolAddr);
756 break;
757 }
758 break;
759 }
760 }
761 }
762 }
763 }
764 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
765 }
766 }
767
768
769
770
771 template <typename A>
772 typename A::P::uint_t Binder<A>::resolveUndefined(const macho_nlist<P>* undefinedSymbol)
773 {
774 if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
775 if ( (undefinedSymbol->n_type() & N_PEXT) != 0 ) {
776 // is a multi-module private_extern internal reference that the linker did not optimize away
777 return undefinedSymbol->n_value();
778 }
779 if ( (undefinedSymbol->n_desc() & N_WEAK_DEF) != 0 ) {
780 // is a weak definition, we should prebind to this one in the same linkage unit
781 return undefinedSymbol->n_value();
782 }
783 }
784 const char* symbolName = &fStrings[undefinedSymbol->n_strx()];
785 if ( (this->fHeader->flags() & MH_TWOLEVEL) == 0 ) {
786 // flat namespace binding
787 throw "flat namespace not supported";
788 }
789 else {
790 uint8_t ordinal = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc());
791 Binder<A>* binder = NULL;
792 switch ( ordinal ) {
793 case EXECUTABLE_ORDINAL:
794 case DYNAMIC_LOOKUP_ORDINAL:
795 throw "magic ordineal not supported";
796 case SELF_LIBRARY_ORDINAL:
797 binder = this;
798 break;
799 default:
800 if ( ordinal > fDependentDylibs.size() )
801 throw "two-level ordinal out of range";
802 binder = fDependentDylibs[ordinal-1].binder;
803 }
804 pint_t addr;
805 if ( ! binder->findExportedSymbolAddress(symbolName, &addr) )
806 throwf("could not resolve %s expected in %s", symbolName, binder->getDylibID());
807 return addr;
808 }
809 }
810
811 template <typename A>
812 bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result)
813 {
814 typename NameToAddrMap::iterator pos = fHashTable.find(name);
815 if ( pos != fHashTable.end() ) {
816 *result = pos->second;
817 //fprintf(stderr, "findExportedSymbolAddress(%s) => 0x%08llX in %s\n", name, (uint64_t)*result, this->getDylibID());
818 return true;
819 }
820
821 // search re-exports
822 for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
823 if ( it->reExport ) {
824 if ( it->binder->findExportedSymbolAddress(name, result) )
825 return true;
826 }
827 }
828 //fprintf(stderr, "findExportedSymbolAddress(%s) => not found in %s\n", name, this->getDylibID());
829 return false;
830 }
831
832
833
834 #endif // __MACHO_BINDER__
835
836
837
838