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