]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoaderMachOClassic.cpp
dyld-519.2.1.tar.gz
[apple/dyld.git] / src / ImageLoaderMachOClassic.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 // work around until conformance work is complete rdar://problem/4508801
26 #define __srr0 srr0
27 #define __eip eip
28 #define __rip rip
29
30
31 #include <string.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/fcntl.h>
36 #include <sys/stat.h>
37 #include <sys/mman.h>
38 #include <mach/mach.h>
39 #include <mach/thread_status.h>
40 #include <mach-o/loader.h>
41 #include <mach-o/reloc.h>
42 #include <mach-o/nlist.h>
43 #include <sys/sysctl.h>
44 #include <libkern/OSAtomic.h>
45 #include <libkern/OSCacheControl.h>
46
47 #if __x86_64__
48 #include <mach-o/x86_64/reloc.h>
49 #endif
50 #if __arm__
51 #include <mach-o/arm/reloc.h>
52 #endif
53
54 #include "ImageLoaderMachOClassic.h"
55 #include "mach-o/dyld_images.h"
56
57 // in dyldStartup.s
58 extern "C" void stub_binding_helper_i386_old();
59
60
61 #if __x86_64__
62 #define POINTER_RELOC X86_64_RELOC_UNSIGNED
63 #else
64 #define POINTER_RELOC GENERIC_RELOC_VANILLA
65 #endif
66
67
68 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
69 #if __LP64__
70 #define RELOC_SIZE 3
71 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
72 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
73 struct macho_segment_command : public segment_command_64 {};
74 struct macho_section : public section_64 {};
75 struct macho_routines_command : public routines_command_64 {};
76 #else
77 #define RELOC_SIZE 2
78 #define LC_SEGMENT_COMMAND LC_SEGMENT
79 #define LC_ROUTINES_COMMAND LC_ROUTINES
80 struct macho_segment_command : public segment_command {};
81 struct macho_section : public section {};
82 struct macho_routines_command : public routines_command {};
83 #endif
84
85
86
87
88 // create image for main executable
89 ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path,
90 unsigned int segCount, unsigned int libCount, const LinkContext& context)
91 {
92 ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount);
93
94 // set slide for PIE programs
95 image->setSlide(slide);
96
97 // for PIE record end of program, to know where to start loading dylibs
98 if ( slide != 0 )
99 fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
100
101 image->disableCoverageCheck();
102 image->instantiateFinish(context);
103 image->setMapped(context);
104
105 #if __i386__
106 // kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding
107 if ( image->fReadOnlyImportSegment ) {
108 for(unsigned int i=0; i < image->fSegmentsCount; ++i) {
109 if ( image->segIsReadOnlyImport(i) )
110 image->segMakeWritable(i, context);
111 }
112 }
113 #endif
114
115 if ( context.verboseMapping ) {
116 dyld::log("dyld: Main executable mapped %s\n", path);
117 for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
118 const char* name = image->segName(i);
119 if ( (strcmp(name, "__PAGEZERO") == 0) || (strcmp(name, "__UNIXSTACK") == 0) )
120 dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segPreferredLoadAddress(i), image->segPreferredLoadAddress(i)+image->segSize(i));
121 else
122 dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segActualLoadAddress(i), image->segActualEndAddress(i));
123 }
124 }
125
126 return image;
127 }
128
129 // create image by mapping in a mach-o file
130 ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char* path, int fd, const uint8_t* fileData, size_t lenFileData,
131 uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info,
132 unsigned int segCount, unsigned int libCount,
133 const struct linkedit_data_command* codeSigCmd, const LinkContext& context)
134 {
135 ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart((macho_header*)fileData, path, segCount, libCount);
136 try {
137 // record info about file
138 image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
139
140 // if this image is code signed, let kernel validate signature before mapping any pages from image
141 image->loadCodeSignature(codeSigCmd, fd, offsetInFat, context);
142
143 // Validate that first data we read with pread actually matches with code signature
144 image->validateFirstPages(codeSigCmd, fd, fileData, lenFileData, offsetInFat, context);
145
146 // mmap segments
147 image->mapSegmentsClassic(fd, offsetInFat, lenInFat, info.st_size, context);
148
149 // finish up
150 image->instantiateFinish(context);
151
152 // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path
153 const char* installName = image->getInstallPath();
154 if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') )
155 image->setPathUnowned(installName);
156 else if ( (path[0] != '/') || (strstr(path, "../") != NULL) ) {
157 // rdar://problem/10733082 Fix up @path based paths during introspection
158 // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
159 char realPath[MAXPATHLEN];
160 if ( fcntl(fd, F_GETPATH, realPath) == 0 )
161 image->setPaths(path, realPath);
162 else
163 image->setPath(path);
164 }
165 else
166 image->setPath(path);
167
168 // make sure path is stable before recording in dyld_all_image_infos
169 image->setMapped(context);
170
171 // pre-fetch content of __DATA segment for faster launches
172 // don't do this on prebound images or if prefetching is disabled
173 if ( !context.preFetchDisabled && !image->isPrebindable())
174 image->preFetchDATA(fd, offsetInFat, context);
175
176 }
177 catch (...) {
178 // ImageLoader::setMapped() can throw an exception to block loading of image
179 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
180 delete image;
181 throw;
182 }
183
184 return image;
185 }
186
187 // create image by using cached mach-o file
188 ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info,
189 unsigned int segCount, unsigned int libCount, const LinkContext& context)
190 {
191 ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount);
192 try {
193 // record info about file
194 image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
195
196 // remember this is from shared cache and cannot be unloaded
197 image->fInSharedCache = true;
198 image->setNeverUnload();
199 image->disableCoverageCheck();
200
201 // segments already mapped in cache
202 if ( context.verboseMapping ) {
203 dyld::log("dyld: Using shared cached for %s\n", path);
204 for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
205 dyld::log("%18s at 0x%08lX->0x%08lX\n", image->segName(i), image->segActualLoadAddress(i), image->segActualEndAddress(i));
206 }
207 }
208
209 image->instantiateFinish(context);
210 image->setMapped(context);
211 }
212 catch (...) {
213 // ImageLoader::setMapped() can throw an exception to block loading of image
214 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
215 delete image;
216 throw;
217 }
218
219 return image;
220 }
221
222 // create image by copying an in-memory mach-o file
223 ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len,
224 unsigned int segCount, unsigned int libCount, const LinkContext& context)
225 {
226 ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, moduleName, segCount, libCount);
227 try {
228 // map segments
229 if ( mh->filetype == MH_EXECUTE )
230 throw "can't load another MH_EXECUTE";
231
232 // vmcopy segments
233 image->ImageLoaderMachO::mapSegments((const void*)mh, len, context);
234
235 // for compatibility, never unload dylibs loaded from memory
236 image->setNeverUnload();
237
238 image->disableCoverageCheck();
239
240 // bundle loads need path copied
241 if ( moduleName != NULL )
242 image->setPath(moduleName);
243
244 image->instantiateFinish(context);
245 image->setMapped(context);
246 }
247 catch (...) {
248 // ImageLoader::setMapped() can throw an exception to block loading of image
249 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
250 delete image;
251 throw;
252 }
253
254 return image;
255 }
256
257
258 ImageLoaderMachOClassic::ImageLoaderMachOClassic(const macho_header* mh, const char* path,
259 unsigned int segCount, uint32_t segOffsets[], unsigned int libCount)
260 : ImageLoaderMachO(mh, path, segCount, segOffsets, libCount), fStrings(NULL), fSymbolTable(NULL), fDynamicInfo(NULL)
261 {
262 }
263
264 // construct ImageLoaderMachOClassic using "placement new" with SegmentMachO objects array at end
265 ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateStart(const macho_header* mh, const char* path,
266 unsigned int segCount, unsigned int libCount)
267 {
268 size_t size = sizeof(ImageLoaderMachOClassic) + segCount * sizeof(uint32_t) + libCount * sizeof(ImageLoader*);
269 ImageLoaderMachOClassic* allocatedSpace = static_cast<ImageLoaderMachOClassic*>(malloc(size));
270 if ( allocatedSpace == NULL )
271 throw "malloc failed";
272 uint32_t* segOffsets = ((uint32_t*)(((uint8_t*)allocatedSpace) + sizeof(ImageLoaderMachOClassic)));
273 bzero(&segOffsets[segCount], libCount*sizeof(void*)); // zero out lib array
274 return new (allocatedSpace) ImageLoaderMachOClassic(mh, path, segCount, segOffsets, libCount);
275 }
276
277
278
279 // common code to finish initializing object
280 void ImageLoaderMachOClassic::instantiateFinish(const LinkContext& context)
281 {
282 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
283 this->parseLoadCmds(context);
284 }
285
286 ImageLoaderMachOClassic::~ImageLoaderMachOClassic()
287 {
288 // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work
289 destroy();
290 }
291
292 uint32_t* ImageLoaderMachOClassic::segmentCommandOffsets() const
293 {
294 return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic)));
295 }
296
297
298 ImageLoader* ImageLoaderMachOClassic::libImage(unsigned int libIndex) const
299 {
300 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
301 // mask off low bits
302 return (ImageLoader*)(images[libIndex] & (-4));
303 }
304
305 bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex) const
306 {
307 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
308 // re-export flag is low bit
309 return ((images[libIndex] & 1) != 0);
310 }
311
312 bool ImageLoaderMachOClassic::libIsUpward(unsigned int libIndex) const
313 {
314 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
315 // upward flag is second bit
316 return ((images[libIndex] & 2) != 0);
317 }
318
319
320 void ImageLoaderMachOClassic::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported, bool upward)
321 {
322 uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
323 uintptr_t value = (uintptr_t)image;
324 if ( reExported )
325 value |= 1;
326 if ( upward )
327 value |= 2;
328 images[libIndex] = value;
329 }
330
331
332 void ImageLoaderMachOClassic::setSymbolTableInfo(const macho_nlist* symbols, const char* strings, const dysymtab_command* dynSym)
333 {
334 fSymbolTable = symbols;
335 fStrings = strings;
336 fDynamicInfo = dynSym;
337 }
338
339 void ImageLoaderMachOClassic::prefetchLINKEDIT(const LinkContext& context)
340 {
341 // always prefetch a subrange of __LINKEDIT pages
342 uintptr_t symbolTableStart = (uintptr_t)fSymbolTable;
343 uintptr_t stringTableStart = (uintptr_t)fStrings;
344 uintptr_t start;
345 // if image did not load at preferred address
346 if ( segPreferredLoadAddress(0) != (uintptr_t)fMachOData ) {
347 // local relocations will be processed, so start pre-fetch at local symbols
348 start = (uintptr_t)fMachOData + fDynamicInfo->locreloff;
349 }
350 else {
351 // otherwise start pre-fetch at global symbols section of symbol table
352 start = symbolTableStart + fDynamicInfo->iextdefsym * sizeof(macho_nlist);
353 }
354 // prefetch ends at end of last undefined string in string pool
355 uintptr_t end = stringTableStart;
356 if ( fDynamicInfo->nundefsym != 0 )
357 end += fSymbolTable[fDynamicInfo->iundefsym+fDynamicInfo->nundefsym-1].n_un.n_strx;
358 else if ( fDynamicInfo->nextdefsym != 0 )
359 end += fSymbolTable[fDynamicInfo->iextdefsym+fDynamicInfo->nextdefsym-1].n_un.n_strx;
360
361 // round to whole pages
362 start = dyld_page_trunc(start);
363 end = dyld_page_round(end);
364
365 // skip if there is only one page
366 if ( (end-start) > dyld_page_size ) {
367 madvise((void*)start, end-start, MADV_WILLNEED);
368 fgTotalBytesPreFetched += (end-start);
369 if ( context.verboseMapping ) {
370 dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n", "__LINKEDIT", start, end-1);
371 }
372 }
373 }
374
375
376 #if SPLIT_SEG_DYLIB_SUPPORT
377 unsigned int
378 ImageLoaderMachOClassic::getExtraZeroFillEntriesCount()
379 {
380 // calculate mapping entries
381 unsigned int extraZeroFillEntries = 0;
382 for(unsigned int i=0; i < fSegmentsCount; ++i) {
383 if ( segHasTrailingZeroFill(i) )
384 ++extraZeroFillEntries;
385 }
386
387 return extraZeroFillEntries;
388 }
389
390 void
391 ImageLoaderMachOClassic::initMappingTable(uint64_t offsetInFat,
392 shared_file_mapping_np *mappingTable)
393 {
394 for(unsigned int i=0,entryIndex=0; i < fSegmentsCount; ++i, ++entryIndex) {
395 shared_file_mapping_np* entry = &mappingTable[entryIndex];
396 entry->sfm_address = segActualLoadAddress(i);
397 entry->sfm_size = segFileSize(i);
398 entry->sfm_file_offset = segFileOffset(i) + offsetInFat;
399 entry->sfm_init_prot = VM_PROT_NONE;
400 if ( !segUnaccessible(i) ) {
401 if ( segExecutable(i) )
402 entry->sfm_init_prot |= VM_PROT_EXECUTE;
403 if ( segReadable(i) )
404 entry->sfm_init_prot |= VM_PROT_READ;
405 if ( segWriteable(i) )
406 entry->sfm_init_prot |= VM_PROT_WRITE | VM_PROT_COW;
407 }
408 entry->sfm_max_prot = entry->sfm_init_prot;
409 if ( segHasTrailingZeroFill(i) ) {
410 shared_file_mapping_np* zfentry = &mappingTable[++entryIndex];
411 zfentry->sfm_address = entry->sfm_address + segFileSize(i);
412 zfentry->sfm_size = segSize(i) - segFileSize(i);
413 zfentry->sfm_file_offset = 0;
414 zfentry->sfm_init_prot = entry->sfm_init_prot | VM_PROT_COW | VM_PROT_ZF;
415 zfentry->sfm_max_prot = zfentry->sfm_init_prot;
416 }
417 }
418 }
419
420 int
421 ImageLoaderMachOClassic::mapSplitSegDylibOutsideSharedRegion(int fd,
422 uint64_t offsetInFat,
423 uint64_t lenInFat,
424 uint64_t fileLen,
425 const LinkContext& context)
426 {
427 uintptr_t nextAltLoadAddress = 0;
428 const unsigned int segmentCount = fSegmentsCount;
429 const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
430 const unsigned int regionCount = segmentCount+extraZeroFillEntries;
431 shared_file_mapping_np regions[regionCount];
432 initMappingTable(offsetInFat, regions);
433 int r = -1;
434 // find space somewhere to allocate split seg
435 bool foundRoom = false;
436 while ( ! foundRoom ) {
437 foundRoom = true;
438 for(unsigned int i=0; i < regionCount; ++i) {
439 vm_address_t addr = (vm_address_t)(nextAltLoadAddress + regions[i].sfm_address - regions[0].sfm_address);
440 vm_size_t size = (vm_size_t)regions[i].sfm_size ;
441 r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/);
442 if ( 0 != r ) {
443 // no room here, deallocate what has succeeded so far
444 for(unsigned int j=0; j < i; ++j) {
445 addr = (vm_address_t)(nextAltLoadAddress + regions[j].sfm_address - regions[0].sfm_address);
446 size = (vm_size_t)(regions[j].sfm_size);
447 (void)vm_deallocate(mach_task_self(), addr, size);
448 }
449 nextAltLoadAddress += 0x00100000; // skip ahead 1MB and try again
450 // skip over shared region
451 if ( (SHARED_REGION_BASE <= nextAltLoadAddress) && (nextAltLoadAddress < (SHARED_REGION_BASE + SHARED_REGION_SIZE)) )
452 nextAltLoadAddress = (SHARED_REGION_BASE + SHARED_REGION_SIZE);
453 if ( nextAltLoadAddress > 0xFF000000 )
454 throw "can't map split seg anywhere";
455 foundRoom = false;
456 break;
457 }
458 }
459 }
460
461 // map in each region
462 uintptr_t slide = (uintptr_t)(nextAltLoadAddress - regions[0].sfm_address);
463 this->setSlide(slide);
464 for(unsigned int i=0; i < regionCount; ++i) {
465 if ( ((regions[i].sfm_init_prot & VM_PROT_ZF) != 0) || (regions[i].sfm_size == 0) ) {
466 // nothing to mmap for zero-fills areas, they are just vm_allocated
467 }
468 else {
469 void* mmapAddress = (void*)(uintptr_t)(regions[i].sfm_address + slide);
470 size_t size = (size_t)regions[i].sfm_size;
471 int protection = 0;
472 if ( regions[i].sfm_init_prot & VM_PROT_EXECUTE )
473 protection |= PROT_EXEC;
474 if ( regions[i].sfm_init_prot & VM_PROT_READ )
475 protection |= PROT_READ;
476 if ( regions[i].sfm_init_prot & VM_PROT_WRITE )
477 protection |= PROT_WRITE;
478 off_t offset = regions[i].sfm_file_offset;
479 //dyld::log("mmap(%p, 0x%08lX, %s\n", mmapAddress, size, fPath);
480 mmapAddress = mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset);
481 if ( mmapAddress == ((void*)(-1)) )
482 throw "mmap error";
483 }
484 }
485
486 // logging
487 if ( context.verboseMapping ) {
488 dyld::log("dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide, this->getPath());
489 for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
490 const shared_file_mapping_np* entry = &regions[entryIndex];
491 if ( (entry->sfm_init_prot & VM_PROT_ZF) == 0 )
492 dyld::log("%18s at 0x%08lX->0x%08lX\n",
493 segName(segIndex), segActualLoadAddress(segIndex), segActualEndAddress(segIndex)-1);
494 if ( entryIndex < (regionCount-1) ) {
495 const shared_file_mapping_np* nextEntry = &regions[entryIndex+1];
496 if ( (nextEntry->sfm_init_prot & VM_PROT_ZF) != 0 ) {
497 uint64_t segOffset = nextEntry->sfm_address - entry->sfm_address;
498 dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n",
499 segName(segIndex), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset + nextEntry->sfm_size - 1));
500 ++entryIndex;
501 }
502 }
503 }
504 }
505
506 return r;
507 }
508 #endif // SPLIT_SEG_DYLIB_SUPPORT
509
510
511 void ImageLoaderMachOClassic::mapSegmentsClassic(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
512 {
513 // non-split segment libraries handled by super class
514 if ( !fIsSplitSeg )
515 return ImageLoaderMachO::mapSegments(fd, offsetInFat, lenInFat, fileLen, context);
516
517 #if SPLIT_SEG_SHARED_REGION_SUPPORT
518 // don't map split-seg dylibs into shared region if shared cache is in use
519 if ( ! context.dyldLoadedAtSameAddressNeededBySharedCache ) {
520 // try to map into shared region at preferred address
521 if ( mapSplitSegDylibInfoSharedRegion(fd, offsetInFat, lenInFat, fileLen, context) == 0)
522 return;
523 }
524 // if there is a problem, fall into case where we map file somewhere outside the shared region
525 #endif
526
527 #if SPLIT_SEG_DYLIB_SUPPORT
528 // support old split-seg dylibs by mapping them where ever we find space
529 if ( mapSplitSegDylibOutsideSharedRegion(fd, offsetInFat, lenInFat, fileLen, context) != 0 )
530 #endif
531 throw "mapping error";
532 }
533
534
535 #if SPLIT_SEG_SHARED_REGION_SUPPORT
536 static int _shared_region_map_np(int fd, uint32_t count, const shared_file_mapping_np mappings[])
537 {
538 return syscall(295, fd, count, mappings);
539 }
540
541 int
542 ImageLoaderMachOClassic::mapSplitSegDylibInfoSharedRegion(int fd,
543 uint64_t offsetInFat,
544 uint64_t lenInFat,
545 uint64_t fileLen,
546 const LinkContext& context)
547 {
548 // build table of segments to map
549 const unsigned int segmentCount = fSegmentsCount;
550 const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
551 const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries;
552 shared_file_mapping_np mappingTable[mappingTableCount];
553 initMappingTable(offsetInFat, mappingTable);
554
555 // try to map it in shared
556 int r = _shared_region_map_np(fd, mappingTableCount, mappingTable);
557 if ( 0 == r ) {
558 this->setNeverUnload();
559 if ( context.verboseMapping ) {
560 dyld::log("dyld: Mapping split-seg shared %s\n", this->getPath());
561 for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
562 const shared_file_mapping_np* entry = &mappingTable[entryIndex];
563 if ( (entry->sfm_init_prot & VM_PROT_ZF) == 0 )
564 dyld::log("%18s at 0x%08lX->0x%08lX\n",
565 segName(segIndex), segActualLoadAddress(segIndex), segActualEndAddress(segIndex)-1);
566 if ( entryIndex < (mappingTableCount-1) ) {
567 const shared_file_mapping_np* nextEntry = &mappingTable[entryIndex+1];
568 if ( (nextEntry->sfm_init_prot & VM_PROT_ZF) != 0 ) {
569 uint64_t segOffset = nextEntry->sfm_address - entry->sfm_address;
570 dyld::log("%18s at 0x%08lX->0x%08lX\n",
571 segName(segIndex), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset),
572 (uintptr_t)(segActualLoadAddress(segIndex) + segOffset + nextEntry->sfm_size - 1));
573 ++entryIndex;
574 }
575 }
576 }
577 }
578 }
579 return r;
580 }
581
582 #endif // SPLIT_SEG_SHARED_REGION_SUPPORT
583
584 // test if this image is re-exported through parent (the image that loaded this one)
585 bool ImageLoaderMachOClassic::isSubframeworkOf(const LinkContext& context, const ImageLoader* parent) const
586 {
587 if ( fInUmbrella ) {
588 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
589 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
590 const struct load_command* cmd = cmds;
591 for (uint32_t i = 0; i < cmd_count; ++i) {
592 if (cmd->cmd == LC_SUB_FRAMEWORK) {
593 const struct sub_framework_command* subf = (struct sub_framework_command*)cmd;
594 const char* exportThruName = (char*)cmd + subf->umbrella.offset;
595 // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent...
596 const char* parentInstallPath = parent->getInstallPath();
597 if ( parentInstallPath != NULL ) {
598 const char* lastSlash = strrchr(parentInstallPath, '/');
599 if ( lastSlash != NULL ) {
600 if ( strcmp(&lastSlash[1], exportThruName) == 0 )
601 return true;
602 if ( context.imageSuffix != NULL ) {
603 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
604 char reexportAndSuffix[strlen(context.imageSuffix)+strlen(exportThruName)+1];
605 strcpy(reexportAndSuffix, exportThruName);
606 strcat(reexportAndSuffix, context.imageSuffix);
607 if ( strcmp(&lastSlash[1], reexportAndSuffix) == 0 )
608 return true;
609 }
610 }
611 }
612 }
613 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
614 }
615 }
616 return false;
617 }
618
619 // test if child is re-exported
620 bool ImageLoaderMachOClassic::hasSubLibrary(const LinkContext& context, const ImageLoader* child) const
621 {
622 if ( fHasSubLibraries ) {
623 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child...
624 const char* childInstallPath = child->getInstallPath();
625 if ( childInstallPath != NULL ) {
626 const char* lastSlash = strrchr(childInstallPath, '/');
627 if ( lastSlash != NULL ) {
628 const char* firstDot = strchr(lastSlash, '.');
629 size_t len;
630 if ( firstDot == NULL )
631 len = strlen(lastSlash);
632 else
633 len = firstDot-lastSlash-1;
634 char childLeafName[len+1];
635 strncpy(childLeafName, &lastSlash[1], len);
636 childLeafName[len] = '\0';
637 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
638 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
639 const struct load_command* cmd = cmds;
640 for (uint32_t i = 0; i < cmd_count; ++i) {
641 switch (cmd->cmd) {
642 case LC_SUB_LIBRARY:
643 {
644 const struct sub_library_command* lib = (struct sub_library_command*)cmd;
645 const char* aSubLibName = (char*)cmd + lib->sub_library.offset;
646 if ( strcmp(aSubLibName, childLeafName) == 0 )
647 return true;
648 if ( context.imageSuffix != NULL ) {
649 // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end
650 char aSubLibNameAndSuffix[strlen(context.imageSuffix)+strlen(aSubLibName)+1];
651 strcpy(aSubLibNameAndSuffix, aSubLibName);
652 strcat(aSubLibNameAndSuffix, context.imageSuffix);
653 if ( strcmp(aSubLibNameAndSuffix, childLeafName) == 0 )
654 return true;
655 }
656 }
657 break;
658 }
659 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
660 }
661 }
662 }
663 }
664 if ( fHasSubUmbrella ) {
665 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child...
666 const char* childInstallPath = child->getInstallPath();
667 if ( childInstallPath != NULL ) {
668 const char* lastSlash = strrchr(childInstallPath, '/');
669 if ( lastSlash != NULL ) {
670 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
671 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
672 const struct load_command* cmd = cmds;
673 for (uint32_t i = 0; i < cmd_count; ++i) {
674 switch (cmd->cmd) {
675 case LC_SUB_UMBRELLA:
676 {
677 const struct sub_umbrella_command* um = (struct sub_umbrella_command*)cmd;
678 const char* aSubUmbrellaName = (char*)cmd + um->sub_umbrella.offset;
679 if ( strcmp(aSubUmbrellaName, &lastSlash[1]) == 0 )
680 return true;
681 if ( context.imageSuffix != NULL ) {
682 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
683 char umbrellaAndSuffix[strlen(context.imageSuffix)+strlen(aSubUmbrellaName)+1];
684 strcpy(umbrellaAndSuffix, aSubUmbrellaName);
685 strcat(umbrellaAndSuffix, context.imageSuffix);
686 if ( strcmp(umbrellaAndSuffix, &lastSlash[1]) == 0 )
687 return true;
688 }
689 }
690 break;
691 }
692 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
693 }
694 }
695 }
696 }
697 return false;
698 }
699
700
701 uintptr_t ImageLoaderMachOClassic::getFirstWritableSegmentAddress()
702 {
703 // in split segment libraries r_address is offset from first writable segment
704 for(unsigned int i=0; i < fSegmentsCount; ++i) {
705 if ( segWriteable(i) )
706 return segActualLoadAddress(i);
707 }
708 throw "no writable segment";
709 }
710
711 uintptr_t ImageLoaderMachOClassic::getRelocBase()
712 {
713 // r_address is either an offset from the first segment address
714 // or from the first writable segment address
715 #if __x86_64__
716 return getFirstWritableSegmentAddress();
717 #else
718 if ( fIsSplitSeg )
719 return getFirstWritableSegmentAddress();
720 else
721 return segActualLoadAddress(0);
722 #endif
723 }
724
725
726 #if PREBOUND_IMAGE_SUPPORT
727 void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext& context)
728 {
729 // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values
730 const uintptr_t relocBase = this->getRelocBase();
731 const uintptr_t slide = this->fSlide;
732 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
733 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
734 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
735 if ( (reloc->r_address & R_SCATTERED) != 0 ) {
736 const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
737 if (sreloc->r_length == RELOC_SIZE) {
738 uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
739 switch(sreloc->r_type) {
740 #if __i386__
741 case GENERIC_RELOC_PB_LA_PTR:
742 *locationToFix = sreloc->r_value + slide;
743 break;
744 #endif
745 #if __arm__
746 case ARM_RELOC_PB_LA_PTR:
747 *locationToFix = sreloc->r_value + slide;
748 break;
749 #endif
750 }
751 }
752 }
753 }
754 }
755 #endif
756
757
758
759
760 void ImageLoaderMachOClassic::rebase(const LinkContext& context, uintptr_t slide)
761 {
762 CRSetCrashLogMessage2(this->getPath());
763 const uintptr_t relocBase = this->getRelocBase();
764
765 // prefetch any LINKEDIT pages needed
766 if ( !context.preFetchDisabled && !this->isPrebindable())
767 this->prefetchLINKEDIT(context);
768
769 // loop through all local (internal) relocation records
770 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
771 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
772 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
773 uintptr_t rebaseAddr;
774 try {
775 #if LINKEDIT_USAGE_DEBUG
776 noteAccessedLinkEditAddress(reloc);
777 #endif
778 #if __x86_64__
779 // only one kind of local relocation supported for x86_64
780 if ( reloc->r_length != 3 )
781 throw "bad local relocation length";
782 if ( reloc->r_type != X86_64_RELOC_UNSIGNED )
783 throw "unknown local relocation type";
784 if ( reloc->r_pcrel != 0 )
785 throw "bad local relocation pc_rel";
786 if ( reloc->r_extern != 0 )
787 throw "extern relocation found with local relocations";
788 rebaseAddr = reloc->r_address + relocBase;
789 if ( ! this->containsAddress((void*)rebaseAddr) )
790 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr);
791 *((uintptr_t*)rebaseAddr) += slide;
792 if ( context.verboseRebase )
793 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide);
794 #else
795 if ( (reloc->r_address & R_SCATTERED) == 0 ) {
796 if ( reloc->r_symbolnum == R_ABS ) {
797 // ignore absolute relocations
798 }
799 else if (reloc->r_length == RELOC_SIZE) {
800 switch(reloc->r_type) {
801 case GENERIC_RELOC_VANILLA:
802 rebaseAddr = reloc->r_address + relocBase;
803 if ( ! this->containsAddress((void*)rebaseAddr) )
804 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr);
805 *((uintptr_t*)rebaseAddr) += slide;
806 if ( context.verboseRebase )
807 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide);
808 break;
809 default:
810 throw "unknown local relocation type";
811 }
812 }
813 else {
814 throw "bad local relocation length";
815 }
816 }
817 else {
818 const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
819 if (sreloc->r_length == RELOC_SIZE) {
820 uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
821 switch(sreloc->r_type) {
822 case GENERIC_RELOC_VANILLA:
823 if ( ! this->containsAddress((void*)locationToFix) )
824 dyld::throwf("local scattered reloc %p not in mapped image\n", locationToFix);
825 *locationToFix += slide;
826 if ( context.verboseRebase )
827 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)locationToFix, slide);
828 break;
829 #if __i386__
830 case GENERIC_RELOC_PB_LA_PTR:
831 // do nothing
832 break;
833 #elif __arm__
834 case ARM_RELOC_PB_LA_PTR:
835 // do nothing
836 break;
837 #endif
838 default:
839 throw "unknown local scattered relocation type";
840 }
841 }
842 else {
843 throw "bad local scattered relocation length";
844 }
845 }
846 #endif // x86_64
847 }
848 catch (const char* msg) {
849 const uint8_t* r = (uint8_t*)reloc;
850 dyld::throwf("%s in %s. reloc record at %p: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
851 msg, this->getPath(), reloc, r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]);
852 }
853 }
854
855 // update stats
856 fgTotalRebaseFixups += fDynamicInfo->nlocrel;
857 CRSetCrashLogMessage2(NULL);
858 }
859
860
861
862 const struct macho_nlist* ImageLoaderMachOClassic::binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[],
863 const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) const
864 {
865 int32_t high = symbolCount-1;
866 int32_t mid = hintIndex;
867
868 // handle out of range hint
869 if ( mid >= (int32_t)symbolCount )
870 mid = symbolCount/2;
871 ++ImageLoaderMachO::fgSymbolTableBinarySearchs;
872 ++fgTotalBindImageSearches;
873
874 //dyld::log("dyld: binarySearchWithToc for %s in %s\n", key, this->getShortName());
875
876 for (int32_t low = 0; low <= high; mid = (low+high)/2) {
877 const uint32_t index = toc[mid].symbol_index;
878 const struct macho_nlist* pivot = &symbols[index];
879 const char* pivotStr = &stringPool[pivot->n_un.n_strx];
880 #if LINKEDIT_USAGE_DEBUG
881 noteAccessedLinkEditAddress(&toc[mid]);
882 noteAccessedLinkEditAddress(pivot);
883 noteAccessedLinkEditAddress(pivotStr);
884 #endif
885 int cmp = strcmp(key, pivotStr);
886 if ( cmp == 0 )
887 return pivot;
888 if ( cmp > 0 ) {
889 // key > pivot
890 low = mid + 1;
891 }
892 else {
893 // key < pivot
894 high = mid - 1;
895 }
896 }
897 return NULL;
898 }
899
900 const struct macho_nlist* ImageLoaderMachOClassic::binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount) const
901 {
902 // update stats
903 ++fgTotalBindImageSearches;
904 ++ImageLoaderMachO::fgSymbolTableBinarySearchs;
905
906 //dyld::log("dyld: binarySearch for %s in %s, stringpool=%p, symbols=%p, symbolCount=%u\n",
907 // key, this->getShortName(), stringPool, symbols, symbolCount);
908
909 const struct macho_nlist* base = symbols;
910 for (uint32_t n = symbolCount; n > 0; n /= 2) {
911 const struct macho_nlist* pivot = &base[n/2];
912 const char* pivotStr = &stringPool[pivot->n_un.n_strx];
913 #if LINKEDIT_USAGE_DEBUG
914 noteAccessedLinkEditAddress(pivot);
915 noteAccessedLinkEditAddress(pivotStr);
916 #endif
917 int cmp = strcmp(key, pivotStr);
918 if ( cmp == 0 )
919 return pivot;
920 if ( cmp > 0 ) {
921 // key > pivot
922 // move base to symbol after pivot
923 base = &pivot[1];
924 --n;
925 }
926 else {
927 // key < pivot
928 // keep same base
929 }
930 }
931 return NULL;
932 }
933
934
935 const ImageLoader::Symbol* ImageLoaderMachOClassic::findShallowExportedSymbol(const char* name, const ImageLoader** foundIn) const
936 {
937 const struct macho_nlist* sym = NULL;
938 if ( fDynamicInfo->tocoff == 0 )
939 sym = binarySearch(name, fStrings, &fSymbolTable[fDynamicInfo->iextdefsym], fDynamicInfo->nextdefsym);
940 else
941 sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff],
942 fDynamicInfo->ntoc, fDynamicInfo->nextdefsym);
943 if ( sym != NULL ) {
944 if ( foundIn != NULL )
945 *foundIn = (ImageLoader*)this;
946 return (const Symbol*)sym;
947 }
948 return NULL;
949 }
950
951
952
953 bool ImageLoaderMachOClassic::containsSymbol(const void* addr) const
954 {
955 return ( (fSymbolTable <= addr) && (addr < fStrings) );
956 }
957
958
959 uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const
960 {
961 const struct macho_nlist* sym = (macho_nlist*)symbol;
962 uintptr_t result = sym->n_value + fSlide;
963 #if __arm__
964 // processor assumes code address with low bit set is thumb
965 if (sym->n_desc & N_ARM_THUMB_DEF)
966 result |= 1;
967 #endif
968 return result;
969 }
970
971 bool ImageLoaderMachOClassic::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
972 {
973 const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
974 return ( (nlistSym->n_desc & N_WEAK_DEF) != 0 );
975 }
976
977 const char* ImageLoaderMachOClassic::exportedSymbolName(const Symbol* symbol) const
978 {
979 const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
980 return &fStrings[nlistSym->n_un.n_strx];
981 }
982
983 unsigned int ImageLoaderMachOClassic::exportedSymbolCount() const
984 {
985 return fDynamicInfo->nextdefsym;
986 }
987
988 const ImageLoader::Symbol* ImageLoaderMachOClassic::exportedSymbolIndexed(unsigned int index) const
989 {
990 if ( index < fDynamicInfo->nextdefsym ) {
991 const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym + index];
992 return (const ImageLoader::Symbol*)sym;
993 }
994 return NULL;
995 }
996
997 unsigned int ImageLoaderMachOClassic::importedSymbolCount() const
998 {
999 return fDynamicInfo->nundefsym;
1000 }
1001
1002 const ImageLoader::Symbol* ImageLoaderMachOClassic::importedSymbolIndexed(unsigned int index) const
1003 {
1004 if ( index < fDynamicInfo->nundefsym ) {
1005 const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iundefsym + index];
1006 return (const ImageLoader::Symbol*)sym;
1007 }
1008 return NULL;
1009 }
1010
1011 const char* ImageLoaderMachOClassic::importedSymbolName(const Symbol* symbol) const
1012 {
1013 const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
1014 return &fStrings[nlistSym->n_un.n_strx];
1015 }
1016
1017
1018
1019 bool ImageLoaderMachOClassic::symbolIsWeakDefinition(const struct macho_nlist* symbol)
1020 {
1021 // if a define and weak ==> coalesced
1022 if ( ((symbol->n_type & N_TYPE) == N_SECT) && ((symbol->n_desc & N_WEAK_DEF) != 0) )
1023 return true;
1024
1025 // regular symbol
1026 return false;
1027 }
1028
1029 bool ImageLoaderMachOClassic::symbolIsWeakReference(const struct macho_nlist* symbol)
1030 {
1031 // if an undefine and not referencing a weak symbol ==> coalesced
1032 if ( ((symbol->n_type & N_TYPE) != N_SECT) && ((symbol->n_desc & N_REF_TO_WEAK) != 0) )
1033 return true;
1034
1035 // regular symbol
1036 return false;
1037 }
1038
1039 uintptr_t ImageLoaderMachOClassic::getSymbolAddress(const macho_nlist* sym, const LinkContext& context, bool runResolver) const
1040 {
1041 return ImageLoaderMachO::getSymbolAddress((Symbol*)sym, this, context, runResolver);
1042 }
1043
1044 uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context, const struct macho_nlist* undefinedSymbol,
1045 bool twoLevel, bool dontCoalesce, bool runResolver, const ImageLoader** foundIn)
1046 {
1047 ++fgTotalBindSymbolsResolved;
1048 const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
1049
1050 #if LINKEDIT_USAGE_DEBUG
1051 noteAccessedLinkEditAddress(undefinedSymbol);
1052 noteAccessedLinkEditAddress(symbolName);
1053 #endif
1054 if ( context.bindFlat || !twoLevel ) {
1055 // flat lookup
1056 if ( ((undefinedSymbol->n_type & N_PEXT) != 0) && ((undefinedSymbol->n_type & N_TYPE) == N_SECT) ) {
1057 // is a multi-module private_extern internal reference that the linker did not optimize away
1058 uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
1059 *foundIn = this;
1060 return addr;
1061 }
1062 const Symbol* sym;
1063 if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
1064 if ( *foundIn != this )
1065 context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
1066 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1067 }
1068 // if a bundle is loaded privately the above will not find its exports
1069 if ( this->isBundle() && this->hasHiddenExports() ) {
1070 // look in self for needed symbol
1071 sym = this->findShallowExportedSymbol(symbolName, foundIn);
1072 if ( sym != NULL )
1073 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1074 }
1075 if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
1076 // definition can't be found anywhere
1077 // if reference is weak_import, then it is ok, just return 0
1078 return 0;
1079 }
1080 throwSymbolNotFound(context, symbolName, this->getPath(), "", "flat namespace");
1081 }
1082 else {
1083 // symbol requires searching images with coalesced symbols (not done during prebinding)
1084 if ( !context.prebinding && !dontCoalesce && (symbolIsWeakReference(undefinedSymbol) || symbolIsWeakDefinition(undefinedSymbol)) ) {
1085 const Symbol* sym;
1086 if ( context.coalescedExportFinder(symbolName, &sym, foundIn) ) {
1087 if ( *foundIn != this )
1088 context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
1089 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1090 }
1091 //throwSymbolNotFound(context, symbolName, this->getPath(), "coalesced namespace");
1092 //dyld::log("dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
1093 }
1094
1095 // if this is a real definition (not an undefined symbol) there is no ordinal
1096 if ( (undefinedSymbol->n_type & N_TYPE) == N_SECT ) {
1097 // static linker should never generate this case, but if it does, do something sane
1098 uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
1099 *foundIn = this;
1100 return addr;
1101 }
1102
1103 // two level lookup
1104 ImageLoader* target = NULL;
1105 uint8_t ord = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc);
1106 if ( ord == EXECUTABLE_ORDINAL ) {
1107 target = context.mainExecutable;
1108 }
1109 else if ( ord == SELF_LIBRARY_ORDINAL ) {
1110 target = this;
1111 }
1112 else if ( ord == DYNAMIC_LOOKUP_ORDINAL ) {
1113 // rnielsen: HACKHACK
1114 // flat lookup
1115 const Symbol* sym;
1116 if ( context.flatExportFinder(symbolName, &sym, foundIn) )
1117 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1118 // no image has exports this symbol
1119 // report error
1120 context.undefinedHandler(symbolName);
1121 // try looking again
1122 if ( context.flatExportFinder(symbolName, &sym, foundIn) )
1123 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1124
1125 throwSymbolNotFound(context, symbolName, this->getPath(), "", "dynamic lookup");
1126 }
1127 else if ( ord <= libraryCount() ) {
1128 target = libImage(ord-1);
1129 if ( target == NULL ) {
1130 // if target library not loaded and reference is weak or library is weak return 0
1131 return 0;
1132 }
1133 }
1134 else {
1135 dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s",
1136 ord, libraryCount(), symbolName, this->getPath());
1137 }
1138
1139 if ( target == NULL ) {
1140 //dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath());
1141 throw "symbol not found";
1142 }
1143
1144 uintptr_t address;
1145 if ( target->findExportedSymbolAddress(context, symbolName, this, ord, runResolver, foundIn, &address) )
1146 return address;
1147
1148 if ( (undefinedSymbol->n_type & N_PEXT) != 0 ) {
1149 // don't know why the static linker did not eliminate the internal reference to a private extern definition
1150 *foundIn = this;
1151 return this->getSymbolAddress(undefinedSymbol, context, false);
1152 }
1153 else if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
1154 // if definition not found and reference is weak return 0
1155 return 0;
1156 }
1157
1158 // nowhere to be found
1159 throwSymbolNotFound(context, symbolName, this->getPath(), "", target->getPath());
1160 }
1161 }
1162
1163
1164
1165 // returns if 'addr' is within the address range of section 'sectionIndex'
1166 // fSlide is not used. 'addr' is assumed to be a prebound address in this image
1167 bool ImageLoaderMachOClassic::isAddrInSection(uintptr_t addr, uint8_t sectionIndex)
1168 {
1169 uint8_t currentSectionIndex = 1;
1170 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1171 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1172 const struct load_command* cmd = cmds;
1173 for (uint32_t i = 0; i < cmd_count; ++i) {
1174 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1175 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1176 if ( (currentSectionIndex <= sectionIndex) && (sectionIndex < currentSectionIndex+seg->nsects) ) {
1177 // 'sectionIndex' is in this segment, get section info
1178 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1179 const struct macho_section* const section = &sectionsStart[sectionIndex-currentSectionIndex];
1180 return ( (section->addr <= addr) && (addr < section->addr+section->size) );
1181 }
1182 else {
1183 // 'sectionIndex' not in this segment, skip to next segment
1184 currentSectionIndex += seg->nsects;
1185 }
1186 }
1187 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1188 }
1189
1190 return false;
1191 }
1192
1193 void ImageLoaderMachOClassic::doBindExternalRelocations(const LinkContext& context)
1194 {
1195 const uintptr_t relocBase = this->getRelocBase();
1196 const bool twoLevel = this->usesTwoLevelNameSpace();
1197 const bool prebound = this->isPrebindable();
1198
1199 #if TEXT_RELOC_SUPPORT
1200 // if there are __TEXT fixups, temporarily make __TEXT writable
1201 if ( fTextSegmentBinds )
1202 this->makeTextSegmentWritable(context, true);
1203 #endif
1204 // cache last lookup
1205 const struct macho_nlist* lastUndefinedSymbol = NULL;
1206 uintptr_t symbolAddr = 0;
1207 const ImageLoader* image = NULL;
1208
1209 // loop through all external relocation records and bind each
1210 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
1211 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
1212 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1213 if (reloc->r_length == RELOC_SIZE) {
1214 switch(reloc->r_type) {
1215 case POINTER_RELOC:
1216 {
1217 const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
1218 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
1219 if ( ! this->containsAddress((void*)location) )
1220 dyld::throwf("external reloc %p not in mapped image %s\n", (void*)location, this->getPath());
1221 uintptr_t value = *location;
1222 bool symbolAddrCached = true;
1223 #if __i386__
1224 if ( reloc->r_pcrel ) {
1225 value += (uintptr_t)location + 4 - fSlide;
1226 }
1227 #endif
1228 if ( prebound ) {
1229 // we are doing relocations, so prebinding was not usable
1230 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1231 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1232 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
1233 if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
1234 // weak symbols need special casing, since *location may have been prebound to a definition in another image.
1235 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1236 // that we can subtract off the weak symbol address to get the addend.
1237 // If prebound elsewhere, we've lost the addend and have to assume it is zero.
1238 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1239 if ( (value == undefinedSymbol->n_value) || this->isAddrInSection(value, undefinedSymbol->n_sect) ) {
1240 value -= undefinedSymbol->n_value;
1241 #if __arm__
1242 // if weak and thumb subtract off extra thumb bit
1243 if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
1244 value -= 1;
1245 #endif
1246 }
1247 else
1248 value = 0;
1249 }
1250 #if __arm__
1251 else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) {
1252 // it was prebound to a defined symbol for thumb code in the same linkage unit
1253 // we need to subtract off one to get real addend
1254 value -= (undefinedSymbol->n_value+1);
1255 }
1256 #endif
1257 else {
1258 // is undefined or non-weak symbol, so do subtraction to get addend
1259 value -= undefinedSymbol->n_value;
1260 }
1261 }
1262 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
1263 if ( undefinedSymbol != lastUndefinedSymbol ) {
1264 bool dontCoalesce = true;
1265 if ( symbolIsWeakReference(undefinedSymbol) ) {
1266 // when weakbind() is run on a classic mach-o encoding, it won't try
1267 // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted
1268 // range of global symbols. To handle that case we do the coalesing now.
1269 dontCoalesce = false;
1270 }
1271 symbolAddr = this->resolveUndefined(context, undefinedSymbol, twoLevel, dontCoalesce, false, &image);
1272 lastUndefinedSymbol = undefinedSymbol;
1273 symbolAddrCached = false;
1274 }
1275 if ( context.verboseBind ) {
1276 const char *path = NULL;
1277 if ( image != NULL ) {
1278 path = image->getShortName();
1279 }
1280 const char* cachedString = "(cached)";
1281 if ( !symbolAddrCached )
1282 cachedString = "";
1283 if ( value == 0 ) {
1284 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s\n",
1285 this->getShortName(), (uintptr_t)location,
1286 path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString);
1287 }
1288 else {
1289 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s + %ld\n",
1290 this->getShortName(), (uintptr_t)location,
1291 path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString, value);
1292 }
1293 }
1294 value += symbolAddr;
1295 #if __i386__
1296 if ( reloc->r_pcrel ) {
1297 *location = value - ((uintptr_t)location + 4);
1298 }
1299 else {
1300 // don't dirty page if prebound value was correct
1301 if ( !prebound || (*location != value) )
1302 *location = value;
1303 }
1304 #else
1305 // don't dirty page if prebound value was correct
1306 if ( !prebound || (*location != value) )
1307 *location = value;
1308 #endif
1309 // update stats
1310 ++fgTotalBindFixups;
1311 }
1312 break;
1313 default:
1314 throw "unknown external relocation type";
1315 }
1316 }
1317 else {
1318 throw "bad external relocation length";
1319 }
1320 }
1321
1322 #if TEXT_RELOC_SUPPORT
1323 // if there were __TEXT fixups, restore write protection
1324 if ( fTextSegmentBinds ) {
1325 this->makeTextSegmentWritable(context, true);
1326 }
1327 #endif
1328 }
1329
1330
1331
1332 uintptr_t ImageLoaderMachOClassic::bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, const char* symbolName, uintptr_t targetAddr, const ImageLoader* targetImage, const LinkContext& context)
1333 {
1334 if ( context.verboseBind ) {
1335 const char* path = NULL;
1336 if ( targetImage != NULL )
1337 path = targetImage->getShortName();
1338 dyld::log("dyld: bind indirect sym: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
1339 this->getShortName(), symbolName, (((sect->flags & SECTION_TYPE)==S_NON_LAZY_SYMBOL_POINTERS) ? "non_lazy_ptr" : "lazy_ptr"),
1340 ((path != NULL) ? path : "<weak_import-not-found>"), symbolName, (uintptr_t)ptrToBind, targetAddr);
1341 }
1342 if ( context.bindingHandler != NULL ) {
1343 const char* path = NULL;
1344 if ( targetImage != NULL )
1345 path = targetImage->getShortName();
1346 targetAddr = (uintptr_t)context.bindingHandler(path, symbolName, (void *)targetAddr);
1347 }
1348 #if __i386__
1349 // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
1350 if ( ((sect->flags & SECTION_TYPE) == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
1351 uint32_t rel32 = targetAddr - (((uint32_t)ptrToBind)+5);
1352 // re-write instruction in a thread-safe manner
1353 // use 8-byte compare-and-swap to alter 5-byte jump table entries
1354 // loop is required in case the extra three bytes that cover the next entry are altered by another thread
1355 bool done = false;
1356 while ( !done ) {
1357 volatile int64_t* jumpPtr = (int64_t*)ptrToBind;
1358 int pad = 0;
1359 // By default the three extra bytes swapped follow the 5-byte JMP.
1360 // But, if the 5-byte jump is up against the end of the __IMPORT segment
1361 // We don't want to access bytes off the end of the segment, so we shift
1362 // the extra bytes to precede the 5-byte JMP.
1363 if ( (((uint32_t)ptrToBind + 8) & 0x00000FFC) == 0x00000000 ) {
1364 jumpPtr = (int64_t*)((uint32_t)ptrToBind - 3);
1365 pad = 3;
1366 }
1367 int64_t oldEntry = *jumpPtr;
1368 union {
1369 int64_t int64;
1370 uint8_t bytes[8];
1371 } newEntry;
1372 newEntry.int64 = oldEntry;
1373 newEntry.bytes[pad+0] = 0xE9; // JMP rel32
1374 newEntry.bytes[pad+1] = rel32 & 0xFF;
1375 newEntry.bytes[pad+2] = (rel32 >> 8) & 0xFF;
1376 newEntry.bytes[pad+3] = (rel32 >> 16) & 0xFF;
1377 newEntry.bytes[pad+4] = (rel32 >> 24) & 0xFF;
1378 done = OSAtomicCompareAndSwap64Barrier(oldEntry, newEntry.int64, (int64_t*)jumpPtr);
1379 }
1380 }
1381 else
1382 #endif
1383 *ptrToBind = targetAddr;
1384 return targetAddr;
1385 }
1386
1387 uintptr_t ImageLoaderMachOClassic::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, void (*lock)(), void (*unlock)())
1388 {
1389 throw "compressed LINKEDIT lazy binder called with classic LINKEDIT";
1390 }
1391
1392 uintptr_t ImageLoaderMachOClassic::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context)
1393 {
1394 // scan for all lazy-pointer sections
1395 const bool twoLevel = this->usesTwoLevelNameSpace();
1396 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1397 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1398 const struct load_command* cmd = cmds;
1399 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1400 for (uint32_t i = 0; i < cmd_count; ++i) {
1401 switch (cmd->cmd) {
1402 case LC_SEGMENT_COMMAND:
1403 {
1404 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1405 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1406 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1407 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1408 const uint8_t type = sect->flags & SECTION_TYPE;
1409 uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
1410 if ( type == S_LAZY_SYMBOL_POINTERS ) {
1411 const size_t pointerCount = sect->size / sizeof(uintptr_t);
1412 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
1413 if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
1414 const uint32_t indirectTableOffset = sect->reserved1;
1415 const size_t lazyIndex = lazyPointer - symbolPointers;
1416 symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
1417 }
1418 }
1419 #if __i386__
1420 else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
1421 // 5 bytes stubs on i386 are new "fast stubs"
1422 uint8_t* const jmpTableBase = (uint8_t*)(sect->addr + fSlide);
1423 uint8_t* const jmpTableEnd = jmpTableBase + sect->size;
1424 // initial CALL instruction in jump table leaves pointer to next entry, so back up
1425 uint8_t* const jmpTableEntryToPatch = ((uint8_t*)lazyPointer) - 5;
1426 lazyPointer = (uintptr_t*)jmpTableEntryToPatch;
1427 if ( (jmpTableEntryToPatch >= jmpTableBase) && (jmpTableEntryToPatch < jmpTableEnd) ) {
1428 const uint32_t indirectTableOffset = sect->reserved1;
1429 const uint32_t entryIndex = (jmpTableEntryToPatch - jmpTableBase)/5;
1430 symbolIndex = indirectTable[indirectTableOffset + entryIndex];
1431 }
1432 }
1433 #endif
1434 if ( symbolIndex != INDIRECT_SYMBOL_ABS && symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
1435 const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
1436 const ImageLoader* image = NULL;
1437 uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], twoLevel, false, true, &image);
1438 symbolAddr = this->bindIndirectSymbol(lazyPointer, sect, symbolName, symbolAddr, image, context);
1439 ++fgTotalLazyBindFixups;
1440 return symbolAddr;
1441 }
1442 }
1443 }
1444 break;
1445 }
1446 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1447 }
1448 dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
1449 }
1450
1451
1452
1453 void ImageLoaderMachOClassic::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder, unsigned)
1454 {
1455 it.image = this;
1456 it.symbolName = " ";
1457 it.loadOrder = loadOrder;
1458 it.weakSymbol = false;
1459 it.symbolMatches = false;
1460 it.done = false;
1461 it.type = 0;
1462 if ( fDynamicInfo->tocoff != 0 ) {
1463 it.curIndex = 0;
1464 it.endIndex = fDynamicInfo->ntoc;
1465 }
1466 else {
1467 it.curIndex = 0;
1468 it.endIndex = fDynamicInfo->nextdefsym;
1469 }
1470 }
1471
1472
1473 bool ImageLoaderMachOClassic::incrementCoalIterator(CoalIterator& it)
1474 {
1475 if ( it.done )
1476 return false;
1477
1478 if ( fDynamicInfo->tocoff != 0 ) {
1479 if ( it.curIndex >= fDynamicInfo->ntoc ) {
1480 it.done = true;
1481 it.symbolName = "~~~";
1482 return true;
1483 }
1484 else {
1485 const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
1486 const uint32_t index = toc[it.curIndex].symbol_index;
1487 const struct macho_nlist* sym = &fSymbolTable[index];
1488 const char* symStr = &fStrings[sym->n_un.n_strx];
1489 it.symbolName = symStr;
1490 it.weakSymbol = (sym->n_desc & N_WEAK_DEF);
1491 it.symbolMatches = false;
1492 it.type = 0; // clear flag that says we applied updates for this symbol
1493 //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath());
1494 it.curIndex++;
1495 return false;
1496 }
1497 }
1498 else {
1499 if ( it.curIndex >= fDynamicInfo->nextdefsym ) {
1500 it.done = true;
1501 it.symbolName = "~~~";
1502 return true;
1503 }
1504 else {
1505 const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym+it.curIndex];
1506 const char* symStr = &fStrings[sym->n_un.n_strx];
1507 it.symbolName = symStr;
1508 it.weakSymbol = (sym->n_desc & N_WEAK_DEF);
1509 it.symbolMatches = false;
1510 it.type = 0; // clear flag that says we applied updates for this symbol
1511 //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath());
1512 it.curIndex++;
1513 return false;
1514 }
1515 }
1516
1517 return false;
1518 }
1519
1520 uintptr_t ImageLoaderMachOClassic::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
1521 {
1522 uint32_t symbol_index = 0;
1523 if ( fDynamicInfo->tocoff != 0 ) {
1524 const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
1525 symbol_index = toc[it.curIndex-1].symbol_index;
1526 }
1527 else {
1528 symbol_index = fDynamicInfo->iextdefsym + (uint32_t)it.curIndex - 1;
1529 }
1530 const struct macho_nlist* sym = &fSymbolTable[symbol_index];
1531 //dyld::log("getAddressCoalIterator() => 0x%llX, %s symbol_index=%d, in %s\n", (uint64_t)(sym->n_value + fSlide), &fStrings[sym->n_un.n_strx], symbol_index, this->getPath());
1532 #if __arm__
1533 // processor assumes code address with low bit set is thumb
1534 if (sym->n_desc & N_ARM_THUMB_DEF)
1535 return (sym->n_value | 1) + fSlide ;
1536 else
1537 return sym->n_value + fSlide;
1538 #else
1539 return sym->n_value + fSlide;
1540 #endif
1541 }
1542
1543
1544 void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, unsigned targetIndex, const LinkContext& context)
1545 {
1546 // flat_namespace images with classic LINKEDIT do not need late coalescing.
1547 // They still need to be iterated becuase they may implement
1548 // something needed by other coalescing images.
1549 // But they need no updating because during the bind phase every symbol lookup is a full scan.
1550 if ( !this->usesTwoLevelNameSpace() )
1551 return;
1552
1553 // <rdar://problem/6570879> weak binding done too early with inserted libraries
1554 if ( this->getState() < dyld_image_state_bound )
1555 return;
1556
1557 uint32_t symbol_index = 0;
1558 if ( fDynamicInfo->tocoff != 0 ) {
1559 const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
1560 symbol_index = toc[it.curIndex-1].symbol_index;
1561 }
1562 else {
1563 symbol_index = fDynamicInfo->iextdefsym + (uint32_t)it.curIndex - 1;
1564 }
1565
1566 // if this image's copy of the symbol is not a weak definition nor a weak reference then nothing to coalesce here
1567 if ( !symbolIsWeakReference(&fSymbolTable[symbol_index]) && !symbolIsWeakDefinition(&fSymbolTable[symbol_index]) ) {
1568 return;
1569 }
1570
1571 // <rdar://problem/6555720> malformed dylib with duplicate weak symbols causes re-binding
1572 if ( it.type )
1573 return;
1574
1575 bool boundSomething = false;
1576 // scan external relocations for uses of symbol_index
1577 const uintptr_t relocBase = this->getRelocBase();
1578 const bool prebound = this->isPrebindable();
1579 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
1580 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
1581 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1582 if ( reloc->r_symbolnum == symbol_index ) {
1583 //dyld::log("found external reloc using symbol_index=%d in %s\n",symbol_index, this->getPath());
1584 const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
1585 const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
1586 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
1587 const uintptr_t initialValue = *location;
1588 uintptr_t addend = 0;
1589 if ( prebound ) {
1590 // we are doing relocations, so prebinding was not usable
1591 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1592 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1593 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
1594 if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
1595 // weak symbols need special casing, since *location may have been prebound to a definition in another image.
1596 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1597 // that we can subtract off the weak symbol address to get the addend.
1598 // If prebound elsewhere, we've lost the addend and have to assume it is zero.
1599 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1600 if ( (initialValue == undefinedSymbol->n_value) || this->isAddrInSection(initialValue, undefinedSymbol->n_sect) ) {
1601 addend = initialValue - undefinedSymbol->n_value;
1602 #if __arm__
1603 // if weak and thumb subtract off extra thumb bit
1604 if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
1605 addend &= -2;
1606 #endif
1607 }
1608 }
1609 #if __arm__
1610 else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) {
1611 // it was prebound to a defined symbol for thumb code in the same linkage unit
1612 // we need to subtract off one to get real addend
1613 addend = initialValue - (undefinedSymbol->n_value+1);
1614 }
1615 #endif
1616 else {
1617 // is undefined or non-weak symbol, so do subtraction to get addend
1618 addend = initialValue - undefinedSymbol->n_value;
1619 }
1620 }
1621 else {
1622 // non-prebound case
1623 if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
1624 // if target is weak-def in same linkage unit, then bind phase has already set initialValue
1625 // to be definition address plus addend
1626 //dyld::log("weak def, initialValue=0x%lX, undefAddr=0x%lX\n", initialValue, undefinedSymbol->n_value+fSlide);
1627 addend = initialValue - (undefinedSymbol->n_value + fSlide);
1628 #if __arm__
1629 // if weak and thumb subtract off extra thumb bit
1630 if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
1631 addend &= -2;
1632 #endif
1633 }
1634 else {
1635 // nothing fixed up yet, addend is just initial value
1636 //dyld::log("addend=0x%lX\n", initialValue);
1637 addend = initialValue;
1638 }
1639 }
1640
1641 uint8_t type = BIND_TYPE_POINTER;
1642 #if __i386__
1643 if ( reloc->r_pcrel )
1644 type = BIND_TYPE_TEXT_PCREL32;
1645 #endif
1646 this->bindLocation(context, (uintptr_t)location, value, type, symbolName, addend, this->getPath(), targetImage ? targetImage->getPath() : NULL, "weak ");
1647 boundSomething = true;
1648 }
1649 }
1650
1651 // scan lazy and non-lazy pointers for uses of symbol_index
1652 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1653 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1654 const struct load_command* cmd = cmds;
1655 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1656 for (uint32_t i = 0; i < cmd_count; ++i) {
1657 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1658 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1659 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1660 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1661 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1662 uint32_t elementSize = sizeof(uintptr_t);
1663 switch ( sect->flags & SECTION_TYPE ) {
1664 #if __i386__
1665 case S_SYMBOL_STUBS:
1666 if ( ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) ==0) || (sect->reserved2 != 5) )
1667 continue;
1668 elementSize = 5;
1669 #endif
1670 case S_NON_LAZY_SYMBOL_POINTERS:
1671 case S_LAZY_SYMBOL_POINTERS:
1672 {
1673 size_t elementCount = sect->size / elementSize;
1674 const uint32_t indirectTableOffset = sect->reserved1;
1675 uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
1676 //dyld::log(" scanning section %s of %s starting at %p\n", sect->sectname, this->getShortName(), ptrToBind);
1677 for (size_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
1678 if ( indirectTable[indirectTableOffset + j] == symbol_index ) {
1679 //dyld::log(" found symbol index match at %d/%d, ptrToBind=%p\n", j, elementCount, ptrToBind);
1680 // update pointer
1681 this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, it.symbolName, value, targetImage, context);
1682 boundSomething = true;
1683 }
1684 }
1685 }
1686 break;
1687 }
1688 }
1689 }
1690 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1691 }
1692 if ( boundSomething && (targetImage != this) ) {
1693 context.addDynamicReference(this, targetImage);
1694 }
1695
1696 // mark that this symbol has already been bound, so we don't try to bind again
1697 it.type = 1;
1698 }
1699
1700
1701 void ImageLoaderMachOClassic::bindIndirectSymbolPointers(const LinkContext& context, bool bindNonLazys, bool bindLazys)
1702 {
1703 // scan for all non-lazy-pointer sections
1704 const bool twoLevel = this->usesTwoLevelNameSpace();
1705 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1706 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1707 const struct load_command* cmd = cmds;
1708 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1709 for (uint32_t i = 0; i < cmd_count; ++i) {
1710 switch (cmd->cmd) {
1711 case LC_SEGMENT_COMMAND:
1712 {
1713 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1714 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1715 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1716 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1717 bool isLazySymbol = false;
1718 const uint8_t type = sect->flags & SECTION_TYPE;
1719 uint32_t elementSize = sizeof(uintptr_t);
1720 size_t elementCount = sect->size / elementSize;
1721 if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
1722 if ( ! bindNonLazys )
1723 continue;
1724 }
1725 else if ( type == S_LAZY_SYMBOL_POINTERS ) {
1726 // process each symbol pointer in this section
1727 fgTotalPossibleLazyBindFixups += elementCount;
1728 isLazySymbol = true;
1729 if ( ! bindLazys )
1730 continue;
1731 }
1732 #if __i386__
1733 else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
1734 // process each jmp entry in this section
1735 elementCount = sect->size / 5;
1736 elementSize = 5;
1737 fgTotalPossibleLazyBindFixups += elementCount;
1738 isLazySymbol = true;
1739 if ( ! bindLazys )
1740 continue;
1741 }
1742 #endif
1743 else {
1744 continue;
1745 }
1746 const uint32_t indirectTableOffset = sect->reserved1;
1747 uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
1748 for (size_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
1749 #if LINKEDIT_USAGE_DEBUG
1750 noteAccessedLinkEditAddress(&indirectTable[indirectTableOffset + j]);
1751 #endif
1752 uint32_t symbolIndex = indirectTable[indirectTableOffset + j];
1753 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL) {
1754 *((uintptr_t*)ptrToBind) += this->fSlide;
1755 }
1756 else if ( symbolIndex == INDIRECT_SYMBOL_ABS) {
1757 // do nothing since already has absolute address
1758 }
1759 else {
1760 const struct macho_nlist* sym = &fSymbolTable[symbolIndex];
1761 if ( symbolIndex == 0 ) {
1762 // This could be rdar://problem/3534709
1763 if ( ((const macho_header*)fMachOData)->filetype == MH_EXECUTE ) {
1764 static bool alreadyWarned = false;
1765 if ( (sym->n_type & N_TYPE) != N_UNDF ) {
1766 // The indirect table parallels the (non)lazy pointer sections. For
1767 // instance, to find info about the fifth lazy pointer you look at the
1768 // fifth entry in the indirect table. (try otool -Iv on a file).
1769 // The entry in the indirect table contains an index into the symbol table.
1770
1771 // The bug in ld caused the entry in the indirect table to be zero
1772 // (instead of a magic value that means a local symbol). So, if the
1773 // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
1774 // symbol table index. The check I put in place is to see if the zero'th
1775 // symbol table entry is an import entry (usually it is a local symbol
1776 // definition).
1777 if ( context.verboseWarnings && !alreadyWarned ) {
1778 dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n",
1779 this->getPath(), &fStrings[sym->n_un.n_strx]);
1780 alreadyWarned = true;
1781 }
1782 continue;
1783 }
1784 }
1785 }
1786 const ImageLoader* image = NULL;
1787 // let weak definitions resolve to themselves, later coalescing may overwrite them
1788 bool dontCoalesce = true;
1789 if ( bindLazys && isLazySymbol ) {
1790 // if this is something normally lazy bound, but we are forcing
1791 // it to be bound now, do coalescing
1792 dontCoalesce = false;
1793 }
1794 if ( symbolIsWeakReference(sym) ) {
1795 // when weakbind() is run on a classic mach-o encoding, it won't try
1796 // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted
1797 // range of global symbols. To handle that case we do the coalesing now.
1798 dontCoalesce = false;
1799 }
1800 uintptr_t symbolAddr = resolveUndefined(context, sym, twoLevel, dontCoalesce, false, &image);
1801 // update pointer
1802 symbolAddr = this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, &fStrings[sym->n_un.n_strx], symbolAddr, image, context);
1803 // update stats
1804 ++fgTotalBindFixups;
1805 }
1806 }
1807 }
1808 }
1809 break;
1810 }
1811 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1812 }
1813 }
1814
1815
1816
1817 #if __i386__
1818 void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext& context)
1819 {
1820 if ( ! this->usablePrebinding(context) ) {
1821 // reset all "fast" stubs
1822 const macho_header* mh = (macho_header*)fMachOData;
1823 const uint32_t cmd_count = mh->ncmds;
1824 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1825 const struct load_command* cmd = cmds;
1826 for (uint32_t i = 0; i < cmd_count; ++i) {
1827 switch (cmd->cmd) {
1828 case LC_SEGMENT_COMMAND:
1829 {
1830 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1831 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1832 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1833 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1834 const uint8_t type = sect->flags & SECTION_TYPE;
1835 if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
1836 // reset each jmp entry in this section
1837 const uint32_t indirectTableOffset = sect->reserved1;
1838 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1839 uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
1840 uint8_t* end = start + sect->size;
1841 uintptr_t dyldHandler = (uintptr_t)&stub_binding_helper_i386_old;
1842 uint32_t entryIndex = 0;
1843 for (uint8_t* entry = start; entry < end; entry += 5, ++entryIndex) {
1844 bool installLazyHandler = true;
1845 // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes
1846 // if the instruction is updated by one thread while being executed by another
1847 if ( ((uint32_t)entry & 0xFFFFFFC0) != ((uint32_t)entry+4 & 0xFFFFFFC0) ) {
1848 // need to bind this now to avoid a potential problem if bound lazily
1849 uint32_t symbolIndex = indirectTable[indirectTableOffset + entryIndex];
1850 // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used
1851 if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
1852 const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
1853 const ImageLoader* image = NULL;
1854 try {
1855 uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], this->usesTwoLevelNameSpace(), false, false, &image);
1856 symbolAddr = this->bindIndirectSymbol((uintptr_t*)entry, sect, symbolName, symbolAddr, image, context);
1857 ++fgTotalBindFixups;
1858 uint32_t rel32 = symbolAddr - (((uint32_t)entry)+5);
1859 entry[0] = 0xE9; // JMP rel32
1860 entry[1] = rel32 & 0xFF;
1861 entry[2] = (rel32 >> 8) & 0xFF;
1862 entry[3] = (rel32 >> 16) & 0xFF;
1863 entry[4] = (rel32 >> 24) & 0xFF;
1864 installLazyHandler = false;
1865 }
1866 catch (const char* msg) {
1867 // ignore errors when binding symbols early
1868 // maybe the function is never called, and therefore erroring out now would be a regression
1869 }
1870 }
1871 }
1872 if ( installLazyHandler ) {
1873 uint32_t rel32 = dyldHandler - (((uint32_t)entry)+5);
1874 entry[0] = 0xE8; // CALL rel32
1875 entry[1] = rel32 & 0xFF;
1876 entry[2] = (rel32 >> 8) & 0xFF;
1877 entry[3] = (rel32 >> 16) & 0xFF;
1878 entry[4] = (rel32 >> 24) & 0xFF;
1879 }
1880 }
1881 }
1882 }
1883 }
1884 }
1885 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1886 }
1887 }
1888 }
1889 #endif // __i386__
1890
1891
1892 void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazysBound)
1893 {
1894 CRSetCrashLogMessage2(this->getPath());
1895 #if __i386__
1896 this->initializeLazyStubs(context);
1897 #endif
1898
1899 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
1900 // note: flat-namespace binaries need to have imports rebound (even if correctly prebound)
1901 if ( this->usablePrebinding(context) ) {
1902 // binding already up to date
1903 }
1904 else {
1905 // no valid prebinding, so bind symbols.
1906 // values bound by name are stored two different ways in classic mach-o:
1907
1908 #if TEXT_RELOC_SUPPORT
1909 // if there are __TEXT fixups, temporarily make __TEXT writable
1910 if ( fTextSegmentBinds )
1911 this->makeTextSegmentWritable(context, true);
1912 #endif
1913
1914 // 1) external relocations are used for data initialized to external symbols
1915 this->doBindExternalRelocations(context);
1916
1917 // 2) "indirect symbols" are used for code references to external symbols
1918 // if this image is in the shared cache, there is no way to reset the lazy pointers, so bind them now
1919 this->bindIndirectSymbolPointers(context, true, forceLazysBound || fInSharedCache);
1920
1921 #if TEXT_RELOC_SUPPORT
1922 // if there were __TEXT fixups, restore write protection
1923 if ( fTextSegmentBinds )
1924 this->makeTextSegmentWritable(context, false);
1925 #endif
1926 }
1927
1928 // set up dyld entry points in image
1929 this->setupLazyPointerHandler(context);
1930
1931 CRSetCrashLogMessage2(NULL);
1932 }
1933
1934 void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context)
1935 {
1936 // some API called requested that all lazy pointers in this image be force bound
1937 this->bindIndirectSymbolPointers(context, false, true);
1938 }
1939
1940 void ImageLoaderMachOClassic::doInterpose(const LinkContext& context)
1941 {
1942 if ( context.verboseInterposing )
1943 dyld::log("dyld: interposing %lu tuples onto: %s\n", fgInterposingTuples.size(), this->getPath());
1944
1945 // scan indirect symbols
1946 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1947 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1948 const struct load_command* cmd = cmds;
1949 for (uint32_t i = 0; i < cmd_count; ++i) {
1950 switch (cmd->cmd) {
1951 case LC_SEGMENT_COMMAND:
1952 {
1953 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1954 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1955 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1956 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1957 const uint8_t type = sect->flags & SECTION_TYPE;
1958 if ( (type == S_NON_LAZY_SYMBOL_POINTERS) || (type == S_LAZY_SYMBOL_POINTERS) ) {
1959 const size_t pointerCount = sect->size / sizeof(uintptr_t);
1960 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
1961 for (size_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) {
1962 uintptr_t newValue = interposedAddress(context, symbolPointers[pointerIndex], this);
1963 if ( newValue != symbolPointers[pointerIndex] )
1964 symbolPointers[pointerIndex] = newValue;
1965 }
1966 }
1967 #if __i386__
1968 // i386 has special self-modifying stubs that might be prebound to "JMP rel32" that need checking
1969 else if ( (type == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
1970 // check each jmp entry in this section
1971 uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
1972 uint8_t* end = start + sect->size;
1973 for (uint8_t* entry = start; entry < end; entry += 5) {
1974 if ( entry[0] == 0xE9 ) { // 0xE9 == JMP
1975 uint32_t rel32 = *((uint32_t*)&entry[1]); // assume unaligned load of uint32_t is ok
1976 uint32_t target = (uint32_t)&entry[5] + rel32;
1977 uint32_t newTarget = interposedAddress(context, target, this);
1978 if ( newTarget != target ) {
1979 uint32_t newRel32 = newTarget - (uint32_t)&entry[5];
1980 *((uint32_t*)&entry[1]) = newRel32; // assume unaligned store of uint32_t is ok
1981 }
1982 }
1983 }
1984 }
1985 #endif
1986 }
1987 }
1988 break;
1989 }
1990 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1991 }
1992
1993 // scan external relocations
1994 const uintptr_t relocBase = this->getRelocBase();
1995 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
1996 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
1997 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1998 if (reloc->r_length == RELOC_SIZE) {
1999 switch(reloc->r_type) {
2000 case POINTER_RELOC:
2001 {
2002 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
2003 uintptr_t value = *location;
2004 uintptr_t newValue = interposedAddress(context, value, this);
2005 if ( newValue != value )
2006 *location = newValue;
2007 }
2008 break;
2009 }
2010 }
2011 }
2012 }
2013
2014 void ImageLoaderMachOClassic::dynamicInterpose(const LinkContext& context)
2015 {
2016 if ( context.verboseInterposing )
2017 dyld::log("dyld: dynamic interposing %lu tuples onto image: %s\n", context.dynamicInterposeCount, this->getPath());
2018
2019 // scan indirect symbols
2020 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2021 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2022 const struct load_command* cmd = cmds;
2023 for (uint32_t i = 0; i < cmd_count; ++i) {
2024 switch (cmd->cmd) {
2025 case LC_SEGMENT_COMMAND:
2026 {
2027 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2028 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2029 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2030 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2031 const uint8_t type = sect->flags & SECTION_TYPE;
2032 if ( (type == S_NON_LAZY_SYMBOL_POINTERS) || (type == S_LAZY_SYMBOL_POINTERS) ) {
2033 const size_t pointerCount = sect->size / sizeof(uintptr_t);
2034 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
2035 for (size_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) {
2036 for(size_t j=0; j < context.dynamicInterposeCount; ++j) {
2037 // replace all references to 'replacee' with 'replacement'
2038 if ( symbolPointers[pointerIndex] == (uintptr_t)context.dynamicInterposeArray[j].replacee ) {
2039 if ( context.verboseInterposing ) {
2040 dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n",
2041 &symbolPointers[pointerIndex], context.dynamicInterposeArray[j].replacee, context.dynamicInterposeArray[j].replacement, this->getPath());
2042 }
2043 symbolPointers[pointerIndex] = (uintptr_t)context.dynamicInterposeArray[j].replacement;
2044 }
2045 }
2046 }
2047 }
2048 }
2049 }
2050 break;
2051 }
2052 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2053 }
2054
2055 // scan external relocations
2056 const uintptr_t relocBase = this->getRelocBase();
2057 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
2058 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
2059 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
2060 if (reloc->r_length == RELOC_SIZE) {
2061 switch(reloc->r_type) {
2062 case POINTER_RELOC:
2063 {
2064 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
2065 for(size_t i=0; i < context.dynamicInterposeCount; ++i) {
2066 // replace all references to 'replacee' with 'replacement'
2067 if ( *location == (uintptr_t)context.dynamicInterposeArray[i].replacee ) {
2068 if ( context.verboseInterposing ) {
2069 dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n",
2070 location, context.dynamicInterposeArray[i].replacee, context.dynamicInterposeArray[i].replacement, this->getPath());
2071 }
2072 *location = (uintptr_t)context.dynamicInterposeArray[i].replacement;
2073 }
2074 }
2075 }
2076 break;
2077 }
2078 }
2079 }
2080 }
2081
2082
2083 const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr, const void** closestAddr) const
2084 {
2085 uintptr_t targetAddress = (uintptr_t)addr - fSlide;
2086 const struct macho_nlist* bestSymbol = NULL;
2087 // first walk all global symbols
2088 const struct macho_nlist* const globalsStart = &fSymbolTable[fDynamicInfo->iextdefsym];
2089 const struct macho_nlist* const globalsEnd= &globalsStart[fDynamicInfo->nextdefsym];
2090 for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
2091 if ( (s->n_type & N_TYPE) == N_SECT ) {
2092 if ( bestSymbol == NULL ) {
2093 if ( s->n_value <= targetAddress )
2094 bestSymbol = s;
2095 }
2096 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2097 bestSymbol = s;
2098 }
2099 }
2100 }
2101 // next walk all local symbols
2102 const struct macho_nlist* const localsStart = &fSymbolTable[fDynamicInfo->ilocalsym];
2103 const struct macho_nlist* const localsEnd= &localsStart[fDynamicInfo->nlocalsym];
2104 for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
2105 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
2106 if ( bestSymbol == NULL ) {
2107 if ( s->n_value <= targetAddress )
2108 bestSymbol = s;
2109 }
2110 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2111 bestSymbol = s;
2112 }
2113 }
2114 }
2115 if ( bestSymbol != NULL ) {
2116 #if __arm__
2117 if (bestSymbol->n_desc & N_ARM_THUMB_DEF)
2118 *closestAddr = (void*)((bestSymbol->n_value | 1) + fSlide);
2119 else
2120 *closestAddr = (void*)(bestSymbol->n_value + fSlide);
2121 #else
2122 *closestAddr = (void*)(bestSymbol->n_value + fSlide);
2123 #endif
2124 return &fStrings[bestSymbol->n_un.n_strx];
2125 }
2126 return NULL;
2127 }
2128
2129