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