]>
Commit | Line | Data |
---|---|---|
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 | ||
25 | ||
26 | #ifndef __IMAGELOADER__ | |
27 | #define __IMAGELOADER__ | |
28 | ||
29 | #include <sys/types.h> | |
39a8cd10 | 30 | #include <unistd.h> |
2fd3f4e8 | 31 | #include <stdlib.h> |
0959b6d4 | 32 | #include <mach/mach_time.h> // struct mach_timebase_info |
bac542e6 | 33 | #include <mach/mach_init.h> // struct mach_thread_self |
39a8cd10 A |
34 | #include <mach/shared_region.h> |
35 | #include <mach-o/loader.h> | |
36 | #include <mach-o/nlist.h> | |
0959b6d4 | 37 | #include <stdint.h> |
2fd3f4e8 A |
38 | #include <stdlib.h> |
39 | #include <TargetConditionals.h> | |
0959b6d4 | 40 | #include <vector> |
39a8cd10 | 41 | #include <new> |
0959b6d4 | 42 | |
19894a12 A |
43 | #if __arm__ |
44 | #include <mach/vm_page_size.h> | |
45 | #endif | |
46 | ||
47 | #if __x86_64__ || __i386__ | |
412ebb8e A |
48 | #include <CrashReporterClient.h> |
49 | #else | |
50 | // work around until iOS has CrashReporterClient.h | |
51 | #define CRSetCrashLogMessage(x) | |
52 | #define CRSetCrashLogMessage2(x) | |
53 | #endif | |
54 | ||
19894a12 A |
55 | #ifndef SHARED_REGION_BASE_ARM64 |
56 | #define SHARED_REGION_BASE_ARM64 0x7FFF80000000LL | |
57 | #endif | |
58 | ||
59 | #ifndef SHARED_REGION_SIZE_ARM64 | |
60 | #define SHARED_REGION_SIZE_ARM64 0x10000000LL | |
61 | #endif | |
62 | ||
63 | ||
412ebb8e A |
64 | #define LOG_BINDINGS 0 |
65 | ||
bac542e6 A |
66 | #include "mach-o/dyld_images.h" |
67 | #include "mach-o/dyld_priv.h" | |
68 | ||
39a8cd10 A |
69 | #if __i386__ |
70 | #define SHARED_REGION_BASE SHARED_REGION_BASE_I386 | |
71 | #define SHARED_REGION_SIZE SHARED_REGION_SIZE_I386 | |
72 | #elif __x86_64__ | |
73 | #define SHARED_REGION_BASE SHARED_REGION_BASE_X86_64 | |
74 | #define SHARED_REGION_SIZE SHARED_REGION_SIZE_X86_64 | |
39a8cd10 A |
75 | #elif __arm__ |
76 | #define SHARED_REGION_BASE SHARED_REGION_BASE_ARM | |
77 | #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM | |
19894a12 A |
78 | #elif __arm64__ |
79 | #define SHARED_REGION_BASE SHARED_REGION_BASE_ARM64 | |
80 | #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM64 | |
39a8cd10 A |
81 | #endif |
82 | ||
412ebb8e A |
83 | #ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER |
84 | #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10 | |
85 | #endif | |
86 | #ifndef EXPORT_SYMBOL_FLAGS_REEXPORT | |
87 | #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08 | |
88 | #endif | |
bac542e6 | 89 | |
832b6fce A |
90 | #ifndef LC_MAIN |
91 | #define LC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */ | |
92 | struct entry_point_command { | |
93 | uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */ | |
94 | uint32_t cmdsize; /* 24 */ | |
95 | uint64_t entryoff; /* file (__TEXT) offset of main() */ | |
96 | uint64_t stacksize;/* if not zero, initial stack size */ | |
97 | }; | |
98 | #endif | |
39a8cd10 | 99 | |
2fd3f4e8 A |
100 | #if __IPHONE_OS_VERSION_MIN_REQUIRED |
101 | #define SPLIT_SEG_SHARED_REGION_SUPPORT 0 | |
102 | #define SPLIT_SEG_DYLIB_SUPPORT 0 | |
19894a12 | 103 | #define PREBOUND_IMAGE_SUPPORT __arm__ |
2fd3f4e8 | 104 | #define TEXT_RELOC_SUPPORT __i386__ |
19894a12 | 105 | #define DYLD_SHARED_CACHE_SUPPORT (__arm__ || __arm64__) |
2fd3f4e8 | 106 | #define SUPPORT_OLD_CRT_INITIALIZATION 0 |
df9d6cf7 A |
107 | #define SUPPORT_LC_DYLD_ENVIRONMENT 1 |
108 | #define SUPPORT_VERSIONED_PATHS 1 | |
2fd3f4e8 | 109 | #define SUPPORT_CLASSIC_MACHO __arm__ |
19894a12 | 110 | #define SUPPORT_ZERO_COST_EXCEPTIONS (!__USING_SJLJ_EXCEPTIONS__) |
2fd3f4e8 | 111 | #define INITIAL_IMAGE_COUNT 256 |
412ebb8e | 112 | #else |
2fd3f4e8 A |
113 | #define SPLIT_SEG_SHARED_REGION_SUPPORT 0 |
114 | #define SPLIT_SEG_DYLIB_SUPPORT __i386__ | |
115 | #define PREBOUND_IMAGE_SUPPORT __i386__ | |
116 | #define TEXT_RELOC_SUPPORT __i386__ | |
117 | #define DYLD_SHARED_CACHE_SUPPORT 1 | |
118 | #define SUPPORT_OLD_CRT_INITIALIZATION __i386__ | |
119 | #define SUPPORT_LC_DYLD_ENVIRONMENT (__i386__ || __x86_64__) | |
120 | #define SUPPORT_VERSIONED_PATHS 1 | |
121 | #define SUPPORT_CLASSIC_MACHO 1 | |
19894a12 | 122 | #define SUPPORT_ZERO_COST_EXCEPTIONS 1 |
2fd3f4e8 | 123 | #define INITIAL_IMAGE_COUNT 200 |
39a8cd10 | 124 | #endif |
bac542e6 | 125 | |
2fd3f4e8 A |
126 | |
127 | ||
128 | // <rdar://problem/13590567> optimize away dyld's initializers | |
129 | #define VECTOR_NEVER_DESTRUCTED(type) \ | |
130 | namespace std { \ | |
131 | template <> \ | |
132 | __vector_base<type, std::allocator<type> >::~__vector_base() { } \ | |
133 | } | |
134 | #define VECTOR_NEVER_DESTRUCTED_EXTERN(type) \ | |
135 | namespace std { \ | |
136 | template <> \ | |
137 | __vector_base<type, std::allocator<type> >::~__vector_base(); \ | |
138 | } | |
139 | #define VECTOR_NEVER_DESTRUCTED_IMPL(type) \ | |
140 | namespace std { \ | |
141 | template <> \ | |
142 | __vector_base<type, std::allocator<type> >::~__vector_base() { } \ | |
143 | } | |
bac542e6 A |
144 | |
145 | // utilities | |
146 | namespace dyld { | |
147 | extern __attribute__((noreturn)) void throwf(const char* format, ...) __attribute__((format(printf, 1, 2))); | |
148 | extern void log(const char* format, ...) __attribute__((format(printf, 1, 2))); | |
149 | extern void warn(const char* format, ...) __attribute__((format(printf, 1, 2))); | |
150 | extern const char* mkstringf(const char* format, ...) __attribute__((format(printf, 1, 2))); | |
412ebb8e A |
151 | #if LOG_BINDINGS |
152 | extern void logBindings(const char* format, ...) __attribute__((format(printf, 1, 2))); | |
153 | #endif | |
2fd3f4e8 A |
154 | } |
155 | extern "C" int vm_alloc(vm_address_t* addr, vm_size_t size, uint32_t flags); | |
156 | extern "C" void* xmmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset); | |
bac542e6 A |
157 | |
158 | ||
39a8cd10 A |
159 | #if __LP64__ |
160 | struct macho_header : public mach_header_64 {}; | |
161 | struct macho_nlist : public nlist_64 {}; | |
162 | #else | |
163 | struct macho_header : public mach_header {}; | |
164 | struct macho_nlist : public nlist {}; | |
165 | #endif | |
166 | ||
167 | ||
19894a12 A |
168 | #if __arm64__ |
169 | #define dyld_page_trunc(__addr) (__addr & (-16384)) | |
170 | #define dyld_page_round(__addr) ((__addr + 16383) & (-16384)) | |
171 | #define dyld_page_size 16384 | |
172 | #elif __arm__ | |
173 | #define dyld_page_trunc(__addr) trunc_page_kernel(__addr) | |
174 | #define dyld_page_round(__addr) round_page_kernel(__addr) | |
175 | #define dyld_page_size vm_kernel_page_size | |
176 | #else | |
177 | #define dyld_page_trunc(__addr) (__addr & (-4096)) | |
178 | #define dyld_page_round(__addr) ((__addr + 4095) & (-4096)) | |
179 | #define dyld_page_size 4096 | |
180 | #endif | |
181 | ||
182 | ||
183 | ||
bac542e6 A |
184 | struct ProgramVars |
185 | { | |
186 | const void* mh; | |
187 | int* NXArgcPtr; | |
188 | const char*** NXArgvPtr; | |
189 | const char*** environPtr; | |
190 | const char** __prognamePtr; | |
191 | }; | |
0959b6d4 A |
192 | |
193 | ||
0959b6d4 A |
194 | |
195 | // | |
196 | // ImageLoader is an abstract base class. To support loading a particular executable | |
197 | // file format, you make a concrete subclass of ImageLoader. | |
198 | // | |
199 | // For each executable file (dynamic shared object) in use, an ImageLoader is instantiated. | |
200 | // | |
201 | // The ImageLoader base class does the work of linking together images, but it knows nothing | |
202 | // about any particular file format. | |
203 | // | |
204 | // | |
205 | class ImageLoader { | |
206 | public: | |
207 | ||
208 | typedef uint32_t DefinitionFlags; | |
209 | static const DefinitionFlags kNoDefinitionOptions = 0; | |
210 | static const DefinitionFlags kWeakDefinition = 1; | |
211 | ||
212 | typedef uint32_t ReferenceFlags; | |
213 | static const ReferenceFlags kNoReferenceOptions = 0; | |
214 | static const ReferenceFlags kWeakReference = 1; | |
215 | static const ReferenceFlags kTentativeDefinition = 2; | |
216 | ||
0959b6d4 A |
217 | enum PrebindMode { kUseAllPrebinding, kUseSplitSegPrebinding, kUseAllButAppPredbinding, kUseNoPrebinding }; |
218 | enum BindingOptions { kBindingNone, kBindingLazyPointers, kBindingNeverSetLazyPointers }; | |
bac542e6 | 219 | enum SharedRegionMode { kUseSharedRegion, kUsePrivateSharedRegion, kDontUseSharedRegion, kSharedRegionIsSharedCache }; |
0959b6d4 A |
220 | |
221 | struct Symbol; // abstact symbol | |
222 | ||
223 | struct MappedRegion { | |
224 | uintptr_t address; | |
225 | size_t size; | |
226 | }; | |
bac542e6 A |
227 | |
228 | struct RPathChain { | |
229 | RPathChain(const RPathChain* n, std::vector<const char*>* p) : next(n), paths(p) {}; | |
230 | const RPathChain* next; | |
231 | std::vector<const char*>* paths; | |
232 | }; | |
233 | ||
234 | struct DOFInfo { | |
235 | void* dof; | |
236 | const mach_header* imageHeader; | |
237 | const char* imageShortName; | |
238 | }; | |
0959b6d4 | 239 | |
2fd3f4e8 A |
240 | struct DynamicReference { |
241 | ImageLoader* from; | |
242 | ImageLoader* to; | |
243 | }; | |
244 | ||
0959b6d4 | 245 | struct LinkContext { |
39a8cd10 | 246 | ImageLoader* (*loadLibrary)(const char* libraryName, bool search, const char* origin, const RPathChain* rpaths); |
0959b6d4 | 247 | void (*terminationRecorder)(ImageLoader* image); |
bac542e6 A |
248 | bool (*flatExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image); |
249 | bool (*coalescedExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image); | |
39a8cd10 | 250 | unsigned int (*getCoalescedImages)(ImageLoader* images[]); |
0959b6d4 | 251 | void (*undefinedHandler)(const char* name); |
bac542e6 | 252 | MappedRegion* (*getAllMappedRegions)(MappedRegion*); |
0959b6d4 | 253 | void * (*bindingHandler)(const char *, const char *, void *); |
39a8cd10 | 254 | void (*notifySingle)(dyld_image_states, const ImageLoader* image); |
bac542e6 A |
255 | void (*notifyBatch)(dyld_image_states state); |
256 | void (*removeImage)(ImageLoader* image); | |
257 | void (*registerDOFs)(const std::vector<DOFInfo>& dofs); | |
258 | void (*clearAllDepths)(); | |
832b6fce | 259 | void (*printAllDepths)(); |
bac542e6 | 260 | unsigned int (*imageCount)(); |
bac542e6 | 261 | void (*setNewProgramVars)(const ProgramVars&); |
39a8cd10 | 262 | bool (*inSharedCache)(const char* path); |
412ebb8e A |
263 | void (*setErrorStrings)(unsigned errorCode, const char* errorClientOfDylibPath, |
264 | const char* errorTargetDylibPath, const char* errorSymbol); | |
2fd3f4e8 A |
265 | ImageLoader* (*findImageContainingAddress)(const void* addr); |
266 | void (*addDynamicReference)(ImageLoader* from, ImageLoader* to); | |
267 | ||
bac542e6 A |
268 | #if SUPPORT_OLD_CRT_INITIALIZATION |
269 | void (*setRunInitialzersOldWay)(); | |
270 | #endif | |
0959b6d4 A |
271 | BindingOptions bindingOptions; |
272 | int argc; | |
273 | const char** argv; | |
274 | const char** envp; | |
275 | const char** apple; | |
bac542e6 A |
276 | const char* progname; |
277 | ProgramVars programVars; | |
0959b6d4 A |
278 | ImageLoader* mainExecutable; |
279 | const char* imageSuffix; | |
39a8cd10 | 280 | const char** rootPaths; |
19894a12 A |
281 | const dyld_interpose_tuple* dynamicInterposeArray; |
282 | size_t dynamicInterposeCount; | |
0959b6d4 A |
283 | PrebindMode prebindUsage; |
284 | SharedRegionMode sharedRegionMode; | |
2fd3f4e8 A |
285 | bool dyldLoadedAtSameAddressNeededBySharedCache; |
286 | bool codeSigningEnforced; | |
287 | bool mainExecutableCodeSigned; | |
bac542e6 | 288 | bool preFetchDisabled; |
577cc7d1 | 289 | bool prebinding; |
0959b6d4 | 290 | bool bindFlat; |
bac542e6 | 291 | bool linkingMainExecutable; |
2028a915 | 292 | bool startedInitializingMainExecutable; |
39a8cd10 | 293 | bool processIsRestricted; |
df9d6cf7 | 294 | bool processRequiresLibraryValidation; |
0959b6d4 A |
295 | bool verboseOpts; |
296 | bool verboseEnv; | |
297 | bool verboseMapping; | |
298 | bool verboseRebase; | |
299 | bool verboseBind; | |
39a8cd10 | 300 | bool verboseWeakBind; |
0959b6d4 | 301 | bool verboseInit; |
bac542e6 | 302 | bool verboseDOF; |
0959b6d4 | 303 | bool verbosePrebinding; |
412ebb8e | 304 | bool verboseCoreSymbolication; |
0959b6d4 | 305 | bool verboseWarnings; |
412ebb8e A |
306 | bool verboseRPaths; |
307 | bool verboseInterposing; | |
2fd3f4e8 | 308 | bool verboseCodeSignatures; |
0959b6d4 A |
309 | }; |
310 | ||
39a8cd10 A |
311 | struct CoalIterator |
312 | { | |
313 | ImageLoader* image; | |
314 | const char* symbolName; | |
315 | unsigned int loadOrder; | |
316 | bool weakSymbol; | |
317 | bool symbolMatches; | |
318 | bool done; | |
319 | // the following are private to the ImageLoader subclass | |
320 | uintptr_t curIndex; | |
321 | uintptr_t endIndex; | |
322 | uintptr_t address; | |
323 | uintptr_t type; | |
324 | uintptr_t addend; | |
325 | }; | |
326 | ||
327 | virtual void initializeCoalIterator(CoalIterator&, unsigned int loadOrder) = 0; | |
328 | virtual bool incrementCoalIterator(CoalIterator&) = 0; | |
329 | virtual uintptr_t getAddressCoalIterator(CoalIterator&, const LinkContext& context) = 0; | |
330 | virtual void updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context) = 0; | |
331 | ||
412ebb8e A |
332 | struct InitializerTimingList |
333 | { | |
334 | uintptr_t count; | |
335 | struct { | |
336 | ImageLoader* image; | |
337 | uint64_t initTime; | |
338 | } images[1]; | |
339 | }; | |
39a8cd10 | 340 | |
19894a12 A |
341 | struct UninitedUpwards |
342 | { | |
343 | uintptr_t count; | |
344 | ImageLoader* images[1]; | |
345 | }; | |
346 | ||
39a8cd10 | 347 | |
0959b6d4 A |
348 | // constructor is protected, but anyone can delete an image |
349 | virtual ~ImageLoader(); | |
350 | ||
351 | // link() takes a newly instantiated ImageLoader and does all | |
352 | // fixups needed to make it usable by the process | |
2fd3f4e8 | 353 | void link(const LinkContext& context, bool forceLazysBound, bool preflight, bool neverUnload, const RPathChain& loaderRPaths); |
0959b6d4 A |
354 | |
355 | // runInitializers() is normally called in link() but the main executable must | |
356 | // run crt code before initializers | |
412ebb8e | 357 | void runInitializers(const LinkContext& context, InitializerTimingList& timingInfo); |
0959b6d4 | 358 | |
bac542e6 A |
359 | // called after link() forces all lazy pointers to be bound |
360 | void bindAllLazyPointers(const LinkContext& context, bool recursive); | |
361 | ||
0959b6d4 A |
362 | // used by dyld to see if a requested library is already loaded (might be symlink) |
363 | bool statMatch(const struct stat& stat_buf) const; | |
364 | ||
365 | // get short name of this image | |
366 | const char* getShortName() const; | |
367 | ||
368 | // get path used to load this image, not necessarily the "real" path | |
369 | const char* getPath() const { return fPath; } | |
370 | ||
371 | uint32_t getPathHash() const { return fPathHash; } | |
372 | ||
832b6fce A |
373 | // get the "real" path for this image (e.g. no @rpath) |
374 | const char* getRealPath() const; | |
375 | ||
0959b6d4 A |
376 | // get path this image is intended to be placed on disk or NULL if no preferred install location |
377 | virtual const char* getInstallPath() const = 0; | |
378 | ||
379 | // image was loaded with NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME and all clients are looking for install path | |
380 | bool matchInstallPath() const; | |
381 | void setMatchInstallPath(bool); | |
382 | ||
0959b6d4 A |
383 | // mark that this image's exported symbols should be ignored when linking other images (e.g. RTLD_LOCAL) |
384 | void setHideExports(bool hide = true); | |
385 | ||
386 | // check if this image's exported symbols should be ignored when linking other images | |
387 | bool hasHiddenExports() const; | |
388 | ||
389 | // checks if this image is already linked into the process | |
390 | bool isLinked() const; | |
391 | ||
392 | // even if image is deleted, leave segments mapped in | |
393 | void setLeaveMapped(); | |
394 | ||
bac542e6 A |
395 | // even if image is deleted, leave segments mapped in |
396 | bool leaveMapped() { return fLeaveMapped; } | |
397 | ||
412ebb8e A |
398 | // image resides in dyld shared cache |
399 | virtual bool inSharedCache() const = 0; | |
400 | ||
0959b6d4 A |
401 | // checks if the specifed address is within one of this image's segments |
402 | virtual bool containsAddress(const void* addr) const; | |
403 | ||
39a8cd10 A |
404 | // checks if the specifed symbol is within this image's symbol table |
405 | virtual bool containsSymbol(const void* addr) const = 0; | |
406 | ||
bac542e6 A |
407 | // checks if the specifed address range overlaps any of this image's segments |
408 | virtual bool overlapsWithAddressRange(const void* start, const void* end) const; | |
409 | ||
0959b6d4 | 410 | // adds to list of ranges of memory mapped in |
bac542e6 | 411 | void getMappedRegions(MappedRegion*& region) const; |
0959b6d4 A |
412 | |
413 | // st_mtime from stat() on file | |
bac542e6 | 414 | time_t lastModified() const; |
0959b6d4 | 415 | |
832b6fce A |
416 | // only valid for main executables, returns a pointer its entry point from LC_UNIXTHREAD |
417 | virtual void* getThreadPC() const = 0; | |
418 | ||
419 | // only valid for main executables, returns a pointer its main from LC_<MAIN | |
0959b6d4 A |
420 | virtual void* getMain() const = 0; |
421 | ||
422 | // dyld API's require each image to have an associated mach_header | |
423 | virtual const struct mach_header* machHeader() const = 0; | |
424 | ||
425 | // dyld API's require each image to have a slide (actual load address minus preferred load address) | |
426 | virtual uintptr_t getSlide() const = 0; | |
427 | ||
bac542e6 A |
428 | // last address mapped by image |
429 | virtual const void* getEnd() const = 0; | |
0959b6d4 A |
430 | |
431 | // image has exports that participate in runtime coalescing | |
432 | virtual bool hasCoalescedExports() const = 0; | |
433 | ||
434 | // search symbol table of definitions in this image for requested name | |
39a8cd10 | 435 | virtual const Symbol* findExportedSymbol(const char* name, bool searchReExports, const ImageLoader** foundIn) const = 0; |
0959b6d4 A |
436 | |
437 | // gets address of implementation (code) of the specified exported symbol | |
412ebb8e A |
438 | virtual uintptr_t getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, |
439 | const ImageLoader* requestor=NULL, bool runResolver=false) const = 0; | |
0959b6d4 A |
440 | |
441 | // gets attributes of the specified exported symbol | |
442 | virtual DefinitionFlags getExportedSymbolInfo(const Symbol* sym) const = 0; | |
443 | ||
444 | // gets name of the specified exported symbol | |
445 | virtual const char* getExportedSymbolName(const Symbol* sym) const = 0; | |
446 | ||
447 | // gets how many symbols are exported by this image | |
448 | virtual uint32_t getExportedSymbolCount() const = 0; | |
449 | ||
450 | // gets the i'th exported symbol | |
451 | virtual const Symbol* getIndexedExportedSymbol(uint32_t index) const = 0; | |
452 | ||
453 | // find exported symbol as if imported by this image | |
0be5d81c | 454 | // used by RTLD_NEXT |
bac542e6 | 455 | virtual const Symbol* findExportedSymbolInDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const; |
0be5d81c A |
456 | |
457 | // find exported symbol as if imported by this image | |
458 | // used by RTLD_SELF | |
bac542e6 | 459 | virtual const Symbol* findExportedSymbolInImageOrDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const; |
0959b6d4 A |
460 | |
461 | // gets how many symbols are imported by this image | |
462 | virtual uint32_t getImportedSymbolCount() const = 0; | |
463 | ||
464 | // gets the i'th imported symbol | |
465 | virtual const Symbol* getIndexedImportedSymbol(uint32_t index) const = 0; | |
466 | ||
467 | // gets attributes of the specified imported symbol | |
39a8cd10 | 468 | virtual ReferenceFlags getImportedSymbolInfo(const Symbol* sym) const = 0; |
0959b6d4 A |
469 | |
470 | // gets name of the specified imported symbol | |
471 | virtual const char* getImportedSymbolName(const Symbol* sym) const = 0; | |
472 | ||
39a8cd10 A |
473 | // find the closest symbol before addr |
474 | virtual const char* findClosestSymbol(const void* addr, const void** closestAddr) const = 0; | |
475 | ||
0959b6d4 A |
476 | // checks if this image is a bundle and can be loaded but not linked |
477 | virtual bool isBundle() const = 0; | |
478 | ||
479 | // checks if this image is a dylib | |
480 | virtual bool isDylib() const = 0; | |
481 | ||
39a8cd10 A |
482 | // checks if this image is a main executable |
483 | virtual bool isExecutable() const = 0; | |
484 | ||
485 | // checks if this image is a main executable | |
486 | virtual bool isPositionIndependentExecutable() const = 0; | |
487 | ||
0959b6d4 A |
488 | // only for main executable |
489 | virtual bool forceFlat() const = 0; | |
490 | ||
491 | // called at runtime when a lazily bound function is first called | |
492 | virtual uintptr_t doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0; | |
493 | ||
39a8cd10 | 494 | // called at runtime when a fast lazily bound function is first called |
412ebb8e A |
495 | virtual uintptr_t doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, |
496 | void (*lock)(), void (*unlock)()) = 0; | |
39a8cd10 | 497 | |
0959b6d4 A |
498 | // calls termination routines (e.g. C++ static destructors for image) |
499 | virtual void doTermination(const LinkContext& context) = 0; | |
500 | ||
0959b6d4 A |
501 | // return if this image has initialization routines |
502 | virtual bool needsInitialization() = 0; | |
503 | ||
0959b6d4 A |
504 | // return if this image has specified section and set start and length |
505 | virtual bool getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length) = 0; | |
39a8cd10 A |
506 | |
507 | // fills in info about __eh_frame and __unwind_info sections | |
508 | virtual void getUnwindInfo(dyld_unwind_sections* info) = 0; | |
509 | ||
0959b6d4 A |
510 | // given a pointer into an image, find which segment and section it is in |
511 | virtual bool findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset) = 0; | |
512 | ||
513 | // the image supports being prebound | |
514 | virtual bool isPrebindable() const = 0; | |
515 | ||
516 | // the image is prebindable and its prebinding is valid | |
517 | virtual bool usablePrebinding(const LinkContext& context) const = 0; | |
518 | ||
bac542e6 A |
519 | // add all RPATH paths this image contains |
520 | virtual void getRPaths(const LinkContext& context, std::vector<const char*>&) const = 0; | |
521 | ||
39a8cd10 A |
522 | // image has or uses weak definitions that need runtime coalescing |
523 | virtual bool participatesInCoalescing() const = 0; | |
524 | ||
525 | // if image has a UUID, copy into parameter and return true | |
526 | virtual bool getUUID(uuid_t) const = 0; | |
19894a12 A |
527 | |
528 | // dynamic interpose values onto this image | |
529 | virtual void dynamicInterpose(const LinkContext& context) = 0; | |
530 | ||
531 | // record interposing for any late binding | |
532 | void addDynamicInterposingTuples(const struct dyld_interpose_tuple array[], size_t count); | |
533 | ||
39a8cd10 A |
534 | // |
535 | // A segment is a chunk of an executable file that is mapped into memory. | |
536 | // | |
537 | virtual unsigned int segmentCount() const = 0; | |
538 | virtual const char* segName(unsigned int) const = 0; | |
539 | virtual uintptr_t segSize(unsigned int) const = 0; | |
540 | virtual uintptr_t segFileSize(unsigned int) const = 0; | |
541 | virtual bool segHasTrailingZeroFill(unsigned int) = 0; | |
542 | virtual uintptr_t segFileOffset(unsigned int) const = 0; | |
543 | virtual bool segReadable(unsigned int) const = 0; | |
544 | virtual bool segWriteable(unsigned int) const = 0; | |
545 | virtual bool segExecutable(unsigned int) const = 0; | |
546 | virtual bool segUnaccessible(unsigned int) const = 0; | |
547 | virtual bool segHasPreferredLoadAddress(unsigned int) const = 0; | |
548 | virtual uintptr_t segPreferredLoadAddress(unsigned int) const = 0; | |
549 | virtual uintptr_t segActualLoadAddress(unsigned int) const = 0; | |
550 | virtual uintptr_t segActualEndAddress(unsigned int) const = 0; | |
551 | ||
bac542e6 | 552 | |
19894a12 | 553 | // info from LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS |
2fd3f4e8 | 554 | virtual uint32_t sdkVersion() const = 0; |
19894a12 | 555 | virtual uint32_t minOSVersion() const = 0; |
2fd3f4e8 | 556 | |
412ebb8e A |
557 | // if the image contains interposing functions, register them |
558 | virtual void registerInterposing() = 0; | |
559 | ||
560 | // when resolving symbols look in subImage if symbol can't be found | |
561 | void reExport(ImageLoader* subImage); | |
562 | ||
2fd3f4e8 A |
563 | void weakBind(const LinkContext& context); |
564 | ||
412ebb8e | 565 | void applyInterposing(const LinkContext& context); |
bac542e6 A |
566 | |
567 | dyld_image_states getState() { return (dyld_image_states)fState; } | |
568 | ||
569 | // used to sort images bottom-up | |
570 | int compare(const ImageLoader* right) const; | |
571 | ||
572 | void incrementDlopenReferenceCount() { ++fDlopenReferenceCount; } | |
573 | ||
574 | bool decrementDlopenReferenceCount(); | |
575 | ||
576 | void printReferenceCounts(); | |
577 | ||
2fd3f4e8 A |
578 | uint32_t dlopenCount() const { return fDlopenReferenceCount; } |
579 | ||
580 | void setCanUnload() { fNeverUnload = false; fLeaveMapped = false; } | |
bac542e6 A |
581 | |
582 | bool neverUnload() const { return fNeverUnload; } | |
583 | ||
584 | void setNeverUnload() { fNeverUnload = true; fLeaveMapped = true; } | |
2fd3f4e8 | 585 | void setNeverUnloadRecursive(); |
832b6fce A |
586 | |
587 | bool isReferencedDownward() { return fIsReferencedDownward; } | |
0959b6d4 | 588 | |
832b6fce | 589 | |
0959b6d4 | 590 | // triggered by DYLD_PRINT_STATISTICS to write info on work done and how fast |
412ebb8e | 591 | static void printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo); |
0959b6d4 A |
592 | |
593 | // used with DYLD_IMAGE_SUFFIX | |
594 | static void addSuffix(const char* path, const char* suffix, char* result); | |
595 | ||
596 | static uint32_t hash(const char*); | |
39a8cd10 A |
597 | |
598 | // used instead of directly deleting image | |
599 | static void deleteImage(ImageLoader*); | |
bac542e6 | 600 | |
2fd3f4e8 A |
601 | bool dependsOn(ImageLoader* image); |
602 | ||
603 | void setPath(const char* path); | |
832b6fce | 604 | void setPaths(const char* path, const char* realPath); |
bac542e6 | 605 | void setPathUnowned(const char* path); |
39a8cd10 | 606 | |
bac542e6 | 607 | void clearDepth() { fDepth = 0; } |
832b6fce | 608 | int getDepth() { return fDepth; } |
bac542e6 A |
609 | |
610 | void setBeingRemoved() { fBeingRemoved = true; } | |
611 | bool isBeingRemoved() const { return fBeingRemoved; } | |
612 | ||
2fd3f4e8 A |
613 | void markNotUsed() { fMarkedInUse = false; } |
614 | void markedUsedRecursive(const std::vector<DynamicReference>&); | |
615 | bool isMarkedInUse() const { return fMarkedInUse; } | |
616 | ||
2028a915 A |
617 | void setAddFuncNotified() { fAddFuncNotified = true; } |
618 | bool addFuncNotified() const { return fAddFuncNotified; } | |
bac542e6 | 619 | |
2fd3f4e8 A |
620 | struct InterposeTuple { |
621 | uintptr_t replacement; | |
19894a12 A |
622 | ImageLoader* neverImage; // don't apply replacement to this image |
623 | ImageLoader* onlyImage; // only apply replacement to this image | |
2fd3f4e8 A |
624 | uintptr_t replacee; |
625 | }; | |
626 | ||
39a8cd10 | 627 | protected: |
0959b6d4 | 628 | // abstract base class so all constructors protected |
39a8cd10 | 629 | ImageLoader(const char* path, unsigned int libCount); |
0959b6d4 A |
630 | ImageLoader(const ImageLoader&); |
631 | void operator=(const ImageLoader&); | |
2fd3f4e8 | 632 | void operator delete(void* image) throw() { ::free(image); } |
0959b6d4 A |
633 | |
634 | ||
635 | struct LibraryInfo { | |
bac542e6 | 636 | uint32_t checksum; |
0959b6d4 A |
637 | uint32_t minVersion; |
638 | uint32_t maxVersion; | |
639 | }; | |
640 | ||
641 | struct DependentLibrary { | |
0959b6d4 | 642 | ImageLoader* image; |
bac542e6 A |
643 | uint32_t required : 1, |
644 | checksumMatches : 1, | |
645 | isReExported : 1, | |
646 | isSubFramework : 1; | |
0959b6d4 A |
647 | }; |
648 | ||
bac542e6 A |
649 | struct DependentLibraryInfo { |
650 | const char* name; | |
651 | LibraryInfo info; | |
652 | bool required; | |
653 | bool reExported; | |
412ebb8e | 654 | bool upward; |
bac542e6 A |
655 | }; |
656 | ||
bac542e6 A |
657 | |
658 | typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[], const ProgramVars* vars); | |
0959b6d4 A |
659 | typedef void (*Terminator)(void); |
660 | ||
39a8cd10 A |
661 | |
662 | ||
663 | unsigned int libraryCount() const { return fLibraryCount; } | |
664 | virtual ImageLoader* libImage(unsigned int) const = 0; | |
665 | virtual bool libReExported(unsigned int) const = 0; | |
412ebb8e A |
666 | virtual bool libIsUpward(unsigned int) const = 0; |
667 | virtual void setLibImage(unsigned int, ImageLoader*, bool, bool) = 0; | |
39a8cd10 | 668 | |
0959b6d4 A |
669 | // To link() an image, its dependent libraries are loaded, it is rebased, bound, and initialized. |
670 | // These methods do the above, exactly once, and it the right order | |
39a8cd10 | 671 | void recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths); |
bac542e6 A |
672 | void recursiveUnLoadMappedLibraries(const LinkContext& context); |
673 | unsigned int recursiveUpdateDepth(unsigned int maxDepth); | |
674 | void recursiveValidate(const LinkContext& context); | |
0959b6d4 | 675 | void recursiveRebase(const LinkContext& context); |
2fd3f4e8 | 676 | void recursiveBind(const LinkContext& context, bool forceLazysBound, bool neverUnload); |
412ebb8e | 677 | void recursiveApplyInterposing(const LinkContext& context); |
bac542e6 | 678 | void recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs); |
19894a12 A |
679 | void recursiveInitialization(const LinkContext& context, mach_port_t this_thread, |
680 | ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&); | |
0959b6d4 | 681 | |
39a8cd10 | 682 | // fill in information about dependent libraries (array length is fLibraryCount) |
bac542e6 | 683 | virtual void doGetDependentLibraries(DependentLibraryInfo libs[]) = 0; |
0959b6d4 A |
684 | |
685 | // called on images that are libraries, returns info about itself | |
686 | virtual LibraryInfo doGetLibraryInfo() = 0; | |
687 | ||
688 | // do any fix ups in this image that depend only on the load address of the image | |
689 | virtual void doRebase(const LinkContext& context) = 0; | |
690 | ||
691 | // do any symbolic fix ups in this image | |
bac542e6 A |
692 | virtual void doBind(const LinkContext& context, bool forceLazysBound) = 0; |
693 | ||
2028a915 A |
694 | // called later via API to force all lazy pointer to be bound |
695 | virtual void doBindJustLazies(const LinkContext& context) = 0; | |
696 | ||
bac542e6 A |
697 | // if image has any dtrace DOF sections, append them to list to be registered |
698 | virtual void doGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs) = 0; | |
0959b6d4 | 699 | |
412ebb8e A |
700 | // do interpose |
701 | virtual void doInterpose(const LinkContext& context) = 0; | |
702 | ||
0959b6d4 | 703 | // run any initialization routines in this image |
412ebb8e | 704 | virtual bool doInitialization(const LinkContext& context) = 0; |
0959b6d4 | 705 | |
0959b6d4 A |
706 | // return if this image has termination routines |
707 | virtual bool needsTermination() = 0; | |
708 | ||
709 | // support for runtimes in which segments don't have to maintain their relative positions | |
710 | virtual bool segmentsMustSlideTogether() const = 0; | |
711 | ||
712 | // built with PIC code and can load at any address | |
713 | virtual bool segmentsCanSlide() const = 0; | |
714 | ||
715 | // set how much all segments slide | |
716 | virtual void setSlide(intptr_t slide) = 0; | |
717 | ||
0959b6d4 A |
718 | // returns if all dependent libraries checksum's were as expected and none slide |
719 | bool allDependentLibrariesAsWhenPreBound() const; | |
720 | ||
721 | // in mach-o a child tells it parent to re-export, instead of the other way around... | |
722 | virtual bool isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const = 0; | |
723 | ||
724 | // in mach-o a parent library knows name of sub libraries it re-exports.. | |
725 | virtual bool hasSubLibrary(const LinkContext& context, const ImageLoader* child) const = 0; | |
726 | ||
bac542e6 A |
727 | // set fState to dyld_image_state_memory_mapped |
728 | void setMapped(const LinkContext& context); | |
2fd3f4e8 | 729 | |
39a8cd10 | 730 | void setFileInfo(dev_t device, ino_t inode, time_t modDate); |
bac542e6 | 731 | |
19894a12 A |
732 | static uintptr_t interposedAddress(const LinkContext& context, uintptr_t address, const ImageLoader* notInImage, const ImageLoader* onlyInImage=NULL); |
733 | ||
39a8cd10 | 734 | static uintptr_t fgNextPIEDylibAddress; |
0959b6d4 | 735 | static uint32_t fgImagesWithUsedPrebinding; |
bac542e6 | 736 | static uint32_t fgImagesUsedFromSharedCache; |
39a8cd10 A |
737 | static uint32_t fgImagesHasWeakDefinitions; |
738 | static uint32_t fgImagesRequiringCoalescing; | |
0959b6d4 A |
739 | static uint32_t fgTotalRebaseFixups; |
740 | static uint32_t fgTotalBindFixups; | |
bac542e6 A |
741 | static uint32_t fgTotalBindSymbolsResolved; |
742 | static uint32_t fgTotalBindImageSearches; | |
0959b6d4 A |
743 | static uint32_t fgTotalLazyBindFixups; |
744 | static uint32_t fgTotalPossibleLazyBindFixups; | |
bac542e6 A |
745 | static uint32_t fgTotalSegmentsMapped; |
746 | static uint64_t fgTotalBytesMapped; | |
747 | static uint64_t fgTotalBytesPreFetched; | |
0959b6d4 A |
748 | static uint64_t fgTotalLoadLibrariesTime; |
749 | static uint64_t fgTotalRebaseTime; | |
750 | static uint64_t fgTotalBindTime; | |
39a8cd10 A |
751 | static uint64_t fgTotalWeakBindTime; |
752 | static uint64_t fgTotalDOF; | |
0959b6d4 | 753 | static uint64_t fgTotalInitTime; |
412ebb8e | 754 | static std::vector<InterposeTuple> fgInterposingTuples; |
2fd3f4e8 | 755 | |
0959b6d4 | 756 | const char* fPath; |
832b6fce | 757 | const char* fRealPath; |
0959b6d4 A |
758 | dev_t fDevice; |
759 | ino_t fInode; | |
760 | time_t fLastModified; | |
0959b6d4 | 761 | uint32_t fPathHash; |
bac542e6 | 762 | uint32_t fDlopenReferenceCount; // count of how many dlopens have been done on this image |
0959b6d4 A |
763 | |
764 | private: | |
bac542e6 A |
765 | struct recursive_lock { |
766 | recursive_lock(mach_port_t t) : thread(t), count(0) {} | |
767 | mach_port_t thread; | |
768 | int count; | |
769 | }; | |
770 | void recursiveSpinLock(recursive_lock&); | |
771 | void recursiveSpinUnLock(); | |
bac542e6 | 772 | |
bac542e6 A |
773 | const ImageLoader::Symbol* findExportedSymbolInDependentImagesExcept(const char* name, const ImageLoader** dsiStart, |
774 | const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const; | |
775 | ||
19894a12 A |
776 | void processInitializers(const LinkContext& context, mach_port_t this_thread, |
777 | InitializerTimingList& timingInfo, ImageLoader::UninitedUpwards& ups); | |
bac542e6 A |
778 | |
779 | ||
39a8cd10 | 780 | recursive_lock* fInitializerRecursiveLock; |
bac542e6 A |
781 | uint16_t fDepth; |
782 | uint16_t fLoadOrder; | |
783 | uint32_t fState : 8, | |
39a8cd10 | 784 | fLibraryCount : 10, |
bac542e6 A |
785 | fAllLibraryChecksumsAndLoadAddressesMatch : 1, |
786 | fLeaveMapped : 1, // when unloaded, leave image mapped in cause some other code may have pointers into it | |
787 | fNeverUnload : 1, // image was statically loaded by main executable | |
788 | fHideSymbols : 1, // ignore this image's exported symbols when linking other images | |
789 | fMatchByInstallName : 1,// look at image's install-path not its load path | |
412ebb8e | 790 | fInterposed : 1, |
bac542e6 | 791 | fRegisteredDOF : 1, |
bac542e6 | 792 | fAllLazyPointersBound : 1, |
2fd3f4e8 | 793 | fMarkedInUse : 1, |
bac542e6 | 794 | fBeingRemoved : 1, |
2028a915 | 795 | fAddFuncNotified : 1, |
39a8cd10 | 796 | fPathOwnedByImage : 1, |
832b6fce | 797 | fIsReferencedDownward : 1, |
39a8cd10 | 798 | fWeakSymbolsBound : 1; |
bac542e6 | 799 | |
bac542e6 | 800 | static uint16_t fgLoadOrdinal; |
0959b6d4 A |
801 | }; |
802 | ||
803 | ||
2fd3f4e8 | 804 | VECTOR_NEVER_DESTRUCTED_EXTERN(ImageLoader::InterposeTuple); |
0959b6d4 A |
805 | |
806 | ||
807 | #endif | |
808 |