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