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