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