]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoaderMachO.cpp
dyld-210.2.3.tar.gz
[apple/dyld.git] / src / ImageLoaderMachO.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 // work around until conformance work is complete rdar://problem/4508801
26 #define __srr0 srr0
27 #define __eip eip
28 #define __rip rip
29
30 #define __STDC_LIMIT_MACROS
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/nlist.h>
42 #include <sys/sysctl.h>
43 #include <libkern/OSAtomic.h>
44 #include <libkern/OSCacheControl.h>
45 #include <stdint.h>
46
47 #include "ImageLoaderMachO.h"
48 #include "ImageLoaderMachOCompressed.h"
49 #include "ImageLoaderMachOClassic.h"
50 #include "mach-o/dyld_images.h"
51
52 // <rdar://problem/8718137> use stack guard random value to add padding between dylibs
53 extern "C" long __stack_chk_guard;
54
55 #ifndef LC_LOAD_UPWARD_DYLIB
56 #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
57 #endif
58
59 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
60 #if __LP64__
61 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
62 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
63 struct macho_segment_command : public segment_command_64 {};
64 struct macho_section : public section_64 {};
65 struct macho_routines_command : public routines_command_64 {};
66 #else
67 #define LC_SEGMENT_COMMAND LC_SEGMENT
68 #define LC_ROUTINES_COMMAND LC_ROUTINES
69 struct macho_segment_command : public segment_command {};
70 struct macho_section : public section {};
71 struct macho_routines_command : public routines_command {};
72 #endif
73
74 uint32_t ImageLoaderMachO::fgSymbolTableBinarySearchs = 0;
75 uint32_t ImageLoaderMachO::fgSymbolTrieSearchs = 0;
76
77
78 ImageLoaderMachO::ImageLoaderMachO(const macho_header* mh, const char* path, unsigned int segCount,
79 uint32_t segOffsets[], unsigned int libCount)
80 : ImageLoader(path, libCount), fMachOData((uint8_t*)mh), fLinkEditBase(NULL), fSlide(0),
81 fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),
82 fSegmentsCount(segCount), fIsSplitSeg(false), fInSharedCache(false),
83 #if TEXT_RELOC_SUPPORT
84 fTextSegmentRebases(false),
85 fTextSegmentBinds(false),
86 #endif
87 #if __i386__
88 fReadOnlyImportSegment(false),
89 #endif
90 fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
91 fHasInitializers(false), fHasTerminators(false), fRegisteredAsRequiresCoalescing(false)
92 {
93 fIsSplitSeg = ((mh->flags & MH_SPLIT_SEGS) != 0);
94
95 // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put
96 // each SegmentMachO object in array at end of ImageLoaderMachO object
97 const uint32_t cmd_count = mh->ncmds;
98 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
99 const struct load_command* cmd = cmds;
100 for (uint32_t i = 0, segIndex=0; i < cmd_count; ++i) {
101 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
102 const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
103 // ignore zero-sized segments
104 if ( segCmd->vmsize != 0 ) {
105 // record offset of load command
106 segOffsets[segIndex++] = (uint8_t*)segCmd - fMachOData;
107 }
108 }
109 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
110 }
111
112 }
113
114
115 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
116 void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* path, bool* compressed,
117 unsigned int* segCount, unsigned int* libCount,
118 const linkedit_data_command** codeSigCmd)
119 {
120 *compressed = false;
121 *segCount = 0;
122 *libCount = 0;
123 *codeSigCmd = NULL;
124 struct macho_segment_command* segCmd;
125 #if CODESIGNING_SUPPORT
126 bool foundLoadCommandSegment = false;
127 #endif
128 const uint32_t cmd_count = mh->ncmds;
129 const struct load_command* const startCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
130 const struct load_command* const endCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header) + mh->sizeofcmds);
131 const struct load_command* cmd = startCmds;
132 for (uint32_t i = 0; i < cmd_count; ++i) {
133 switch (cmd->cmd) {
134 case LC_DYLD_INFO:
135 case LC_DYLD_INFO_ONLY:
136 *compressed = true;
137 break;
138 case LC_SEGMENT_COMMAND:
139 segCmd = (struct macho_segment_command*)cmd;
140 // ignore zero-sized segments
141 if ( segCmd->vmsize != 0 )
142 *segCount += 1;
143 #if CODESIGNING_SUPPORT
144 // <rdar://problem/7942521> all load commands must be in an executable segment
145 if ( (segCmd->fileoff < mh->sizeofcmds) && (segCmd->filesize != 0) ) {
146 if ( (segCmd->fileoff != 0) || (segCmd->filesize < (mh->sizeofcmds+sizeof(macho_header))) )
147 dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd->segname);
148 if ( segCmd->initprot != (VM_PROT_READ | VM_PROT_EXECUTE) )
149 dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd->segname);
150 foundLoadCommandSegment = true;
151 }
152 #endif
153 break;
154 case LC_LOAD_DYLIB:
155 case LC_LOAD_WEAK_DYLIB:
156 case LC_REEXPORT_DYLIB:
157 case LC_LOAD_UPWARD_DYLIB:
158 *libCount += 1;
159 break;
160 case LC_CODE_SIGNATURE:
161 *codeSigCmd = (struct linkedit_data_command*)cmd; // only support one LC_CODE_SIGNATURE per image
162 break;
163 }
164 uint32_t cmdLength = cmd->cmdsize;
165 cmd = (const struct load_command*)(((char*)cmd)+cmdLength);
166 if ( (cmd > endCmds) || (cmd < startCmds) ) {
167 dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
168 i, cmdLength, mh->sizeofcmds, path);
169 }
170 }
171
172 #if CODESIGNING_SUPPORT
173 if ( ! foundLoadCommandSegment )
174 throw "load commands not in a segment";
175 #endif
176
177 // fSegmentsArrayCount is only 8-bits
178 if ( *segCount > 255 )
179 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path);
180
181 // fSegmentsArrayCount is only 8-bits
182 if ( *libCount > 4095 )
183 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path);
184
185 if ( needsAddedLibSystemDepency(*libCount, mh) )
186 *libCount = 1;
187 }
188
189
190
191 // create image for main executable
192 ImageLoader* ImageLoaderMachO::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, const LinkContext& context)
193 {
194 //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
195 // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
196 bool compressed;
197 unsigned int segCount;
198 unsigned int libCount;
199 const linkedit_data_command* codeSigCmd;
200 sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, &codeSigCmd);
201 // instantiate concrete class based on content of load commands
202 if ( compressed )
203 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
204 else
205 return ImageLoaderMachOClassic::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
206 }
207
208
209 // create image by mapping in a mach-o file
210 ImageLoader* ImageLoaderMachO::instantiateFromFile(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offsetInFat,
211 uint64_t lenInFat, const struct stat& info, const LinkContext& context)
212 {
213 // get load commands
214 const unsigned int dataSize = sizeof(macho_header) + ((macho_header*)firstPage)->sizeofcmds;
215 uint8_t buffer[dataSize];
216 const uint8_t* fileData = firstPage;
217 if ( dataSize > 4096 ) {
218 // only read more if cmds take up more space than first page
219 fileData = buffer;
220 memcpy(buffer, firstPage, 4096);
221 pread(fd, &buffer[4096], dataSize-4096, offsetInFat+4096);
222 }
223
224 bool compressed;
225 unsigned int segCount;
226 unsigned int libCount;
227 const linkedit_data_command* codeSigCmd;
228 sniffLoadCommands((const macho_header*)fileData, path, &compressed, &segCount, &libCount, &codeSigCmd);
229 // instantiate concrete class based on content of load commands
230 if ( compressed )
231 return ImageLoaderMachOCompressed::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context);
232 else
233 return ImageLoaderMachOClassic::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context);
234 }
235
236 // create image by using cached mach-o file
237 ImageLoader* ImageLoaderMachO::instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info, const LinkContext& context)
238 {
239 // instantiate right concrete class
240 bool compressed;
241 unsigned int segCount;
242 unsigned int libCount;
243 const linkedit_data_command* codeSigCmd;
244 sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, &codeSigCmd);
245 // instantiate concrete class based on content of load commands
246 if ( compressed )
247 return ImageLoaderMachOCompressed::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
248 else
249 return ImageLoaderMachOClassic::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
250 }
251
252 // create image by copying an in-memory mach-o file
253 ImageLoader* ImageLoaderMachO::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, const LinkContext& context)
254 {
255 bool compressed;
256 unsigned int segCount;
257 unsigned int libCount;
258 const linkedit_data_command* sigcmd;
259 sniffLoadCommands(mh, moduleName, &compressed, &segCount, &libCount, &sigcmd);
260 // instantiate concrete class based on content of load commands
261 if ( compressed )
262 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
263 else
264 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
265 }
266
267
268
269 void ImageLoaderMachO::parseLoadCmds()
270 {
271 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
272 for(unsigned int i=0; i < fSegmentsCount; ++i) {
273 // set up pointer to __LINKEDIT segment
274 if ( strcmp(segName(i),"__LINKEDIT") == 0 )
275 fLinkEditBase = (uint8_t*)(segActualLoadAddress(i) - segFileOffset(i));
276 #if TEXT_RELOC_SUPPORT
277 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
278 if ( strcmp(segName(i),"__TEXT") == 0 ) {
279 if ( segHasRebaseFixUps(i) && (fSlide != 0) )
280 fTextSegmentRebases = true;
281 if ( segHasBindFixUps(i) )
282 fTextSegmentBinds = true;
283 }
284 #endif
285 #if __i386__
286 if ( segIsReadOnlyImport(i) )
287 fReadOnlyImportSegment = true;
288 #endif
289 // some segment always starts at beginning of file and contains mach_header and load commands
290 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
291 fMachOData = (uint8_t*)(segActualLoadAddress(i));
292 }
293 }
294
295 // keep count of prebound images with weak exports
296 if ( this->participatesInCoalescing() ) {
297 ++fgImagesRequiringCoalescing;
298 fRegisteredAsRequiresCoalescing = true;
299 if ( this->hasCoalescedExports() )
300 ++fgImagesHasWeakDefinitions;
301 }
302
303 // keep count of images used in shared cache
304 if ( fInSharedCache )
305 ++fgImagesUsedFromSharedCache;
306
307 // walk load commands (mapped in at start of __TEXT segment)
308 const dyld_info_command* dyldInfo = NULL;
309 const macho_nlist* symbolTable = NULL;
310 const char* symbolTableStrings = NULL;
311 const struct load_command* firstUnknownCmd = NULL;
312 const struct version_min_command* minOSVersionCmd = NULL;
313 const dysymtab_command* dynSymbolTable = NULL;
314 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
315 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
316 const struct load_command* cmd = cmds;
317 for (uint32_t i = 0; i < cmd_count; ++i) {
318 switch (cmd->cmd) {
319 case LC_SYMTAB:
320 {
321 const struct symtab_command* symtab = (struct symtab_command*)cmd;
322 symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
323 symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
324 }
325 break;
326 case LC_DYSYMTAB:
327 dynSymbolTable = (struct dysymtab_command*)cmd;
328 break;
329 case LC_SUB_UMBRELLA:
330 fHasSubUmbrella = true;
331 break;
332 case LC_SUB_FRAMEWORK:
333 fInUmbrella = true;
334 break;
335 case LC_SUB_LIBRARY:
336 fHasSubLibraries = true;
337 break;
338 case LC_ROUTINES_COMMAND:
339 fHasDashInit = true;
340 break;
341 case LC_DYLD_INFO:
342 case LC_DYLD_INFO_ONLY:
343 dyldInfo = (struct dyld_info_command*)cmd;
344 break;
345 case LC_SEGMENT_COMMAND:
346 {
347 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
348 const bool isTextSeg = (strcmp(seg->segname, "__TEXT") == 0);
349 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
350 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
351 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
352 const uint8_t type = sect->flags & SECTION_TYPE;
353 if ( type == S_MOD_INIT_FUNC_POINTERS )
354 fHasInitializers = true;
355 else if ( type == S_MOD_TERM_FUNC_POINTERS )
356 fHasTerminators = true;
357 else if ( type == S_DTRACE_DOF )
358 fHasDOFSections = true;
359 else if ( isTextSeg && (strcmp(sect->sectname, "__eh_frame") == 0) )
360 fEHFrameSectionOffset = (uint8_t*)sect - fMachOData;
361 else if ( isTextSeg && (strcmp(sect->sectname, "__unwind_info") == 0) )
362 fUnwindInfoSectionOffset = (uint8_t*)sect - fMachOData;;
363 }
364 }
365 break;
366 case LC_TWOLEVEL_HINTS:
367 // no longer supported
368 break;
369 case LC_ID_DYLIB:
370 {
371 fDylibIDOffset = (uint8_t*)cmd - fMachOData;
372 }
373 break;
374 case LC_RPATH:
375 case LC_LOAD_WEAK_DYLIB:
376 case LC_REEXPORT_DYLIB:
377 case LC_LOAD_UPWARD_DYLIB:
378 case LC_MAIN:
379 // do nothing, just prevent LC_REQ_DYLD exception from occuring
380 break;
381 case LC_VERSION_MIN_MACOSX:
382 case LC_VERSION_MIN_IPHONEOS:
383 minOSVersionCmd = (version_min_command*)cmd;
384 break;
385 default:
386 if ( (cmd->cmd & LC_REQ_DYLD) != 0 ) {
387 if ( firstUnknownCmd == NULL )
388 firstUnknownCmd = cmd;
389 }
390 break;
391 }
392 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
393 }
394 if ( firstUnknownCmd != NULL ) {
395 if ( minOSVersionCmd != NULL ) {
396 dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)",
397 this->getShortName(),
398 minOSVersionCmd->version >> 16, ((minOSVersionCmd->version >> 8) & 0xff),
399 firstUnknownCmd->cmd);
400 }
401 else {
402 dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd->cmd);
403 }
404 }
405
406
407 if ( dyldInfo != NULL )
408 this->setDyldInfo(dyldInfo);
409 if ( symbolTable != NULL)
410 this->setSymbolTableInfo(symbolTable, symbolTableStrings, dynSymbolTable);
411
412 }
413
414 // don't do this work in destructor because we need object to be full subclass
415 // for UnmapSegments() to work
416 void ImageLoaderMachO::destroy()
417 {
418 // update count of images with weak exports
419 if ( fRegisteredAsRequiresCoalescing ) {
420 --fgImagesRequiringCoalescing;
421 if ( this->hasCoalescedExports() )
422 --fgImagesHasWeakDefinitions;
423 }
424
425 // keep count of images used in shared cache
426 if ( fInSharedCache )
427 --fgImagesUsedFromSharedCache;
428
429 // unmap image when done
430 UnmapSegments();
431 }
432
433
434 unsigned int ImageLoaderMachO::segmentCount() const
435 {
436 return fSegmentsCount;
437 }
438
439
440 const macho_segment_command* ImageLoaderMachO::segLoadCommand(unsigned int segIndex) const
441 {
442 uint32_t* lcOffsets = this->segmentCommandOffsets();
443 uint32_t lcOffset = lcOffsets[segIndex];
444 return (macho_segment_command*)(&fMachOData[lcOffset]);
445 }
446
447 const char* ImageLoaderMachO::segName(unsigned int segIndex) const
448 {
449 return segLoadCommand(segIndex)->segname;
450 }
451
452
453 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex) const
454 {
455 return segLoadCommand(segIndex)->vmsize;
456 }
457
458
459 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex) const
460 {
461 return segLoadCommand(segIndex)->filesize;
462 }
463
464
465 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex)
466 {
467 return ( segWriteable(segIndex) && (segSize(segIndex) > segFileSize(segIndex)) );
468 }
469
470
471 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex) const
472 {
473 return segLoadCommand(segIndex)->fileoff;
474 }
475
476
477 bool ImageLoaderMachO::segReadable(unsigned int segIndex) const
478 {
479 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_READ) != 0);
480 }
481
482
483 bool ImageLoaderMachO::segWriteable(unsigned int segIndex) const
484 {
485 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_WRITE) != 0);
486 }
487
488
489 bool ImageLoaderMachO::segExecutable(unsigned int segIndex) const
490 {
491 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_EXECUTE) != 0);
492 }
493
494
495 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex) const
496 {
497 return (segLoadCommand(segIndex)->initprot == 0);
498 }
499
500 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex) const
501 {
502 return (segLoadCommand(segIndex)->vmaddr != 0);
503 }
504
505 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex) const
506 {
507 return segLoadCommand(segIndex)->vmaddr;
508 }
509
510 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex) const
511 {
512 return segLoadCommand(segIndex)->vmaddr + fSlide;
513 }
514
515
516 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex) const
517 {
518 return segActualLoadAddress(segIndex) + segSize(segIndex);
519 }
520
521 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex) const
522 {
523 // scan sections for fix-up bit
524 const macho_segment_command* segCmd = segLoadCommand(segIndex);
525 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
526 const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
527 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
528 if ( (sect->flags & S_ATTR_LOC_RELOC) != 0 )
529 return true;
530 }
531 return false;
532 }
533
534 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex) const
535 {
536 // scan sections for fix-up bit
537 const macho_segment_command* segCmd = segLoadCommand(segIndex);
538 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
539 const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
540 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
541 if ( (sect->flags & S_ATTR_EXT_RELOC) != 0 )
542 return true;
543 }
544 return false;
545 }
546
547 #if __i386__
548 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex) const
549 {
550 const macho_segment_command* segCmd = segLoadCommand(segIndex);
551 return ( (segCmd->initprot & VM_PROT_EXECUTE)
552 && ((segCmd->initprot & VM_PROT_WRITE) == 0)
553 && (strcmp(segCmd->segname, "__IMPORT") == 0) );
554 }
555 #endif
556
557
558 void ImageLoaderMachO::UnmapSegments()
559 {
560 // usually unmap image when done
561 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped) ) {
562 // unmap TEXT segment last because it contains load command being inspected
563 unsigned int textSegmentIndex = 0;
564 for(unsigned int i=0; i < fSegmentsCount; ++i) {
565 //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this));
566 if ( strcmp(segName(i), "__TEXT") == 0 ) {
567 textSegmentIndex = i;
568 }
569 else {
570 // update stats
571 --ImageLoader::fgTotalSegmentsMapped;
572 ImageLoader::fgTotalBytesMapped -= segSize(i);
573 munmap((void*)segActualLoadAddress(i), segSize(i));
574 }
575 }
576 // now unmap TEXT
577 --ImageLoader::fgTotalSegmentsMapped;
578 ImageLoader::fgTotalBytesMapped -= segSize(textSegmentIndex);
579 munmap((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex));
580 }
581 }
582
583
584 // prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code
585 void ImageLoaderMachO::preFetchDATA(int fd, uint64_t offsetInFat, const LinkContext& context)
586 {
587 if ( context.linkingMainExecutable ) {
588 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
589 if ( segWriteable(i) && (segFileSize(i) > 0) ) {
590 // prefetch writable segment that have mmap'ed regions
591 radvisory advice;
592 advice.ra_offset = offsetInFat + segFileOffset(i);
593 advice.ra_count = segFileSize(i);
594 // limit prefetch to 1MB (256 pages)
595 if ( advice.ra_count > 1024*1024 )
596 advice.ra_count = 1024*1024;
597 // don't prefetch single pages, let them fault in
598 fgTotalBytesPreFetched += advice.ra_count;
599 fcntl(fd, F_RDADVISE, &advice);
600 if ( context.verboseMapping ) {
601 dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n",
602 segName(i), segActualLoadAddress(i), segActualLoadAddress(i)+advice.ra_count-1);
603 }
604 }
605 }
606 }
607 }
608
609
610 bool ImageLoaderMachO::segmentsMustSlideTogether() const
611 {
612 return true;
613 }
614
615 bool ImageLoaderMachO::segmentsCanSlide() const
616 {
617 return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable());
618 }
619
620 bool ImageLoaderMachO::isBundle() const
621 {
622 const macho_header* mh = (macho_header*)fMachOData;
623 return ( mh->filetype == MH_BUNDLE );
624 }
625
626 bool ImageLoaderMachO::isDylib() const
627 {
628 const macho_header* mh = (macho_header*)fMachOData;
629 return ( mh->filetype == MH_DYLIB );
630 }
631
632 bool ImageLoaderMachO::isExecutable() const
633 {
634 const macho_header* mh = (macho_header*)fMachOData;
635 return ( mh->filetype == MH_EXECUTE );
636 }
637
638 bool ImageLoaderMachO::isPositionIndependentExecutable() const
639 {
640 const macho_header* mh = (macho_header*)fMachOData;
641 return ( (mh->filetype == MH_EXECUTE) && ((mh->flags & MH_PIE) != 0) );
642 }
643
644
645 bool ImageLoaderMachO::forceFlat() const
646 {
647 const macho_header* mh = (macho_header*)fMachOData;
648 return ( (mh->flags & MH_FORCE_FLAT) != 0 );
649 }
650
651 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
652 {
653 const macho_header* mh = (macho_header*)fMachOData;
654 return ( (mh->flags & MH_TWOLEVEL) != 0 );
655 }
656
657 bool ImageLoaderMachO::isPrebindable() const
658 {
659 const macho_header* mh = (macho_header*)fMachOData;
660 return ( (mh->flags & MH_PREBOUND) != 0 );
661 }
662
663 bool ImageLoaderMachO::hasCoalescedExports() const
664 {
665 const macho_header* mh = (macho_header*)fMachOData;
666 return ( (mh->flags & MH_WEAK_DEFINES) != 0 );
667 }
668
669 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const
670 {
671 const macho_header* mh = (macho_header*)fMachOData;
672 return ( (mh->flags & MH_BINDS_TO_WEAK) != 0 );
673 }
674
675 bool ImageLoaderMachO::participatesInCoalescing() const
676 {
677 const macho_header* mh = (macho_header*)fMachOData;
678 // if image is loaded with RTLD_LOCAL, then its symbols' visibility
679 // is reduced and it can't coalesce with other images
680 if ( this->hasHiddenExports() )
681 return false;
682 return ( (mh->flags & (MH_WEAK_DEFINES|MH_BINDS_TO_WEAK)) != 0 );
683 }
684
685
686
687 void ImageLoaderMachO::setSlide(intptr_t slide)
688 {
689 fSlide = slide;
690 }
691
692 #if CODESIGNING_SUPPORT
693 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile)
694 {
695 fsignatures_t siginfo;
696 siginfo.fs_file_start=offsetInFatFile; // start of mach-o slice in fat file
697 siginfo.fs_blob_start=(void*)(codeSigCmd->dataoff); // start of CD in mach-o file
698 siginfo.fs_blob_size=codeSigCmd->datasize; // size of CD
699 int result = fcntl(fd, F_ADDFILESIGS, &siginfo);
700 if ( result == -1 )
701 dyld::log("dyld: F_ADDFILESIGS failed for %s with errno=%d\n", this->getPath(), errno);
702 //dyld::log("dyld: registered code signature for %s\n", this->getPath());
703 }
704 #endif
705
706
707 const char* ImageLoaderMachO::getInstallPath() const
708 {
709 if ( fDylibIDOffset != 0 ) {
710 const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]);
711 return (char*)dylibID + dylibID->dylib.name.offset;
712 }
713 return NULL;
714 }
715
716 void ImageLoaderMachO::registerInterposing()
717 {
718 // mach-o files advertise interposing by having a __DATA __interpose section
719 struct InterposeData { uintptr_t replacement; uintptr_t replacee; };
720 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
721 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
722 const struct load_command* cmd = cmds;
723 for (uint32_t i = 0; i < cmd_count; ++i) {
724 switch (cmd->cmd) {
725 case LC_SEGMENT_COMMAND:
726 {
727 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
728 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
729 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
730 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
731 if ( ((sect->flags & SECTION_TYPE) == S_INTERPOSING) || ((strcmp(sect->sectname, "__interpose") == 0) && (strcmp(seg->segname, "__DATA") == 0)) ) {
732 const InterposeData* interposeArray = (InterposeData*)(sect->addr + fSlide);
733 const unsigned int count = sect->size / sizeof(InterposeData);
734 for (uint32_t i=0; i < count; ++i) {
735 ImageLoader::InterposeTuple tuple;
736 tuple.replacement = interposeArray[i].replacement;
737 tuple.replacementImage = this;
738 tuple.replacee = interposeArray[i].replacee;
739 // <rdar://problem/7937695> verify that replacement is in this image
740 if ( this->containsAddress((void*)tuple.replacement) ) {
741 for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
742 if ( it->replacee == tuple.replacee ) {
743 tuple.replacee = it->replacement;
744 }
745 }
746 ImageLoader::fgInterposingTuples.push_back(tuple);
747 }
748 }
749 }
750 }
751 }
752 break;
753 }
754 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
755 }
756 }
757
758 void* ImageLoaderMachO::getThreadPC() const
759 {
760 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
761 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
762 const struct load_command* cmd = cmds;
763 for (uint32_t i = 0; i < cmd_count; ++i) {
764 if ( cmd->cmd == LC_MAIN ) {
765 entry_point_command* mainCmd = (entry_point_command*)cmd;
766 void* entry = (void*)(mainCmd->entryoff + (char*)fMachOData);
767 // <rdar://problem/8543820&9228031> verify entry point is in image
768 if ( this->containsAddress(entry) )
769 return entry;
770 else
771 throw "LC_MAIN entryoff is out of range";
772 }
773 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
774 }
775 return NULL;
776 }
777
778
779 void* ImageLoaderMachO::getMain() const
780 {
781 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
782 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
783 const struct load_command* cmd = cmds;
784 for (uint32_t i = 0; i < cmd_count; ++i) {
785 switch (cmd->cmd) {
786 case LC_UNIXTHREAD:
787 {
788 #if __i386__
789 const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
790 void* entry = (void*)(registers->eip + fSlide);
791 #elif __x86_64__
792 const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
793 void* entry = (void*)(registers->rip + fSlide);
794 #elif __arm__
795 const arm_thread_state_t* registers = (arm_thread_state_t*)(((char*)cmd) + 16);
796 void* entry = (void*)(registers->__pc + fSlide);
797 #else
798 #warning need processor specific code
799 #endif
800 // <rdar://problem/8543820&9228031> verify entry point is in image
801 if ( this->containsAddress(entry) ) {
802 return entry;
803 }
804 }
805 break;
806 }
807 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
808 }
809 throw "no valid entry point";
810 }
811
812 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh)
813 {
814 // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem
815 if ( libCount > 1 )
816 return false;
817
818 // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
819 if ( mh->filetype == MH_EXECUTE )
820 return false;
821
822 bool isNonOSdylib = false;
823 const uint32_t cmd_count = mh->ncmds;
824 const struct load_command* const cmds = (struct load_command*)((uint8_t*)mh+sizeof(macho_header));
825 const struct load_command* cmd = cmds;
826 for (uint32_t i = 0; i < cmd_count; ++i) {
827 switch (cmd->cmd) {
828 case LC_LOAD_DYLIB:
829 case LC_LOAD_WEAK_DYLIB:
830 case LC_REEXPORT_DYLIB:
831 case LC_LOAD_UPWARD_DYLIB:
832 return false;
833 case LC_ID_DYLIB:
834 {
835 const dylib_command* dylibID = (dylib_command*)cmd;
836 const char* installPath = (char*)cmd + dylibID->dylib.name.offset;
837 // It is OK for OS dylibs (libSystem or libmath or Rosetta shims) to have no dependents
838 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first
839 // <rdar://problem/6497528> rosetta circular dependency spew
840 isNonOSdylib = ( (strncmp(installPath, "/usr/lib/", 9) != 0) && (strncmp(installPath, "/usr/libexec/oah/Shims", 9) != 0) );
841 }
842 break;
843 }
844 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
845 }
846 return isNonOSdylib;
847 }
848
849
850 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs[])
851 {
852 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header*)fMachOData) ) {
853 DependentLibraryInfo* lib = &libs[0];
854 lib->name = "/usr/lib/libSystem.B.dylib";
855 lib->info.checksum = 0;
856 lib->info.minVersion = 0;
857 lib->info.maxVersion = 0;
858 lib->required = false;
859 lib->reExported = false;
860 lib->upward = false;
861 }
862 else {
863 uint32_t index = 0;
864 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
865 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
866 const struct load_command* cmd = cmds;
867 for (uint32_t i = 0; i < cmd_count; ++i) {
868 switch (cmd->cmd) {
869 case LC_LOAD_DYLIB:
870 case LC_LOAD_WEAK_DYLIB:
871 case LC_REEXPORT_DYLIB:
872 case LC_LOAD_UPWARD_DYLIB:
873 {
874 const struct dylib_command* dylib = (struct dylib_command*)cmd;
875 DependentLibraryInfo* lib = &libs[index++];
876 lib->name = (char*)cmd + dylib->dylib.name.offset;
877 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
878 lib->info.checksum = dylib->dylib.timestamp;
879 lib->info.minVersion = dylib->dylib.compatibility_version;
880 lib->info.maxVersion = dylib->dylib.current_version;
881 lib->required = (cmd->cmd != LC_LOAD_WEAK_DYLIB);
882 lib->reExported = (cmd->cmd == LC_REEXPORT_DYLIB);
883 lib->upward = (cmd->cmd == LC_LOAD_UPWARD_DYLIB);
884 }
885 break;
886 }
887 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
888 }
889 }
890 }
891
892 ImageLoader::LibraryInfo ImageLoaderMachO::doGetLibraryInfo()
893 {
894 LibraryInfo info;
895 if ( fDylibIDOffset != 0 ) {
896 const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]);
897 info.minVersion = dylibID->dylib.compatibility_version;
898 info.maxVersion = dylibID->dylib.current_version;
899 info.checksum = dylibID->dylib.timestamp;
900 }
901 else {
902 info.minVersion = 0;
903 info.maxVersion = 0;
904 info.checksum = 0;
905 }
906 return info;
907 }
908
909 void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const char*>& paths) const
910 {
911 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
912 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
913 const struct load_command* cmd = cmds;
914 for (uint32_t i = 0; i < cmd_count; ++i) {
915 switch (cmd->cmd) {
916 case LC_RPATH:
917 const char* pathToAdd = NULL;
918 const char* path = (char*)cmd + ((struct rpath_command*)cmd)->path.offset;
919 if ( strncmp(path, "@loader_path/", 13) == 0 ) {
920 if ( context.processIsRestricted && (context.mainExecutable == this) ) {
921 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path\n", path, this->getPath());
922 break;
923 }
924 char resolvedPath[PATH_MAX];
925 if ( realpath(this->getPath(), resolvedPath) != NULL ) {
926 char newRealPath[strlen(resolvedPath) + strlen(path)];
927 strcpy(newRealPath, resolvedPath);
928 char* addPoint = strrchr(newRealPath,'/');
929 if ( addPoint != NULL )
930 strcpy(&addPoint[1], &path[13]);
931 else
932 strcpy(newRealPath, &path[13]);
933 pathToAdd = strdup(newRealPath);
934 }
935 }
936 else if ( strncmp(path, "@executable_path/", 17) == 0 ) {
937 if ( context.processIsRestricted ) {
938 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path\n", path, this->getPath());
939 break;
940 }
941 char resolvedPath[PATH_MAX];
942 if ( realpath(context.mainExecutable->getPath(), resolvedPath) != NULL ) {
943 char newRealPath[strlen(resolvedPath) + strlen(path)];
944 strcpy(newRealPath, resolvedPath);
945 char* addPoint = strrchr(newRealPath,'/');
946 if ( addPoint != NULL )
947 strcpy(&addPoint[1], &path[17]);
948 else
949 strcpy(newRealPath, &path[17]);
950 pathToAdd = strdup(newRealPath);
951 }
952 }
953 else if ( (path[0] != '/') && context.processIsRestricted ) {
954 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path, this->getPath());
955 break;
956 }
957 else if ( (path[0] == '/') && (context.rootPaths != NULL) ) {
958 // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
959 // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists
960 bool found = false;
961 for(const char** rp = context.rootPaths; *rp != NULL; ++rp) {
962 char newPath[PATH_MAX];
963 strcpy(newPath, *rp);
964 strcat(newPath, path);
965 struct stat stat_buf;
966 if ( stat(newPath, &stat_buf) != -1 ) {
967 //dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
968 pathToAdd = strdup(newPath);
969 found = true;
970 break;
971 }
972 }
973 if ( ! found ) {
974 // make copy so that all elements of 'paths' can be freed
975 pathToAdd = strdup(path);
976 }
977 }
978 else {
979 // make copy so that all elements of 'paths' can be freed
980 pathToAdd = strdup(path);
981 }
982 if ( pathToAdd != NULL )
983 paths.push_back(pathToAdd);
984 break;
985 }
986 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
987 }
988 }
989
990 bool ImageLoaderMachO::getUUID(uuid_t uuid) const
991 {
992 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
993 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
994 const struct load_command* cmd = cmds;
995 for (uint32_t i = 0; i < cmd_count; ++i) {
996 switch (cmd->cmd) {
997 case LC_UUID:
998 uuid_command* uc = (uuid_command*)cmd;
999 memcpy(uuid, uc->uuid, 16);
1000 return true;
1001 }
1002 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1003 }
1004 bzero(uuid, 16);
1005 return false;
1006 }
1007
1008 void ImageLoaderMachO::doRebase(const LinkContext& context)
1009 {
1010 // if prebound and loaded at prebound address, then no need to rebase
1011 if ( this->usablePrebinding(context) ) {
1012 // skip rebasing because prebinding is valid
1013 ++fgImagesWithUsedPrebinding; // bump totals for statistics
1014 return;
1015 }
1016
1017 // print why prebinding was not used
1018 if ( context.verbosePrebinding ) {
1019 if ( !this->isPrebindable() ) {
1020 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1021 }
1022 else if ( fSlide != 0 ) {
1023 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1024 }
1025 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1026 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1027 }
1028 else if ( !this->usesTwoLevelNameSpace() ){
1029 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1030 }
1031 else {
1032 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1033 }
1034 }
1035
1036 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
1037
1038 #if PREBOUND_IMAGE_SUPPORT
1039 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1040 // if this image is in the shared cache, do not reset, they will be bound in doBind()
1041 if ( this->isPrebindable() && !fInSharedCache )
1042 this->resetPreboundLazyPointers(context);
1043 #endif
1044
1045 // if loaded at preferred address, no rebasing necessary
1046 if ( this->fSlide == 0 )
1047 return;
1048
1049 #if TEXT_RELOC_SUPPORT
1050 // if there are __TEXT fixups, temporarily make __TEXT writable
1051 if ( fTextSegmentRebases )
1052 this->makeTextSegmentWritable(context, true);
1053 #endif
1054
1055 // do actual rebasing
1056 this->rebase(context);
1057
1058 #if TEXT_RELOC_SUPPORT
1059 // if there were __TEXT fixups, restore write protection
1060 if ( fTextSegmentRebases )
1061 this->makeTextSegmentWritable(context, false);
1062
1063 #endif
1064 }
1065
1066 #if TEXT_RELOC_SUPPORT
1067 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext& context, bool writeable)
1068 {
1069 int textSegmentIndex = 0;
1070 for(unsigned int i=0; i < fSegmentsCount; ++i) {
1071 if ( strcmp(segName(i), "__TEXT") == 0 ) {
1072 textSegmentIndex = i;
1073 break;
1074 }
1075 }
1076
1077 if ( writeable ) {
1078 segMakeWritable(textSegmentIndex, context);
1079 }
1080 else {
1081 // iPhoneOS requires range to be invalidated before it is made executable
1082 sys_icache_invalidate((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex));
1083 segProtect(textSegmentIndex, context);
1084 }
1085 }
1086 #endif
1087
1088 const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name, bool searchReExports, const ImageLoader** foundIn) const
1089 {
1090 // look in this image first
1091 const ImageLoader::Symbol* result = this->findExportedSymbol(name, foundIn);
1092 if ( result != NULL )
1093 return result;
1094
1095 if ( searchReExports ) {
1096 for(unsigned int i=0; i < libraryCount(); ++i){
1097 if ( libReExported(i) ) {
1098 ImageLoader* image = libImage(i);
1099 if ( image != NULL ) {
1100 const Symbol* result = image->findExportedSymbol(name, searchReExports, foundIn);
1101 if ( result != NULL )
1102 return result;
1103 }
1104 }
1105 }
1106 }
1107
1108
1109 return NULL;
1110 }
1111
1112
1113
1114 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context,
1115 const ImageLoader* requestor, bool runResolver) const
1116 {
1117 return this->getSymbolAddress(sym, requestor, context, runResolver);
1118 }
1119
1120 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol* sym, const ImageLoader* requestor,
1121 const LinkContext& context, bool runResolver) const
1122 {
1123 uintptr_t result = exportedSymbolAddress(context, sym, runResolver);
1124 // check for interposing overrides
1125 for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
1126 // replace all references to 'replacee' with 'replacement'
1127 if ( (result == it->replacee) && (requestor != it->replacementImage) ) {
1128 if ( context.verboseInterposing ) {
1129 dyld::log("dyld interposing: replace 0x%lX with 0x%lX in %s\n",
1130 it->replacee, it->replacement, this->getPath());
1131 }
1132 result = it->replacement;
1133 }
1134 }
1135 return result;
1136 }
1137
1138 ImageLoader::DefinitionFlags ImageLoaderMachO::getExportedSymbolInfo(const Symbol* sym) const
1139 {
1140 if ( exportedSymbolIsWeakDefintion(sym) )
1141 return kWeakDefinition;
1142 else
1143 return kNoDefinitionOptions;
1144 }
1145
1146 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol* sym) const
1147 {
1148 return exportedSymbolName(sym);
1149 }
1150
1151 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1152 {
1153 return exportedSymbolCount();
1154 }
1155
1156
1157 const ImageLoader::Symbol* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index) const
1158 {
1159 return exportedSymbolIndexed(index);
1160 }
1161
1162
1163 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1164 {
1165 return importedSymbolCount();
1166 }
1167
1168
1169 const ImageLoader::Symbol* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index) const
1170 {
1171 return importedSymbolIndexed(index);
1172 }
1173
1174
1175 ImageLoader::ReferenceFlags ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol* sym) const
1176 {
1177 ImageLoader::ReferenceFlags flags = kNoReferenceOptions;
1178 return flags;
1179 }
1180
1181
1182 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol* sym) const
1183 {
1184 return importedSymbolName(sym);
1185 }
1186
1187
1188 bool ImageLoaderMachO::getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length)
1189 {
1190 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1191 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1192 const struct load_command* cmd = cmds;
1193 for (uint32_t i = 0; i < cmd_count; ++i) {
1194 switch (cmd->cmd) {
1195 case LC_SEGMENT_COMMAND:
1196 {
1197 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1198 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1199 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1200 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1201 if ( (strcmp(sect->segname, segmentName) == 0) && (strcmp(sect->sectname, sectionName) == 0) ) {
1202 *start = (uintptr_t*)(sect->addr + fSlide);
1203 *length = sect->size;
1204 return true;
1205 }
1206 }
1207 }
1208 break;
1209 }
1210 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1211 }
1212 *start = NULL;
1213 *length = 0;
1214 return false;
1215 }
1216
1217 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections* info)
1218 {
1219 info->mh = this->machHeader();
1220 info->dwarf_section = 0;
1221 info->dwarf_section_length = 0;
1222 info->compact_unwind_section = 0;
1223 info->compact_unwind_section_length = 0;
1224 if ( fEHFrameSectionOffset != 0 ) {
1225 const macho_section* sect = (macho_section*)&fMachOData[fEHFrameSectionOffset];
1226 info->dwarf_section = (void*)(sect->addr + fSlide);
1227 info->dwarf_section_length = sect->size;
1228 }
1229 if ( fUnwindInfoSectionOffset != 0 ) {
1230 const macho_section* sect = (macho_section*)&fMachOData[fUnwindInfoSectionOffset];
1231 info->compact_unwind_section = (void*)(sect->addr + fSlide);
1232 info->compact_unwind_section_length = sect->size;
1233 }
1234 }
1235
1236
1237 bool ImageLoaderMachO::findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset)
1238 {
1239 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1240 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1241 const struct load_command* cmd = cmds;
1242 const uintptr_t unslidInteriorAddress = (uintptr_t)imageInterior - this->getSlide();
1243 for (uint32_t i = 0; i < cmd_count; ++i) {
1244 switch (cmd->cmd) {
1245 case LC_SEGMENT_COMMAND:
1246 {
1247 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1248 if ( (unslidInteriorAddress >= seg->vmaddr) && (unslidInteriorAddress < (seg->vmaddr+seg->vmsize)) ) {
1249 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1250 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1251 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1252 if ((sect->addr <= unslidInteriorAddress) && (unslidInteriorAddress < (sect->addr+sect->size))) {
1253 if ( segmentName != NULL )
1254 *segmentName = sect->segname;
1255 if ( sectionName != NULL )
1256 *sectionName = sect->sectname;
1257 if ( sectionOffset != NULL )
1258 *sectionOffset = unslidInteriorAddress - sect->addr;
1259 return true;
1260 }
1261 }
1262 }
1263 }
1264 break;
1265 }
1266 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1267 }
1268 return false;
1269 }
1270
1271
1272 void __attribute__((noreturn)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext& context, const char* symbol,
1273 const char* referencedFrom, const char* expectedIn)
1274 {
1275 // record values for possible use by CrashReporter or Finder
1276 (*context.setErrorStrings)(dyld_error_kind_symbol_missing, referencedFrom, expectedIn, symbol);
1277 dyld::throwf("Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n", symbol, referencedFrom, expectedIn);
1278 }
1279
1280 const mach_header* ImageLoaderMachO::machHeader() const
1281 {
1282 return (mach_header*)fMachOData;
1283 }
1284
1285 uintptr_t ImageLoaderMachO::getSlide() const
1286 {
1287 return fSlide;
1288 }
1289
1290 // hmm. maybe this should be up in ImageLoader??
1291 const void* ImageLoaderMachO::getEnd() const
1292 {
1293 uintptr_t lastAddress = 0;
1294 for(unsigned int i=0; i < fSegmentsCount; ++i) {
1295 uintptr_t segEnd = segActualEndAddress(i);
1296 if ( strcmp(segName(i), "__UNIXSTACK") != 0 ) {
1297 if ( segEnd > lastAddress )
1298 lastAddress = segEnd;
1299 }
1300 }
1301 return (const void*)lastAddress;
1302 }
1303
1304
1305 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext& context, uintptr_t location, uintptr_t value,
1306 const ImageLoader* targetImage, uint8_t type, const char* symbolName,
1307 intptr_t addend, const char* msg)
1308 {
1309 // log
1310 if ( context.verboseBind ) {
1311 if ( addend != 0 )
1312 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n",
1313 msg, this->getShortName(), (uintptr_t)location,
1314 ((targetImage != NULL) ? targetImage->getShortName() : "<weak_import-missing>"),
1315 symbolName, (uintptr_t)location, value, addend);
1316 else
1317 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n",
1318 msg, this->getShortName(), (uintptr_t)location,
1319 ((targetImage != NULL) ? targetImage->getShortName() : "<weak>import-missing>"),
1320 symbolName, (uintptr_t)location, value);
1321 }
1322 #if LOG_BINDINGS
1323 // dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
1324 #endif
1325
1326 // do actual update
1327 uintptr_t* locationToFix = (uintptr_t*)location;
1328 uint32_t* loc32;
1329 uintptr_t newValue = value+addend;
1330 uint32_t value32;
1331 switch (type) {
1332 case BIND_TYPE_POINTER:
1333 // test first so we don't needless dirty pages
1334 if ( *locationToFix != newValue )
1335 *locationToFix = newValue;
1336 break;
1337 case BIND_TYPE_TEXT_ABSOLUTE32:
1338 loc32 = (uint32_t*)locationToFix;
1339 value32 = (uint32_t)newValue;
1340 if ( *loc32 != value32 )
1341 *loc32 = value32;
1342 break;
1343 case BIND_TYPE_TEXT_PCREL32:
1344 loc32 = (uint32_t*)locationToFix;
1345 value32 = (uint32_t)newValue - (((uintptr_t)locationToFix) + 4);
1346 if ( *loc32 != value32 )
1347 *loc32 = value32;
1348 break;
1349 default:
1350 dyld::throwf("bad bind type %d", type);
1351 }
1352
1353 // update statistics
1354 ++fgTotalBindFixups;
1355
1356 return newValue;
1357 }
1358
1359
1360
1361
1362
1363 #if SUPPORT_OLD_CRT_INITIALIZATION
1364 // first 16 bytes of "start" in crt1.o
1365 #if __i386__
1366 static uint8_t sStandardEntryPointInstructions[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
1367 #endif
1368 #endif
1369
1370 struct DATAdyld {
1371 void* dyldLazyBinder; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
1372 void* dyldFuncLookup; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
1373 // the following only exist in main executables built for 10.5 or later
1374 ProgramVars vars;
1375 };
1376
1377 // These are defined in dyldStartup.s
1378 extern "C" void stub_binding_helper();
1379 extern "C" bool dyld_func_lookup(const char* name, uintptr_t* address);
1380
1381
1382 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
1383 {
1384 const macho_header* mh = (macho_header*)fMachOData;
1385 const uint32_t cmd_count = mh->ncmds;
1386 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1387 const struct load_command* cmd;
1388 // There used to be some optimizations to skip this section scan, but we need to handle the
1389 // __dyld section in libdyld.dylib, so everything needs to be scanned for now.
1390 // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv
1391 if ( true ) {
1392 cmd = cmds;
1393 for (uint32_t i = 0; i < cmd_count; ++i) {
1394 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1395 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1396 if ( strcmp(seg->segname, "__DATA") == 0 ) {
1397 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1398 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1399 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1400 if ( strcmp(sect->sectname, "__dyld" ) == 0 ) {
1401 struct DATAdyld* dd = (struct DATAdyld*)(sect->addr + fSlide);
1402 if ( sect->size > offsetof(DATAdyld, dyldLazyBinder) ) {
1403 if ( dd->dyldLazyBinder != (void*)&stub_binding_helper )
1404 dd->dyldLazyBinder = (void*)&stub_binding_helper;
1405 }
1406 if ( sect->size > offsetof(DATAdyld, dyldFuncLookup) ) {
1407 if ( dd->dyldFuncLookup != (void*)&dyld_func_lookup )
1408 dd->dyldFuncLookup = (void*)&dyld_func_lookup;
1409 }
1410 if ( mh->filetype == MH_EXECUTE ) {
1411 // there are two ways to get the program variables
1412 if ( (sect->size > offsetof(DATAdyld, vars)) && (dd->vars.mh == mh) ) {
1413 // some really old binaries have space for vars, but it is zero filled
1414 // main executable has 10.5 style __dyld section that has program variable pointers
1415 context.setNewProgramVars(dd->vars);
1416 }
1417 else {
1418 // main executable is pre-10.5 and requires the symbols names to be looked up
1419 this->lookupProgramVars(context);
1420 #if SUPPORT_OLD_CRT_INITIALIZATION
1421 // If the first 16 bytes of the entry point's instructions do not
1422 // match what crt1.o supplies, then the program has a custom entry point.
1423 // This means it might be doing something that needs to be executed before
1424 // initializers are run.
1425 if ( memcmp(this->getMain(), sStandardEntryPointInstructions, 16) != 0 ) {
1426 if ( context.verboseInit )
1427 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
1428 context.setRunInitialzersOldWay();
1429 }
1430 #endif
1431 }
1432 }
1433 else if ( mh->filetype == MH_DYLIB ) {
1434 const char* installPath = this->getInstallPath();
1435 if ( (installPath != NULL) && (strncmp(installPath, "/usr/lib/", 9) == 0) ) {
1436 if ( sect->size > offsetof(DATAdyld, vars) ) {
1437 // use ProgramVars from libdyld.dylib but tweak mh field to correct value
1438 dd->vars.mh = context.mainExecutable->machHeader();
1439 context.setNewProgramVars(dd->vars);
1440 }
1441 }
1442 }
1443 }
1444 else if ( (strcmp(sect->sectname, "__program_vars" ) == 0) && (mh->filetype == MH_EXECUTE) ) {
1445 // this is a Mac OS X 10.6 or later main executable
1446 struct ProgramVars* pv = (struct ProgramVars*)(sect->addr + fSlide);
1447 context.setNewProgramVars(*pv);
1448 }
1449 }
1450 }
1451 }
1452 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1453 }
1454 }
1455 }
1456
1457
1458 void ImageLoaderMachO::lookupProgramVars(const LinkContext& context) const
1459 {
1460 ProgramVars vars = context.programVars;
1461 const ImageLoader::Symbol* sym;
1462
1463 // get mach header directly
1464 vars.mh = (macho_header*)fMachOData;
1465
1466 // lookup _NXArgc
1467 sym = this->findExportedSymbol("_NXArgc", false, NULL);
1468 if ( sym != NULL )
1469 vars.NXArgcPtr = (int*)this->getExportedSymbolAddress(sym, context, this, false);
1470
1471 // lookup _NXArgv
1472 sym = this->findExportedSymbol("_NXArgv", false, NULL);
1473 if ( sym != NULL )
1474 vars.NXArgvPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false);
1475
1476 // lookup _environ
1477 sym = this->findExportedSymbol("_environ", false, NULL);
1478 if ( sym != NULL )
1479 vars.environPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false);
1480
1481 // lookup __progname
1482 sym = this->findExportedSymbol("___progname", false, NULL);
1483 if ( sym != NULL )
1484 vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this, false);
1485
1486 context.setNewProgramVars(vars);
1487 }
1488
1489
1490 bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
1491 {
1492 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
1493 if ( ((this->isPrebindable() && (this->getSlide() == 0)) || fInSharedCache)
1494 && this->usesTwoLevelNameSpace()
1495 && this->allDependentLibrariesAsWhenPreBound() ) {
1496 // allow environment variables to disable prebinding
1497 if ( context.bindFlat )
1498 return false;
1499 switch ( context.prebindUsage ) {
1500 case kUseAllPrebinding:
1501 return true;
1502 case kUseSplitSegPrebinding:
1503 return this->fIsSplitSeg;
1504 case kUseAllButAppPredbinding:
1505 return (this != context.mainExecutable);
1506 case kUseNoPrebinding:
1507 return false;
1508 }
1509 }
1510 return false;
1511 }
1512
1513
1514 void ImageLoaderMachO::doImageInit(const LinkContext& context)
1515 {
1516 if ( fHasDashInit ) {
1517 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1518 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1519 const struct load_command* cmd = cmds;
1520 for (uint32_t i = 0; i < cmd_count; ++i) {
1521 switch (cmd->cmd) {
1522 case LC_ROUTINES_COMMAND:
1523 Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
1524 // <rdar://problem/8543820&9228031> verify initializers are in image
1525 if ( ! this->containsAddress((void*)func) ) {
1526 dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
1527 }
1528 if ( context.verboseInit )
1529 dyld::log("dyld: calling -init function 0x%p in %s\n", func, this->getPath());
1530 func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
1531 break;
1532 }
1533 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1534 }
1535 }
1536 }
1537
1538 void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
1539 {
1540 if ( fHasInitializers ) {
1541 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1542 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1543 const struct load_command* cmd = cmds;
1544 for (uint32_t i = 0; i < cmd_count; ++i) {
1545 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1546 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1547 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1548 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1549 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1550 const uint8_t type = sect->flags & SECTION_TYPE;
1551 if ( type == S_MOD_INIT_FUNC_POINTERS ) {
1552 Initializer* inits = (Initializer*)(sect->addr + fSlide);
1553 const uint32_t count = sect->size / sizeof(uintptr_t);
1554 for (uint32_t i=0; i < count; ++i) {
1555 Initializer func = inits[i];
1556 // <rdar://problem/8543820&9228031> verify initializers are in image
1557 if ( ! this->containsAddress((void*)func) ) {
1558 dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
1559 }
1560 if ( context.verboseInit )
1561 dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
1562 func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
1563 }
1564 }
1565 }
1566 }
1567 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1568 }
1569 }
1570 }
1571
1572
1573
1574
1575
1576
1577 void ImageLoaderMachO::doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs)
1578 {
1579 if ( fHasDOFSections ) {
1580 // walk load commands (mapped in at start of __TEXT segment)
1581 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1582 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1583 const struct load_command* cmd = cmds;
1584 for (uint32_t i = 0; i < cmd_count; ++i) {
1585 switch (cmd->cmd) {
1586 case LC_SEGMENT_COMMAND:
1587 {
1588 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1589 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1590 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1591 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1592 if ( (sect->flags & SECTION_TYPE) == S_DTRACE_DOF ) {
1593 ImageLoader::DOFInfo info;
1594 info.dof = (void*)(sect->addr + fSlide);
1595 info.imageHeader = this->machHeader();
1596 info.imageShortName = this->getShortName();
1597 dofs.push_back(info);
1598 }
1599 }
1600 }
1601 break;
1602 }
1603 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1604 }
1605 }
1606 }
1607
1608
1609 bool ImageLoaderMachO::doInitialization(const LinkContext& context)
1610 {
1611 CRSetCrashLogMessage2(this->getPath());
1612
1613 // mach-o has -init and static initializers
1614 doImageInit(context);
1615 doModInitFunctions(context);
1616
1617 CRSetCrashLogMessage2(NULL);
1618
1619 return (fHasDashInit || fHasInitializers);
1620 }
1621
1622 bool ImageLoaderMachO::needsInitialization()
1623 {
1624 return ( fHasDashInit || fHasInitializers );
1625 }
1626
1627
1628 bool ImageLoaderMachO::needsTermination()
1629 {
1630 return fHasTerminators;
1631 }
1632
1633
1634 void ImageLoaderMachO::doTermination(const LinkContext& context)
1635 {
1636 if ( fHasTerminators ) {
1637 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1638 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1639 const struct load_command* cmd = cmds;
1640 for (uint32_t i = 0; i < cmd_count; ++i) {
1641 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1642 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1643 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1644 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1645 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1646 const uint8_t type = sect->flags & SECTION_TYPE;
1647 if ( type == S_MOD_TERM_FUNC_POINTERS ) {
1648 Terminator* terms = (Terminator*)(sect->addr + fSlide);
1649 const uint32_t count = sect->size / sizeof(uintptr_t);
1650 for (uint32_t i=count; i > 0; --i) {
1651 Terminator func = terms[i-1];
1652 // <rdar://problem/8543820&9228031> verify terminators are in image
1653 if ( ! this->containsAddress((void*)func) ) {
1654 dyld::throwf("termination function %p not in mapped image for %s\n", func, this->getPath());
1655 }
1656 if ( context.verboseInit )
1657 dyld::log("dyld: calling termination function %p in %s\n", func, this->getPath());
1658 func();
1659 }
1660 }
1661 }
1662 }
1663 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1664 }
1665 }
1666 }
1667
1668
1669 void ImageLoaderMachO::printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo)
1670 {
1671 ImageLoader::printStatistics(imageCount, timingInfo);
1672 dyld::log("total symbol trie searches: %d\n", fgSymbolTrieSearchs);
1673 dyld::log("total symbol table binary searches: %d\n", fgSymbolTableBinarySearchs);
1674 dyld::log("total images defining weak symbols: %u\n", fgImagesHasWeakDefinitions);
1675 dyld::log("total images using weak symbols: %u\n", fgImagesRequiringCoalescing);
1676 }
1677
1678
1679 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext& context)
1680 {
1681 // preflight and calculate slide if needed
1682 const bool inPIE = (fgNextPIEDylibAddress != 0);
1683 intptr_t slide = 0;
1684 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
1685 bool needsToSlide = false;
1686 bool imageHasPreferredLoadAddress = segHasPreferredLoadAddress(0);
1687 uintptr_t lowAddr = (unsigned long)(-1);
1688 uintptr_t highAddr = 0;
1689 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
1690 const uintptr_t segLow = segPreferredLoadAddress(i);
1691 const uintptr_t segHigh = (segLow + segSize(i) + 4095) & -4096;
1692 if ( segLow < lowAddr )
1693 lowAddr = segLow;
1694 if ( segHigh > highAddr )
1695 highAddr = segHigh;
1696
1697 if ( needsToSlide || !imageHasPreferredLoadAddress || inPIE || !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
1698 needsToSlide = true;
1699 }
1700 if ( needsToSlide ) {
1701 // find a chunk of address space to hold all segments
1702 uintptr_t addr = reserveAnAddressRange(highAddr-lowAddr, context);
1703 slide = addr - lowAddr;
1704 }
1705 }
1706 else if ( ! this->segmentsCanSlide() ) {
1707 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
1708 if ( strcmp(segName(i), "__PAGEZERO") == 0 )
1709 continue;
1710 if ( !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
1711 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i), segPreferredLoadAddress(i), segSize(i));
1712 }
1713 }
1714 else {
1715 throw "mach-o does not support independently sliding segments";
1716 }
1717 return slide;
1718 }
1719
1720
1721 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context)
1722 {
1723 vm_address_t addr = 0;
1724 vm_size_t size = length;
1725 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
1726 if ( fgNextPIEDylibAddress != 0 ) {
1727 // add small (0-3 pages) random padding between dylibs
1728 addr = fgNextPIEDylibAddress + (__stack_chk_guard/fgNextPIEDylibAddress & (sizeof(long)-1))*4096;
1729 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
1730 kern_return_t r = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_FIXED);
1731 if ( r == KERN_SUCCESS ) {
1732 fgNextPIEDylibAddress = addr + size;
1733 return addr;
1734 }
1735 fgNextPIEDylibAddress = 0;
1736 }
1737 kern_return_t r = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE);
1738 if ( r != KERN_SUCCESS )
1739 throw "out of address space";
1740
1741 return addr;
1742 }
1743
1744 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start, size_t length)
1745 {
1746 vm_address_t addr = start;
1747 vm_size_t size = length;
1748 kern_return_t r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/);
1749 if ( r != KERN_SUCCESS )
1750 return false;
1751 return true;
1752 }
1753
1754
1755
1756 void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
1757 {
1758 // find address range for image
1759 intptr_t slide = this->assignSegmentAddresses(context);
1760 if ( context.verboseMapping )
1761 dyld::log("dyld: Mapping %s\n", this->getPath());
1762 // map in all segments
1763 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
1764 vm_offset_t fileOffset = segFileOffset(i) + offsetInFat;
1765 vm_size_t size = segFileSize(i);
1766 uintptr_t requestedLoadAddress = segPreferredLoadAddress(i) + slide;
1767 int protection = 0;
1768 if ( !segUnaccessible(i) ) {
1769 // If has text-relocs, don't set x-bit initially.
1770 // Instead set it later after text-relocs have been done.
1771 // The iPhone OS does not like it when you make executable code writable.
1772 if ( segExecutable(i) && !(segHasRebaseFixUps(i) && (slide != 0)) )
1773 protection |= PROT_EXEC;
1774 if ( segReadable(i) )
1775 protection |= PROT_READ;
1776 if ( segWriteable(i) )
1777 protection |= PROT_WRITE;
1778 }
1779 #if __i386__
1780 // initially map __IMPORT segments R/W so dyld can update them
1781 if ( segIsReadOnlyImport(i) )
1782 protection |= PROT_WRITE;
1783 #endif
1784 // wholly zero-fill segments have nothing to mmap() in
1785 if ( size > 0 ) {
1786 if ( (fileOffset+size) > fileLen ) {
1787 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",
1788 segName(i), (uint64_t)(fileOffset+size), fileLen);
1789 }
1790 void* loadAddress = mmap((void*)requestedLoadAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, fileOffset);
1791 if ( loadAddress == ((void*)(-1)) ) {
1792 dyld::throwf("mmap() error %d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",
1793 errno, requestedLoadAddress, (uintptr_t)size, segName(i), getPath());
1794 }
1795 }
1796 // update stats
1797 ++ImageLoader::fgTotalSegmentsMapped;
1798 ImageLoader::fgTotalBytesMapped += size;
1799 if ( context.verboseMapping )
1800 dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i), requestedLoadAddress, requestedLoadAddress+size-1,
1801 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' );
1802 }
1803
1804 // update slide to reflect load location
1805 this->setSlide(slide);
1806 }
1807
1808 void ImageLoaderMachO::mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context)
1809 {
1810 // find address range for image
1811 intptr_t slide = this->assignSegmentAddresses(context);
1812 if ( context.verboseMapping )
1813 dyld::log("dyld: Mapping memory %p\n", memoryImage);
1814 // map in all segments
1815 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
1816 vm_address_t loadAddress = segPreferredLoadAddress(i) + slide;
1817 vm_address_t srcAddr = (uintptr_t)memoryImage + segFileOffset(i);
1818 vm_size_t size = segFileSize(i);
1819 kern_return_t r = vm_copy(mach_task_self(), srcAddr, size, loadAddress);
1820 if ( r != KERN_SUCCESS )
1821 throw "can't map segment";
1822 if ( context.verboseMapping )
1823 dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i), (uintptr_t)loadAddress, (uintptr_t)loadAddress+size-1);
1824 }
1825 // update slide to reflect load location
1826 this->setSlide(slide);
1827 // set R/W permissions on all segments at slide location
1828 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
1829 segProtect(i, context);
1830 }
1831 }
1832
1833
1834 void ImageLoaderMachO::segProtect(unsigned int segIndex, const ImageLoader::LinkContext& context)
1835 {
1836 vm_prot_t protection = 0;
1837 if ( !segUnaccessible(segIndex) ) {
1838 if ( segExecutable(segIndex) )
1839 protection |= PROT_EXEC;
1840 if ( segReadable(segIndex) )
1841 protection |= PROT_READ;
1842 if ( segWriteable(segIndex) )
1843 protection |= PROT_WRITE;
1844 }
1845 vm_address_t addr = segActualLoadAddress(segIndex);
1846 vm_size_t size = segSize(segIndex);
1847 const bool setCurrentPermissions = false;
1848 kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
1849 if ( r != KERN_SUCCESS ) {
1850 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
1851 (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath());
1852 }
1853 if ( context.verboseMapping ) {
1854 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1,
1855 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' );
1856 }
1857 }
1858
1859 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex, const ImageLoader::LinkContext& context)
1860 {
1861 vm_address_t addr = segActualLoadAddress(segIndex);
1862 vm_size_t size = segSize(segIndex);
1863 const bool setCurrentPermissions = false;
1864 vm_prot_t protection = VM_PROT_WRITE | VM_PROT_READ;
1865 if ( segExecutable(segIndex) && !segHasRebaseFixUps(segIndex) )
1866 protection |= VM_PROT_EXECUTE;
1867 kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
1868 if ( r != KERN_SUCCESS ) {
1869 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
1870 (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath());
1871 }
1872 if ( context.verboseMapping ) {
1873 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1,
1874 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' );
1875 }
1876 }
1877
1878