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