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