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