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