/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#define __IMAGELOADER__
#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
#include <mach/mach_time.h> // struct mach_timebase_info
#include <mach/mach_init.h> // struct mach_thread_self
+#include <mach/shared_region.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
#include <stdint.h>
+#include <stdlib.h>
+#include <TargetConditionals.h>
#include <vector>
-#include <set>
+#include <new>
+
+#if __arm__
+ #include <mach/vm_page_size.h>
+#endif
+
+#if __x86_64__ || __i386__
+ #include <CrashReporterClient.h>
+#else
+ // work around until iOS has CrashReporterClient.h
+ #define CRSetCrashLogMessage(x)
+ #define CRSetCrashLogMessage2(x)
+#endif
+
+#ifndef SHARED_REGION_BASE_ARM64
+ #define SHARED_REGION_BASE_ARM64 0x7FFF80000000LL
+#endif
+
+#ifndef SHARED_REGION_SIZE_ARM64
+ #define SHARED_REGION_SIZE_ARM64 0x10000000LL
+#endif
+
+
+#define LOG_BINDINGS 0
#include "mach-o/dyld_images.h"
#include "mach-o/dyld_priv.h"
+#if __i386__
+ #define SHARED_REGION_BASE SHARED_REGION_BASE_I386
+ #define SHARED_REGION_SIZE SHARED_REGION_SIZE_I386
+#elif __x86_64__
+ #define SHARED_REGION_BASE SHARED_REGION_BASE_X86_64
+ #define SHARED_REGION_SIZE SHARED_REGION_SIZE_X86_64
+#elif __arm__
+ #define SHARED_REGION_BASE SHARED_REGION_BASE_ARM
+ #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM
+#elif __arm64__
+ #define SHARED_REGION_BASE SHARED_REGION_BASE_ARM64
+ #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM64
+#endif
+
+#ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
+ #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
+#endif
+#ifndef EXPORT_SYMBOL_FLAGS_REEXPORT
+ #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
+#endif
-#define SPLIT_SEG_SHARED_REGION_SUPPORT 0
-#define SPLIT_SEG_DYLIB_SUPPORT (__ppc__ || __i386__)
-#define TEXT_RELOC_SUPPORT (__ppc__ || __i386__)
-#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__)
-#define IMAGE_NOTIFY_SUPPORT 0
-#define RECURSIVE_INITIALIZER_LOCK 1
-#define SUPPORT_OLD_CRT_INITIALIZATION (__ppc__ || __i386__)
+#ifndef LC_MAIN
+ #define LC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */
+ struct entry_point_command {
+ uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */
+ uint32_t cmdsize; /* 24 */
+ uint64_t entryoff; /* file (__TEXT) offset of main() */
+ uint64_t stacksize;/* if not zero, initial stack size */
+ };
+#endif
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+ #define SPLIT_SEG_SHARED_REGION_SUPPORT 0
+ #define SPLIT_SEG_DYLIB_SUPPORT 0
+ #define PREBOUND_IMAGE_SUPPORT __arm__
+ #define TEXT_RELOC_SUPPORT __i386__
+ #define SUPPORT_OLD_CRT_INITIALIZATION 0
+ #define SUPPORT_LC_DYLD_ENVIRONMENT 1
+ #define SUPPORT_VERSIONED_PATHS 1
+ #define SUPPORT_CLASSIC_MACHO __arm__
+ #define SUPPORT_ZERO_COST_EXCEPTIONS (!__USING_SJLJ_EXCEPTIONS__)
+ #define INITIAL_IMAGE_COUNT 150
+ #define SUPPORT_ACCELERATE_TABLES (__arm__ || __arm64__)
+ #define SUPPORT_ROOT_PATH TARGET_IPHONE_SIMULATOR
+#else
+ #define SPLIT_SEG_SHARED_REGION_SUPPORT 0
+ #define SPLIT_SEG_DYLIB_SUPPORT __i386__
+ #define PREBOUND_IMAGE_SUPPORT __i386__
+ #define TEXT_RELOC_SUPPORT __i386__
+ #define SUPPORT_OLD_CRT_INITIALIZATION __i386__
+ #define SUPPORT_LC_DYLD_ENVIRONMENT (__i386__ || __x86_64__)
+ #define SUPPORT_VERSIONED_PATHS 1
+ #define SUPPORT_CLASSIC_MACHO 1
+ #define SUPPORT_ZERO_COST_EXCEPTIONS 1
+ #define INITIAL_IMAGE_COUNT 200
+ #define SUPPORT_ACCELERATE_TABLES 0
+ #define SUPPORT_ROOT_PATH 1
+#endif
+#define MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE (32*1024)
+
+#define MH_HAS_OBJC 0x40000000
+
+// <rdar://problem/13590567> optimize away dyld's initializers
+#define VECTOR_NEVER_DESTRUCTED(type) \
+ namespace std { \
+ template <> \
+ __vector_base<type, std::allocator<type> >::~__vector_base() { } \
+ }
+#define VECTOR_NEVER_DESTRUCTED_EXTERN(type) \
+ namespace std { \
+ template <> \
+ __vector_base<type, std::allocator<type> >::~__vector_base(); \
+ }
+#define VECTOR_NEVER_DESTRUCTED_IMPL(type) \
+ namespace std { \
+ template <> \
+ __vector_base<type, std::allocator<type> >::~__vector_base() { } \
+ }
// utilities
namespace dyld {
extern void log(const char* format, ...) __attribute__((format(printf, 1, 2)));
extern void warn(const char* format, ...) __attribute__((format(printf, 1, 2)));
extern const char* mkstringf(const char* format, ...) __attribute__((format(printf, 1, 2)));
-};
+#if LOG_BINDINGS
+ extern void logBindings(const char* format, ...) __attribute__((format(printf, 1, 2)));
+#endif
+}
+extern "C" int vm_alloc(vm_address_t* addr, vm_size_t size, uint32_t flags);
+extern "C" void* xmmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);
+
+
+#if __LP64__
+ struct macho_header : public mach_header_64 {};
+ struct macho_nlist : public nlist_64 {};
+#else
+ struct macho_header : public mach_header {};
+ struct macho_nlist : public nlist {};
+#endif
+
+
+#if __arm64__
+ #define dyld_page_trunc(__addr) (__addr & (-16384))
+ #define dyld_page_round(__addr) ((__addr + 16383) & (-16384))
+ #define dyld_page_size 16384
+#elif __arm__
+ #define dyld_page_trunc(__addr) trunc_page_kernel(__addr)
+ #define dyld_page_round(__addr) round_page_kernel(__addr)
+ #define dyld_page_size vm_kernel_page_size
+#else
+ #define dyld_page_trunc(__addr) (__addr & (-4096))
+ #define dyld_page_round(__addr) ((__addr + 4095) & (-4096))
+ #define dyld_page_size 4096
+#endif
+
struct ProgramVars
const char* imageShortName;
};
+ struct DynamicReference {
+ ImageLoader* from;
+ ImageLoader* to;
+ };
+
+ struct InitializerTimingList
+ {
+ uintptr_t count;
+ struct {
+ const char* shortName;
+ uint64_t initTime;
+ } images[1];
+
+ void addTime(const char* name, uint64_t time);
+ };
+
struct LinkContext {
- ImageLoader* (*loadLibrary)(const char* libraryName, bool search, bool findDLL, const char* origin, const RPathChain* rpaths);
+ ImageLoader* (*loadLibrary)(const char* libraryName, bool search, const char* origin, const RPathChain* rpaths, unsigned& cacheIndex);
void (*terminationRecorder)(ImageLoader* image);
bool (*flatExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image);
bool (*coalescedExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image);
+ unsigned int (*getCoalescedImages)(ImageLoader* images[], unsigned imageIndex[]);
void (*undefinedHandler)(const char* name);
-#if IMAGE_NOTIFY_SUPPORT
- void (*addImageNeedingNotification)(ImageLoader* image);
- void (*notifyAdding)(const ImageLoader* const * images, unsigned int count);
-#endif
MappedRegion* (*getAllMappedRegions)(MappedRegion*);
void * (*bindingHandler)(const char *, const char *, void *);
- void (*notifySingle)(dyld_image_states, const struct mach_header*, const char* path, time_t modDate);
- void (*notifyBatch)(dyld_image_states state);
+ void (*notifySingle)(dyld_image_states, const ImageLoader* image, InitializerTimingList*);
+ void (*notifyBatch)(dyld_image_states state, bool preflightOnly);
void (*removeImage)(ImageLoader* image);
void (*registerDOFs)(const std::vector<DOFInfo>& dofs);
void (*clearAllDepths)();
+ void (*printAllDepths)();
unsigned int (*imageCount)();
- void (*notifySharedCacheInvalid)();
-#if __i386__
- void (*makeSharedCacheImportSegmentsWritable)(bool writable);
-#endif
void (*setNewProgramVars)(const ProgramVars&);
+ bool (*inSharedCache)(const char* path);
+ void (*setErrorStrings)(unsigned errorCode, const char* errorClientOfDylibPath,
+ const char* errorTargetDylibPath, const char* errorSymbol);
+ ImageLoader* (*findImageContainingAddress)(const void* addr);
+ void (*addDynamicReference)(ImageLoader* from, ImageLoader* to);
+#if SUPPORT_ACCELERATE_TABLES
+ void (*notifySingleFromCache)(dyld_image_states, const mach_header* mh, const char* path);
+ dyld_image_state_change_handler (*getPreInitNotifyHandler)(unsigned index);
+ dyld_image_state_change_handler (*getBoundBatchHandler)(unsigned index);
+#endif
+
#if SUPPORT_OLD_CRT_INITIALIZATION
void (*setRunInitialzersOldWay)();
#endif
ProgramVars programVars;
ImageLoader* mainExecutable;
const char* imageSuffix;
+#if SUPPORT_ROOT_PATH
+ const char** rootPaths;
+#endif
+ const dyld_interpose_tuple* dynamicInterposeArray;
+ size_t dynamicInterposeCount;
PrebindMode prebindUsage;
SharedRegionMode sharedRegionMode;
- bool dyldLoadedAtSameAddressNeededBySharedCache;
+ bool dyldLoadedAtSameAddressNeededBySharedCache;
+ bool strictMachORequired;
+ bool requireCodeSignature;
+ bool mainExecutableCodeSigned;
bool preFetchDisabled;
bool prebinding;
bool bindFlat;
bool linkingMainExecutable;
+ bool startedInitializingMainExecutable;
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ bool processIsRestricted;
+ bool processUsingLibraryValidation;
+#endif
bool verboseOpts;
bool verboseEnv;
+ bool verboseLoading;
bool verboseMapping;
bool verboseRebase;
bool verboseBind;
+ bool verboseWeakBind;
bool verboseInit;
bool verboseDOF;
bool verbosePrebinding;
+ bool verboseCoreSymbolication;
bool verboseWarnings;
+ bool verboseRPaths;
+ bool verboseInterposing;
+ bool verboseCodeSignatures;
};
+ struct CoalIterator
+ {
+ ImageLoader* image;
+ const char* symbolName;
+ unsigned int loadOrder;
+ bool weakSymbol;
+ bool symbolMatches;
+ bool done;
+ // the following are private to the ImageLoader subclass
+ uintptr_t curIndex;
+ uintptr_t endIndex;
+ uintptr_t address;
+ uintptr_t type;
+ uintptr_t addend;
+ uintptr_t imageIndex;
+ };
+
+ virtual void initializeCoalIterator(CoalIterator&, unsigned int loadOrder, unsigned imageIndex) = 0;
+ virtual bool incrementCoalIterator(CoalIterator&) = 0;
+ virtual uintptr_t getAddressCoalIterator(CoalIterator&, const LinkContext& context) = 0;
+ virtual void updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, unsigned targetIndex, const LinkContext& context) = 0;
+
+ struct UninitedUpwards
+ {
+ uintptr_t count;
+ ImageLoader* images[1];
+ };
+
+
// constructor is protected, but anyone can delete an image
virtual ~ImageLoader();
// link() takes a newly instantiated ImageLoader and does all
// fixups needed to make it usable by the process
- void link(const LinkContext& context, bool forceLazysBound, bool preflight, const RPathChain& loaderRPaths);
+ void link(const LinkContext& context, bool forceLazysBound, bool preflight, bool neverUnload, const RPathChain& loaderRPaths, const char* imagePath);
// runInitializers() is normally called in link() but the main executable must
// run crt code before initializers
- void runInitializers(const LinkContext& context);
+ void runInitializers(const LinkContext& context, InitializerTimingList& timingInfo);
// called after link() forces all lazy pointers to be bound
void bindAllLazyPointers(const LinkContext& context, bool recursive);
// get short name of this image
const char* getShortName() const;
+ // returns leaf name
+ static const char* shortName(const char* fullName);
+
// get path used to load this image, not necessarily the "real" path
const char* getPath() const { return fPath; }
uint32_t getPathHash() const { return fPathHash; }
- // get path used to load this image represents (ZeroLink only) which image this .o is part of
- const char* getLogicalPath() const;
+ // get the "real" path for this image (e.g. no @rpath)
+ const char* getRealPath() const;
// get path this image is intended to be placed on disk or NULL if no preferred install location
virtual const char* getInstallPath() const = 0;
- // image was loaded with NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME and all clients are looking for install path
+ // image was loaded with NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME and all clients are looking for install path
bool matchInstallPath() const;
void setMatchInstallPath(bool);
- // if path was a fat file, offset of image loaded in that fat file
- uint64_t getOffsetInFatFile() const;
-
// mark that this image's exported symbols should be ignored when linking other images (e.g. RTLD_LOCAL)
void setHideExports(bool hide = true);
// even if image is deleted, leave segments mapped in
bool leaveMapped() { return fLeaveMapped; }
+ // image resides in dyld shared cache
+ virtual bool inSharedCache() const = 0;
+
// checks if the specifed address is within one of this image's segments
virtual bool containsAddress(const void* addr) const;
+ // checks if the specifed symbol is within this image's symbol table
+ virtual bool containsSymbol(const void* addr) const = 0;
+
// checks if the specifed address range overlaps any of this image's segments
virtual bool overlapsWithAddressRange(const void* start, const void* end) const;
// st_mtime from stat() on file
time_t lastModified() const;
- // only valid for main executables, returns a pointer its entry point
+ // only valid for main executables, returns a pointer its entry point from LC_UNIXTHREAD
+ virtual void* getThreadPC() const = 0;
+
+ // only valid for main executables, returns a pointer its main from LC_<MAIN
virtual void* getMain() const = 0;
// dyld API's require each image to have an associated mach_header
// image has exports that participate in runtime coalescing
virtual bool hasCoalescedExports() const = 0;
+
+ // search symbol table of definitions in this image for requested name
+ virtual bool findExportedSymbolAddress(const LinkContext& context, const char* symbolName,
+ const ImageLoader* requestorImage, int requestorOrdinalOfDef,
+ bool runResolver, const ImageLoader** foundIn, uintptr_t* address) const;
+
+ // search symbol table of definitions in this image for requested name
+ virtual const Symbol* findExportedSymbol(const char* name, bool searchReExports, const char* thisPath, const ImageLoader** foundIn) const = 0;
// search symbol table of definitions in this image for requested name
- virtual const Symbol* findExportedSymbol(const char* name, const void* hint, bool searchReExports, const ImageLoader** foundIn) const = 0;
+ virtual const Symbol* findExportedSymbol(const char* name, bool searchReExports, const ImageLoader** foundIn) const {
+ return findExportedSymbol(name, searchReExports, this->getPath(), foundIn);
+ }
// gets address of implementation (code) of the specified exported symbol
- virtual uintptr_t getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, const ImageLoader* requestor=NULL) const = 0;
+ virtual uintptr_t getExportedSymbolAddress(const Symbol* sym, const LinkContext& context,
+ const ImageLoader* requestor=NULL, bool runResolver=false, const char* symbolName=NULL) const = 0;
// gets attributes of the specified exported symbol
virtual DefinitionFlags getExportedSymbolInfo(const Symbol* sym) const = 0;
virtual const Symbol* getIndexedImportedSymbol(uint32_t index) const = 0;
// gets attributes of the specified imported symbol
- virtual ReferenceFlags geImportedSymbolInfo(const Symbol* sym) const = 0;
+ virtual ReferenceFlags getImportedSymbolInfo(const Symbol* sym) const = 0;
// gets name of the specified imported symbol
virtual const char* getImportedSymbolName(const Symbol* sym) const = 0;
+ // find the closest symbol before addr
+ virtual const char* findClosestSymbol(const void* addr, const void** closestAddr) const = 0;
+
+ // for use with accelerator tables
+ virtual const char* getIndexedPath(unsigned) const { return getPath(); }
+ virtual const char* getIndexedShortName(unsigned) const { return getShortName(); }
+
// checks if this image is a bundle and can be loaded but not linked
virtual bool isBundle() const = 0;
// checks if this image is a dylib
virtual bool isDylib() const = 0;
+ // checks if this image is a main executable
+ virtual bool isExecutable() const = 0;
+
+ // checks if this image is a main executable
+ virtual bool isPositionIndependentExecutable() const = 0;
+
// only for main executable
virtual bool forceFlat() const = 0;
// called at runtime when a lazily bound function is first called
virtual uintptr_t doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
+ // called at runtime when a fast lazily bound function is first called
+ virtual uintptr_t doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context,
+ void (*lock)(), void (*unlock)()) = 0;
+
// calls termination routines (e.g. C++ static destructors for image)
virtual void doTermination(const LinkContext& context) = 0;
-#if IMAGE_NOTIFY_SUPPORT
- // tell this image about other images
- virtual void doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]) = 0;
-#endif
// return if this image has initialization routines
virtual bool needsInitialization() = 0;
-#if IMAGE_NOTIFY_SUPPORT
- // return if this image has a routine to be called when any image is loaded or unloaded
- virtual bool hasImageNotification() = 0;
-#endif
// return if this image has specified section and set start and length
virtual bool getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length) = 0;
-
+
+ // fills in info about __eh_frame and __unwind_info sections
+ virtual void getUnwindInfo(dyld_unwind_sections* info) = 0;
+
// given a pointer into an image, find which segment and section it is in
virtual bool findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset) = 0;
// add all RPATH paths this image contains
virtual void getRPaths(const LinkContext& context, std::vector<const char*>&) const = 0;
+ // image has or uses weak definitions that need runtime coalescing
+ virtual bool participatesInCoalescing() const = 0;
+
+ // if image has a UUID, copy into parameter and return true
+ virtual bool getUUID(uuid_t) const = 0;
+
+ // dynamic interpose values onto this image
+ virtual void dynamicInterpose(const LinkContext& context) = 0;
+
+ // record interposing for any late binding
+ void addDynamicInterposingTuples(const struct dyld_interpose_tuple array[], size_t count);
+
+ virtual const char* libPath(unsigned int) const = 0;
+
+ // Image has objc sections, so information objc about when it comes and goes
+ virtual bool notifyObjC() const { return false; }
+
+//
+// A segment is a chunk of an executable file that is mapped into memory.
+//
+ virtual unsigned int segmentCount() const = 0;
+ virtual const char* segName(unsigned int) const = 0;
+ virtual uintptr_t segSize(unsigned int) const = 0;
+ virtual uintptr_t segFileSize(unsigned int) const = 0;
+ virtual bool segHasTrailingZeroFill(unsigned int) = 0;
+ virtual uintptr_t segFileOffset(unsigned int) const = 0;
+ virtual bool segReadable(unsigned int) const = 0;
+ virtual bool segWriteable(unsigned int) const = 0;
+ virtual bool segExecutable(unsigned int) const = 0;
+ virtual bool segUnaccessible(unsigned int) const = 0;
+ virtual bool segHasPreferredLoadAddress(unsigned int) const = 0;
+ virtual uintptr_t segPreferredLoadAddress(unsigned int) const = 0;
+ virtual uintptr_t segActualLoadAddress(unsigned int) const = 0;
+ virtual uintptr_t segActualEndAddress(unsigned int) const = 0;
+
+
+ // info from LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS
+ virtual uint32_t sdkVersion() const = 0;
+ virtual uint32_t minOSVersion() const = 0;
+ // if the image contains interposing functions, register them
+ virtual void registerInterposing() = 0;
- dyld_image_states getState() { return (dyld_image_states)fState; }
+ // when resolving symbols look in subImage if symbol can't be found
+ void reExport(ImageLoader* subImage);
+ void weakBind(const LinkContext& context);
+
+ void applyInterposing(const LinkContext& context);
+
+ dyld_image_states getState() { return (dyld_image_states)fState; }
+
+ ino_t getInode() const { return fInode; }
+ dev_t getDevice() const { return fDevice; }
+
// used to sort images bottom-up
int compare(const ImageLoader* right) const;
void printReferenceCounts();
- uint32_t referenceCount() const { return fDlopenReferenceCount + fStaticReferenceCount + fDynamicReferenceCount; }
+ uint32_t dlopenCount() const { return fDlopenReferenceCount; }
+
+ void setCanUnload() { fNeverUnload = false; fLeaveMapped = false; }
bool neverUnload() const { return fNeverUnload; }
void setNeverUnload() { fNeverUnload = true; fLeaveMapped = true; }
+ void setNeverUnloadRecursive();
+
+ bool isReferencedDownward() { return fIsReferencedDownward; }
+
// triggered by DYLD_PRINT_STATISTICS to write info on work done and how fast
- static void printStatistics(unsigned int imageCount);
-
+ static void printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo);
+ static void printStatisticsDetails(unsigned int imageCount, const InitializerTimingList& timingInfo);
+
// used with DYLD_IMAGE_SUFFIX
static void addSuffix(const char* path, const char* suffix, char* result);
static uint32_t hash(const char*);
-
- void setPath(const char* path); // only called for images created from memory
- void setPathUnowned(const char* path);
-
- void setLogicalPath(const char* path);
+
+ static const uint8_t* trieWalk(const uint8_t* start, const uint8_t* end, const char* stringToFind);
+
+ // used instead of directly deleting image
+ static void deleteImage(ImageLoader*);
+
+ static bool haveInterposingTuples() { return !fgInterposingTuples.empty(); }
+ static void clearInterposingTuples() { fgInterposingTuples.clear(); }
+
+ bool dependsOn(ImageLoader* image);
+ void setPath(const char* path);
+ void setPaths(const char* path, const char* realPath);
+ void setPathUnowned(const char* path);
+
void clearDepth() { fDepth = 0; }
+ int getDepth() { return fDepth; }
void setBeingRemoved() { fBeingRemoved = true; }
bool isBeingRemoved() const { return fBeingRemoved; }
-
-protected:
- struct DependentLibrary;
-public:
- friend class iterator;
-
- class iterator
- {
- public:
- iterator& operator++() { ++fLocation; return *this; }
- bool operator!=(const iterator& it) const { return (it.fLocation != this->fLocation); }
- ImageLoader* operator*() const { return fLocation->image; }
- private:
- friend class ImageLoader;
- iterator(DependentLibrary* loc) : fLocation(loc) {}
- DependentLibrary* fLocation;
- };
-
- iterator beginDependents() { return iterator(fLibraries); }
- iterator endDependents() { return iterator(&fLibraries[fLibrariesCount]); }
-
-
-
- friend class Segment;
+ void markNotUsed() { fMarkedInUse = false; }
+ void markedUsedRecursive(const std::vector<DynamicReference>&);
+ bool isMarkedInUse() const { return fMarkedInUse; }
-protected:
+ void setAddFuncNotified() { fAddFuncNotified = true; }
+ bool addFuncNotified() const { return fAddFuncNotified; }
+
+ struct InterposeTuple {
+ uintptr_t replacement;
+ ImageLoader* neverImage; // don't apply replacement to this image
+ ImageLoader* onlyImage; // only apply replacement to this image
+ uintptr_t replacee;
+ };
+
+ static uintptr_t read_uleb128(const uint8_t*& p, const uint8_t* end);
+ static intptr_t read_sleb128(const uint8_t*& p, const uint8_t* end);
+
+protected:
// abstract base class so all constructors protected
- ImageLoader(const char* path, uint64_t offsetInFat, const struct stat& info);
- ImageLoader(const char* moduleName);
+ ImageLoader(const char* path, unsigned int libCount);
ImageLoader(const ImageLoader&);
void operator=(const ImageLoader&);
+ void operator delete(void* image) throw() { ::free(image); }
struct LibraryInfo {
LibraryInfo info;
bool required;
bool reExported;
+ bool upward;
};
- class SegmentIterator
- {
- public:
- SegmentIterator& operator++(); // use inline later to work around circular reference
- bool operator!=(const SegmentIterator& it) const { return (it.fLocation != this->fLocation); }
- class Segment* operator*() const { return fLocation; }
- SegmentIterator(class Segment* loc) : fLocation(loc) {}
- private:
- class Segment* fLocation;
- };
typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[], const ProgramVars* vars);
typedef void (*Terminator)(void);
+
+
+ unsigned int libraryCount() const { return fLibraryCount; }
+ virtual ImageLoader* libImage(unsigned int) const = 0;
+ virtual bool libReExported(unsigned int) const = 0;
+ virtual bool libIsUpward(unsigned int) const = 0;
+ virtual void setLibImage(unsigned int, ImageLoader*, bool, bool) = 0;
+
// To link() an image, its dependent libraries are loaded, it is rebased, bound, and initialized.
// These methods do the above, exactly once, and it the right order
- void recursiveLoadLibraries(const LinkContext& context, const RPathChain& loaderRPaths);
- void recursiveUnLoadMappedLibraries(const LinkContext& context);
- unsigned int recursiveUpdateDepth(unsigned int maxDepth);
- void recursiveValidate(const LinkContext& context);
- void recursiveRebase(const LinkContext& context);
- void recursiveBind(const LinkContext& context, bool forceLazysBound);
- void recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs);
-#if IMAGE_NOTIFY_SUPPORT
- void recursiveImageAnnouncement(const LinkContext& context, ImageLoader**& newImages);
-#endif
- void recursiveInitialization(const LinkContext& context, mach_port_t this_thread);
-
- // return how many libraries this image depends on
- virtual uint32_t doGetDependentLibraryCount() = 0;
-
- // fill in information about dependent libraries (array length is doGetDependentLibraryCount())
+ virtual void recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths, const char* loadPath);
+ virtual unsigned recursiveUpdateDepth(unsigned int maxDepth);
+ virtual void recursiveRebase(const LinkContext& context);
+ virtual void recursiveBind(const LinkContext& context, bool forceLazysBound, bool neverUnload);
+ virtual void recursiveApplyInterposing(const LinkContext& context);
+ virtual void recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs);
+ virtual void recursiveInitialization(const LinkContext& context, mach_port_t this_thread, const char* pathToInitialize,
+ ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&);
+
+ // fill in information about dependent libraries (array length is fLibraryCount)
virtual void doGetDependentLibraries(DependentLibraryInfo libs[]) = 0;
// called on images that are libraries, returns info about itself
- virtual LibraryInfo doGetLibraryInfo() = 0;
+ virtual LibraryInfo doGetLibraryInfo(const LibraryInfo& requestorInfo) = 0;
// do any fix ups in this image that depend only on the load address of the image
virtual void doRebase(const LinkContext& context) = 0;
// do any symbolic fix ups in this image
virtual void doBind(const LinkContext& context, bool forceLazysBound) = 0;
- // update any segment permissions
- virtual void doUpdateMappingPermissions(const LinkContext& context) = 0;
+ // called later via API to force all lazy pointer to be bound
+ virtual void doBindJustLazies(const LinkContext& context) = 0;
// if image has any dtrace DOF sections, append them to list to be registered
virtual void doGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs) = 0;
+ // do interpose
+ virtual void doInterpose(const LinkContext& context) = 0;
+
// run any initialization routines in this image
- virtual void doInitialization(const LinkContext& context) = 0;
+ virtual bool doInitialization(const LinkContext& context) = 0;
// return if this image has termination routines
virtual bool needsTermination() = 0;
// built with PIC code and can load at any address
virtual bool segmentsCanSlide() const = 0;
-
+
// set how much all segments slide
virtual void setSlide(intptr_t slide) = 0;
-
- // utility routine to map in all segements in fSegments from a file
- virtual void mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
-
- // utility routine to map in all segements in fSegments from a memory image
- virtual void mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context);
// returns if all dependent libraries checksum's were as expected and none slide
bool allDependentLibrariesAsWhenPreBound() const;
// in mach-o a parent library knows name of sub libraries it re-exports..
virtual bool hasSubLibrary(const LinkContext& context, const ImageLoader* child) const = 0;
-
+
+ virtual bool weakSymbolsBound(unsigned index) { return fWeakSymbolsBound; }
+ virtual void setWeakSymbolsBound(unsigned index) { fWeakSymbolsBound = true; }
+
// set fState to dyld_image_state_memory_mapped
void setMapped(const LinkContext& context);
-
- // mark that target should not be unloaded unless this is also unloaded
- void addDynamicReference(const ImageLoader* target);
-
- // used to start iterating Segments
- virtual SegmentIterator beginSegments() const = 0;
-
- // used to end iterating Segments
- virtual SegmentIterator endSegments() const = 0;
-
+
+ void setFileInfo(dev_t device, ino_t inode, time_t modDate);
+ void setDepth(uint16_t depth) { fDepth = depth; }
+
+ static uintptr_t interposedAddress(const LinkContext& context, uintptr_t address, const ImageLoader* notInImage, const ImageLoader* onlyInImage=NULL);
+
+ static uintptr_t fgNextPIEDylibAddress;
static uint32_t fgImagesWithUsedPrebinding;
static uint32_t fgImagesUsedFromSharedCache;
- static uint32_t fgImagesRequiringNoFixups;
+ static uint32_t fgImagesHasWeakDefinitions;
+ static uint32_t fgImagesRequiringCoalescing;
static uint32_t fgTotalRebaseFixups;
static uint32_t fgTotalBindFixups;
static uint32_t fgTotalBindSymbolsResolved;
static uint32_t fgTotalLazyBindFixups;
static uint32_t fgTotalPossibleLazyBindFixups;
static uint32_t fgTotalSegmentsMapped;
+ static uint32_t fgSymbolTrieSearchs;
static uint64_t fgTotalBytesMapped;
static uint64_t fgTotalBytesPreFetched;
static uint64_t fgTotalLoadLibrariesTime;
+public:
+ static uint64_t fgTotalObjCSetupTime;
+ static uint64_t fgTotalDebuggerPausedTime;
+ static uint64_t fgTotalRebindCacheTime;
+protected:
static uint64_t fgTotalRebaseTime;
static uint64_t fgTotalBindTime;
+ static uint64_t fgTotalWeakBindTime;
+ static uint64_t fgTotalDOF;
static uint64_t fgTotalInitTime;
- static uintptr_t fgNextSplitSegAddress;
+ static std::vector<InterposeTuple> fgInterposingTuples;
+
const char* fPath;
- const char* fLogicalPath; // for ZeroLink - the image which this bundle is part of
+ const char* fRealPath;
dev_t fDevice;
ino_t fInode;
time_t fLastModified;
- uint64_t fOffsetInFatFile;
- DependentLibrary* fLibraries;
- uint32_t fLibrariesCount;
uint32_t fPathHash;
uint32_t fDlopenReferenceCount; // count of how many dlopens have been done on this image
- uint32_t fStaticReferenceCount; // count of images that have a fLibraries entry pointing to this image
- uint32_t fDynamicReferenceCount; // count of images that have a fDynamicReferences entry pointer to this image
- std::set<const ImageLoader*>* fDynamicReferences; // list of all images this image used because of a flat/coalesced lookup
-private:
-#if RECURSIVE_INITIALIZER_LOCK
struct recursive_lock {
recursive_lock(mach_port_t t) : thread(t), count(0) {}
mach_port_t thread;
};
void recursiveSpinLock(recursive_lock&);
void recursiveSpinUnLock();
-#endif
- void init(const char* path, uint64_t offsetInFat, dev_t device, ino_t inode, time_t modDate);
- intptr_t assignSegmentAddresses(const LinkContext& context);
+private:
const ImageLoader::Symbol* findExportedSymbolInDependentImagesExcept(const char* name, const ImageLoader** dsiStart,
const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const;
+ void processInitializers(const LinkContext& context, mach_port_t this_thread,
+ InitializerTimingList& timingInfo, ImageLoader::UninitedUpwards& ups);
+ recursive_lock* fInitializerRecursiveLock;
uint16_t fDepth;
uint16_t fLoadOrder;
uint32_t fState : 8,
+ fLibraryCount : 10,
fAllLibraryChecksumsAndLoadAddressesMatch : 1,
fLeaveMapped : 1, // when unloaded, leave image mapped in cause some other code may have pointers into it
fNeverUnload : 1, // image was statically loaded by main executable
fHideSymbols : 1, // ignore this image's exported symbols when linking other images
fMatchByInstallName : 1,// look at image's install-path not its load path
+ fInterposed : 1,
fRegisteredDOF : 1,
-#if IMAGE_NOTIFY_SUPPORT
- fAnnounced : 1,
-#endif
fAllLazyPointersBound : 1,
+ fMarkedInUse : 1,
fBeingRemoved : 1,
- fPathOwnedByImage : 1;
+ fAddFuncNotified : 1,
+ fPathOwnedByImage : 1,
+ fIsReferencedDownward : 1,
+ fWeakSymbolsBound : 1;
-#if RECURSIVE_INITIALIZER_LOCK
- recursive_lock* fInitializerRecursiveLock;
-#else
- uint32_t fInitializerLock;
-#endif
static uint16_t fgLoadOrdinal;
};
-//
-// Segment is an abstract base class. A segment is a chunk of an executable
-// file that is mapped into memory. Each subclass of ImageLoader typically
-// implements its own concrete subclass of Segment.
-//
-//
-class Segment {
-public:
- virtual ~Segment() {}
-
- virtual const char* getName() = 0;
- virtual uintptr_t getSize() = 0;
- virtual uintptr_t getFileSize() = 0;
- virtual bool hasTrailingZeroFill();
- virtual uintptr_t getFileOffset() = 0;
- virtual bool readable() = 0;
- virtual bool writeable() = 0;
- virtual bool executable() = 0;
- virtual bool unaccessible() = 0;
- virtual uintptr_t getActualLoadAddress(const ImageLoader*) = 0;
- virtual uintptr_t getPreferredLoadAddress() = 0;
- virtual void unmap(const ImageLoader*) = 0;
- virtual Segment* next(Segment*) = 0;
-#if __i386__
- virtual bool readOnlyImportStubs() = 0;
-#endif
-
-
-protected:
- // abstract base class so all constructors protected
- Segment() {}
- Segment(const Segment&);
- void operator=(const Segment&);
-
- virtual bool hasPreferredLoadAddress() = 0;
- //virtual void setActualLoadAddress(uint64_t addr) = 0;
- virtual void map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context);
-
- static bool reserveAddressRange(uintptr_t start, size_t length);
- static uintptr_t reserveAnAddressRange(size_t length, const class ImageLoader::LinkContext& context);
- static uintptr_t fgNextPIEDylibAddress;
-
-private:
- void setPermissions(const ImageLoader::LinkContext& context, const ImageLoader* image);
- void map(const void* memoryImage, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context);
- void tempWritable(const ImageLoader::LinkContext& context, const ImageLoader* image);
-
- friend class ImageLoader;
- friend class ImageLoaderMachO;
-};
-
-inline ImageLoader::SegmentIterator& ImageLoader::SegmentIterator::operator++() { fLocation = fLocation->next(fLocation); return *this; }
-
-
+VECTOR_NEVER_DESTRUCTED_EXTERN(ImageLoader::InterposeTuple);
#endif