dyld-832.7.1.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 <mach-o/dyld_images.h>
43 #include <sys/sysctl.h>
44 #include <sys/syscall.h>
45 #include <libkern/OSAtomic.h>
46 #include <libkern/OSCacheControl.h>
47 #include <stdint.h>
48 #include <System/sys/codesign.h>
49
50 #if __has_feature(ptrauth_calls)
51 #include <ptrauth.h>
52 #endif
53
54 #include "ImageLoaderMachO.h"
55 #include "ImageLoaderMachOCompressed.h"
56 #if SUPPORT_CLASSIC_MACHO
57 #include "ImageLoaderMachOClassic.h"
58 #endif
59 #include "Tracing.h"
60 #include "dyld2.h"
61
62 // <rdar://problem/8718137> use stack guard random value to add padding between dylibs
63 extern "C" long __stack_chk_guard;
64
65 #define LIBSYSTEM_DYLIB_PATH "/usr/lib/libSystem.B.dylib"
66 #define LIBDYLD_DYLIB_PATH "/usr/lib/system/libdyld.dylib"
67 #if TARGET_OS_OSX
68 #define DRIVERKIT_LIBSYSTEM_DYLIB_PATH "/System/DriverKit/usr/lib/libSystem.dylib"
69 #define DRIVERKIT_LIBDYLD_DYLIB_PATH "/System/DriverKit/usr/lib/system/libdyld.dylib"
70 #endif
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
91
92 ImageLoaderMachO::ImageLoaderMachO(const macho_header* mh, const char* path, unsigned int segCount,
93 uint32_t segOffsets[], unsigned int libCount)
94 : ImageLoader(path, libCount), fCoveredCodeLength(0), fMachOData((uint8_t*)mh), fLinkEditBase(NULL), fSlide(0),
95 fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),
96 fSegmentsCount(segCount), fIsSplitSeg(false), fInSharedCache(false),
97 #if TEXT_RELOC_SUPPORT
98 fTextSegmentRebases(false),
99 fTextSegmentBinds(false),
100 #else
101 fReadOnlyDataSegment(false),
102 #endif
103 #if __i386__
104 fReadOnlyImportSegment(false),
105 #endif
106 fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
107 fHasInitializers(false), fHasTerminators(false), fNotifyObjC(false), fRetainForObjC(false), fRegisteredAsRequiresCoalescing(false), fOverrideOfCacheImageNum(0)
108 {
109 fIsSplitSeg = ((mh->flags & MH_SPLIT_SEGS) != 0);
110
111 // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put
112 // each SegmentMachO object in array at end of ImageLoaderMachO object
113 const uint32_t cmd_count = mh->ncmds;
114 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
115 const struct load_command* cmd = cmds;
116 for (uint32_t i = 0, segIndex=0; i < cmd_count; ++i) {
117 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
118 const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
119 // ignore zero-sized segments
120 if ( segCmd->vmsize != 0 ) {
121 // record offset of load command
122 segOffsets[segIndex++] = (uint32_t)((uint8_t*)segCmd - fMachOData);
123 }
124 }
125 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
126 }
127
128 }
129
130 #if TARGET_OS_OSX
131 static uintptr_t pageAlign(uintptr_t value)
132 {
133 return (value + 4095) & (-4096);
134 }
135 #endif
136
137 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
138 void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* path, bool inCache, bool* compressed,
139 unsigned int* segCount, unsigned int* libCount, const LinkContext& context,
140 const linkedit_data_command** codeSigCmd,
141 const encryption_info_command** encryptCmd)
142 {
143 *compressed = false;
144 *segCount = 0;
145 *libCount = 0;
146 *codeSigCmd = NULL;
147 *encryptCmd = NULL;
148
149 const uint32_t cmd_count = mh->ncmds;
150 const uint32_t sizeofcmds = mh->sizeofcmds;
151 if ( cmd_count > (sizeofcmds/sizeof(load_command)) )
152 dyld::throwf("malformed mach-o: ncmds (%u) too large to fit in sizeofcmds (%u)", cmd_count, sizeofcmds);
153 const struct load_command* const startCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
154 const struct load_command* const endCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header) + sizeofcmds);
155 const struct load_command* cmd = startCmds;
156 bool foundLoadCommandSegment = false;
157 const macho_segment_command* linkeditSegCmd = NULL;
158 const macho_segment_command* startOfFileSegCmd = NULL;
159 const dyld_info_command* dyldInfoCmd = NULL;
160 const linkedit_data_command* chainedFixupsCmd = NULL;
161 const linkedit_data_command* exportsTrieCmd = NULL;
162 const symtab_command* symTabCmd = NULL;
163 const dysymtab_command* dynSymbTabCmd = NULL;
164 for (uint32_t i = 0; i < cmd_count; ++i) {
165 uint32_t cmdLength = cmd->cmdsize;
166 const macho_segment_command* segCmd;
167 const dylib_command* dylibCmd;
168 if ( cmdLength < 8 ) {
169 dyld::throwf("malformed mach-o image: load command #%d length (%u) too small in %s",
170 i, cmdLength, path);
171 }
172 const struct load_command* const nextCmd = (const struct load_command*)(((char*)cmd)+cmdLength);
173 if ( (nextCmd > endCmds) || (nextCmd < cmd) ) {
174 dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
175 i, cmdLength, mh->sizeofcmds, path);
176 }
177 switch (cmd->cmd) {
178 case LC_DYLD_INFO:
179 case LC_DYLD_INFO_ONLY:
180 if ( cmd->cmdsize != sizeof(dyld_info_command) )
181 throw "malformed mach-o image: LC_DYLD_INFO size wrong";
182 dyldInfoCmd = (struct dyld_info_command*)cmd;
183 *compressed = true;
184 break;
185 case LC_DYLD_CHAINED_FIXUPS:
186 if ( cmd->cmdsize != sizeof(linkedit_data_command) )
187 throw "malformed mach-o image: LC_DYLD_CHAINED_FIXUPS size wrong";
188 chainedFixupsCmd = (struct linkedit_data_command*)cmd;
189 *compressed = true;
190 break;
191 case LC_DYLD_EXPORTS_TRIE:
192 if ( cmd->cmdsize != sizeof(linkedit_data_command) )
193 throw "malformed mach-o image: LC_DYLD_EXPORTS_TRIE size wrong";
194 exportsTrieCmd = (struct linkedit_data_command*)cmd;
195 break;
196 case LC_SEGMENT_COMMAND:
197 segCmd = (struct macho_segment_command*)cmd;
198 #if TARGET_OS_OSX
199 // rdar://problem/19617624 allow unmapped segments on OSX (but not iOS)
200 if ( ((segCmd->filesize) > pageAlign(segCmd->vmsize)) && (segCmd->vmsize != 0) )
201 #else
202 // <rdar://problem/19986776> dyld should support non-allocatable __LLVM segment
203 if ( (segCmd->filesize > segCmd->vmsize) && ((segCmd->vmsize != 0) || ((segCmd->flags & SG_NORELOC) == 0)) )
204 #endif
205 dyld::throwf("malformed mach-o image: segment load command %s filesize (0x%0lX) is larger than vmsize (0x%0lX)", segCmd->segname, (long)segCmd->filesize , (long)segCmd->vmsize );
206 if ( cmd->cmdsize < sizeof(macho_segment_command) )
207 throw "malformed mach-o image: LC_SEGMENT size too small";
208 if ( cmd->cmdsize != (sizeof(macho_segment_command) + segCmd->nsects * sizeof(macho_section)) )
209 throw "malformed mach-o image: LC_SEGMENT size wrong for number of sections";
210 // ignore zero-sized segments
211 if ( segCmd->vmsize != 0 )
212 *segCount += 1;
213 if ( strcmp(segCmd->segname, "__LINKEDIT") == 0 ) {
214 #if TARGET_OS_SIMULATOR
215 // Note: should check on all platforms that __LINKEDIT is read-only, but <rdar://problem/22637626&22525618>
216 if ( segCmd->initprot != VM_PROT_READ )
217 throw "malformed mach-o image: __LINKEDIT segment does not have read-only permissions";
218 #endif
219 if ( segCmd->fileoff == 0 )
220 throw "malformed mach-o image: __LINKEDIT has fileoff==0 which overlaps mach_header";
221 if ( linkeditSegCmd != NULL )
222 throw "malformed mach-o image: multiple __LINKEDIT segments";
223 linkeditSegCmd = segCmd;
224 }
225 else {
226 if ( segCmd->initprot & 0xFFFFFFF8 )
227 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in initprot", segCmd->segname, segCmd->initprot);
228 if ( segCmd->maxprot & 0xFFFFFFF8 )
229 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in maxprot", segCmd->segname, segCmd->maxprot);
230 if ( (segCmd->initprot != 0) && ((segCmd->initprot & VM_PROT_READ) == 0) )
231 dyld::throwf("malformed mach-o image: %s segment is not mapped readable", segCmd->segname);
232 }
233 if ( (segCmd->fileoff == 0) && (segCmd->filesize != 0) ) {
234 if ( (segCmd->initprot & VM_PROT_READ) == 0 )
235 dyld::throwf("malformed mach-o image: %s segment maps start of file but is not readable", segCmd->segname);
236 if ( (segCmd->initprot & VM_PROT_WRITE) == VM_PROT_WRITE ) {
237 if ( context.strictMachORequired )
238 dyld::throwf("malformed mach-o image: %s segment maps start of file but is writable", segCmd->segname);
239 }
240 if ( segCmd->filesize < (sizeof(macho_header) + mh->sizeofcmds) )
241 dyld::throwf("malformed mach-o image: %s segment does not map all of load commands", segCmd->segname);
242 if ( startOfFileSegCmd != NULL )
243 dyld::throwf("malformed mach-o image: multiple segments map start of file: %s %s", startOfFileSegCmd->segname, segCmd->segname);
244 startOfFileSegCmd = segCmd;
245 }
246 if ( context.strictMachORequired ) {
247 uintptr_t vmStart = segCmd->vmaddr;
248 uintptr_t vmSize = segCmd->vmsize;
249 uintptr_t vmEnd = vmStart + vmSize;
250 uintptr_t fileStart = segCmd->fileoff;
251 uintptr_t fileSize = segCmd->filesize;
252 if ( (intptr_t)(vmSize) < 0 )
253 dyld::throwf("malformed mach-o image: segment load command %s vmsize too large in %s", segCmd->segname, path);
254 if ( vmStart > vmEnd )
255 dyld::throwf("malformed mach-o image: segment load command %s wraps around address space", segCmd->segname);
256 if ( vmSize != fileSize ) {
257 if ( segCmd->initprot == 0 ) {
258 // allow: fileSize == 0 && initprot == 0 e.g. __PAGEZERO
259 // allow: vmSize == 0 && initprot == 0 e.g. __LLVM
260 if ( (fileSize != 0) && (vmSize != 0) )
261 dyld::throwf("malformed mach-o image: unaccessable segment %s has non-zero filesize and vmsize", segCmd->segname);
262 }
263 else {
264 // allow: vmSize > fileSize && initprot != X e.g. __DATA
265 if ( vmSize < fileSize ) {
266 dyld::throwf("malformed mach-o image: segment %s has vmsize < filesize", segCmd->segname);
267 }
268 if ( segCmd->initprot & VM_PROT_EXECUTE ) {
269 dyld::throwf("malformed mach-o image: segment %s has vmsize != filesize and is executable", segCmd->segname);
270 }
271 }
272 }
273 if ( inCache ) {
274 if ( (fileSize != 0) && (segCmd->initprot == (VM_PROT_READ | VM_PROT_EXECUTE)) ) {
275 if ( foundLoadCommandSegment )
276 throw "load commands in multiple segments";
277 foundLoadCommandSegment = true;
278 }
279 }
280 else if ( (fileStart < mh->sizeofcmds) && (fileSize != 0) ) {
281 // <rdar://problem/7942521> all load commands must be in an executable segment
282 if ( (fileStart != 0) || (fileSize < (mh->sizeofcmds+sizeof(macho_header))) )
283 dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd->segname);
284 if ( segCmd->initprot != (VM_PROT_READ | VM_PROT_EXECUTE) )
285 dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd->segname);
286 if ( foundLoadCommandSegment )
287 throw "load commands in multiple segments";
288 foundLoadCommandSegment = true;
289 }
290
291 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
292 const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
293 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
294 if (!inCache && sect->offset != 0 && ((sect->offset + sect->size) > (segCmd->fileoff + segCmd->filesize)))
295 dyld::throwf("malformed mach-o image: section %s,%s of '%s' exceeds segment %s booundary", sect->segname, sect->sectname, path, segCmd->segname);
296 }
297 }
298 break;
299 case LC_SEGMENT_COMMAND_WRONG:
300 dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");
301 break;
302 case LC_LOAD_DYLIB:
303 case LC_LOAD_WEAK_DYLIB:
304 case LC_REEXPORT_DYLIB:
305 case LC_LOAD_UPWARD_DYLIB:
306 *libCount += 1;
307 // fall thru
308 [[clang::fallthrough]];
309 case LC_ID_DYLIB:
310 dylibCmd = (dylib_command*)cmd;
311 if ( dylibCmd->dylib.name.offset > cmdLength )
312 dyld::throwf("malformed mach-o image: dylib load command #%d has offset (%u) outside its size (%u)", i, dylibCmd->dylib.name.offset, cmdLength);
313 if ( (dylibCmd->dylib.name.offset + strlen((char*)dylibCmd + dylibCmd->dylib.name.offset) + 1) > cmdLength )
314 dyld::throwf("malformed mach-o image: dylib load command #%d string extends beyond end of load command", i);
315 break;
316 case LC_CODE_SIGNATURE:
317 if ( cmd->cmdsize != sizeof(linkedit_data_command) )
318 throw "malformed mach-o image: LC_CODE_SIGNATURE size wrong";
319 // <rdar://problem/22799652> only support one LC_CODE_SIGNATURE per image
320 if ( *codeSigCmd != NULL )
321 throw "malformed mach-o image: multiple LC_CODE_SIGNATURE load commands";
322 *codeSigCmd = (struct linkedit_data_command*)cmd;
323 break;
324 case LC_ENCRYPTION_INFO:
325 if ( cmd->cmdsize != sizeof(encryption_info_command) )
326 throw "malformed mach-o image: LC_ENCRYPTION_INFO size wrong";
327 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO per image
328 if ( *encryptCmd != NULL )
329 throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO load commands";
330 *encryptCmd = (encryption_info_command*)cmd;
331 break;
332 case LC_ENCRYPTION_INFO_64:
333 if ( cmd->cmdsize != sizeof(encryption_info_command_64) )
334 throw "malformed mach-o image: LC_ENCRYPTION_INFO_64 size wrong";
335 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO_64 per image
336 if ( *encryptCmd != NULL )
337 throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO_64 load commands";
338 *encryptCmd = (encryption_info_command*)cmd;
339 break;
340 case LC_SYMTAB:
341 if ( cmd->cmdsize != sizeof(symtab_command) )
342 throw "malformed mach-o image: LC_SYMTAB size wrong";
343 symTabCmd = (symtab_command*)cmd;
344 break;
345 case LC_DYSYMTAB:
346 if ( cmd->cmdsize != sizeof(dysymtab_command) )
347 throw "malformed mach-o image: LC_DYSYMTAB size wrong";
348 dynSymbTabCmd = (dysymtab_command*)cmd;
349 break;
350 #if TARGET_OS_OSX
351 // <rdar://problem/26797345> error when loading iOS Simulator mach-o binary into macOS process
352 case LC_VERSION_MIN_WATCHOS:
353 case LC_VERSION_MIN_TVOS:
354 case LC_VERSION_MIN_IPHONEOS:
355 if ( !context.iOSonMac )
356 throw "mach-o, but built for simulator (not macOS)";
357 break;
358 #endif
359 }
360 cmd = nextCmd;
361 }
362
363 if ( context.strictMachORequired && !foundLoadCommandSegment )
364 throw "load commands not in a segment";
365 if ( linkeditSegCmd == NULL )
366 throw "malformed mach-o image: missing __LINKEDIT segment";
367 if ( !inCache && (startOfFileSegCmd == NULL) )
368 throw "malformed mach-o image: missing __TEXT segment that maps start of file";
369 // <rdar://problem/13145644> verify every segment does not overlap another segment
370 if ( context.strictMachORequired ) {
371 uintptr_t lastFileStart = 0;
372 uintptr_t linkeditFileStart = 0;
373 const struct load_command* cmd1 = startCmds;
374 for (uint32_t i = 0; i < cmd_count; ++i) {
375 if ( cmd1->cmd == LC_SEGMENT_COMMAND ) {
376 struct macho_segment_command* segCmd1 = (struct macho_segment_command*)cmd1;
377 uintptr_t vmStart1 = segCmd1->vmaddr;
378 uintptr_t vmEnd1 = segCmd1->vmaddr + segCmd1->vmsize;
379 uintptr_t fileStart1 = segCmd1->fileoff;
380 uintptr_t fileEnd1 = segCmd1->fileoff + segCmd1->filesize;
381
382 if (fileStart1 > lastFileStart)
383 lastFileStart = fileStart1;
384
385 if ( strcmp(&segCmd1->segname[0], "__LINKEDIT") == 0 ) {
386 linkeditFileStart = fileStart1;
387 }
388
389 const struct load_command* cmd2 = startCmds;
390 for (uint32_t j = 0; j < cmd_count; ++j) {
391 if ( cmd2 == cmd1 )
392 continue;
393 if ( cmd2->cmd == LC_SEGMENT_COMMAND ) {
394 struct macho_segment_command* segCmd2 = (struct macho_segment_command*)cmd2;
395 uintptr_t vmStart2 = segCmd2->vmaddr;
396 uintptr_t vmEnd2 = segCmd2->vmaddr + segCmd2->vmsize;
397 uintptr_t fileStart2 = segCmd2->fileoff;
398 uintptr_t fileEnd2 = segCmd2->fileoff + segCmd2->filesize;
399 if ( ((vmStart2 <= vmStart1) && (vmEnd2 > vmStart1) && (vmEnd1 > vmStart1))
400 || ((vmStart2 >= vmStart1) && (vmStart2 < vmEnd1) && (vmEnd2 > vmStart2)) )
401 dyld::throwf("malformed mach-o image: segment %s vm overlaps segment %s", segCmd1->segname, segCmd2->segname);
402 if ( ((fileStart2 <= fileStart1) && (fileEnd2 > fileStart1) && (fileEnd1 > fileStart1))
403 || ((fileStart2 >= fileStart1) && (fileStart2 < fileEnd1) && (fileEnd2 > fileStart2)) )
404 dyld::throwf("malformed mach-o image: segment %s file content overlaps segment %s", segCmd1->segname, segCmd2->segname);
405 }
406 cmd2 = (const struct load_command*)(((char*)cmd2)+cmd2->cmdsize);
407 }
408 }
409 cmd1 = (const struct load_command*)(((char*)cmd1)+cmd1->cmdsize);
410 }
411
412 if (lastFileStart != linkeditFileStart)
413 dyld::throwf("malformed mach-o image: __LINKEDIT must be last segment");
414 }
415
416 // validate linkedit content
417 if ( (dyldInfoCmd == NULL) && (chainedFixupsCmd == NULL) && (symTabCmd == NULL) )
418 throw "malformed mach-o image: missing LC_SYMTAB, LC_DYLD_INFO, or LC_DYLD_CHAINED_FIXUPS";
419 if ( dynSymbTabCmd == NULL )
420 throw "malformed mach-o image: missing LC_DYSYMTAB";
421
422 uint32_t linkeditFileOffsetStart = (uint32_t)linkeditSegCmd->fileoff;
423 uint32_t linkeditFileOffsetEnd = (uint32_t)linkeditSegCmd->fileoff + (uint32_t)linkeditSegCmd->filesize;
424
425 if ( !inCache && (dyldInfoCmd != NULL) && context.strictMachORequired ) {
426 // validate all LC_DYLD_INFO chunks fit in LINKEDIT and don't overlap
427 uint32_t offset = linkeditFileOffsetStart;
428 if ( dyldInfoCmd->rebase_size != 0 ) {
429 if ( dyldInfoCmd->rebase_size & 0x80000000 )
430 throw "malformed mach-o image: dyld rebase info size overflow";
431 if ( dyldInfoCmd->rebase_off < offset )
432 throw "malformed mach-o image: dyld rebase info underruns __LINKEDIT";
433 offset = dyldInfoCmd->rebase_off + dyldInfoCmd->rebase_size;
434 if ( offset > linkeditFileOffsetEnd )
435 throw "malformed mach-o image: dyld rebase info overruns __LINKEDIT";
436 }
437 if ( dyldInfoCmd->bind_size != 0 ) {
438 if ( dyldInfoCmd->bind_size & 0x80000000 )
439 throw "malformed mach-o image: dyld bind info size overflow";
440 if ( dyldInfoCmd->bind_off < offset )
441 throw "malformed mach-o image: dyld bind info overlaps rebase info";
442 offset = dyldInfoCmd->bind_off + dyldInfoCmd->bind_size;
443 if ( offset > linkeditFileOffsetEnd )
444 throw "malformed mach-o image: dyld bind info overruns __LINKEDIT";
445 }
446 if ( dyldInfoCmd->weak_bind_size != 0 ) {
447 if ( dyldInfoCmd->weak_bind_size & 0x80000000 )
448 throw "malformed mach-o image: dyld weak bind info size overflow";
449 if ( dyldInfoCmd->weak_bind_off < offset )
450 throw "malformed mach-o image: dyld weak bind info overlaps bind info";
451 offset = dyldInfoCmd->weak_bind_off + dyldInfoCmd->weak_bind_size;
452 if ( offset > linkeditFileOffsetEnd )
453 throw "malformed mach-o image: dyld weak bind info overruns __LINKEDIT";
454 }
455 if ( dyldInfoCmd->lazy_bind_size != 0 ) {
456 if ( dyldInfoCmd->lazy_bind_size & 0x80000000 )
457 throw "malformed mach-o image: dyld lazy bind info size overflow";
458 if ( dyldInfoCmd->lazy_bind_off < offset )
459 throw "malformed mach-o image: dyld lazy bind info overlaps weak bind info";
460 offset = dyldInfoCmd->lazy_bind_off + dyldInfoCmd->lazy_bind_size;
461 if ( offset > linkeditFileOffsetEnd )
462 throw "malformed mach-o image: dyld lazy bind info overruns __LINKEDIT";
463 }
464 if ( dyldInfoCmd->export_size != 0 ) {
465 if ( dyldInfoCmd->export_size & 0x80000000 )
466 throw "malformed mach-o image: dyld export info size overflow";
467 if ( dyldInfoCmd->export_off < offset )
468 throw "malformed mach-o image: dyld export info overlaps lazy bind info";
469 offset = dyldInfoCmd->export_off + dyldInfoCmd->export_size;
470 if ( offset > linkeditFileOffsetEnd )
471 throw "malformed mach-o image: dyld export info overruns __LINKEDIT";
472 }
473 }
474
475 if ( !inCache && (chainedFixupsCmd != NULL) && context.strictMachORequired ) {
476 // validate all LC_DYLD_CHAINED_FIXUPS chunks fit in LINKEDIT and don't overlap
477 if ( chainedFixupsCmd->dataoff < linkeditFileOffsetStart )
478 throw "malformed mach-o image: dyld chained fixups info underruns __LINKEDIT";
479 if ( (chainedFixupsCmd->dataoff + chainedFixupsCmd->datasize) > linkeditFileOffsetEnd )
480 throw "malformed mach-o image: dyld chained fixups info overruns __LINKEDIT";
481 }
482
483 if ( !inCache && (exportsTrieCmd != NULL) && context.strictMachORequired ) {
484 // validate all LC_DYLD_EXPORTS_TRIE chunks fit in LINKEDIT and don't overlap
485 if ( exportsTrieCmd->dataoff < linkeditFileOffsetStart )
486 throw "malformed mach-o image: dyld chained fixups info underruns __LINKEDIT";
487 if ( (exportsTrieCmd->dataoff + exportsTrieCmd->datasize) > linkeditFileOffsetEnd )
488 throw "malformed mach-o image: dyld chained fixups info overruns __LINKEDIT";
489 }
490
491 if ( symTabCmd != NULL ) {
492 // validate symbol table fits in LINKEDIT
493 if ( (symTabCmd->nsyms > 0) && (symTabCmd->symoff < linkeditFileOffsetStart) )
494 throw "malformed mach-o image: symbol table underruns __LINKEDIT";
495 if ( symTabCmd->nsyms > 0x10000000 )
496 throw "malformed mach-o image: symbol table too large";
497 uint32_t symbolsSize = symTabCmd->nsyms * sizeof(macho_nlist);
498 if ( symbolsSize > linkeditSegCmd->filesize )
499 throw "malformed mach-o image: symbol table overruns __LINKEDIT";
500 if ( symTabCmd->symoff + symbolsSize < symTabCmd->symoff )
501 throw "malformed mach-o image: symbol table size wraps";
502 if ( symTabCmd->symoff + symbolsSize > symTabCmd->stroff )
503 throw "malformed mach-o image: symbol table overlaps symbol strings";
504 if ( symTabCmd->stroff + symTabCmd->strsize < symTabCmd->stroff )
505 throw "malformed mach-o image: symbol string size wraps";
506 if ( symTabCmd->stroff + symTabCmd->strsize > linkeditFileOffsetEnd ) {
507 // <rdar://problem/24220313> let old apps overflow as long as it stays within mapped page
508 if ( context.strictMachORequired || (symTabCmd->stroff + symTabCmd->strsize > ((linkeditFileOffsetEnd + 4095) & (-4096))) )
509 throw "malformed mach-o image: symbol strings overrun __LINKEDIT";
510 }
511 #if TARGET_OS_OSX
512 if ( (symTabCmd->symoff % sizeof(void*)) != 0 ) {
513 // <rdar://53723577> allow old malformed plugins in new app
514 if ( sdkVersion((mach_header*)mh) >= DYLD_PACKED_VERSION(10,15,0) )
515 throw "malformed mach-o image: mis-aligned symbol table __LINKEDIT";
516 }
517 #endif
518 // validate indirect symbol table
519 if ( dynSymbTabCmd->nindirectsyms != 0 ) {
520 if ( dynSymbTabCmd->indirectsymoff < linkeditFileOffsetStart )
521 throw "malformed mach-o image: indirect symbol table underruns __LINKEDIT";
522 if ( dynSymbTabCmd->nindirectsyms > 0x10000000 )
523 throw "malformed mach-o image: indirect symbol table too large";
524 uint32_t indirectTableSize = dynSymbTabCmd->nindirectsyms * sizeof(uint32_t);
525 if ( indirectTableSize > linkeditSegCmd->filesize )
526 throw "malformed mach-o image: indirect symbol table overruns __LINKEDIT";
527 if ( dynSymbTabCmd->indirectsymoff + indirectTableSize < dynSymbTabCmd->indirectsymoff )
528 throw "malformed mach-o image: indirect symbol table size wraps";
529 if ( context.strictMachORequired && (dynSymbTabCmd->indirectsymoff + indirectTableSize > symTabCmd->stroff) )
530 throw "malformed mach-o image: indirect symbol table overruns string pool";
531 }
532 if ( (dynSymbTabCmd->nlocalsym > symTabCmd->nsyms) || (dynSymbTabCmd->ilocalsym > symTabCmd->nsyms) )
533 throw "malformed mach-o image: indirect symbol table local symbol count exceeds total symbols";
534 if ( dynSymbTabCmd->ilocalsym + dynSymbTabCmd->nlocalsym < dynSymbTabCmd->ilocalsym )
535 throw "malformed mach-o image: indirect symbol table local symbol count wraps";
536 if ( (dynSymbTabCmd->nextdefsym > symTabCmd->nsyms) || (dynSymbTabCmd->iextdefsym > symTabCmd->nsyms) )
537 throw "malformed mach-o image: indirect symbol table extern symbol count exceeds total symbols";
538 if ( dynSymbTabCmd->iextdefsym + dynSymbTabCmd->nextdefsym < dynSymbTabCmd->iextdefsym )
539 throw "malformed mach-o image: indirect symbol table extern symbol count wraps";
540 if ( (dynSymbTabCmd->nundefsym > symTabCmd->nsyms) || (dynSymbTabCmd->iundefsym > symTabCmd->nsyms) )
541 throw "malformed mach-o image: indirect symbol table undefined symbol count exceeds total symbols";
542 if ( dynSymbTabCmd->iundefsym + dynSymbTabCmd->nundefsym < dynSymbTabCmd->iundefsym )
543 throw "malformed mach-o image: indirect symbol table undefined symbol count wraps";
544 }
545
546
547 // fSegmentsArrayCount is only 8-bits
548 if ( *segCount > 255 )
549 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path);
550
551 // fSegmentsArrayCount is only 8-bits
552 if ( *libCount > 4095 )
553 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path);
554
555 if ( needsAddedLibSystemDepency(*libCount, mh) )
556 *libCount = 1;
557
558 // dylibs that use LC_DYLD_CHAINED_FIXUPS have that load command removed when put in the dyld cache
559 if ( !*compressed && (mh->flags & MH_DYLIB_IN_CACHE) )
560 *compressed = true;
561 }
562
563
564
565 // create image for main executable
566 ImageLoader* ImageLoaderMachO::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, const LinkContext& context)
567 {
568 //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
569 // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
570 bool compressed;
571 unsigned int segCount;
572 unsigned int libCount;
573 const linkedit_data_command* codeSigCmd;
574 const encryption_info_command* encryptCmd;
575 sniffLoadCommands(mh, path, false, &compressed, &segCount, &libCount, context, &codeSigCmd, &encryptCmd);
576 // instantiate concrete class based on content of load commands
577 if ( compressed )
578 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
579 else
580 #if SUPPORT_CLASSIC_MACHO
581 return ImageLoaderMachOClassic::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
582 #else
583 throw "missing LC_DYLD_INFO load command";
584 #endif
585 }
586
587
588 // create image by mapping in a mach-o file
589 ImageLoader* ImageLoaderMachO::instantiateFromFile(const char* path, int fd, const uint8_t firstPages[], size_t firstPagesSize, uint64_t offsetInFat,
590 uint64_t lenInFat, const struct stat& info, const LinkContext& context)
591 {
592 bool compressed;
593 unsigned int segCount;
594 unsigned int libCount;
595 const linkedit_data_command* codeSigCmd;
596 const encryption_info_command* encryptCmd;
597 sniffLoadCommands((const macho_header*)firstPages, path, false, &compressed, &segCount, &libCount, context, &codeSigCmd, &encryptCmd);
598 // instantiate concrete class based on content of load commands
599 if ( compressed )
600 return ImageLoaderMachOCompressed::instantiateFromFile(path, fd, firstPages, firstPagesSize, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, encryptCmd, context);
601 else
602 #if SUPPORT_CLASSIC_MACHO
603 return ImageLoaderMachOClassic::instantiateFromFile(path, fd, firstPages, firstPagesSize, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context);
604 #else
605 throw "missing LC_DYLD_INFO load command";
606 #endif
607 }
608
609 // create image by using cached mach-o file
610 ImageLoader* ImageLoaderMachO::instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info, const LinkContext& context)
611 {
612 // instantiate right concrete class
613 bool compressed;
614 unsigned int segCount;
615 unsigned int libCount;
616 const linkedit_data_command* codeSigCmd;
617 const encryption_info_command* encryptCmd;
618 sniffLoadCommands(mh, path, true, &compressed, &segCount, &libCount, context, &codeSigCmd, &encryptCmd);
619 // instantiate concrete class based on content of load commands
620 if ( compressed )
621 return ImageLoaderMachOCompressed::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
622 else
623 #if SUPPORT_CLASSIC_MACHO
624 return ImageLoaderMachOClassic::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
625 #else
626 throw "missing LC_DYLD_INFO load command";
627 #endif
628 }
629
630 // create image by copying an in-memory mach-o file
631 ImageLoader* ImageLoaderMachO::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, const LinkContext& context)
632 {
633 bool compressed;
634 unsigned int segCount;
635 unsigned int libCount;
636 const linkedit_data_command* sigcmd;
637 const encryption_info_command* encryptCmd;
638 sniffLoadCommands(mh, moduleName, false, &compressed, &segCount, &libCount, context, &sigcmd, &encryptCmd);
639 // instantiate concrete class based on content of load commands
640 if ( compressed )
641 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
642 else
643 #if SUPPORT_CLASSIC_MACHO
644 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
645 #else
646 throw "missing LC_DYLD_INFO load command";
647 #endif
648 }
649
650
651 int ImageLoaderMachO::crashIfInvalidCodeSignature()
652 {
653 // Now that segments are mapped in, try reading from first executable segment.
654 // If code signing is enabled the kernel will validate the code signature
655 // when paging in, and kill the process if invalid.
656 for(unsigned int i=0; i < fSegmentsCount; ++i) {
657 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
658 // return read value to ensure compiler does not optimize away load
659 int* p = (int*)segActualLoadAddress(i);
660 return *p;
661 }
662 }
663 return 0;
664 }
665
666
667 void ImageLoaderMachO::parseLoadCmds(const LinkContext& context)
668 {
669 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
670 for(unsigned int i=0; i < fSegmentsCount; ++i) {
671 // set up pointer to __LINKEDIT segment
672 if ( strcmp(segName(i),"__LINKEDIT") == 0 ) {
673 #if !TARGET_OS_OSX
674 // <rdar://problem/42419336> historically, macOS never did this check
675 if ( segFileOffset(i) > fCoveredCodeLength )
676 dyld::throwf("cannot load '%s' (segment outside of code signature)", this->getShortName());
677 #endif
678 fLinkEditBase = (uint8_t*)(segActualLoadAddress(i) - segFileOffset(i));
679 }
680 #if TEXT_RELOC_SUPPORT
681 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
682 if ( segExecutable(i) ) {
683 if ( segHasRebaseFixUps(i) && (fSlide != 0) )
684 fTextSegmentRebases = true;
685 if ( segHasBindFixUps(i) )
686 fTextSegmentBinds = true;
687 }
688 #else
689 if ( segIsReadOnlyData(i) )
690 fReadOnlyDataSegment = true;
691 #endif
692 #if __i386__
693 if ( segIsReadOnlyImport(i) )
694 fReadOnlyImportSegment = true;
695 #endif
696 // some segment always starts at beginning of file and contains mach_header and load commands
697 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
698 fMachOData = (uint8_t*)(segActualLoadAddress(i));
699 }
700 }
701
702 // keep count of prebound images with weak exports
703 if ( this->participatesInCoalescing() ) {
704 ++fgImagesRequiringCoalescing;
705 fRegisteredAsRequiresCoalescing = true;
706 if ( this->hasCoalescedExports() )
707 ++fgImagesHasWeakDefinitions;
708 }
709
710 // keep count of images used in shared cache
711 if ( fInSharedCache )
712 ++fgImagesUsedFromSharedCache;
713
714 // walk load commands (mapped in at start of __TEXT segment)
715 const dyld_info_command* dyldInfo = NULL;
716 const linkedit_data_command* chainedFixupsCmd = NULL;
717 const linkedit_data_command* exportsTrieCmd = NULL;
718 const macho_nlist* symbolTable = NULL;
719 const char* symbolTableStrings = NULL;
720 const struct load_command* firstUnknownCmd = NULL;
721 const struct version_min_command* minOSVersionCmd = NULL;
722 const dysymtab_command* dynSymbolTable = NULL;
723 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
724 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
725 const struct load_command* cmd = cmds;
726 for (uint32_t i = 0; i < cmd_count; ++i) {
727 switch (cmd->cmd) {
728 case LC_SYMTAB:
729 {
730 const struct symtab_command* symtab = (struct symtab_command*)cmd;
731 symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
732 symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
733 }
734 break;
735 case LC_DYSYMTAB:
736 dynSymbolTable = (struct dysymtab_command*)cmd;
737 break;
738 case LC_SUB_UMBRELLA:
739 fHasSubUmbrella = true;
740 break;
741 case LC_SUB_FRAMEWORK:
742 fInUmbrella = true;
743 break;
744 case LC_SUB_LIBRARY:
745 fHasSubLibraries = true;
746 break;
747 case LC_ROUTINES_COMMAND:
748 fHasDashInit = true;
749 break;
750 case LC_DYLD_INFO:
751 case LC_DYLD_INFO_ONLY:
752 dyldInfo = (struct dyld_info_command*)cmd;
753 break;
754 case LC_DYLD_CHAINED_FIXUPS:
755 chainedFixupsCmd = (struct linkedit_data_command*)cmd;
756 break;
757 case LC_DYLD_EXPORTS_TRIE:
758 exportsTrieCmd = (struct linkedit_data_command*)cmd;
759 break;
760 case LC_SEGMENT_COMMAND:
761 {
762 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
763 const bool isTextSeg = (strcmp(seg->segname, "__TEXT") == 0);
764 #if __i386__ && TARGET_OS_OSX
765 const bool isObjCSeg = (strcmp(seg->segname, "__OBJC") == 0);
766 if ( isObjCSeg )
767 fNotifyObjC = true;
768 #else
769 const bool isDataSeg = (strncmp(seg->segname, "__DATA", 6) == 0);
770 #endif
771 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
772 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
773 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
774 const uint8_t type = sect->flags & SECTION_TYPE;
775 if ( type == S_MOD_INIT_FUNC_POINTERS )
776 fHasInitializers = true;
777 else if ( type == S_INIT_FUNC_OFFSETS )
778 fHasInitializers = true;
779 else if ( type == S_MOD_TERM_FUNC_POINTERS )
780 fHasTerminators = true;
781 else if ( type == S_DTRACE_DOF )
782 fHasDOFSections = true;
783 else if ( isTextSeg && (strcmp(sect->sectname, "__eh_frame") == 0) )
784 fEHFrameSectionOffset = (uint32_t)((uint8_t*)sect - fMachOData);
785 else if ( isTextSeg && (strcmp(sect->sectname, "__unwind_info") == 0) )
786 fUnwindInfoSectionOffset = (uint32_t)((uint8_t*)sect - fMachOData);
787
788 #if __i386__ && TARGET_OS_OSX
789 else if ( isObjCSeg ) {
790 if ( strcmp(sect->sectname, "__image_info") == 0 ) {
791 const uint32_t* imageInfo = (uint32_t*)(sect->addr + fSlide);
792 uint32_t flags = imageInfo[1];
793 if ( (flags & 4) && (((macho_header*)fMachOData)->filetype != MH_EXECUTE) )
794 dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath());
795 }
796 else if ( ((macho_header*)fMachOData)->filetype == MH_DYLIB ) {
797 fRetainForObjC = true;
798 }
799 }
800 #else
801 else if ( isDataSeg && (strncmp(sect->sectname, "__objc_imageinfo", 16) == 0) ) {
802 #if TARGET_OS_OSX
803 const uint32_t* imageInfo = (uint32_t*)(sect->addr + fSlide);
804 uint32_t flags = imageInfo[1];
805 if ( (flags & 4) && (((macho_header*)fMachOData)->filetype != MH_EXECUTE) )
806 dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath());
807 #endif
808 fNotifyObjC = true;
809 }
810 else if ( isDataSeg && (strncmp(sect->sectname, "__objc_", 7) == 0) && (((macho_header*)fMachOData)->filetype == MH_DYLIB) )
811 fRetainForObjC = true;
812 #endif
813 }
814 }
815 break;
816 case LC_TWOLEVEL_HINTS:
817 // no longer supported
818 break;
819 case LC_ID_DYLIB:
820 {
821 fDylibIDOffset = (uint32_t)((uint8_t*)cmd - fMachOData);
822 }
823 break;
824 case LC_RPATH:
825 case LC_LOAD_WEAK_DYLIB:
826 case LC_REEXPORT_DYLIB:
827 case LC_LOAD_UPWARD_DYLIB:
828 case LC_MAIN:
829 break;
830 case LC_VERSION_MIN_MACOSX:
831 case LC_VERSION_MIN_IPHONEOS:
832 case LC_VERSION_MIN_TVOS:
833 case LC_VERSION_MIN_WATCHOS:
834 minOSVersionCmd = (version_min_command*)cmd;
835 break;
836 default:
837 if ( (cmd->cmd & LC_REQ_DYLD) != 0 ) {
838 if ( firstUnknownCmd == NULL )
839 firstUnknownCmd = cmd;
840 }
841 break;
842 }
843 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
844 }
845 if ( firstUnknownCmd != NULL ) {
846 if ( minOSVersionCmd != NULL ) {
847 dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)",
848 this->getShortName(),
849 minOSVersionCmd->version >> 16, ((minOSVersionCmd->version >> 8) & 0xff),
850 firstUnknownCmd->cmd);
851 }
852 else {
853 dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd->cmd);
854 }
855 }
856
857
858 if ( dyldInfo != NULL )
859 this->setDyldInfo(dyldInfo);
860 if ( chainedFixupsCmd != NULL )
861 this->setChainedFixups(chainedFixupsCmd);
862 if ( exportsTrieCmd != NULL )
863 this->setExportsTrie(exportsTrieCmd);
864
865 if ( symbolTable != NULL)
866 this->setSymbolTableInfo(symbolTable, symbolTableStrings, dynSymbolTable);
867 }
868
869 // don't do this work in destructor because we need object to be full subclass
870 // for UnmapSegments() to work
871 void ImageLoaderMachO::destroy()
872 {
873 // update count of images with weak exports
874 if ( fRegisteredAsRequiresCoalescing ) {
875 --fgImagesRequiringCoalescing;
876 if ( this->hasCoalescedExports() )
877 --fgImagesHasWeakDefinitions;
878 }
879
880 // keep count of images used in shared cache
881 if ( fInSharedCache )
882 --fgImagesUsedFromSharedCache;
883
884 // unmap image when done
885 UnmapSegments();
886 }
887
888
889 unsigned int ImageLoaderMachO::segmentCount() const
890 {
891 return fSegmentsCount;
892 }
893
894
895 const macho_segment_command* ImageLoaderMachO::segLoadCommand(unsigned int segIndex) const
896 {
897 uint32_t* lcOffsets = this->segmentCommandOffsets();
898 uint32_t lcOffset = lcOffsets[segIndex];
899 return (macho_segment_command*)(&fMachOData[lcOffset]);
900 }
901
902 const char* ImageLoaderMachO::segName(unsigned int segIndex) const
903 {
904 return segLoadCommand(segIndex)->segname;
905 }
906
907
908 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex) const
909 {
910 return segLoadCommand(segIndex)->vmsize;
911 }
912
913
914 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex) const
915 {
916 return segLoadCommand(segIndex)->filesize;
917 }
918
919
920 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex)
921 {
922 return ( segWriteable(segIndex) && (segSize(segIndex) > segFileSize(segIndex)) );
923 }
924
925
926 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex) const
927 {
928 return segLoadCommand(segIndex)->fileoff;
929 }
930
931
932 bool ImageLoaderMachO::segReadable(unsigned int segIndex) const
933 {
934 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_READ) != 0);
935 }
936
937
938 bool ImageLoaderMachO::segWriteable(unsigned int segIndex) const
939 {
940 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_WRITE) != 0);
941 }
942
943
944 bool ImageLoaderMachO::segExecutable(unsigned int segIndex) const
945 {
946 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_EXECUTE) != 0);
947 }
948
949
950 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex) const
951 {
952 return (segLoadCommand(segIndex)->initprot == 0);
953 }
954
955 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex) const
956 {
957 return (segLoadCommand(segIndex)->vmaddr != 0);
958 }
959
960 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex) const
961 {
962 return segLoadCommand(segIndex)->vmaddr;
963 }
964
965 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex) const
966 {
967 return segLoadCommand(segIndex)->vmaddr + fSlide;
968 }
969
970
971 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex) const
972 {
973 return segActualLoadAddress(segIndex) + segSize(segIndex);
974 }
975
976 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex) const
977 {
978 #if TEXT_RELOC_SUPPORT
979 // scan sections for fix-up bit
980 const macho_segment_command* segCmd = segLoadCommand(segIndex);
981 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
982 const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
983 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
984 if ( (sect->flags & S_ATTR_LOC_RELOC) != 0 )
985 return true;
986 }
987 #endif
988 return false;
989 }
990
991 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex) const
992 {
993 #if TEXT_RELOC_SUPPORT
994 // scan sections for fix-up bit
995 const macho_segment_command* segCmd = segLoadCommand(segIndex);
996 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
997 const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
998 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
999 if ( (sect->flags & S_ATTR_EXT_RELOC) != 0 )
1000 return true;
1001 }
1002 #endif
1003 return false;
1004 }
1005
1006 #if __i386__
1007 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex) const
1008 {
1009 const macho_segment_command* segCmd = segLoadCommand(segIndex);
1010 return ( (segCmd->initprot & VM_PROT_EXECUTE)
1011 && ((segCmd->initprot & VM_PROT_WRITE) == 0)
1012 && (strcmp(segCmd->segname, "__IMPORT") == 0) );
1013 }
1014 #endif
1015
1016 bool ImageLoaderMachO::segIsReadOnlyData(unsigned int segIndex) const
1017 {
1018 const macho_segment_command* segCmd = segLoadCommand(segIndex);
1019 return ( (segCmd->initprot & VM_PROT_WRITE)
1020 && ((segCmd->initprot & VM_PROT_EXECUTE) == 0)
1021 && (segCmd->flags & SG_READ_ONLY) );
1022 }
1023
1024 void ImageLoaderMachO::UnmapSegments()
1025 {
1026 // usually unmap image when done
1027 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped) ) {
1028 // unmap TEXT segment last because it contains load command being inspected
1029 unsigned int textSegmentIndex = 0;
1030 for(unsigned int i=0; i < fSegmentsCount; ++i) {
1031 //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this));
1032 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
1033 textSegmentIndex = i;
1034 }
1035 else {
1036 // update stats
1037 --ImageLoader::fgTotalSegmentsMapped;
1038 ImageLoader::fgTotalBytesMapped -= segSize(i);
1039 munmap((void*)segActualLoadAddress(i), segSize(i));
1040 }
1041 }
1042 // now unmap TEXT
1043 --ImageLoader::fgTotalSegmentsMapped;
1044 ImageLoader::fgTotalBytesMapped -= segSize(textSegmentIndex);
1045 munmap((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex));
1046 }
1047 }
1048
1049
1050 bool ImageLoaderMachO::segmentsMustSlideTogether() const
1051 {
1052 return true;
1053 }
1054
1055 bool ImageLoaderMachO::segmentsCanSlide() const
1056 {
1057 return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable());
1058 }
1059
1060 bool ImageLoaderMachO::isBundle() const
1061 {
1062 const macho_header* mh = (macho_header*)fMachOData;
1063 return ( mh->filetype == MH_BUNDLE );
1064 }
1065
1066 bool ImageLoaderMachO::isDylib() const
1067 {
1068 const macho_header* mh = (macho_header*)fMachOData;
1069 return ( mh->filetype == MH_DYLIB );
1070 }
1071
1072 bool ImageLoaderMachO::isExecutable() const
1073 {
1074 const macho_header* mh = (macho_header*)fMachOData;
1075 return ( mh->filetype == MH_EXECUTE );
1076 }
1077
1078 bool ImageLoaderMachO::isPositionIndependentExecutable() const
1079 {
1080 const macho_header* mh = (macho_header*)fMachOData;
1081 return ( (mh->filetype == MH_EXECUTE) && ((mh->flags & MH_PIE) != 0) );
1082 }
1083
1084
1085 bool ImageLoaderMachO::forceFlat() const
1086 {
1087 const macho_header* mh = (macho_header*)fMachOData;
1088 return ( (mh->flags & MH_FORCE_FLAT) != 0 );
1089 }
1090
1091 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
1092 {
1093 const macho_header* mh = (macho_header*)fMachOData;
1094 return ( (mh->flags & MH_TWOLEVEL) != 0 );
1095 }
1096
1097 bool ImageLoaderMachO::isPrebindable() const
1098 {
1099 const macho_header* mh = (macho_header*)fMachOData;
1100 return ( (mh->flags & MH_PREBOUND) != 0 );
1101 }
1102
1103 bool ImageLoaderMachO::hasCoalescedExports() const
1104 {
1105 const macho_header* mh = (macho_header*)fMachOData;
1106 return ( (mh->flags & MH_WEAK_DEFINES) != 0 );
1107 }
1108
1109 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const
1110 {
1111 const macho_header* mh = (macho_header*)fMachOData;
1112 return ( (mh->flags & MH_BINDS_TO_WEAK) != 0 );
1113 }
1114
1115 bool ImageLoaderMachO::participatesInCoalescing() const
1116 {
1117 const macho_header* mh = (macho_header*)fMachOData;
1118 // if image is loaded with RTLD_LOCAL, then its symbols' visibility
1119 // is reduced and it can't coalesce with other images
1120 if ( this->hasHiddenExports() )
1121 return false;
1122 return ( (mh->flags & (MH_WEAK_DEFINES|MH_BINDS_TO_WEAK)) != 0 );
1123 }
1124
1125
1126
1127 void ImageLoaderMachO::setSlide(intptr_t slide)
1128 {
1129 fSlide = slide;
1130 }
1131
1132 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile, const LinkContext& context)
1133 {
1134 dyld3::ScopedTimer(DBG_DYLD_TIMING_ATTACH_CODESIGNATURE, 0, 0, 0);
1135 // if dylib being loaded has no code signature load command
1136 if ( codeSigCmd == NULL) {
1137 disableCoverageCheck();
1138 }
1139 else {
1140 #if TARGET_OS_OSX
1141 // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools
1142 if ( this->sdkVersion() < DYLD_PACKED_VERSION(10,9,0) ) {
1143 disableCoverageCheck();
1144 return;
1145 }
1146 #endif
1147
1148 fsignatures_t siginfo;
1149 siginfo.fs_file_start=offsetInFatFile; // start of mach-o slice in fat file
1150 siginfo.fs_blob_start=(void*)(long)(codeSigCmd->dataoff); // start of CD in mach-o file
1151 siginfo.fs_blob_size=codeSigCmd->datasize; // size of CD
1152 int result = fcntl(fd, F_ADDFILESIGS_RETURN, &siginfo);
1153
1154 #if TARGET_OS_SIMULATOR
1155 // rdar://problem/18759224> check range covered by the code directory after loading
1156 // Attempt to fallback only if we are in the simulator
1157
1158 if ( result == -1 ) {
1159 result = fcntl(fd, F_ADDFILESIGS, &siginfo);
1160 siginfo.fs_file_start = codeSigCmd->dataoff;
1161 }
1162 #endif
1163
1164 if ( result == -1 ) {
1165 if ( (errno == EPERM) || (errno == EBADEXEC) )
1166 dyld::throwf("code signature invalid for '%s'\n", this->getPath());
1167 if ( context.verboseCodeSignatures )
1168 dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno);
1169 siginfo.fs_file_start = UINT64_MAX;
1170 } else if ( context.verboseCodeSignatures ) {
1171 dyld::log("dyld: Registered code signature for %s\n", this->getPath());
1172 }
1173 fCoveredCodeLength = siginfo.fs_file_start;
1174 }
1175
1176 {
1177 fchecklv checkInfo;
1178 char messageBuffer[512];
1179 messageBuffer[0] = '\0';
1180 checkInfo.lv_file_start = offsetInFatFile;
1181 checkInfo.lv_error_message_size = sizeof(messageBuffer);
1182 checkInfo.lv_error_message = messageBuffer;
1183 int res = fcntl(fd, F_CHECK_LV, &checkInfo);
1184 if ( res == -1 ) {
1185 dyld::throwf("code signature in (%s) not valid for use in process using Library Validation: %s", this->getPath(), messageBuffer);
1186 }
1187 }
1188 }
1189
1190 void ImageLoaderMachO::validateFirstPages(const struct linkedit_data_command* codeSigCmd, int fd, const uint8_t *fileData, size_t lenFileData, off_t offsetInFat, const LinkContext& context)
1191 {
1192 #if TARGET_OS_OSX
1193 // rdar://problem/21839703> 15A226d: dyld crashes in mageLoaderMachO::validateFirstPages during dlopen() after encountering an mmap failure
1194 // We need to ignore older code signatures because they will be bad.
1195 if ( this->sdkVersion() < DYLD_PACKED_VERSION(10,9,0) ) {
1196 return;
1197 }
1198 #endif
1199 if (codeSigCmd != NULL) {
1200 void *fdata = xmmap(NULL, lenFileData, PROT_READ, MAP_SHARED, fd, offsetInFat);
1201 if ( fdata == MAP_FAILED ) {
1202 int errnoCopy = errno;
1203 if ( errnoCopy == EPERM ) {
1204 if ( dyld::sandboxBlockedMmap(getPath()) )
1205 dyld::throwf("file system sandbox blocked mmap() of '%s'", getPath());
1206 else
1207 dyld::throwf("code signing blocked mmap() of '%s'", getPath());
1208 }
1209 else
1210 dyld::throwf("mmap() errno=%d validating first page of '%s'", errnoCopy, getPath());
1211 }
1212 if ( memcmp(fdata, fileData, lenFileData) != 0 )
1213 dyld::throwf("mmap() page compare failed for '%s'", getPath());
1214 munmap(fdata, lenFileData);
1215 }
1216 }
1217
1218
1219 const char* ImageLoaderMachO::getInstallPath() const
1220 {
1221 if ( fDylibIDOffset != 0 ) {
1222 const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]);
1223 return (char*)dylibID + dylibID->dylib.name.offset;
1224 }
1225 return NULL;
1226 }
1227
1228 void ImageLoaderMachO::registerInterposing(const LinkContext& context)
1229 {
1230 // mach-o files advertise interposing by having a __DATA __interpose section
1231 struct InterposeData { uintptr_t replacement; uintptr_t replacee; };
1232 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1233 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1234 const struct load_command* cmd = cmds;
1235 for (uint32_t i = 0; i < cmd_count; ++i) {
1236 switch (cmd->cmd) {
1237 case LC_SEGMENT_COMMAND:
1238 {
1239 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1240 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1241 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1242 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1243 if ( ((sect->flags & SECTION_TYPE) == S_INTERPOSING) || ((strcmp(sect->sectname, "__interpose") == 0) && (strcmp(seg->segname, "__DATA") == 0)) ) {
1244 // <rdar://problem/23929217> Ensure section is within segment
1245 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
1246 dyld::throwf("interpose section has malformed address range for %s\n", this->getPath());
1247 const InterposeData* interposeArray = (InterposeData*)(sect->addr + fSlide);
1248 const size_t count = sect->size / sizeof(InterposeData);
1249 for (size_t j=0; j < count; ++j) {
1250 ImageLoader::InterposeTuple tuple;
1251 tuple.replacement = interposeArray[j].replacement;
1252 tuple.neverImage = this;
1253 tuple.onlyImage = NULL;
1254 tuple.replacee = interposeArray[j].replacee;
1255 // <rdar://problem/25686570> ignore interposing on a weak function that does not exist
1256 if ( tuple.replacee == 0 )
1257 continue;
1258 // <rdar://problem/7937695> verify that replacement is in this image
1259 if ( this->containsAddress((void*)tuple.replacement) ) {
1260 // chain to any existing interpositions
1261 for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
1262 if ( it->replacee == tuple.replacee ) {
1263 tuple.replacee = it->replacement;
1264 }
1265 }
1266 ImageLoader::fgInterposingTuples.push_back(tuple);
1267 }
1268 }
1269 }
1270 }
1271 }
1272 break;
1273 }
1274 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1275 }
1276 }
1277
1278 uint32_t ImageLoaderMachO::sdkVersion(const mach_header* mh)
1279 {
1280 const uint32_t cmd_count = mh->ncmds;
1281 const struct load_command* const cmds = (struct load_command*)(((char*)mh) + sizeof(macho_header));
1282 const struct load_command* cmd = cmds;
1283 const struct version_min_command* versCmd;
1284 const struct build_version_command* buildVersCmd;
1285 for (uint32_t i = 0; i < cmd_count; ++i) {
1286 switch ( cmd->cmd ) {
1287 case LC_VERSION_MIN_MACOSX:
1288 case LC_VERSION_MIN_IPHONEOS:
1289 case LC_VERSION_MIN_TVOS:
1290 case LC_VERSION_MIN_WATCHOS:
1291 versCmd = (version_min_command*)cmd;
1292 return versCmd->sdk;
1293 case LC_BUILD_VERSION:
1294 buildVersCmd = (build_version_command*)cmd;
1295 return buildVersCmd->sdk;
1296 }
1297 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1298 }
1299 return 0;
1300 }
1301
1302 uint32_t ImageLoaderMachO::sdkVersion() const
1303 {
1304 return ImageLoaderMachO::sdkVersion(machHeader());
1305 }
1306
1307 uint32_t ImageLoaderMachO::minOSVersion(const mach_header* mh)
1308 {
1309 const uint32_t cmd_count = mh->ncmds;
1310 const struct load_command* const cmds = (struct load_command*)(((char*)mh) + sizeof(macho_header));
1311 const struct load_command* cmd = cmds;
1312 const struct version_min_command* versCmd;
1313 const struct build_version_command* buildVersCmd;
1314 for (uint32_t i = 0; i < cmd_count; ++i) {
1315 switch ( cmd->cmd ) {
1316 case LC_VERSION_MIN_MACOSX:
1317 case LC_VERSION_MIN_IPHONEOS:
1318 case LC_VERSION_MIN_TVOS:
1319 case LC_VERSION_MIN_WATCHOS:
1320 versCmd = (version_min_command*)cmd;
1321 return versCmd->version;
1322 case LC_BUILD_VERSION:
1323 buildVersCmd = (build_version_command*)cmd;
1324 return buildVersCmd->minos;
1325 }
1326 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1327 }
1328 return 0;
1329 }
1330
1331 uint32_t ImageLoaderMachO::minOSVersion() const
1332 {
1333 return ImageLoaderMachO::minOSVersion(machHeader());
1334 }
1335
1336
1337 void* ImageLoaderMachO::getEntryFromLC_MAIN() const
1338 {
1339 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1340 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1341 const struct load_command* cmd = cmds;
1342 for (uint32_t i = 0; i < cmd_count; ++i) {
1343 if ( cmd->cmd == LC_MAIN ) {
1344 entry_point_command* mainCmd = (entry_point_command*)cmd;
1345 void* entry = (void*)(mainCmd->entryoff + (char*)fMachOData);
1346 // <rdar://problem/8543820&9228031> verify entry point is in image
1347 if ( this->containsAddress(entry) ) {
1348 #if __has_feature(ptrauth_calls)
1349 // start() calls the result pointer as a function pointer so we need to sign it.
1350 return __builtin_ptrauth_sign_unauthenticated(entry, 0, 0);
1351 #endif
1352 return entry;
1353 }
1354 else
1355 throw "LC_MAIN entryoff is out of range";
1356 }
1357 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1358 }
1359 return NULL;
1360 }
1361
1362
1363 void* ImageLoaderMachO::getEntryFromLC_UNIXTHREAD() const
1364 {
1365 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1366 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1367 const struct load_command* cmd = cmds;
1368 for (uint32_t i = 0; i < cmd_count; ++i) {
1369 if ( cmd->cmd == LC_UNIXTHREAD ) {
1370 #if __i386__
1371 const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
1372 void* entry = (void*)(registers->eip + fSlide);
1373 // <rdar://problem/8543820&9228031> verify entry point is in image
1374 if ( this->containsAddress(entry) )
1375 return entry;
1376 #elif __x86_64__
1377 const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
1378 void* entry = (void*)(registers->rip + fSlide);
1379 // <rdar://problem/8543820&9228031> verify entry point is in image
1380 if ( this->containsAddress(entry) )
1381 return entry;
1382 #endif
1383 }
1384 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1385 }
1386 throw "no valid entry point";
1387 }
1388
1389 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh)
1390 {
1391 // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem
1392 if ( libCount > 1 )
1393 return false;
1394
1395 // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
1396 if ( mh->filetype == MH_EXECUTE )
1397 return false;
1398
1399 bool isNonOSdylib = false;
1400 const uint32_t cmd_count = mh->ncmds;
1401 const struct load_command* const cmds = (struct load_command*)((uint8_t*)mh+sizeof(macho_header));
1402 const struct load_command* cmd = cmds;
1403 for (uint32_t i = 0; i < cmd_count; ++i) {
1404 switch (cmd->cmd) {
1405 case LC_LOAD_DYLIB:
1406 case LC_LOAD_WEAK_DYLIB:
1407 case LC_REEXPORT_DYLIB:
1408 case LC_LOAD_UPWARD_DYLIB:
1409 return false;
1410 case LC_ID_DYLIB:
1411 {
1412 const dylib_command* dylibID = (dylib_command*)cmd;
1413 const char* installPath = (char*)cmd + dylibID->dylib.name.offset;
1414 // It is OK for OS dylibs (libSystem or libmath) to have no dependents
1415 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first
1416 isNonOSdylib = ( (strncmp(installPath, "/usr/lib/", 9) != 0) && (strncmp(installPath, "/System/DriverKit/usr/lib/", 26) != 0) );
1417 // if (isNonOSdylib) dyld::log("ImageLoaderMachO::needsAddedLibSystemDepency(%s)\n", installPath);
1418 }
1419 break;
1420 }
1421 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1422 }
1423 return isNonOSdylib;
1424 }
1425
1426
1427 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs[])
1428 {
1429 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header*)fMachOData) ) {
1430 DependentLibraryInfo* lib = &libs[0];
1431 lib->name = LIBSYSTEM_DYLIB_PATH;
1432 lib->info.checksum = 0;
1433 lib->info.minVersion = 0;
1434 lib->info.maxVersion = 0;
1435 lib->required = false;
1436 lib->reExported = false;
1437 lib->upward = false;
1438 }
1439 else {
1440 uint32_t index = 0;
1441 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1442 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1443 const struct load_command* cmd = cmds;
1444 for (uint32_t i = 0; i < cmd_count; ++i) {
1445 switch (cmd->cmd) {
1446 case LC_LOAD_DYLIB:
1447 case LC_LOAD_WEAK_DYLIB:
1448 case LC_REEXPORT_DYLIB:
1449 case LC_LOAD_UPWARD_DYLIB:
1450 {
1451 const struct dylib_command* dylib = (struct dylib_command*)cmd;
1452 DependentLibraryInfo* lib = &libs[index++];
1453 lib->name = (char*)cmd + dylib->dylib.name.offset;
1454 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
1455 lib->info.checksum = dylib->dylib.timestamp;
1456 lib->info.minVersion = dylib->dylib.compatibility_version;
1457 lib->info.maxVersion = dylib->dylib.current_version;
1458 lib->required = (cmd->cmd != LC_LOAD_WEAK_DYLIB);
1459 lib->reExported = (cmd->cmd == LC_REEXPORT_DYLIB);
1460 lib->upward = (cmd->cmd == LC_LOAD_UPWARD_DYLIB);
1461 }
1462 break;
1463 }
1464 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1465 }
1466 }
1467 }
1468
1469 ImageLoader::LibraryInfo ImageLoaderMachO::doGetLibraryInfo(const LibraryInfo&)
1470 {
1471 LibraryInfo info;
1472 if ( fDylibIDOffset != 0 ) {
1473 const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]);
1474 info.minVersion = dylibID->dylib.compatibility_version;
1475 info.maxVersion = dylibID->dylib.current_version;
1476 info.checksum = dylibID->dylib.timestamp;
1477 }
1478 else {
1479 info.minVersion = 0;
1480 info.maxVersion = 0;
1481 info.checksum = 0;
1482 }
1483 return info;
1484 }
1485
1486 void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const char*>& paths) const
1487 {
1488 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1489 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1490 const struct load_command* cmd = cmds;
1491 for (uint32_t i = 0; i < cmd_count; ++i) {
1492 switch (cmd->cmd) {
1493 case LC_RPATH:
1494 const char* pathToAdd = NULL;
1495 const char* path = (char*)cmd + ((struct rpath_command*)cmd)->path.offset;
1496 if ( (strncmp(path, "@loader_path", 12) == 0) && ((path[12] == '/') || (path[12] == '\0')) ) {
1497 if ( !context.allowAtPaths && (context.mainExecutable == this) ) {
1498 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path (Codesign main executable with Library Validation to allow @ paths)\n", path, this->getPath());
1499 break;
1500 }
1501 char resolvedPath[PATH_MAX];
1502 if ( realpath(this->getPath(), resolvedPath) != NULL ) {
1503 char newRealPath[strlen(resolvedPath) + strlen(path)];
1504 strcpy(newRealPath, resolvedPath);
1505 char* addPoint = strrchr(newRealPath,'/');
1506 if ( addPoint != NULL ) {
1507 strcpy(addPoint, &path[12]);
1508 pathToAdd = strdup(newRealPath);
1509 }
1510 }
1511 }
1512 else if ( (strncmp(path, "@executable_path", 16) == 0) && ((path[16] == '/') || (path[16] == '\0')) ) {
1513 if ( !context.allowAtPaths) {
1514 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path (Codesign main executable with Library Validation to allow @ paths)\n", path, this->getPath());
1515 break;
1516 }
1517 char resolvedPath[PATH_MAX];
1518 if ( realpath(context.mainExecutable->getPath(), resolvedPath) != NULL ) {
1519 char newRealPath[strlen(resolvedPath) + strlen(path)];
1520 strcpy(newRealPath, resolvedPath);
1521 char* addPoint = strrchr(newRealPath,'/');
1522 if ( addPoint != NULL ) {
1523 strcpy(addPoint, &path[16]);
1524 pathToAdd = strdup(newRealPath);
1525 }
1526 }
1527 }
1528 else if ( (path[0] != '/') && !context.allowAtPaths) {
1529 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path, this->getPath());
1530 break;
1531 }
1532 #if SUPPORT_ROOT_PATH
1533 else if ( (path[0] == '/') && (context.rootPaths != NULL) ) {
1534 // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
1535 // <rdar://problem/49576123> Even if DYLD_ROOT_PATH exists, LC_RPATH should add raw path to rpaths
1536 // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists
1537 for (const char** rp = context.rootPaths; *rp != NULL; ++rp) {
1538 char newPath[PATH_MAX];
1539 strlcpy(newPath, *rp, PATH_MAX);
1540 strlcat(newPath, path, PATH_MAX);
1541 struct stat stat_buf;
1542 if ( dyld3::stat(newPath, &stat_buf) != -1 ) {
1543 // dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
1544 paths.push_back(strdup(newPath));
1545 }
1546 }
1547 // add in raw absolute path without root prefix
1548 pathToAdd = strdup(path);
1549 }
1550 #endif
1551 else {
1552 // realpath() is slow, and /usr/lib/swift is a real path, so don't realpath it
1553 if ( strcmp(path, "/usr/lib/swift") != 0 ) {
1554 char resolvedPath[PATH_MAX];
1555 if ( (realpath(path, resolvedPath) != NULL) && (strcmp(path, resolvedPath) != 0) ) {
1556 // <rdar://problem/45470293> support LC_RPATH symlinks to directories of things in the dyld cache
1557 path = resolvedPath;
1558 }
1559 }
1560 // make copy so that all elements of 'paths' can be freed
1561 pathToAdd = strdup(path);
1562 }
1563 if ( pathToAdd != NULL )
1564 paths.push_back(pathToAdd);
1565 break;
1566 }
1567 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1568 }
1569 }
1570
1571
1572 bool ImageLoaderMachO::getUUID(uuid_t uuid) const
1573 {
1574 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1575 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1576 const struct load_command* cmd = cmds;
1577 for (uint32_t i = 0; i < cmd_count; ++i) {
1578 switch (cmd->cmd) {
1579 case LC_UUID:
1580 uuid_command* uc = (uuid_command*)cmd;
1581 memcpy(uuid, uc->uuid, 16);
1582 return true;
1583 }
1584 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1585 }
1586 bzero(uuid, 16);
1587 return false;
1588 }
1589
1590 void ImageLoaderMachO::doRebase(const LinkContext& context)
1591 {
1592 // <rdar://problem/25329861> Delay calling setNeverUnload() until we know this is not for dlopen_preflight()
1593 if ( fRetainForObjC )
1594 this->setNeverUnload();
1595
1596 // dylibs with thread local variables cannot be unloaded because there is no way to clean up all threads
1597 if ( !this->inSharedCache() && (this->machHeader()->flags & MH_HAS_TLV_DESCRIPTORS) )
1598 this->setNeverUnload();
1599
1600 // if prebound and loaded at prebound address, then no need to rebase
1601 if ( this->usablePrebinding(context) ) {
1602 // skip rebasing because prebinding is valid
1603 ++fgImagesWithUsedPrebinding; // bump totals for statistics
1604 return;
1605 }
1606
1607 // print why prebinding was not used
1608 if ( context.verbosePrebinding ) {
1609 if ( !this->isPrebindable() ) {
1610 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1611 }
1612 else if ( fSlide != 0 ) {
1613 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1614 }
1615 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1616 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1617 }
1618 else if ( !this->usesTwoLevelNameSpace() ){
1619 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1620 }
1621 else {
1622 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1623 }
1624 }
1625
1626 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
1627
1628 #if PREBOUND_IMAGE_SUPPORT
1629 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1630 // if this image is in the shared cache, do not reset, they will be bound in doBind()
1631 if ( this->isPrebindable() && !fInSharedCache )
1632 this->resetPreboundLazyPointers(context);
1633 #endif
1634
1635 // if loaded at preferred address, no rebasing necessary
1636 if ( this->fSlide == 0 )
1637 return;
1638
1639 #if TEXT_RELOC_SUPPORT
1640 // if there are __TEXT fixups, temporarily make __TEXT writable
1641 if ( fTextSegmentRebases )
1642 this->makeTextSegmentWritable(context, true);
1643 #endif
1644
1645 // do actual rebasing
1646 this->rebase(context, fSlide);
1647
1648 #if TEXT_RELOC_SUPPORT
1649 // if there were __TEXT fixups, restore write protection
1650 if ( fTextSegmentRebases )
1651 this->makeTextSegmentWritable(context, false);
1652
1653 #endif
1654 }
1655
1656 #if TEXT_RELOC_SUPPORT
1657 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext& context, bool writeable)
1658 {
1659 for(unsigned int i=0; i < fSegmentsCount; ++i) {
1660 if ( segExecutable(i) ) {
1661 if ( writeable ) {
1662 segMakeWritable(i, context);
1663 }
1664 else {
1665 #if !__i386__ && !__x86_64__
1666 // some processors require range to be invalidated before it is made executable
1667 sys_icache_invalidate((void*)segActualLoadAddress(i), segSize(textSegmentIndex));
1668 #endif
1669 segProtect(i, context);
1670 }
1671 }
1672 }
1673
1674 }
1675 #endif
1676
1677 const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name, bool searchReExports, const char* thisPath, const ImageLoader** foundIn) const
1678 {
1679 // look in this image first
1680 const ImageLoader::Symbol* result = this->findShallowExportedSymbol(name, foundIn);
1681 if ( result != NULL )
1682 return result;
1683
1684 if ( searchReExports ) {
1685 for(unsigned int i=0; i < libraryCount(); ++i){
1686 if ( libReExported(i) ) {
1687 ImageLoader* image = libImage(i);
1688 if ( image != NULL ) {
1689 const char* reExPath = libPath(i);
1690 result = image->findExportedSymbol(name, searchReExports, reExPath, foundIn);
1691 if ( result != NULL )
1692 return result;
1693 }
1694 }
1695 }
1696 }
1697
1698
1699 return NULL;
1700 }
1701
1702
1703
1704 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context,
1705 const ImageLoader* requestor, bool runResolver, const char* symbolName) const
1706 {
1707 return this->getSymbolAddress(sym, requestor, context, runResolver);
1708 }
1709
1710 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol* sym, const ImageLoader* requestor,
1711 const LinkContext& context, bool runResolver) const
1712 {
1713 uintptr_t result = exportedSymbolAddress(context, sym, requestor, runResolver);
1714 // check for interposing overrides
1715 result = interposedAddress(context, result, requestor);
1716 return result;
1717 }
1718
1719 ImageLoader::DefinitionFlags ImageLoaderMachO::getExportedSymbolInfo(const Symbol* sym) const
1720 {
1721 if ( exportedSymbolIsWeakDefintion(sym) )
1722 return kWeakDefinition;
1723 else
1724 return kNoDefinitionOptions;
1725 }
1726
1727 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol* sym) const
1728 {
1729 return exportedSymbolName(sym);
1730 }
1731
1732 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1733 {
1734 return exportedSymbolCount();
1735 }
1736
1737
1738 const ImageLoader::Symbol* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index) const
1739 {
1740 return exportedSymbolIndexed(index);
1741 }
1742
1743
1744 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1745 {
1746 return importedSymbolCount();
1747 }
1748
1749
1750 const ImageLoader::Symbol* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index) const
1751 {
1752 return importedSymbolIndexed(index);
1753 }
1754
1755
1756 ImageLoader::ReferenceFlags ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol* sym) const
1757 {
1758 ImageLoader::ReferenceFlags flags = kNoReferenceOptions;
1759 return flags;
1760 }
1761
1762
1763 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol* sym) const
1764 {
1765 return importedSymbolName(sym);
1766 }
1767
1768
1769 bool ImageLoaderMachO::getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length)
1770 {
1771 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1772 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1773 const struct load_command* cmd = cmds;
1774 for (uint32_t i = 0; i < cmd_count; ++i) {
1775 switch (cmd->cmd) {
1776 case LC_SEGMENT_COMMAND:
1777 {
1778 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1779 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1780 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1781 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1782 if ( (strcmp(sect->segname, segmentName) == 0) && (strcmp(sect->sectname, sectionName) == 0) ) {
1783 *start = (uintptr_t*)(sect->addr + fSlide);
1784 *length = sect->size;
1785 return true;
1786 }
1787 }
1788 }
1789 break;
1790 }
1791 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1792 }
1793 *start = NULL;
1794 *length = 0;
1795 return false;
1796 }
1797
1798 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections* info)
1799 {
1800 info->mh = this->machHeader();
1801 info->dwarf_section = 0;
1802 info->dwarf_section_length = 0;
1803 info->compact_unwind_section = 0;
1804 info->compact_unwind_section_length = 0;
1805 if ( fEHFrameSectionOffset != 0 ) {
1806 const macho_section* sect = (macho_section*)&fMachOData[fEHFrameSectionOffset];
1807 info->dwarf_section = (void*)(sect->addr + fSlide);
1808 info->dwarf_section_length = sect->size;
1809 }
1810 if ( fUnwindInfoSectionOffset != 0 ) {
1811 const macho_section* sect = (macho_section*)&fMachOData[fUnwindInfoSectionOffset];
1812 info->compact_unwind_section = (void*)(sect->addr + fSlide);
1813 info->compact_unwind_section_length = sect->size;
1814 }
1815 }
1816
1817 intptr_t ImageLoaderMachO::computeSlide(const mach_header* mh)
1818 {
1819 const uint32_t cmd_count = mh->ncmds;
1820 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
1821 const load_command* cmd = cmds;
1822 for (uint32_t i = 0; i < cmd_count; ++i) {
1823 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1824 const macho_segment_command* seg = (macho_segment_command*)cmd;
1825 if ( strcmp(seg->segname, "__TEXT") == 0 )
1826 return (char*)mh - (char*)(seg->vmaddr);
1827 }
1828 cmd = (const load_command*)(((char*)cmd)+cmd->cmdsize);
1829 }
1830 return 0;
1831 }
1832
1833 bool ImageLoaderMachO::findSection(const mach_header* mh, const char* segmentName, const char* sectionName, void** sectAddress, size_t* sectSize)
1834 {
1835 const uint32_t cmd_count = mh->ncmds;
1836 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
1837 const load_command* cmd = cmds;
1838 for (uint32_t i = 0; i < cmd_count; ++i) {
1839 switch (cmd->cmd) {
1840 case LC_SEGMENT_COMMAND:
1841 {
1842 const macho_segment_command* seg = (macho_segment_command*)cmd;
1843 const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command));
1844 const macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1845 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1846 if ( (strcmp(sect->segname, segmentName) == 0) && (strcmp(sect->sectname, sectionName) == 0) ) {
1847 *sectAddress = (void*)(sect->addr + computeSlide(mh));
1848 *sectSize = sect->size;
1849 return true;
1850 }
1851 }
1852 }
1853 break;
1854 }
1855 cmd = (const load_command*)(((char*)cmd)+cmd->cmdsize);
1856 }
1857 return false;
1858 }
1859
1860
1861 const macho_section* ImageLoaderMachO::findSection(const void* imageInterior) const
1862 {
1863 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1864 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1865 const struct load_command* cmd = cmds;
1866 const uintptr_t unslidInteriorAddress = (uintptr_t)imageInterior - this->getSlide();
1867 for (uint32_t i = 0; i < cmd_count; ++i) {
1868 switch (cmd->cmd) {
1869 case LC_SEGMENT_COMMAND:
1870 {
1871 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1872 if ( (unslidInteriorAddress >= seg->vmaddr) && (unslidInteriorAddress < (seg->vmaddr+seg->vmsize)) ) {
1873 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1874 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1875 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1876 if ((sect->addr <= unslidInteriorAddress) && (unslidInteriorAddress < (sect->addr+sect->size))) {
1877 return sect;
1878 }
1879 }
1880 }
1881 }
1882 break;
1883 }
1884 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1885 }
1886 return nullptr;
1887 }
1888
1889
1890 bool ImageLoaderMachO::findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset)
1891 {
1892 if (const struct macho_section* sect = findSection(imageInterior)) {
1893 const uintptr_t unslidInteriorAddress = (uintptr_t)imageInterior - this->getSlide();
1894 if ( segmentName != NULL )
1895 *segmentName = sect->segname;
1896 if ( sectionName != NULL )
1897 *sectionName = sect->sectname;
1898 if ( sectionOffset != NULL )
1899 *sectionOffset = unslidInteriorAddress - sect->addr;
1900 return true;
1901 }
1902 return false;
1903 }
1904
1905 const char* ImageLoaderMachO::libPath(unsigned int index) const
1906 {
1907 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1908 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1909 const struct load_command* cmd = cmds;
1910 unsigned count = 0;
1911 for (uint32_t i = 0; i < cmd_count; ++i) {
1912 switch ( cmd->cmd ) {
1913 case LC_LOAD_DYLIB:
1914 case LC_LOAD_WEAK_DYLIB:
1915 case LC_REEXPORT_DYLIB:
1916 case LC_LOAD_UPWARD_DYLIB:
1917 if ( index == count ) {
1918 const struct dylib_command* dylibCmd = (struct dylib_command*)cmd;
1919 return (char*)cmd + dylibCmd->dylib.name.offset;
1920 }
1921 ++count;
1922 break;
1923 }
1924 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1925 }
1926
1927 // <rdar://problem/24256354> if image linked with nothing and we implicitly added libSystem.dylib, return that
1928 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header*)fMachOData) ) {
1929 return LIBSYSTEM_DYLIB_PATH;
1930 }
1931
1932 return NULL;
1933 }
1934
1935
1936 void __attribute__((noreturn)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext& context, const char* symbol,
1937 const char* referencedFrom, const char* fromVersMismatch,
1938 const char* expectedIn)
1939 {
1940 // record values for possible use by CrashReporter or Finder
1941 (*context.setErrorStrings)(DYLD_EXIT_REASON_SYMBOL_MISSING, referencedFrom, expectedIn, symbol);
1942 dyld::throwf("Symbol not found: %s\n Referenced from: %s%s\n Expected in: %s\n",
1943 symbol, referencedFrom, fromVersMismatch, expectedIn);
1944 }
1945
1946 const mach_header* ImageLoaderMachO::machHeader() const
1947 {
1948 return (mach_header*)fMachOData;
1949 }
1950
1951 uintptr_t ImageLoaderMachO::getSlide() const
1952 {
1953 return fSlide;
1954 }
1955
1956 // hmm. maybe this should be up in ImageLoader??
1957 const void* ImageLoaderMachO::getEnd() const
1958 {
1959 uintptr_t lastAddress = 0;
1960 for(unsigned int i=0; i < fSegmentsCount; ++i) {
1961 uintptr_t segEnd = segActualEndAddress(i);
1962 if ( strcmp(segName(i), "__UNIXSTACK") != 0 ) {
1963 if ( segEnd > lastAddress )
1964 lastAddress = segEnd;
1965 }
1966 }
1967 return (const void*)lastAddress;
1968 }
1969
1970 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext& context, uintptr_t baseVMAddress,
1971 uintptr_t location, uintptr_t value,
1972 uint8_t type, const char* symbolName,
1973 intptr_t addend, const char* inPath, const char* toPath, const char* msg,
1974 ExtraBindData *extraBindData, uintptr_t slide)
1975 {
1976 auto logBind = [&]() {
1977 if ( !context.verboseBind )
1978 return;
1979 if ( addend != 0 ) {
1980 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n",
1981 msg, shortName(inPath), (uintptr_t)location,
1982 ((toPath != NULL) ? shortName(toPath) : "<missing weak_import>"),
1983 symbolName, (uintptr_t)location, value, addend);
1984 } else {
1985 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n",
1986 msg, shortName(inPath), (uintptr_t)location,
1987 ((toPath != NULL) ? shortName(toPath) : "<missing weak_import>"),
1988 symbolName, (uintptr_t)location, value);
1989 }
1990 };
1991
1992
1993 #if LOG_BINDINGS
1994 // dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
1995 #endif
1996
1997 // do actual update
1998 uintptr_t* locationToFix = (uintptr_t*)location;
1999 uint32_t* loc32;
2000 uintptr_t newValue = value+addend;
2001 uint32_t value32;
2002 switch (type) {
2003 case BIND_TYPE_POINTER:
2004 logBind();
2005 // test first so we don't needless dirty pages
2006 if ( *locationToFix != newValue )
2007 *locationToFix = newValue;
2008 break;
2009 case BIND_TYPE_TEXT_ABSOLUTE32:
2010 logBind();
2011 loc32 = (uint32_t*)locationToFix;
2012 value32 = (uint32_t)newValue;
2013 if ( *loc32 != value32 )
2014 *loc32 = value32;
2015 break;
2016 case BIND_TYPE_TEXT_PCREL32:
2017 logBind();
2018 loc32 = (uint32_t*)locationToFix;
2019 value32 = (uint32_t)(newValue - (((uintptr_t)locationToFix) + 4));
2020 if ( *loc32 != value32 )
2021 *loc32 = value32;
2022 break;
2023 case BIND_TYPE_THREADED_BIND:
2024 logBind();
2025 // test first so we don't needless dirty pages
2026 if ( *locationToFix != newValue )
2027 *locationToFix = newValue;
2028 break;
2029 case BIND_TYPE_THREADED_REBASE: {
2030 // Regular pointer which needs to fit in 51-bits of value.
2031 // C++ RTTI uses the top bit, so we'll allow the whole top-byte
2032 // and the signed-extended bottom 43-bits to be fit in to 51-bits.
2033 uint64_t top8Bits = *locationToFix & 0x0007F80000000000ULL;
2034 uint64_t bottom43Bits = *locationToFix & 0x000007FFFFFFFFFFULL;
2035 uint64_t targetValue = ( top8Bits << 13 ) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
2036 newValue = (uintptr_t)(targetValue + slide);
2037 if ( context.verboseRebase ) {
2038 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX = 0x%08lX\n", shortName(inPath), (uintptr_t)locationToFix, slide, newValue);
2039 }
2040 *locationToFix = newValue;
2041 break;
2042 }
2043 default:
2044 dyld::throwf("bad bind type %d", type);
2045 }
2046
2047 // update statistics
2048 ++fgTotalBindFixups;
2049
2050 return newValue;
2051 }
2052
2053
2054
2055
2056
2057 #if SUPPORT_OLD_CRT_INITIALIZATION
2058 // first 16 bytes of "start" in crt1.o
2059 #if __i386__
2060 static uint8_t sStandardEntryPointInstructions[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
2061 #endif
2062 #endif
2063
2064 struct DATAdyld {
2065 void* dyldLazyBinder; // filled in at launch by dyld to point into dyld to &stub_binding_helper
2066 void* dyldFuncLookup; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
2067 // the following only exist in main executables built for 10.5 or later
2068 ProgramVars vars;
2069 };
2070
2071 // These are defined in dyldStartup.s
2072 extern "C" void stub_binding_helper();
2073 extern "C" int _dyld_func_lookup(const char* name, void** address);
2074
2075 static const char* libDyldPath(const ImageLoader::LinkContext& context)
2076 {
2077 #if TARGET_OS_OSX
2078 if ( context.driverKit )
2079 return DRIVERKIT_LIBDYLD_DYLIB_PATH;
2080 else
2081 #endif
2082 return LIBDYLD_DYLIB_PATH;
2083 }
2084
2085 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
2086 {
2087 const macho_header* mh = (macho_header*)fMachOData;
2088 const uint32_t cmd_count = mh->ncmds;
2089 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2090 const struct load_command* cmd;
2091 // There used to be some optimizations to skip this section scan, but we need to handle the
2092 // __dyld section in libdyld.dylib, so everything needs to be scanned for now.
2093 // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv
2094 if ( true ) {
2095 cmd = cmds;
2096 for (uint32_t i = 0; i < cmd_count; ++i) {
2097 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
2098 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2099 if ( strncmp(seg->segname, "__DATA", 6) == 0 ) {
2100 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2101 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2102 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2103 if ( strcmp(sect->sectname, "__dyld" ) == 0 ) {
2104 struct DATAdyld* dd = (struct DATAdyld*)(sect->addr + fSlide);
2105 #if !__arm64__ && !__ARM_ARCH_7K__
2106 if ( sect->size > offsetof(DATAdyld, dyldLazyBinder) ) {
2107 if ( dd->dyldLazyBinder != (void*)&stub_binding_helper )
2108 dd->dyldLazyBinder = (void*)&stub_binding_helper;
2109 }
2110 #endif // !__arm64__
2111 // <rdar://problem/40352925> Add work around for existing apps that have deprecated __dyld section
2112 const char* installNm = this->getInstallPath();
2113 if ( (mh->filetype != MH_DYLIB) || (installNm == NULL) || (strcmp(installNm, libDyldPath(context)) != 0) ) {
2114 #if TARGET_OS_OSX
2115 // don't allow macOS apps build with 10.14 or later SDK and targeting 10.8 or later to have a __dyld section
2116 if ( (minOSVersion() >= 0x000a0800) && (sdkVersion() >= 0x000a0e00) )
2117 dyld::throwf("__dyld section not supported in %s", this->getPath());
2118 #endif
2119 #if TARGET_OS_IOS || TARGET_OS_TV
2120 // don't allow iOS apps build with 12.0 or later SDK to have a __dyld section
2121 if ( sdkVersion() >= 0x000c0000 )
2122 dyld::throwf("__dyld section not supported in %s", this->getPath());
2123 #endif
2124 #if TARGET_OS_WATCH
2125 if ( sdkVersion() >= 0x00050000 )
2126 dyld::throwf("__dyld section not supported in %s", this->getPath());
2127 #endif
2128 }
2129 if ( sect->size > offsetof(DATAdyld, dyldFuncLookup) ) {
2130 if ( dd->dyldFuncLookup != (void*)&_dyld_func_lookup )
2131 dd->dyldFuncLookup = (void*)&_dyld_func_lookup;
2132 }
2133 if ( mh->filetype == MH_EXECUTE ) {
2134 // there are two ways to get the program variables
2135 if ( (sect->size > offsetof(DATAdyld, vars)) && (dd->vars.mh == mh) ) {
2136 // some really old binaries have space for vars, but it is zero filled
2137 // main executable has 10.5 style __dyld section that has program variable pointers
2138 context.setNewProgramVars(dd->vars);
2139 }
2140 else {
2141 // main executable is pre-10.5 and requires the symbols names to be looked up
2142 this->lookupProgramVars(context);
2143 #if SUPPORT_OLD_CRT_INITIALIZATION
2144 // If the first 16 bytes of the entry point's instructions do not
2145 // match what crt1.o supplies, then the program has a custom entry point.
2146 // This means it might be doing something that needs to be executed before
2147 // initializers are run.
2148 if ( memcmp(this->getEntryFromLC_UNIXTHREAD(), sStandardEntryPointInstructions, 16) != 0 ) {
2149 if ( context.verboseInit )
2150 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
2151 context.setRunInitialzersOldWay();
2152 }
2153 #endif
2154 }
2155 }
2156 else if ( mh->filetype == MH_DYLIB ) {
2157 const char* installPath = this->getInstallPath();
2158 if ( (installPath != NULL) && ((strncmp(installPath, "/usr/lib/", 9) == 0) || (strncmp(installPath, "/System/DriverKit/usr/lib/", 26) == 0)) ) {
2159 if ( sect->size > offsetof(DATAdyld, vars) ) {
2160 // use ProgramVars from libdyld.dylib but tweak mh field to correct value
2161 dd->vars.mh = context.mainExecutable->machHeader();
2162 context.setNewProgramVars(dd->vars);
2163 }
2164 }
2165 }
2166 }
2167 else if ( (strcmp(sect->sectname, "__program_vars" ) == 0) && (mh->filetype == MH_EXECUTE) ) {
2168 // this is a Mac OS X 10.6 or later main executable
2169 struct ProgramVars* pv = (struct ProgramVars*)(sect->addr + fSlide);
2170 context.setNewProgramVars(*pv);
2171 }
2172 }
2173 }
2174 }
2175 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2176 }
2177 }
2178 }
2179
2180
2181 void ImageLoaderMachO::lookupProgramVars(const LinkContext& context) const
2182 {
2183 ProgramVars vars = context.programVars;
2184 const ImageLoader::Symbol* sym;
2185
2186 // get mach header directly
2187 vars.mh = (macho_header*)fMachOData;
2188
2189 // lookup _NXArgc
2190 sym = this->findShallowExportedSymbol("_NXArgc", NULL);
2191 if ( sym != NULL )
2192 vars.NXArgcPtr = (int*)this->getExportedSymbolAddress(sym, context, this, false, NULL);
2193
2194 // lookup _NXArgv
2195 sym = this->findShallowExportedSymbol("_NXArgv", NULL);
2196 if ( sym != NULL )
2197 vars.NXArgvPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false, NULL);
2198
2199 // lookup _environ
2200 sym = this->findShallowExportedSymbol("_environ", NULL);
2201 if ( sym != NULL )
2202 vars.environPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false, NULL);
2203
2204 // lookup __progname
2205 sym = this->findShallowExportedSymbol("___progname", NULL);
2206 if ( sym != NULL )
2207 vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this, false, NULL);
2208
2209 context.setNewProgramVars(vars);
2210 }
2211
2212
2213 bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
2214 {
2215 // dylibs in dyld cache do not need to be rebased or bound
2216 // for chained fixups always pretend dylib is up to date, patch tables will be used later
2217 if ( fInSharedCache && (this->allDependentLibrariesAsWhenPreBound() || context.dyldCache->header.builtFromChainedFixups) ) {
2218 // allow environment variables to disable prebinding
2219 if ( context.bindFlat )
2220 return false;
2221 switch ( context.prebindUsage ) {
2222 case kUseAllPrebinding:
2223 return true;
2224 case kUseSplitSegPrebinding:
2225 return this->fIsSplitSeg;
2226 case kUseAllButAppPredbinding:
2227 return (this != context.mainExecutable);
2228 case kUseNoPrebinding:
2229 return false;
2230 }
2231 }
2232 return false;
2233 }
2234
2235 static void *stripPointer(void *ptr) {
2236 #if __has_feature(ptrauth_calls)
2237 return __builtin_ptrauth_strip(ptr, ptrauth_key_asia);
2238 #else
2239 return ptr;
2240 #endif
2241 }
2242
2243
2244 void ImageLoaderMachO::doImageInit(const LinkContext& context)
2245 {
2246 if ( fHasDashInit ) {
2247 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2248 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2249 const struct load_command* cmd = cmds;
2250 for (uint32_t i = 0; i < cmd_count; ++i) {
2251 switch (cmd->cmd) {
2252 case LC_ROUTINES_COMMAND:
2253 Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
2254 #if __has_feature(ptrauth_calls)
2255 func = (Initializer)__builtin_ptrauth_sign_unauthenticated((void*)func, ptrauth_key_asia, 0);
2256 #endif
2257 // <rdar://problem/8543820&9228031> verify initializers are in image
2258 if ( ! this->containsAddress(stripPointer((void*)func)) ) {
2259 dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
2260 }
2261 if ( ! dyld::gProcessInfo->libSystemInitialized ) {
2262 // <rdar://problem/17973316> libSystem initializer must run first
2263 dyld::throwf("-init function in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2264 }
2265 if ( context.verboseInit )
2266 dyld::log("dyld: calling -init function %p in %s\n", func, this->getPath());
2267 {
2268 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER, (uint64_t)fMachOData, (uint64_t)func, 0);
2269 func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
2270 }
2271 break;
2272 }
2273 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2274 }
2275 }
2276 }
2277
2278 static const char* libSystemPath(const ImageLoader::LinkContext& context)
2279 {
2280 #if TARGET_OS_OSX
2281 if ( context.driverKit )
2282 return DRIVERKIT_LIBSYSTEM_DYLIB_PATH;
2283 else
2284 #endif
2285 return LIBSYSTEM_DYLIB_PATH;
2286 }
2287
2288
2289
2290 void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
2291 {
2292 if ( fHasInitializers ) {
2293 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2294 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2295 const struct load_command* cmd = cmds;
2296 for (uint32_t i = 0; i < cmd_count; ++i) {
2297 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
2298 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2299 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2300 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2301 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2302 const uint8_t type = sect->flags & SECTION_TYPE;
2303 if ( type == S_MOD_INIT_FUNC_POINTERS ) {
2304 Initializer* inits = (Initializer*)(sect->addr + fSlide);
2305 const size_t count = sect->size / sizeof(uintptr_t);
2306 // <rdar://problem/23929217> Ensure __mod_init_func section is within segment
2307 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
2308 dyld::throwf("__mod_init_funcs section has malformed address range for %s\n", this->getPath());
2309 for (size_t j=0; j < count; ++j) {
2310 Initializer func = inits[j];
2311 // <rdar://problem/8543820&9228031> verify initializers are in image
2312 if ( ! this->containsAddress(stripPointer((void*)func)) ) {
2313 dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
2314 }
2315 if ( ! dyld::gProcessInfo->libSystemInitialized ) {
2316 // <rdar://problem/17973316> libSystem initializer must run first
2317 const char* installPath = getInstallPath();
2318 if ( (installPath == NULL) || (strcmp(installPath, libSystemPath(context)) != 0) )
2319 dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2320 }
2321 if ( context.verboseInit )
2322 dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
2323 bool haveLibSystemHelpersBefore = (dyld::gLibSystemHelpers != NULL);
2324 {
2325 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER, (uint64_t)fMachOData, (uint64_t)func, 0);
2326 func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
2327 }
2328 bool haveLibSystemHelpersAfter = (dyld::gLibSystemHelpers != NULL);
2329 if ( !haveLibSystemHelpersBefore && haveLibSystemHelpersAfter ) {
2330 // now safe to use malloc() and other calls in libSystem.dylib
2331 dyld::gProcessInfo->libSystemInitialized = true;
2332 }
2333 }
2334 }
2335 else if ( type == S_INIT_FUNC_OFFSETS ) {
2336 const uint32_t* inits = (uint32_t*)(sect->addr + fSlide);
2337 const size_t count = sect->size / sizeof(uint32_t);
2338 // Ensure section is within segment
2339 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
2340 dyld::throwf("__init_offsets section has malformed address range for %s\n", this->getPath());
2341 if ( seg->initprot & VM_PROT_WRITE )
2342 dyld::throwf("__init_offsets section is not in read-only segment %s\n", this->getPath());
2343 for (size_t j=0; j < count; ++j) {
2344 uint32_t funcOffset = inits[j];
2345 // verify initializers are in image
2346 if ( ! this->containsAddress((uint8_t*)this->machHeader() + funcOffset) ) {
2347 dyld::throwf("initializer function offset 0x%08X not in mapped image for %s\n", funcOffset, this->getPath());
2348 }
2349 if ( ! dyld::gProcessInfo->libSystemInitialized ) {
2350 // <rdar://problem/17973316> libSystem initializer must run first
2351 const char* installPath = getInstallPath();
2352 if ( (installPath == NULL) || (strcmp(installPath, libSystemPath(context)) != 0) )
2353 dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2354 }
2355 Initializer func = (Initializer)((uint8_t*)this->machHeader() + funcOffset);
2356 if ( context.verboseInit )
2357 dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
2358 #if __has_feature(ptrauth_calls)
2359 func = (Initializer)__builtin_ptrauth_sign_unauthenticated((void*)func, ptrauth_key_asia, 0);
2360 #endif
2361 bool haveLibSystemHelpersBefore = (dyld::gLibSystemHelpers != NULL);
2362 {
2363 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER, (uint64_t)fMachOData, (uint64_t)func, 0);
2364 func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
2365 }
2366 bool haveLibSystemHelpersAfter = (dyld::gLibSystemHelpers != NULL);
2367 if ( !haveLibSystemHelpersBefore && haveLibSystemHelpersAfter ) {
2368 // now safe to use malloc() and other calls in libSystem.dylib
2369 dyld::gProcessInfo->libSystemInitialized = true;
2370 }
2371 }
2372 }
2373 }
2374 }
2375 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2376 }
2377 }
2378 }
2379
2380
2381
2382 void ImageLoaderMachO::doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs)
2383 {
2384 if ( fHasDOFSections ) {
2385 // walk load commands (mapped in at start of __TEXT segment)
2386 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2387 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2388 const struct load_command* cmd = cmds;
2389 for (uint32_t i = 0; i < cmd_count; ++i) {
2390 switch (cmd->cmd) {
2391 case LC_SEGMENT_COMMAND:
2392 {
2393 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2394 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2395 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2396 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2397 if ( (sect->flags & SECTION_TYPE) == S_DTRACE_DOF ) {
2398 // <rdar://problem/23929217> Ensure section is within segment
2399 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
2400 dyld::throwf("DOF section has malformed address range for %s\n", this->getPath());
2401 ImageLoader::DOFInfo info;
2402 info.dof = (void*)(sect->addr + fSlide);
2403 info.imageHeader = this->machHeader();
2404 info.imageShortName = this->getShortName();
2405 dofs.push_back(info);
2406 }
2407 }
2408 }
2409 break;
2410 }
2411 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2412 }
2413 }
2414 }
2415
2416
2417 bool ImageLoaderMachO::doInitialization(const LinkContext& context)
2418 {
2419 CRSetCrashLogMessage2(this->getPath());
2420
2421 // mach-o has -init and static initializers
2422 doImageInit(context);
2423 doModInitFunctions(context);
2424
2425 CRSetCrashLogMessage2(NULL);
2426
2427 return (fHasDashInit || fHasInitializers);
2428 }
2429
2430 bool ImageLoaderMachO::needsInitialization()
2431 {
2432 return ( fHasDashInit || fHasInitializers );
2433 }
2434
2435
2436 bool ImageLoaderMachO::needsTermination()
2437 {
2438 return fHasTerminators;
2439 }
2440
2441
2442 void ImageLoaderMachO::doTermination(const LinkContext& context)
2443 {
2444 if ( fHasTerminators ) {
2445 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2446 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2447 const struct load_command* cmd = cmds;
2448 for (uint32_t i = 0; i < cmd_count; ++i) {
2449 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
2450 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2451 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2452 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2453 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2454 const uint8_t type = sect->flags & SECTION_TYPE;
2455 if ( type == S_MOD_TERM_FUNC_POINTERS ) {
2456 // <rdar://problem/23929217> Ensure section is within segment
2457 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
2458 dyld::throwf("DOF section has malformed address range for %s\n", this->getPath());
2459 Terminator* terms = (Terminator*)(sect->addr + fSlide);
2460 const size_t count = sect->size / sizeof(uintptr_t);
2461 for (size_t j=count; j > 0; --j) {
2462 Terminator func = terms[j-1];
2463 #if __has_feature(ptrauth_calls)
2464 func = (Terminator)__builtin_ptrauth_sign_unauthenticated((void*)func, ptrauth_key_asia, 0);
2465 #endif
2466 // <rdar://problem/8543820&9228031> verify terminators are in image
2467 if ( ! this->containsAddress(stripPointer((void*)func)) ) {
2468 dyld::throwf("termination function %p not in mapped image for %s\n", func, this->getPath());
2469 }
2470 if ( context.verboseInit )
2471 dyld::log("dyld: calling termination function %p in %s\n", func, this->getPath());
2472 func();
2473 }
2474 }
2475 }
2476 }
2477 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2478 }
2479 }
2480 }
2481
2482
2483 void ImageLoaderMachO::printStatisticsDetails(unsigned int imageCount, const InitializerTimingList& timingInfo)
2484 {
2485 ImageLoader::printStatisticsDetails(imageCount, timingInfo);
2486 dyld::log("total symbol trie searches: %d\n", fgSymbolTrieSearchs);
2487 dyld::log("total symbol table binary searches: %d\n", fgSymbolTableBinarySearchs);
2488 dyld::log("total images defining weak symbols: %u\n", fgImagesHasWeakDefinitions);
2489 dyld::log("total images using weak symbols: %u\n", fgImagesRequiringCoalescing);
2490 }
2491
2492 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext& context, size_t extraAllocationSize)
2493 {
2494 // preflight and calculate slide if needed
2495 const bool inPIE = (fgNextPIEDylibAddress != 0);
2496 intptr_t slide = 0;
2497 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
2498 intptr_t segmentReAlignSlide = 0;
2499 bool needsToSlide = false;
2500 bool imageHasPreferredLoadAddress = segHasPreferredLoadAddress(0);
2501 uintptr_t lowAddr = (unsigned long)(-1);
2502 uintptr_t highAddr = 0;
2503 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2504 const uintptr_t segLow = segPreferredLoadAddress(i);
2505 const uintptr_t segHigh = dyld_page_round(segLow + segSize(i));
2506 if ( segLow < highAddr ) {
2507 if ( dyld_page_size > 4096 )
2508 dyld::throwf("can't map segments into 16KB pages");
2509 else
2510 dyld::throwf("overlapping segments");
2511 }
2512 if ( segLow < lowAddr )
2513 lowAddr = segLow;
2514 if ( segHigh > highAddr )
2515 highAddr = segHigh;
2516
2517 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
2518 // For Cambria on Aruba systems (16k page size), realign the image so the first segment ends on a 16k boundry.
2519 // FIXME: this can be removed when Aruba dev systems are no longer supported.
2520 if ( dyld::isTranslated() && vm_page_size == 0x4000 && i == 0 && segLow == 0 ) {
2521 const uintptr_t segHighPageOffset = segHigh & vm_page_mask;
2522 if ( segHighPageOffset > 0 ) {
2523 // Adjust the slide to make the first segment end on a page boundry.
2524 needsToSlide = true;
2525 segmentReAlignSlide = vm_page_size - segHighPageOffset;
2526
2527 if (context.verboseMapping) {
2528 dyld::log("dyld: Image %s first segment(%s) does not end on a page boundry [0x%lx, 0x%lx) adding 0x%lx to slide to realign\n", getPath(), segName(i), segLow, segHigh, segmentReAlignSlide);
2529 }
2530 }
2531 }
2532 #endif
2533 if ( needsToSlide || !imageHasPreferredLoadAddress || inPIE || !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
2534 needsToSlide = true;
2535 }
2536 if ( needsToSlide ) {
2537 // find a chunk of address space to hold all segments
2538 size_t size = highAddr-lowAddr+segmentReAlignSlide;
2539 uintptr_t addr = reserveAnAddressRange(size+extraAllocationSize, context);
2540 slide = addr - lowAddr + segmentReAlignSlide;
2541 } else if ( extraAllocationSize ) {
2542 if (!reserveAddressRange(highAddr, extraAllocationSize)) {
2543 throw "failed to reserve space for aot";
2544 }
2545 }
2546 }
2547 else if ( ! this->segmentsCanSlide() ) {
2548 uintptr_t highAddr = 0;
2549 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2550 const uintptr_t segLow = segPreferredLoadAddress(i);
2551 const uintptr_t segHigh = dyld_page_round(segLow + segSize(i));
2552
2553 if ( segHigh > highAddr )
2554 highAddr = segHigh;
2555
2556 if ( (strcmp(segName(i), "__PAGEZERO") == 0) && (segFileSize(i) == 0) && (segPreferredLoadAddress(i) == 0) )
2557 continue;
2558 if ( !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
2559 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i), segPreferredLoadAddress(i), segSize(i));
2560 }
2561 if (extraAllocationSize) {
2562 dyld::throwf("binaries with non-slidable segments don't support aot: %s", this->getPath());
2563 }
2564 }
2565 else {
2566 throw "mach-o does not support independently sliding segments";
2567 }
2568 return slide;
2569 }
2570
2571
2572 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context)
2573 {
2574 vm_address_t addr = 0;
2575 vm_size_t size = length;
2576 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
2577 if ( fgNextPIEDylibAddress != 0 ) {
2578 // add small (0-3 pages) random padding between dylibs
2579 addr = fgNextPIEDylibAddress + (__stack_chk_guard/fgNextPIEDylibAddress & (sizeof(long)-1))*dyld_page_size;
2580 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
2581 kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB));
2582 if ( r == KERN_SUCCESS ) {
2583 fgNextPIEDylibAddress = addr + size;
2584 return addr;
2585 }
2586 fgNextPIEDylibAddress = 0;
2587 }
2588 kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_DYLIB));
2589 if ( r != KERN_SUCCESS )
2590 throw "out of address space";
2591
2592 return addr;
2593 }
2594
2595 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start, size_t length)
2596 {
2597 vm_address_t addr = start;
2598 vm_size_t size = length;
2599 kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB));
2600 if ( r != KERN_SUCCESS )
2601 return false;
2602 return true;
2603 }
2604
2605 void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
2606 {
2607 uint64_t extra_allocation_size = 0;
2608
2609 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
2610 if (dyld::isTranslated()) {
2611 fAotPath = new char[PATH_MAX];
2612 int ret = syscall(0x7000001, fd, this->getPath(), &extra_allocation_size, fAotPath, PATH_MAX);
2613 if (ret != 0) {
2614 delete fAotPath;
2615 fAotPath = nullptr;
2616 }
2617 }
2618 #endif
2619
2620 // find address range for image
2621 intptr_t slide = this->assignSegmentAddresses(context, extra_allocation_size);
2622 if ( context.verboseMapping ) {
2623 if ( offsetInFat != 0 )
2624 dyld::log("dyld: Mapping %s (slice offset=%llu)\n", this->getPath(), (unsigned long long)offsetInFat);
2625 else
2626 dyld::log("dyld: Mapping %s\n", this->getPath());
2627 }
2628
2629 // <rdar://problem/47163421> speculatively read whole slice
2630 fspecread_t specread = {} ;
2631 specread.fsr_offset = offsetInFat;
2632 specread.fsr_length = lenInFat;
2633 specread.fsr_flags = 0;
2634 fcntl(fd, F_SPECULATIVE_READ, &specread);
2635 if ( context.verboseMapping )
2636 dyld::log("dyld: Speculatively read offset=0x%08llX, len=0x%08llX, path=%s\n", offsetInFat, lenInFat, this->getPath());
2637
2638 // map in all segments
2639 uintptr_t baseAddress = (unsigned long)(-1);
2640 uintptr_t endAddress = 0;
2641 uintptr_t mappedMachHeaderAddress = 0;
2642 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2643 vm_offset_t fileOffset = (vm_offset_t)(segFileOffset(i) + offsetInFat);
2644 vm_size_t size = segFileSize(i);
2645 uintptr_t requestedLoadAddress = segPreferredLoadAddress(i) + slide;
2646 const uintptr_t segmentEnd = dyld_page_round(requestedLoadAddress + segSize(i));
2647
2648 if ( requestedLoadAddress < baseAddress )
2649 baseAddress = requestedLoadAddress;
2650 if ( segmentEnd > endAddress )
2651 endAddress = segmentEnd;
2652
2653 if (segFileOffset(i) == 0 && segFileSize(i) != 0) {
2654 mappedMachHeaderAddress = requestedLoadAddress;
2655 }
2656
2657 int protection = 0;
2658 if ( !segUnaccessible(i) ) {
2659 if ( segExecutable(i) )
2660 protection |= PROT_EXEC;
2661 if ( segReadable(i) )
2662 protection |= PROT_READ;
2663 if ( segWriteable(i) ) {
2664 protection |= PROT_WRITE;
2665 // rdar://problem/22525618 force __LINKEDIT to always be mapped read-only
2666 if ( strcmp(segName(i), "__LINKEDIT") == 0 )
2667 protection = PROT_READ;
2668 }
2669 }
2670 #if __i386__
2671 // initially map __IMPORT segments R/W so dyld can update them
2672 if ( segIsReadOnlyImport(i) )
2673 protection |= PROT_WRITE;
2674 #endif
2675 // wholly zero-fill segments have nothing to mmap() in
2676 if ( size > 0 ) {
2677 if ( (fileOffset+size) > fileLen ) {
2678 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",
2679 segName(i), (uint64_t)(fileOffset+size), fileLen);
2680 }
2681 void* loadAddress = xmmap((void*)requestedLoadAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, fileOffset);
2682 if ( loadAddress == ((void*)(-1)) ) {
2683 int mmapErr = errno;
2684 if ( mmapErr == EPERM ) {
2685 if ( dyld::sandboxBlockedMmap(getPath()) )
2686 dyld::throwf("file system sandbox blocked mmap() of '%s'", this->getPath());
2687 else
2688 dyld::throwf("code signing blocked mmap() of '%s'", this->getPath());
2689 }
2690 else
2691 dyld::throwf("mmap() errno=%d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",
2692 mmapErr, requestedLoadAddress, (uintptr_t)size, segName(i), getPath());
2693 }
2694 }
2695 // update stats
2696 ++ImageLoader::fgTotalSegmentsMapped;
2697 ImageLoader::fgTotalBytesMapped += size;
2698 if ( context.verboseMapping )
2699 dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i), requestedLoadAddress, requestedLoadAddress+size-1,
2700 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' );
2701 }
2702
2703 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
2704 if (dyld::isTranslated() && extra_allocation_size != 0) {
2705 const struct mach_header* aot_load_address;
2706 dyld_aot_image_info aot_image_info = {};
2707 int ret = syscall(0x7000002, this->getPath(), mappedMachHeaderAddress, endAddress, &aot_load_address, &aot_image_info.aotImageSize, aot_image_info.aotImageKey);
2708 if (ret == 0) {
2709 extern void addAotImagesToAllAotImages(uint32_t aotInfoCount, const dyld_aot_image_info aotInfo[]);
2710
2711 // fill in the aot load address, at this point the cambria trap has filled in
2712 // the image size and image key fields
2713 aot_image_info.aotLoadAddress = aot_load_address;
2714 aot_image_info.x86LoadAddress = (struct mach_header*)baseAddress;
2715
2716 addAotImagesToAllAotImages(1, &aot_image_info);
2717 }
2718 }
2719 #endif
2720
2721 // update slide to reflect load location
2722 this->setSlide(slide);
2723 }
2724
2725 void ImageLoaderMachO::mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context)
2726 {
2727 // find address range for image
2728 intptr_t slide = this->assignSegmentAddresses(context, 0);
2729 if ( context.verboseMapping )
2730 dyld::log("dyld: Mapping memory %p\n", memoryImage);
2731 // map in all segments
2732 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2733 vm_address_t loadAddress = segPreferredLoadAddress(i) + slide;
2734 vm_address_t srcAddr = (uintptr_t)memoryImage + segFileOffset(i);
2735 vm_size_t size = segFileSize(i);
2736 kern_return_t r = vm_copy(mach_task_self(), srcAddr, size, loadAddress);
2737 if ( r != KERN_SUCCESS )
2738 throw "can't map segment";
2739 if ( context.verboseMapping )
2740 dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i), (uintptr_t)loadAddress, (uintptr_t)loadAddress+size-1);
2741 }
2742 // update slide to reflect load location
2743 this->setSlide(slide);
2744 // set R/W permissions on all segments at slide location
2745 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2746 segProtect(i, context);
2747 }
2748 }
2749
2750 static vm_prot_t protectionForSegIndex(const ImageLoaderMachO* image, unsigned int segIndex)
2751 {
2752 if ( image->segUnaccessible(segIndex) )
2753 return 0;
2754 vm_prot_t protection = 0;
2755 if ( image->segExecutable(segIndex) )
2756 protection |= PROT_EXEC;
2757 if ( image->segReadable(segIndex) )
2758 protection |= PROT_READ;
2759 if ( image->segWriteable(segIndex) )
2760 protection |= PROT_WRITE;
2761 return protection;
2762 }
2763
2764
2765 void ImageLoaderMachO::segProtect(unsigned int segIndex, const ImageLoader::LinkContext& context)
2766 {
2767 vm_prot_t protection = protectionForSegIndex(this, segIndex);
2768 vm_address_t addr = segActualLoadAddress(segIndex);
2769 vm_size_t size = segSize(segIndex);
2770
2771 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
2772 if ( dyld::isTranslated() ) {
2773 // <rdar://problem/60543794> can't vm_protect non-16KB segments
2774 if ( (segIndex > 0) && ((addr & 0x3FFF) != 0) ) {
2775 // overlaps previous segment
2776 vm_prot_t prevProt = protectionForSegIndex(this, segIndex-1);
2777 if ( (protection & prevProt) != prevProt ) {
2778 // previous had more bits, so we need to not apply new permissions to the overlap
2779 vm_size_t overlap = 0x4000 - (addr & 0x3FFF);
2780 addr += overlap;
2781 if ( size >= overlap )
2782 size -= overlap;
2783 else if ( size < overlap )
2784 size = 0;
2785 }
2786 if ( size == 0 )
2787 return;
2788 }
2789 }
2790 #endif
2791
2792 const bool setCurrentPermissions = false;
2793 kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
2794 if ( r != KERN_SUCCESS ) {
2795 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2796 (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath());
2797 }
2798 if ( context.verboseMapping ) {
2799 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,
2800 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' );
2801 }
2802 }
2803
2804 #if TEXT_RELOC_SUPPORT
2805 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex, const ImageLoader::LinkContext& context)
2806 {
2807 vm_address_t addr = segActualLoadAddress(segIndex);
2808 vm_size_t size = segSize(segIndex);
2809 const bool setCurrentPermissions = false;
2810 vm_prot_t protection = VM_PROT_WRITE | VM_PROT_READ | VM_PROT_COPY;
2811 if ( segExecutable(segIndex) && !segHasRebaseFixUps(segIndex) )
2812 protection |= VM_PROT_EXECUTE;
2813 kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
2814 if ( r != KERN_SUCCESS ) {
2815 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2816 (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath());
2817 }
2818 if ( context.verboseMapping ) {
2819 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,
2820 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' );
2821 }
2822 }
2823 #endif
2824
2825 const char* ImageLoaderMachO::findClosestSymbol(const mach_header* mh, const void* addr, const void** closestAddr)
2826 {
2827 // called by dladdr()
2828 // only works with compressed LINKEDIT if classic symbol table is also present
2829 const dysymtab_command* dynSymbolTable = NULL;
2830 const symtab_command* symtab = NULL;
2831 const macho_segment_command* seg;
2832 const uint8_t* unslidLinkEditBase = NULL;
2833 bool linkEditBaseFound = false;
2834 intptr_t slide = 0;
2835 const uint32_t cmd_count = mh->ncmds;
2836 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
2837 const load_command* cmd = cmds;
2838 for (uint32_t i = 0; i < cmd_count; ++i) {
2839 switch (cmd->cmd) {
2840 case LC_SEGMENT_COMMAND:
2841 seg = (macho_segment_command*)cmd;
2842 if ( strcmp(seg->segname, "__LINKEDIT") == 0 ) {
2843 unslidLinkEditBase = (uint8_t*)(seg->vmaddr - seg->fileoff);
2844 linkEditBaseFound = true;
2845 }
2846 else if ( strcmp(seg->segname, "__TEXT") == 0 ) {
2847 slide = (uintptr_t)mh - seg->vmaddr;
2848 }
2849 break;
2850 case LC_SYMTAB:
2851 symtab = (symtab_command*)cmd;
2852 break;
2853 case LC_DYSYMTAB:
2854 dynSymbolTable = (dysymtab_command*)cmd;
2855 break;
2856 }
2857 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2858 }
2859 // no symbol table => no lookup by address
2860 if ( (symtab == NULL) || (dynSymbolTable == NULL) || !linkEditBaseFound )
2861 return NULL;
2862
2863 const uint8_t* linkEditBase = unslidLinkEditBase + slide;
2864 const char* symbolTableStrings = (const char*)&linkEditBase[symtab->stroff];
2865 const macho_nlist* symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
2866
2867 uintptr_t targetAddress = (uintptr_t)addr - slide;
2868 const struct macho_nlist* bestSymbol = NULL;
2869 // first walk all global symbols
2870 const struct macho_nlist* const globalsStart = &symbolTable[dynSymbolTable->iextdefsym];
2871 const struct macho_nlist* const globalsEnd= &globalsStart[dynSymbolTable->nextdefsym];
2872 for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
2873 if ( (s->n_type & N_TYPE) == N_SECT ) {
2874 if ( bestSymbol == NULL ) {
2875 if ( s->n_value <= targetAddress )
2876 bestSymbol = s;
2877 }
2878 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2879 bestSymbol = s;
2880 }
2881 }
2882 }
2883 // next walk all local symbols
2884 const struct macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym];
2885 const struct macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym];
2886 for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
2887 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
2888 if ( bestSymbol == NULL ) {
2889 if ( s->n_value <= targetAddress )
2890 bestSymbol = s;
2891 }
2892 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2893 bestSymbol = s;
2894 }
2895 }
2896 }
2897 if ( bestSymbol != NULL ) {
2898 #if __arm__
2899 if (bestSymbol->n_desc & N_ARM_THUMB_DEF)
2900 *closestAddr = (void*)((bestSymbol->n_value | 1) + slide);
2901 else
2902 *closestAddr = (void*)(bestSymbol->n_value + slide);
2903 #else
2904 *closestAddr = (void*)(bestSymbol->n_value + slide);
2905 #endif
2906 return &symbolTableStrings[bestSymbol->n_un.n_strx];
2907 }
2908 return NULL;
2909 }
2910
2911 bool ImageLoaderMachO::getLazyBindingInfo(uint32_t& lazyBindingInfoOffset, const uint8_t* lazyInfoStart, const uint8_t* lazyInfoEnd,
2912 uint8_t* segIndex, uintptr_t* segOffset, int* ordinal, const char** symbolName, bool* doneAfterBind)
2913 {
2914 if ( lazyBindingInfoOffset > (lazyInfoEnd-lazyInfoStart) )
2915 return false;
2916 bool done = false;
2917 const uint8_t* p = &lazyInfoStart[lazyBindingInfoOffset];
2918 while ( !done && (p < lazyInfoEnd) ) {
2919 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
2920 uint8_t opcode = *p & BIND_OPCODE_MASK;
2921 ++p;
2922 switch (opcode) {
2923 case BIND_OPCODE_DONE:
2924 *doneAfterBind = false;
2925 return true;
2926 break;
2927 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
2928 *ordinal = immediate;
2929 break;
2930 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
2931 *ordinal = (int)read_uleb128(p, lazyInfoEnd);
2932 break;
2933 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
2934 // the special ordinals are negative numbers
2935 if ( immediate == 0 )
2936 *ordinal = 0;
2937 else {
2938 int8_t signExtended = BIND_OPCODE_MASK | immediate;
2939 *ordinal = signExtended;
2940 }
2941 break;
2942 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
2943 *symbolName = (char*)p;
2944 while (*p != '\0')
2945 ++p;
2946 ++p;
2947 break;
2948 case BIND_OPCODE_SET_TYPE_IMM:
2949 break;
2950 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
2951 *segIndex = immediate;
2952 *segOffset = read_uleb128(p, lazyInfoEnd);
2953 break;
2954 case BIND_OPCODE_DO_BIND:
2955 *doneAfterBind = ((*p & BIND_OPCODE_MASK) == BIND_OPCODE_DONE);
2956 lazyBindingInfoOffset += p - &lazyInfoStart[lazyBindingInfoOffset];
2957 return true;
2958 break;
2959 case BIND_OPCODE_SET_ADDEND_SLEB:
2960 case BIND_OPCODE_ADD_ADDR_ULEB:
2961 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
2962 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
2963 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
2964 default:
2965 return false;
2966 }
2967 }
2968 return false;
2969 }
2970
2971 const dyld_info_command* ImageLoaderMachO::findDyldInfoLoadCommand(const mach_header* mh)
2972 {
2973 const uint32_t cmd_count = mh->ncmds;
2974 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
2975 const load_command* cmd = cmds;
2976 for (uint32_t i = 0; i < cmd_count; ++i) {
2977 switch (cmd->cmd) {
2978 case LC_DYLD_INFO:
2979 case LC_DYLD_INFO_ONLY:
2980 return (dyld_info_command*)cmd;
2981 }
2982 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2983 }
2984 return NULL;
2985 }
2986
2987
2988 uintptr_t ImageLoaderMachO::segPreferredAddress(const mach_header* mh, unsigned segIndex)
2989 {
2990 const uint32_t cmd_count = mh->ncmds;
2991 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
2992 const load_command* cmd = cmds;
2993 unsigned curSegIndex = 0;
2994 for (uint32_t i = 0; i < cmd_count; ++i) {
2995 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
2996 if ( segIndex == curSegIndex ) {
2997 const macho_segment_command* segCmd = (macho_segment_command*)cmd;
2998 return segCmd->vmaddr;
2999 }
3000 ++curSegIndex;
3001 }
3002 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
3003 }
3004 return 0;
3005 }
3006
3007
3008
3009 uintptr_t ImageLoaderMachO::imageBaseAddress() const {
3010 //printf("imageBaseAddress: %s %d->%d\n", getPath(), 0, segmentCount());
3011 for (unsigned int i = 0, e = segmentCount(); i != e; ++i) {
3012 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) )
3013 return segPreferredLoadAddress(i);
3014 }
3015 return 0;
3016 }
3017