]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoaderMachOClassic.cpp
dyld-655.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 for(const char* const* suffix = context.imageSuffix; *suffix != NULL; ++suffix) {
605 char reexportAndSuffix[strlen(*suffix)+strlen(exportThruName)+1];
606 strcpy(reexportAndSuffix, exportThruName);
607 strcat(reexportAndSuffix, *suffix);
608 if ( strcmp(&lastSlash[1], reexportAndSuffix) == 0 )
609 return true;
610 }
611 }
612 }
613 }
614 }
615 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
616 }
617 }
618 return false;
619 }
620
621 // test if child is re-exported
622 bool ImageLoaderMachOClassic::hasSubLibrary(const LinkContext& context, const ImageLoader* child) const
623 {
624 if ( fHasSubLibraries ) {
625 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child...
626 const char* childInstallPath = child->getInstallPath();
627 if ( childInstallPath != NULL ) {
628 const char* lastSlash = strrchr(childInstallPath, '/');
629 if ( lastSlash != NULL ) {
630 const char* firstDot = strchr(lastSlash, '.');
631 size_t len;
632 if ( firstDot == NULL )
633 len = strlen(lastSlash);
634 else
635 len = firstDot-lastSlash-1;
636 char childLeafName[len+1];
637 strncpy(childLeafName, &lastSlash[1], len);
638 childLeafName[len] = '\0';
639 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
640 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
641 const struct load_command* cmd = cmds;
642 for (uint32_t i = 0; i < cmd_count; ++i) {
643 switch (cmd->cmd) {
644 case LC_SUB_LIBRARY:
645 {
646 const struct sub_library_command* lib = (struct sub_library_command*)cmd;
647 const char* aSubLibName = (char*)cmd + lib->sub_library.offset;
648 if ( strcmp(aSubLibName, childLeafName) == 0 )
649 return true;
650 if ( context.imageSuffix != NULL ) {
651 // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end
652 for(const char* const* suffix = context.imageSuffix; *suffix != NULL; ++suffix) {
653 char aSubLibNameAndSuffix[strlen(*suffix)+strlen(aSubLibName)+1];
654 strcpy(aSubLibNameAndSuffix, aSubLibName);
655 strcat(aSubLibNameAndSuffix, *suffix);
656 if ( strcmp(aSubLibNameAndSuffix, childLeafName) == 0 )
657 return true;
658 }
659 }
660 }
661 break;
662 }
663 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
664 }
665 }
666 }
667 }
668 if ( fHasSubUmbrella ) {
669 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child...
670 const char* childInstallPath = child->getInstallPath();
671 if ( childInstallPath != NULL ) {
672 const char* lastSlash = strrchr(childInstallPath, '/');
673 if ( lastSlash != NULL ) {
674 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
675 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
676 const struct load_command* cmd = cmds;
677 for (uint32_t i = 0; i < cmd_count; ++i) {
678 switch (cmd->cmd) {
679 case LC_SUB_UMBRELLA:
680 {
681 const struct sub_umbrella_command* um = (struct sub_umbrella_command*)cmd;
682 const char* aSubUmbrellaName = (char*)cmd + um->sub_umbrella.offset;
683 if ( strcmp(aSubUmbrellaName, &lastSlash[1]) == 0 )
684 return true;
685 if ( context.imageSuffix != NULL ) {
686 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
687 for(const char* const* suffix = context.imageSuffix; *suffix != NULL; ++suffix) {
688 char umbrellaAndSuffix[strlen(*suffix)+strlen(aSubUmbrellaName)+1];
689 strcpy(umbrellaAndSuffix, aSubUmbrellaName);
690 strcat(umbrellaAndSuffix, *suffix);
691 if ( strcmp(umbrellaAndSuffix, &lastSlash[1]) == 0 )
692 return true;
693 }
694 }
695 }
696 break;
697 }
698 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
699 }
700 }
701 }
702 }
703 return false;
704 }
705
706
707 uintptr_t ImageLoaderMachOClassic::getFirstWritableSegmentAddress()
708 {
709 // in split segment libraries r_address is offset from first writable segment
710 for(unsigned int i=0; i < fSegmentsCount; ++i) {
711 if ( segWriteable(i) )
712 return segActualLoadAddress(i);
713 }
714 throw "no writable segment";
715 }
716
717 uintptr_t ImageLoaderMachOClassic::getRelocBase()
718 {
719 // r_address is either an offset from the first segment address
720 // or from the first writable segment address
721 #if __x86_64__
722 return getFirstWritableSegmentAddress();
723 #else
724 if ( fIsSplitSeg )
725 return getFirstWritableSegmentAddress();
726 else
727 return segActualLoadAddress(0);
728 #endif
729 }
730
731
732 #if PREBOUND_IMAGE_SUPPORT
733 void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext& context)
734 {
735 // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values
736 const uintptr_t relocBase = this->getRelocBase();
737 const uintptr_t slide = this->fSlide;
738 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
739 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
740 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
741 if ( (reloc->r_address & R_SCATTERED) != 0 ) {
742 const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
743 if (sreloc->r_length == RELOC_SIZE) {
744 uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
745 switch(sreloc->r_type) {
746 #if __i386__
747 case GENERIC_RELOC_PB_LA_PTR:
748 *locationToFix = sreloc->r_value + slide;
749 break;
750 #endif
751 #if __arm__
752 case ARM_RELOC_PB_LA_PTR:
753 *locationToFix = sreloc->r_value + slide;
754 break;
755 #endif
756 }
757 }
758 }
759 }
760 }
761 #endif
762
763
764
765
766 void ImageLoaderMachOClassic::rebase(const LinkContext& context, uintptr_t slide)
767 {
768 CRSetCrashLogMessage2(this->getPath());
769 const uintptr_t relocBase = this->getRelocBase();
770
771 // prefetch any LINKEDIT pages needed
772 if ( !context.preFetchDisabled && !this->isPrebindable())
773 this->prefetchLINKEDIT(context);
774
775 // loop through all local (internal) relocation records
776 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
777 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
778 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
779 uintptr_t rebaseAddr;
780 try {
781 #if LINKEDIT_USAGE_DEBUG
782 noteAccessedLinkEditAddress(reloc);
783 #endif
784 #if __x86_64__
785 // only one kind of local relocation supported for x86_64
786 if ( reloc->r_length != 3 )
787 throw "bad local relocation length";
788 if ( reloc->r_type != X86_64_RELOC_UNSIGNED )
789 throw "unknown local relocation type";
790 if ( reloc->r_pcrel != 0 )
791 throw "bad local relocation pc_rel";
792 if ( reloc->r_extern != 0 )
793 throw "extern relocation found with local relocations";
794 rebaseAddr = reloc->r_address + relocBase;
795 if ( ! this->containsAddress((void*)rebaseAddr) )
796 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr);
797 *((uintptr_t*)rebaseAddr) += slide;
798 if ( context.verboseRebase )
799 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide);
800 #else
801 if ( (reloc->r_address & R_SCATTERED) == 0 ) {
802 if ( reloc->r_symbolnum == R_ABS ) {
803 // ignore absolute relocations
804 }
805 else if (reloc->r_length == RELOC_SIZE) {
806 switch(reloc->r_type) {
807 case GENERIC_RELOC_VANILLA:
808 rebaseAddr = reloc->r_address + relocBase;
809 if ( ! this->containsAddress((void*)rebaseAddr) )
810 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr);
811 *((uintptr_t*)rebaseAddr) += slide;
812 if ( context.verboseRebase )
813 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide);
814 break;
815 default:
816 throw "unknown local relocation type";
817 }
818 }
819 else {
820 throw "bad local relocation length";
821 }
822 }
823 else {
824 const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
825 if (sreloc->r_length == RELOC_SIZE) {
826 uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
827 switch(sreloc->r_type) {
828 case GENERIC_RELOC_VANILLA:
829 if ( ! this->containsAddress((void*)locationToFix) )
830 dyld::throwf("local scattered reloc %p not in mapped image\n", locationToFix);
831 *locationToFix += slide;
832 if ( context.verboseRebase )
833 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)locationToFix, slide);
834 break;
835 #if __i386__
836 case GENERIC_RELOC_PB_LA_PTR:
837 // do nothing
838 break;
839 #elif __arm__
840 case ARM_RELOC_PB_LA_PTR:
841 // do nothing
842 break;
843 #endif
844 default:
845 throw "unknown local scattered relocation type";
846 }
847 }
848 else {
849 throw "bad local scattered relocation length";
850 }
851 }
852 #endif // x86_64
853 }
854 catch (const char* msg) {
855 const uint8_t* r = (uint8_t*)reloc;
856 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",
857 msg, this->getPath(), reloc, r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]);
858 }
859 }
860
861 // update stats
862 fgTotalRebaseFixups += fDynamicInfo->nlocrel;
863 CRSetCrashLogMessage2(NULL);
864 }
865
866
867
868 const struct macho_nlist* ImageLoaderMachOClassic::binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[],
869 const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) const
870 {
871 int32_t high = symbolCount-1;
872 int32_t mid = hintIndex;
873
874 // handle out of range hint
875 if ( mid >= (int32_t)symbolCount )
876 mid = symbolCount/2;
877 ++ImageLoaderMachO::fgSymbolTableBinarySearchs;
878 ++fgTotalBindImageSearches;
879
880 //dyld::log("dyld: binarySearchWithToc for %s in %s\n", key, this->getShortName());
881
882 for (int32_t low = 0; low <= high; mid = (low+high)/2) {
883 const uint32_t index = toc[mid].symbol_index;
884 const struct macho_nlist* pivot = &symbols[index];
885 const char* pivotStr = &stringPool[pivot->n_un.n_strx];
886 #if LINKEDIT_USAGE_DEBUG
887 noteAccessedLinkEditAddress(&toc[mid]);
888 noteAccessedLinkEditAddress(pivot);
889 noteAccessedLinkEditAddress(pivotStr);
890 #endif
891 int cmp = strcmp(key, pivotStr);
892 if ( cmp == 0 )
893 return pivot;
894 if ( cmp > 0 ) {
895 // key > pivot
896 low = mid + 1;
897 }
898 else {
899 // key < pivot
900 high = mid - 1;
901 }
902 }
903 return NULL;
904 }
905
906 const struct macho_nlist* ImageLoaderMachOClassic::binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount) const
907 {
908 // update stats
909 ++fgTotalBindImageSearches;
910 ++ImageLoaderMachO::fgSymbolTableBinarySearchs;
911
912 //dyld::log("dyld: binarySearch for %s in %s, stringpool=%p, symbols=%p, symbolCount=%u\n",
913 // key, this->getShortName(), stringPool, symbols, symbolCount);
914
915 const struct macho_nlist* base = symbols;
916 for (uint32_t n = symbolCount; n > 0; n /= 2) {
917 const struct macho_nlist* pivot = &base[n/2];
918 const char* pivotStr = &stringPool[pivot->n_un.n_strx];
919 #if LINKEDIT_USAGE_DEBUG
920 noteAccessedLinkEditAddress(pivot);
921 noteAccessedLinkEditAddress(pivotStr);
922 #endif
923 int cmp = strcmp(key, pivotStr);
924 if ( cmp == 0 )
925 return pivot;
926 if ( cmp > 0 ) {
927 // key > pivot
928 // move base to symbol after pivot
929 base = &pivot[1];
930 --n;
931 }
932 else {
933 // key < pivot
934 // keep same base
935 }
936 }
937 return NULL;
938 }
939
940
941 const ImageLoader::Symbol* ImageLoaderMachOClassic::findShallowExportedSymbol(const char* name, const ImageLoader** foundIn) const
942 {
943 const struct macho_nlist* sym = NULL;
944 if ( fDynamicInfo->tocoff == 0 )
945 sym = binarySearch(name, fStrings, &fSymbolTable[fDynamicInfo->iextdefsym], fDynamicInfo->nextdefsym);
946 else
947 sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff],
948 fDynamicInfo->ntoc, fDynamicInfo->nextdefsym);
949 if ( sym != NULL ) {
950 if ( foundIn != NULL )
951 *foundIn = (ImageLoader*)this;
952 return (const Symbol*)sym;
953 }
954 return NULL;
955 }
956
957
958
959 bool ImageLoaderMachOClassic::containsSymbol(const void* addr) const
960 {
961 return ( (fSymbolTable <= addr) && (addr < fStrings) );
962 }
963
964
965 uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const
966 {
967 const struct macho_nlist* sym = (macho_nlist*)symbol;
968 uintptr_t result = sym->n_value + fSlide;
969 #if __arm__
970 // processor assumes code address with low bit set is thumb
971 if (sym->n_desc & N_ARM_THUMB_DEF)
972 result |= 1;
973 #endif
974 return result;
975 }
976
977 bool ImageLoaderMachOClassic::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
978 {
979 const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
980 return ( (nlistSym->n_desc & N_WEAK_DEF) != 0 );
981 }
982
983 const char* ImageLoaderMachOClassic::exportedSymbolName(const Symbol* symbol) const
984 {
985 const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
986 return &fStrings[nlistSym->n_un.n_strx];
987 }
988
989 unsigned int ImageLoaderMachOClassic::exportedSymbolCount() const
990 {
991 return fDynamicInfo->nextdefsym;
992 }
993
994 const ImageLoader::Symbol* ImageLoaderMachOClassic::exportedSymbolIndexed(unsigned int index) const
995 {
996 if ( index < fDynamicInfo->nextdefsym ) {
997 const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym + index];
998 return (const ImageLoader::Symbol*)sym;
999 }
1000 return NULL;
1001 }
1002
1003 unsigned int ImageLoaderMachOClassic::importedSymbolCount() const
1004 {
1005 return fDynamicInfo->nundefsym;
1006 }
1007
1008 const ImageLoader::Symbol* ImageLoaderMachOClassic::importedSymbolIndexed(unsigned int index) const
1009 {
1010 if ( index < fDynamicInfo->nundefsym ) {
1011 const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iundefsym + index];
1012 return (const ImageLoader::Symbol*)sym;
1013 }
1014 return NULL;
1015 }
1016
1017 const char* ImageLoaderMachOClassic::importedSymbolName(const Symbol* symbol) const
1018 {
1019 const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
1020 return &fStrings[nlistSym->n_un.n_strx];
1021 }
1022
1023
1024
1025 bool ImageLoaderMachOClassic::symbolIsWeakDefinition(const struct macho_nlist* symbol)
1026 {
1027 // if a define and weak ==> coalesced
1028 if ( ((symbol->n_type & N_TYPE) == N_SECT) && ((symbol->n_desc & N_WEAK_DEF) != 0) )
1029 return true;
1030
1031 // regular symbol
1032 return false;
1033 }
1034
1035 bool ImageLoaderMachOClassic::symbolIsWeakReference(const struct macho_nlist* symbol)
1036 {
1037 // if an undefine and not referencing a weak symbol ==> coalesced
1038 if ( ((symbol->n_type & N_TYPE) != N_SECT) && ((symbol->n_desc & N_REF_TO_WEAK) != 0) )
1039 return true;
1040
1041 // regular symbol
1042 return false;
1043 }
1044
1045 uintptr_t ImageLoaderMachOClassic::getSymbolAddress(const macho_nlist* sym, const LinkContext& context, bool runResolver) const
1046 {
1047 return ImageLoaderMachO::getSymbolAddress((Symbol*)sym, this, context, runResolver);
1048 }
1049
1050 uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context, const struct macho_nlist* undefinedSymbol,
1051 bool twoLevel, bool dontCoalesce, bool runResolver, const ImageLoader** foundIn)
1052 {
1053 ++fgTotalBindSymbolsResolved;
1054 const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
1055
1056 #if LINKEDIT_USAGE_DEBUG
1057 noteAccessedLinkEditAddress(undefinedSymbol);
1058 noteAccessedLinkEditAddress(symbolName);
1059 #endif
1060 if ( context.bindFlat || !twoLevel ) {
1061 // flat lookup
1062 if ( ((undefinedSymbol->n_type & N_PEXT) != 0) && ((undefinedSymbol->n_type & N_TYPE) == N_SECT) ) {
1063 // is a multi-module private_extern internal reference that the linker did not optimize away
1064 uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
1065 *foundIn = this;
1066 return addr;
1067 }
1068 const Symbol* sym;
1069 if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
1070 if ( *foundIn != this )
1071 context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
1072 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1073 }
1074 // if a bundle is loaded privately the above will not find its exports
1075 if ( this->isBundle() && this->hasHiddenExports() ) {
1076 // look in self for needed symbol
1077 sym = this->findShallowExportedSymbol(symbolName, foundIn);
1078 if ( sym != NULL )
1079 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1080 }
1081 if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
1082 // definition can't be found anywhere
1083 // if reference is weak_import, then it is ok, just return 0
1084 return 0;
1085 }
1086 throwSymbolNotFound(context, symbolName, this->getPath(), "", "flat namespace");
1087 }
1088 else {
1089 // symbol requires searching images with coalesced symbols (not done during prebinding)
1090 if ( !context.prebinding && !dontCoalesce && (symbolIsWeakReference(undefinedSymbol) || symbolIsWeakDefinition(undefinedSymbol)) ) {
1091 const Symbol* sym;
1092 if ( context.coalescedExportFinder(symbolName, &sym, foundIn, nullptr) ) {
1093 if ( *foundIn != this )
1094 context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
1095 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1096 }
1097 //throwSymbolNotFound(context, symbolName, this->getPath(), "coalesced namespace");
1098 //dyld::log("dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
1099 }
1100
1101 // if this is a real definition (not an undefined symbol) there is no ordinal
1102 if ( (undefinedSymbol->n_type & N_TYPE) == N_SECT ) {
1103 // static linker should never generate this case, but if it does, do something sane
1104 uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
1105 *foundIn = this;
1106 return addr;
1107 }
1108
1109 // two level lookup
1110 ImageLoader* target = NULL;
1111 uint8_t ord = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc);
1112 if ( ord == EXECUTABLE_ORDINAL ) {
1113 target = context.mainExecutable;
1114 }
1115 else if ( ord == SELF_LIBRARY_ORDINAL ) {
1116 target = this;
1117 }
1118 else if ( ord == DYNAMIC_LOOKUP_ORDINAL ) {
1119 // rnielsen: HACKHACK
1120 // flat lookup
1121 const Symbol* sym;
1122 if ( context.flatExportFinder(symbolName, &sym, foundIn) )
1123 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1124 // no image has exports this symbol
1125 // report error
1126 context.undefinedHandler(symbolName);
1127 // try looking again
1128 if ( context.flatExportFinder(symbolName, &sym, foundIn) )
1129 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1130
1131 throwSymbolNotFound(context, symbolName, this->getPath(), "", "dynamic lookup");
1132 }
1133 else if ( ord <= libraryCount() ) {
1134 target = libImage(ord-1);
1135 if ( target == NULL ) {
1136 // if target library not loaded and reference is weak or library is weak return 0
1137 return 0;
1138 }
1139 }
1140 else {
1141 dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s",
1142 ord, libraryCount(), symbolName, this->getPath());
1143 }
1144
1145 if ( target == NULL ) {
1146 //dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath());
1147 throw "symbol not found";
1148 }
1149
1150 uintptr_t address;
1151 if ( target->findExportedSymbolAddress(context, symbolName, this, ord, runResolver, foundIn, &address) )
1152 return address;
1153
1154 if ( (undefinedSymbol->n_type & N_PEXT) != 0 ) {
1155 // don't know why the static linker did not eliminate the internal reference to a private extern definition
1156 *foundIn = this;
1157 return this->getSymbolAddress(undefinedSymbol, context, false);
1158 }
1159 else if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
1160 // if definition not found and reference is weak return 0
1161 return 0;
1162 }
1163
1164 // nowhere to be found
1165 throwSymbolNotFound(context, symbolName, this->getPath(), "", target->getPath());
1166 }
1167 }
1168
1169
1170
1171 // returns if 'addr' is within the address range of section 'sectionIndex'
1172 // fSlide is not used. 'addr' is assumed to be a prebound address in this image
1173 bool ImageLoaderMachOClassic::isAddrInSection(uintptr_t addr, uint8_t sectionIndex)
1174 {
1175 uint8_t currentSectionIndex = 1;
1176 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1177 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1178 const struct load_command* cmd = cmds;
1179 for (uint32_t i = 0; i < cmd_count; ++i) {
1180 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1181 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1182 if ( (currentSectionIndex <= sectionIndex) && (sectionIndex < currentSectionIndex+seg->nsects) ) {
1183 // 'sectionIndex' is in this segment, get section info
1184 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1185 const struct macho_section* const section = &sectionsStart[sectionIndex-currentSectionIndex];
1186 return ( (section->addr <= addr) && (addr < section->addr+section->size) );
1187 }
1188 else {
1189 // 'sectionIndex' not in this segment, skip to next segment
1190 currentSectionIndex += seg->nsects;
1191 }
1192 }
1193 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1194 }
1195
1196 return false;
1197 }
1198
1199 void ImageLoaderMachOClassic::doBindExternalRelocations(const LinkContext& context)
1200 {
1201 const uintptr_t relocBase = this->getRelocBase();
1202 const bool twoLevel = this->usesTwoLevelNameSpace();
1203 const bool prebound = this->isPrebindable();
1204
1205 #if TEXT_RELOC_SUPPORT
1206 // if there are __TEXT fixups, temporarily make __TEXT writable
1207 if ( fTextSegmentBinds )
1208 this->makeTextSegmentWritable(context, true);
1209 #endif
1210 // cache last lookup
1211 const struct macho_nlist* lastUndefinedSymbol = NULL;
1212 uintptr_t symbolAddr = 0;
1213 const ImageLoader* image = NULL;
1214
1215 // loop through all external relocation records and bind each
1216 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
1217 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
1218 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1219 if (reloc->r_length == RELOC_SIZE) {
1220 switch(reloc->r_type) {
1221 case POINTER_RELOC:
1222 {
1223 const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
1224 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
1225 if ( ! this->containsAddress((void*)location) )
1226 dyld::throwf("external reloc %p not in mapped image %s\n", (void*)location, this->getPath());
1227 uintptr_t value = *location;
1228 bool symbolAddrCached = true;
1229 #if __i386__
1230 if ( reloc->r_pcrel ) {
1231 value += (uintptr_t)location + 4 - fSlide;
1232 }
1233 #endif
1234 if ( prebound ) {
1235 // we are doing relocations, so prebinding was not usable
1236 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1237 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1238 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
1239 if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
1240 // weak symbols need special casing, since *location may have been prebound to a definition in another image.
1241 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1242 // that we can subtract off the weak symbol address to get the addend.
1243 // If prebound elsewhere, we've lost the addend and have to assume it is zero.
1244 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1245 if ( (value == undefinedSymbol->n_value) || this->isAddrInSection(value, undefinedSymbol->n_sect) ) {
1246 value -= undefinedSymbol->n_value;
1247 #if __arm__
1248 // if weak and thumb subtract off extra thumb bit
1249 if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
1250 value -= 1;
1251 #endif
1252 }
1253 else
1254 value = 0;
1255 }
1256 #if __arm__
1257 else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) {
1258 // it was prebound to a defined symbol for thumb code in the same linkage unit
1259 // we need to subtract off one to get real addend
1260 value -= (undefinedSymbol->n_value+1);
1261 }
1262 #endif
1263 else {
1264 // is undefined or non-weak symbol, so do subtraction to get addend
1265 value -= undefinedSymbol->n_value;
1266 }
1267 }
1268 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
1269 if ( undefinedSymbol != lastUndefinedSymbol ) {
1270 bool dontCoalesce = true;
1271 if ( symbolIsWeakReference(undefinedSymbol) ) {
1272 // when weakbind() is run on a classic mach-o encoding, it won't try
1273 // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted
1274 // range of global symbols. To handle that case we do the coalesing now.
1275 dontCoalesce = false;
1276 }
1277 symbolAddr = this->resolveUndefined(context, undefinedSymbol, twoLevel, dontCoalesce, false, &image);
1278 lastUndefinedSymbol = undefinedSymbol;
1279 symbolAddrCached = false;
1280 }
1281 if ( context.verboseBind ) {
1282 const char *path = NULL;
1283 if ( image != NULL ) {
1284 path = image->getShortName();
1285 }
1286 const char* cachedString = "(cached)";
1287 if ( !symbolAddrCached )
1288 cachedString = "";
1289 if ( value == 0 ) {
1290 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s\n",
1291 this->getShortName(), (uintptr_t)location,
1292 path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString);
1293 }
1294 else {
1295 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s + %ld\n",
1296 this->getShortName(), (uintptr_t)location,
1297 path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString, value);
1298 }
1299 }
1300 value += symbolAddr;
1301 #if __i386__
1302 if ( reloc->r_pcrel ) {
1303 *location = value - ((uintptr_t)location + 4);
1304 }
1305 else {
1306 // don't dirty page if prebound value was correct
1307 if ( !prebound || (*location != value) )
1308 *location = value;
1309 }
1310 #else
1311 // don't dirty page if prebound value was correct
1312 if ( !prebound || (*location != value) )
1313 *location = value;
1314 #endif
1315 // update stats
1316 ++fgTotalBindFixups;
1317 }
1318 break;
1319 default:
1320 throw "unknown external relocation type";
1321 }
1322 }
1323 else {
1324 throw "bad external relocation length";
1325 }
1326 }
1327
1328 #if TEXT_RELOC_SUPPORT
1329 // if there were __TEXT fixups, restore write protection
1330 if ( fTextSegmentBinds ) {
1331 this->makeTextSegmentWritable(context, true);
1332 }
1333 #endif
1334 }
1335
1336
1337
1338 uintptr_t ImageLoaderMachOClassic::bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, const char* symbolName, uintptr_t targetAddr, const ImageLoader* targetImage, const LinkContext& context)
1339 {
1340 if ( context.verboseBind ) {
1341 const char* path = NULL;
1342 if ( targetImage != NULL )
1343 path = targetImage->getShortName();
1344 dyld::log("dyld: bind indirect sym: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
1345 this->getShortName(), symbolName, (((sect->flags & SECTION_TYPE)==S_NON_LAZY_SYMBOL_POINTERS) ? "non_lazy_ptr" : "lazy_ptr"),
1346 ((path != NULL) ? path : "<weak_import-not-found>"), symbolName, (uintptr_t)ptrToBind, targetAddr);
1347 }
1348 if ( context.bindingHandler != NULL ) {
1349 const char* path = NULL;
1350 if ( targetImage != NULL )
1351 path = targetImage->getShortName();
1352 targetAddr = (uintptr_t)context.bindingHandler(path, symbolName, (void *)targetAddr);
1353 }
1354 #if __i386__
1355 // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
1356 if ( ((sect->flags & SECTION_TYPE) == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
1357 uint32_t rel32 = targetAddr - (((uint32_t)ptrToBind)+5);
1358 // re-write instruction in a thread-safe manner
1359 // use 8-byte compare-and-swap to alter 5-byte jump table entries
1360 // loop is required in case the extra three bytes that cover the next entry are altered by another thread
1361 bool done = false;
1362 while ( !done ) {
1363 volatile int64_t* jumpPtr = (int64_t*)ptrToBind;
1364 int pad = 0;
1365 // By default the three extra bytes swapped follow the 5-byte JMP.
1366 // But, if the 5-byte jump is up against the end of the __IMPORT segment
1367 // We don't want to access bytes off the end of the segment, so we shift
1368 // the extra bytes to precede the 5-byte JMP.
1369 if ( (((uint32_t)ptrToBind + 8) & 0x00000FFC) == 0x00000000 ) {
1370 jumpPtr = (int64_t*)((uint32_t)ptrToBind - 3);
1371 pad = 3;
1372 }
1373 int64_t oldEntry = *jumpPtr;
1374 union {
1375 int64_t int64;
1376 uint8_t bytes[8];
1377 } newEntry;
1378 newEntry.int64 = oldEntry;
1379 newEntry.bytes[pad+0] = 0xE9; // JMP rel32
1380 newEntry.bytes[pad+1] = rel32 & 0xFF;
1381 newEntry.bytes[pad+2] = (rel32 >> 8) & 0xFF;
1382 newEntry.bytes[pad+3] = (rel32 >> 16) & 0xFF;
1383 newEntry.bytes[pad+4] = (rel32 >> 24) & 0xFF;
1384 done = OSAtomicCompareAndSwap64Barrier(oldEntry, newEntry.int64, (int64_t*)jumpPtr);
1385 }
1386 }
1387 else
1388 #endif
1389 *ptrToBind = targetAddr;
1390 return targetAddr;
1391 }
1392
1393 uintptr_t ImageLoaderMachOClassic::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, void (*lock)(), void (*unlock)())
1394 {
1395 throw "compressed LINKEDIT lazy binder called with classic LINKEDIT";
1396 }
1397
1398 uintptr_t ImageLoaderMachOClassic::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context)
1399 {
1400 // scan for all lazy-pointer sections
1401 const bool twoLevel = this->usesTwoLevelNameSpace();
1402 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1403 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1404 const struct load_command* cmd = cmds;
1405 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1406 for (uint32_t i = 0; i < cmd_count; ++i) {
1407 switch (cmd->cmd) {
1408 case LC_SEGMENT_COMMAND:
1409 {
1410 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1411 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1412 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1413 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1414 const uint8_t type = sect->flags & SECTION_TYPE;
1415 uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
1416 if ( type == S_LAZY_SYMBOL_POINTERS ) {
1417 const size_t pointerCount = sect->size / sizeof(uintptr_t);
1418 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
1419 if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
1420 const uint32_t indirectTableOffset = sect->reserved1;
1421 const size_t lazyIndex = lazyPointer - symbolPointers;
1422 symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
1423 }
1424 }
1425 #if __i386__
1426 else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
1427 // 5 bytes stubs on i386 are new "fast stubs"
1428 uint8_t* const jmpTableBase = (uint8_t*)(sect->addr + fSlide);
1429 uint8_t* const jmpTableEnd = jmpTableBase + sect->size;
1430 // initial CALL instruction in jump table leaves pointer to next entry, so back up
1431 uint8_t* const jmpTableEntryToPatch = ((uint8_t*)lazyPointer) - 5;
1432 lazyPointer = (uintptr_t*)jmpTableEntryToPatch;
1433 if ( (jmpTableEntryToPatch >= jmpTableBase) && (jmpTableEntryToPatch < jmpTableEnd) ) {
1434 const uint32_t indirectTableOffset = sect->reserved1;
1435 const uint32_t entryIndex = (jmpTableEntryToPatch - jmpTableBase)/5;
1436 symbolIndex = indirectTable[indirectTableOffset + entryIndex];
1437 }
1438 }
1439 #endif
1440 if ( symbolIndex != INDIRECT_SYMBOL_ABS && symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
1441 const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
1442 const ImageLoader* image = NULL;
1443 uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], twoLevel, false, true, &image);
1444 symbolAddr = this->bindIndirectSymbol(lazyPointer, sect, symbolName, symbolAddr, image, context);
1445 ++fgTotalLazyBindFixups;
1446 return symbolAddr;
1447 }
1448 }
1449 }
1450 break;
1451 }
1452 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1453 }
1454 dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
1455 }
1456
1457
1458
1459 void ImageLoaderMachOClassic::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder, unsigned)
1460 {
1461 it.image = this;
1462 it.symbolName = " ";
1463 it.loadOrder = loadOrder;
1464 it.weakSymbol = false;
1465 it.symbolMatches = false;
1466 it.done = false;
1467 it.type = 0;
1468 if ( fDynamicInfo->tocoff != 0 ) {
1469 it.curIndex = 0;
1470 it.endIndex = fDynamicInfo->ntoc;
1471 }
1472 else {
1473 it.curIndex = 0;
1474 it.endIndex = fDynamicInfo->nextdefsym;
1475 }
1476 }
1477
1478
1479 bool ImageLoaderMachOClassic::incrementCoalIterator(CoalIterator& it)
1480 {
1481 if ( it.done )
1482 return false;
1483
1484 if ( fDynamicInfo->tocoff != 0 ) {
1485 if ( it.curIndex >= fDynamicInfo->ntoc ) {
1486 it.done = true;
1487 it.symbolName = "~~~";
1488 return true;
1489 }
1490 else {
1491 const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
1492 const uint32_t index = toc[it.curIndex].symbol_index;
1493 const struct macho_nlist* sym = &fSymbolTable[index];
1494 const char* symStr = &fStrings[sym->n_un.n_strx];
1495 it.symbolName = symStr;
1496 it.weakSymbol = (sym->n_desc & N_WEAK_DEF);
1497 it.symbolMatches = false;
1498 it.type = 0; // clear flag that says we applied updates for this symbol
1499 //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath());
1500 it.curIndex++;
1501 return false;
1502 }
1503 }
1504 else {
1505 if ( it.curIndex >= fDynamicInfo->nextdefsym ) {
1506 it.done = true;
1507 it.symbolName = "~~~";
1508 return true;
1509 }
1510 else {
1511 const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym+it.curIndex];
1512 const char* symStr = &fStrings[sym->n_un.n_strx];
1513 it.symbolName = symStr;
1514 it.weakSymbol = (sym->n_desc & N_WEAK_DEF);
1515 it.symbolMatches = false;
1516 it.type = 0; // clear flag that says we applied updates for this symbol
1517 //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath());
1518 it.curIndex++;
1519 return false;
1520 }
1521 }
1522
1523 return false;
1524 }
1525
1526 uintptr_t ImageLoaderMachOClassic::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
1527 {
1528 uint32_t symbol_index = 0;
1529 if ( fDynamicInfo->tocoff != 0 ) {
1530 const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
1531 symbol_index = toc[it.curIndex-1].symbol_index;
1532 }
1533 else {
1534 symbol_index = fDynamicInfo->iextdefsym + (uint32_t)it.curIndex - 1;
1535 }
1536 const struct macho_nlist* sym = &fSymbolTable[symbol_index];
1537 //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());
1538 #if __arm__
1539 // processor assumes code address with low bit set is thumb
1540 if (sym->n_desc & N_ARM_THUMB_DEF)
1541 return (sym->n_value | 1) + fSlide ;
1542 else
1543 return sym->n_value + fSlide;
1544 #else
1545 return sym->n_value + fSlide;
1546 #endif
1547 }
1548
1549
1550 void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, unsigned targetIndex, const LinkContext& context)
1551 {
1552 // flat_namespace images with classic LINKEDIT do not need late coalescing.
1553 // They still need to be iterated becuase they may implement
1554 // something needed by other coalescing images.
1555 // But they need no updating because during the bind phase every symbol lookup is a full scan.
1556 if ( !this->usesTwoLevelNameSpace() )
1557 return;
1558
1559 // <rdar://problem/6570879> weak binding done too early with inserted libraries
1560 if ( this->getState() < dyld_image_state_bound )
1561 return;
1562
1563 uint32_t symbol_index = 0;
1564 if ( fDynamicInfo->tocoff != 0 ) {
1565 const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
1566 symbol_index = toc[it.curIndex-1].symbol_index;
1567 }
1568 else {
1569 symbol_index = fDynamicInfo->iextdefsym + (uint32_t)it.curIndex - 1;
1570 }
1571
1572 // if this image's copy of the symbol is not a weak definition nor a weak reference then nothing to coalesce here
1573 if ( !symbolIsWeakReference(&fSymbolTable[symbol_index]) && !symbolIsWeakDefinition(&fSymbolTable[symbol_index]) ) {
1574 return;
1575 }
1576
1577 // <rdar://problem/6555720> malformed dylib with duplicate weak symbols causes re-binding
1578 if ( it.type )
1579 return;
1580
1581 bool boundSomething = false;
1582 // scan external relocations for uses of symbol_index
1583 const uintptr_t relocBase = this->getRelocBase();
1584 const bool prebound = this->isPrebindable();
1585 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
1586 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
1587 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1588 if ( reloc->r_symbolnum == symbol_index ) {
1589 //dyld::log("found external reloc using symbol_index=%d in %s\n",symbol_index, this->getPath());
1590 const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
1591 const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
1592 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
1593 const uintptr_t initialValue = *location;
1594 uintptr_t addend = 0;
1595 if ( prebound ) {
1596 // we are doing relocations, so prebinding was not usable
1597 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1598 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1599 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
1600 if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
1601 // weak symbols need special casing, since *location may have been prebound to a definition in another image.
1602 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1603 // that we can subtract off the weak symbol address to get the addend.
1604 // If prebound elsewhere, we've lost the addend and have to assume it is zero.
1605 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1606 if ( (initialValue == undefinedSymbol->n_value) || this->isAddrInSection(initialValue, undefinedSymbol->n_sect) ) {
1607 addend = initialValue - undefinedSymbol->n_value;
1608 #if __arm__
1609 // if weak and thumb subtract off extra thumb bit
1610 if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
1611 addend &= -2;
1612 #endif
1613 }
1614 }
1615 #if __arm__
1616 else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) {
1617 // it was prebound to a defined symbol for thumb code in the same linkage unit
1618 // we need to subtract off one to get real addend
1619 addend = initialValue - (undefinedSymbol->n_value+1);
1620 }
1621 #endif
1622 else {
1623 // is undefined or non-weak symbol, so do subtraction to get addend
1624 addend = initialValue - undefinedSymbol->n_value;
1625 }
1626 }
1627 else {
1628 // non-prebound case
1629 if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
1630 // if target is weak-def in same linkage unit, then bind phase has already set initialValue
1631 // to be definition address plus addend
1632 //dyld::log("weak def, initialValue=0x%lX, undefAddr=0x%lX\n", initialValue, undefinedSymbol->n_value+fSlide);
1633 addend = initialValue - (undefinedSymbol->n_value + fSlide);
1634 #if __arm__
1635 // if weak and thumb subtract off extra thumb bit
1636 if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
1637 addend &= -2;
1638 #endif
1639 }
1640 else {
1641 // nothing fixed up yet, addend is just initial value
1642 //dyld::log("addend=0x%lX\n", initialValue);
1643 addend = initialValue;
1644 }
1645 }
1646
1647 uint8_t type = BIND_TYPE_POINTER;
1648 #if __i386__
1649 if ( reloc->r_pcrel )
1650 type = BIND_TYPE_TEXT_PCREL32;
1651 #endif
1652 this->bindLocation(context, this->imageBaseAddress(), (uintptr_t)location, value, type, symbolName, addend, this->getPath(), targetImage ? targetImage->getPath() : NULL, "weak ", NULL, fSlide);
1653 boundSomething = true;
1654 }
1655 }
1656
1657 // scan lazy and non-lazy pointers for uses of symbol_index
1658 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1659 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1660 const struct load_command* cmd = cmds;
1661 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1662 for (uint32_t i = 0; i < cmd_count; ++i) {
1663 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1664 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1665 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1666 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1667 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1668 uint32_t elementSize = sizeof(uintptr_t);
1669 switch ( sect->flags & SECTION_TYPE ) {
1670 #if __i386__
1671 case S_SYMBOL_STUBS:
1672 if ( ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) ==0) || (sect->reserved2 != 5) )
1673 continue;
1674 elementSize = 5;
1675 #endif
1676 case S_NON_LAZY_SYMBOL_POINTERS:
1677 case S_LAZY_SYMBOL_POINTERS:
1678 {
1679 size_t elementCount = sect->size / elementSize;
1680 const uint32_t indirectTableOffset = sect->reserved1;
1681 uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
1682 //dyld::log(" scanning section %s of %s starting at %p\n", sect->sectname, this->getShortName(), ptrToBind);
1683 for (size_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
1684 if ( indirectTable[indirectTableOffset + j] == symbol_index ) {
1685 //dyld::log(" found symbol index match at %d/%d, ptrToBind=%p\n", j, elementCount, ptrToBind);
1686 // update pointer
1687 this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, it.symbolName, value, targetImage, context);
1688 boundSomething = true;
1689 }
1690 }
1691 }
1692 break;
1693 }
1694 }
1695 }
1696 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1697 }
1698 if ( boundSomething && (targetImage != this) ) {
1699 context.addDynamicReference(this, targetImage);
1700 }
1701
1702 // mark that this symbol has already been bound, so we don't try to bind again
1703 it.type = 1;
1704 }
1705
1706
1707 void ImageLoaderMachOClassic::bindIndirectSymbolPointers(const LinkContext& context, bool bindNonLazys, bool bindLazys)
1708 {
1709 // scan for all non-lazy-pointer sections
1710 const bool twoLevel = this->usesTwoLevelNameSpace();
1711 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1712 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1713 const struct load_command* cmd = cmds;
1714 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1715 for (uint32_t i = 0; i < cmd_count; ++i) {
1716 switch (cmd->cmd) {
1717 case LC_SEGMENT_COMMAND:
1718 {
1719 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1720 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1721 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1722 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1723 bool isLazySymbol = false;
1724 const uint8_t type = sect->flags & SECTION_TYPE;
1725 uint32_t elementSize = sizeof(uintptr_t);
1726 size_t elementCount = sect->size / elementSize;
1727 if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
1728 if ( ! bindNonLazys )
1729 continue;
1730 }
1731 else if ( type == S_LAZY_SYMBOL_POINTERS ) {
1732 // process each symbol pointer in this section
1733 fgTotalPossibleLazyBindFixups += elementCount;
1734 isLazySymbol = true;
1735 if ( ! bindLazys )
1736 continue;
1737 }
1738 #if __i386__
1739 else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
1740 // process each jmp entry in this section
1741 elementCount = sect->size / 5;
1742 elementSize = 5;
1743 fgTotalPossibleLazyBindFixups += elementCount;
1744 isLazySymbol = true;
1745 if ( ! bindLazys )
1746 continue;
1747 }
1748 #endif
1749 else {
1750 continue;
1751 }
1752 const uint32_t indirectTableOffset = sect->reserved1;
1753 uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
1754 for (size_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
1755 #if LINKEDIT_USAGE_DEBUG
1756 noteAccessedLinkEditAddress(&indirectTable[indirectTableOffset + j]);
1757 #endif
1758 uint32_t symbolIndex = indirectTable[indirectTableOffset + j];
1759 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL) {
1760 *((uintptr_t*)ptrToBind) += this->fSlide;
1761 }
1762 else if ( symbolIndex == INDIRECT_SYMBOL_ABS) {
1763 // do nothing since already has absolute address
1764 }
1765 else {
1766 const struct macho_nlist* sym = &fSymbolTable[symbolIndex];
1767 if ( symbolIndex == 0 ) {
1768 // This could be rdar://problem/3534709
1769 if ( ((const macho_header*)fMachOData)->filetype == MH_EXECUTE ) {
1770 static bool alreadyWarned = false;
1771 if ( (sym->n_type & N_TYPE) != N_UNDF ) {
1772 // The indirect table parallels the (non)lazy pointer sections. For
1773 // instance, to find info about the fifth lazy pointer you look at the
1774 // fifth entry in the indirect table. (try otool -Iv on a file).
1775 // The entry in the indirect table contains an index into the symbol table.
1776
1777 // The bug in ld caused the entry in the indirect table to be zero
1778 // (instead of a magic value that means a local symbol). So, if the
1779 // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
1780 // symbol table index. The check I put in place is to see if the zero'th
1781 // symbol table entry is an import entry (usually it is a local symbol
1782 // definition).
1783 if ( context.verboseWarnings && !alreadyWarned ) {
1784 dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n",
1785 this->getPath(), &fStrings[sym->n_un.n_strx]);
1786 alreadyWarned = true;
1787 }
1788 continue;
1789 }
1790 }
1791 }
1792 const ImageLoader* image = NULL;
1793 // let weak definitions resolve to themselves, later coalescing may overwrite them
1794 bool dontCoalesce = true;
1795 if ( bindLazys && isLazySymbol ) {
1796 // if this is something normally lazy bound, but we are forcing
1797 // it to be bound now, do coalescing
1798 dontCoalesce = false;
1799 }
1800 if ( symbolIsWeakReference(sym) ) {
1801 // when weakbind() is run on a classic mach-o encoding, it won't try
1802 // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted
1803 // range of global symbols. To handle that case we do the coalesing now.
1804 dontCoalesce = false;
1805 }
1806 uintptr_t symbolAddr = resolveUndefined(context, sym, twoLevel, dontCoalesce, false, &image);
1807 // update pointer
1808 symbolAddr = this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, &fStrings[sym->n_un.n_strx], symbolAddr, image, context);
1809 // update stats
1810 ++fgTotalBindFixups;
1811 }
1812 }
1813 }
1814 }
1815 break;
1816 }
1817 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1818 }
1819 }
1820
1821
1822
1823 #if __i386__
1824 void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext& context)
1825 {
1826 if ( ! this->usablePrebinding(context) ) {
1827 // reset all "fast" stubs
1828 const macho_header* mh = (macho_header*)fMachOData;
1829 const uint32_t cmd_count = mh->ncmds;
1830 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1831 const struct load_command* cmd = cmds;
1832 for (uint32_t i = 0; i < cmd_count; ++i) {
1833 switch (cmd->cmd) {
1834 case LC_SEGMENT_COMMAND:
1835 {
1836 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1837 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1838 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1839 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1840 const uint8_t type = sect->flags & SECTION_TYPE;
1841 if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
1842 // reset each jmp entry in this section
1843 const uint32_t indirectTableOffset = sect->reserved1;
1844 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1845 uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
1846 uint8_t* end = start + sect->size;
1847 uintptr_t dyldHandler = (uintptr_t)&stub_binding_helper_i386_old;
1848 uint32_t entryIndex = 0;
1849 for (uint8_t* entry = start; entry < end; entry += 5, ++entryIndex) {
1850 bool installLazyHandler = true;
1851 // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes
1852 // if the instruction is updated by one thread while being executed by another
1853 if ( ((uint32_t)entry & 0xFFFFFFC0) != ((uint32_t)entry+4 & 0xFFFFFFC0) ) {
1854 // need to bind this now to avoid a potential problem if bound lazily
1855 uint32_t symbolIndex = indirectTable[indirectTableOffset + entryIndex];
1856 // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used
1857 if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
1858 const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
1859 const ImageLoader* image = NULL;
1860 try {
1861 uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], this->usesTwoLevelNameSpace(), false, false, &image);
1862 symbolAddr = this->bindIndirectSymbol((uintptr_t*)entry, sect, symbolName, symbolAddr, image, context);
1863 ++fgTotalBindFixups;
1864 uint32_t rel32 = symbolAddr - (((uint32_t)entry)+5);
1865 entry[0] = 0xE9; // JMP rel32
1866 entry[1] = rel32 & 0xFF;
1867 entry[2] = (rel32 >> 8) & 0xFF;
1868 entry[3] = (rel32 >> 16) & 0xFF;
1869 entry[4] = (rel32 >> 24) & 0xFF;
1870 installLazyHandler = false;
1871 }
1872 catch (const char* msg) {
1873 // ignore errors when binding symbols early
1874 // maybe the function is never called, and therefore erroring out now would be a regression
1875 }
1876 }
1877 }
1878 if ( installLazyHandler ) {
1879 uint32_t rel32 = dyldHandler - (((uint32_t)entry)+5);
1880 entry[0] = 0xE8; // CALL rel32
1881 entry[1] = rel32 & 0xFF;
1882 entry[2] = (rel32 >> 8) & 0xFF;
1883 entry[3] = (rel32 >> 16) & 0xFF;
1884 entry[4] = (rel32 >> 24) & 0xFF;
1885 }
1886 }
1887 }
1888 }
1889 }
1890 }
1891 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1892 }
1893 }
1894 }
1895 #endif // __i386__
1896
1897
1898 void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazysBound)
1899 {
1900 CRSetCrashLogMessage2(this->getPath());
1901 #if __i386__
1902 this->initializeLazyStubs(context);
1903 #endif
1904
1905 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
1906 // note: flat-namespace binaries need to have imports rebound (even if correctly prebound)
1907 if ( this->usablePrebinding(context) ) {
1908 // binding already up to date
1909 }
1910 else {
1911 // no valid prebinding, so bind symbols.
1912 // values bound by name are stored two different ways in classic mach-o:
1913
1914 #if TEXT_RELOC_SUPPORT
1915 // if there are __TEXT fixups, temporarily make __TEXT writable
1916 if ( fTextSegmentBinds )
1917 this->makeTextSegmentWritable(context, true);
1918 #endif
1919
1920 // 1) external relocations are used for data initialized to external symbols
1921 this->doBindExternalRelocations(context);
1922
1923 // 2) "indirect symbols" are used for code references to external symbols
1924 // if this image is in the shared cache, there is no way to reset the lazy pointers, so bind them now
1925 this->bindIndirectSymbolPointers(context, true, forceLazysBound || fInSharedCache);
1926
1927 #if TEXT_RELOC_SUPPORT
1928 // if there were __TEXT fixups, restore write protection
1929 if ( fTextSegmentBinds )
1930 this->makeTextSegmentWritable(context, false);
1931 #endif
1932 }
1933
1934 // set up dyld entry points in image
1935 this->setupLazyPointerHandler(context);
1936
1937 CRSetCrashLogMessage2(NULL);
1938 }
1939
1940 void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context)
1941 {
1942 // some API called requested that all lazy pointers in this image be force bound
1943 this->bindIndirectSymbolPointers(context, false, true);
1944 }
1945
1946 void ImageLoaderMachOClassic::doInterpose(const LinkContext& context)
1947 {
1948 if ( context.verboseInterposing )
1949 dyld::log("dyld: interposing %lu tuples onto: %s\n", fgInterposingTuples.size(), this->getPath());
1950
1951 // scan indirect symbols
1952 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1953 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1954 const struct load_command* cmd = cmds;
1955 for (uint32_t i = 0; i < cmd_count; ++i) {
1956 switch (cmd->cmd) {
1957 case LC_SEGMENT_COMMAND:
1958 {
1959 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1960 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1961 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1962 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1963 const uint8_t type = sect->flags & SECTION_TYPE;
1964 if ( (type == S_NON_LAZY_SYMBOL_POINTERS) || (type == S_LAZY_SYMBOL_POINTERS) ) {
1965 const size_t pointerCount = sect->size / sizeof(uintptr_t);
1966 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
1967 for (size_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) {
1968 uintptr_t newValue = interposedAddress(context, symbolPointers[pointerIndex], this);
1969 if ( newValue != symbolPointers[pointerIndex] )
1970 symbolPointers[pointerIndex] = newValue;
1971 }
1972 }
1973 #if __i386__
1974 // i386 has special self-modifying stubs that might be prebound to "JMP rel32" that need checking
1975 else if ( (type == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
1976 // check each jmp entry in this section
1977 uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
1978 uint8_t* end = start + sect->size;
1979 for (uint8_t* entry = start; entry < end; entry += 5) {
1980 if ( entry[0] == 0xE9 ) { // 0xE9 == JMP
1981 uint32_t rel32 = *((uint32_t*)&entry[1]); // assume unaligned load of uint32_t is ok
1982 uint32_t target = (uint32_t)&entry[5] + rel32;
1983 uint32_t newTarget = interposedAddress(context, target, this);
1984 if ( newTarget != target ) {
1985 uint32_t newRel32 = newTarget - (uint32_t)&entry[5];
1986 *((uint32_t*)&entry[1]) = newRel32; // assume unaligned store of uint32_t is ok
1987 }
1988 }
1989 }
1990 }
1991 #endif
1992 }
1993 }
1994 break;
1995 }
1996 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1997 }
1998
1999 // scan external relocations
2000 const uintptr_t relocBase = this->getRelocBase();
2001 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
2002 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
2003 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
2004 if (reloc->r_length == RELOC_SIZE) {
2005 switch(reloc->r_type) {
2006 case POINTER_RELOC:
2007 {
2008 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
2009 uintptr_t value = *location;
2010 uintptr_t newValue = interposedAddress(context, value, this);
2011 if ( newValue != value )
2012 *location = newValue;
2013 }
2014 break;
2015 }
2016 }
2017 }
2018 }
2019
2020 void ImageLoaderMachOClassic::dynamicInterpose(const LinkContext& context)
2021 {
2022 if ( context.verboseInterposing )
2023 dyld::log("dyld: dynamic interposing %lu tuples onto image: %s\n", context.dynamicInterposeCount, this->getPath());
2024
2025 // scan indirect symbols
2026 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2027 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2028 const struct load_command* cmd = cmds;
2029 for (uint32_t i = 0; i < cmd_count; ++i) {
2030 switch (cmd->cmd) {
2031 case LC_SEGMENT_COMMAND:
2032 {
2033 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2034 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2035 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2036 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2037 const uint8_t type = sect->flags & SECTION_TYPE;
2038 if ( (type == S_NON_LAZY_SYMBOL_POINTERS) || (type == S_LAZY_SYMBOL_POINTERS) ) {
2039 const size_t pointerCount = sect->size / sizeof(uintptr_t);
2040 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
2041 for (size_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) {
2042 for(size_t j=0; j < context.dynamicInterposeCount; ++j) {
2043 // replace all references to 'replacee' with 'replacement'
2044 if ( symbolPointers[pointerIndex] == (uintptr_t)context.dynamicInterposeArray[j].replacee ) {
2045 if ( context.verboseInterposing ) {
2046 dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n",
2047 &symbolPointers[pointerIndex], context.dynamicInterposeArray[j].replacee, context.dynamicInterposeArray[j].replacement, this->getPath());
2048 }
2049 symbolPointers[pointerIndex] = (uintptr_t)context.dynamicInterposeArray[j].replacement;
2050 }
2051 }
2052 }
2053 }
2054 }
2055 }
2056 break;
2057 }
2058 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2059 }
2060
2061 // scan external relocations
2062 const uintptr_t relocBase = this->getRelocBase();
2063 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
2064 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
2065 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
2066 if (reloc->r_length == RELOC_SIZE) {
2067 switch(reloc->r_type) {
2068 case POINTER_RELOC:
2069 {
2070 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
2071 for(size_t i=0; i < context.dynamicInterposeCount; ++i) {
2072 // replace all references to 'replacee' with 'replacement'
2073 if ( *location == (uintptr_t)context.dynamicInterposeArray[i].replacee ) {
2074 if ( context.verboseInterposing ) {
2075 dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n",
2076 location, context.dynamicInterposeArray[i].replacee, context.dynamicInterposeArray[i].replacement, this->getPath());
2077 }
2078 *location = (uintptr_t)context.dynamicInterposeArray[i].replacement;
2079 }
2080 }
2081 }
2082 break;
2083 }
2084 }
2085 }
2086 }
2087
2088
2089 const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr, const void** closestAddr) const
2090 {
2091 uintptr_t targetAddress = (uintptr_t)addr - fSlide;
2092 const struct macho_nlist* bestSymbol = NULL;
2093 // first walk all global symbols
2094 const struct macho_nlist* const globalsStart = &fSymbolTable[fDynamicInfo->iextdefsym];
2095 const struct macho_nlist* const globalsEnd= &globalsStart[fDynamicInfo->nextdefsym];
2096 for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
2097 if ( (s->n_type & N_TYPE) == N_SECT ) {
2098 if ( bestSymbol == NULL ) {
2099 if ( s->n_value <= targetAddress )
2100 bestSymbol = s;
2101 }
2102 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2103 bestSymbol = s;
2104 }
2105 }
2106 }
2107 // next walk all local symbols
2108 const struct macho_nlist* const localsStart = &fSymbolTable[fDynamicInfo->ilocalsym];
2109 const struct macho_nlist* const localsEnd= &localsStart[fDynamicInfo->nlocalsym];
2110 for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
2111 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
2112 if ( bestSymbol == NULL ) {
2113 if ( s->n_value <= targetAddress )
2114 bestSymbol = s;
2115 }
2116 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2117 bestSymbol = s;
2118 }
2119 }
2120 }
2121 if ( bestSymbol != NULL ) {
2122 #if __arm__
2123 if (bestSymbol->n_desc & N_ARM_THUMB_DEF)
2124 *closestAddr = (void*)((bestSymbol->n_value | 1) + fSlide);
2125 else
2126 *closestAddr = (void*)(bestSymbol->n_value + fSlide);
2127 #else
2128 *closestAddr = (void*)(bestSymbol->n_value + fSlide);
2129 #endif
2130 return &fStrings[bestSymbol->n_un.n_strx];
2131 }
2132 return NULL;
2133 }
2134
2135