/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#define __IMAGELOADERMACHO__
#include <stdint.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
#include "ImageLoader.h"
+#include "mach-o/dyld_images.h"
-struct sf_mapping;
-struct _shared_region_mapping_np;
//
-// ImageLoaderMachO is the concrete subclass of ImageLoader which loads mach-o format files.
-// The class is written to be 64-bit clean and support both 32-bit and 64-bit executables in
-// mach-o.
+// ImageLoaderMachO is a subclass of ImageLoader which loads mach-o format files.
//
//
class ImageLoaderMachO : public ImageLoader {
public:
- ImageLoaderMachO(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offset, uint64_t len, const struct stat& info, const LinkContext& context);
- ImageLoaderMachO(const char* moduleName, const struct mach_header* mh, uint64_t len, const LinkContext& context);
- virtual ~ImageLoaderMachO() {}
+ static ImageLoader* instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, const LinkContext& context);
+ static ImageLoader* instantiateFromFile(const char* path, int fd, const uint8_t firstPages[], size_t firstPagesSize, uint64_t offsetInFat,
+ uint64_t lenInFat, const struct stat& info, const LinkContext& context);
+ static ImageLoader* instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info, const LinkContext& context);
+ static ImageLoader* instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, const LinkContext& context);
+
+
+ bool inSharedCache() const { return fInSharedCache; }
+ void disableCoverageCheck() { fCoveredCodeLength = UINT64_MAX; }
const char* getInstallPath() const;
virtual void* getMain() const;
+ virtual void* getThreadPC() const;
virtual const struct mach_header* machHeader() const;
virtual uintptr_t getSlide() const;
- virtual const void* getBaseAddress() const;
+ virtual const void* getEnd() const;
virtual bool hasCoalescedExports() const;
- virtual const Symbol* findExportedSymbol(const char* name, const void* hint, bool searchReExports, ImageLoader** foundIn) const;
- virtual uintptr_t getExportedSymbolAddress(const Symbol* sym) const;
+ virtual const Symbol* findExportedSymbol(const char* name, bool searchReExports, const char* thisPath, const ImageLoader** foundIn) const;
+ virtual uintptr_t getExportedSymbolAddress(const Symbol* sym, const LinkContext& context,
+ const ImageLoader* requestor, bool runResolver, const char*) const;
virtual DefinitionFlags getExportedSymbolInfo(const Symbol* sym) const;
virtual const char* getExportedSymbolName(const Symbol* sym) const;
virtual uint32_t getExportedSymbolCount() const;
virtual const Symbol* getIndexedExportedSymbol(uint32_t index) const;
virtual uint32_t getImportedSymbolCount() const;
virtual const Symbol* getIndexedImportedSymbol(uint32_t index) const;
- virtual ReferenceFlags geImportedSymbolInfo(const Symbol* sym) const;
+ virtual ReferenceFlags getImportedSymbolInfo(const Symbol* sym) const;
virtual const char* getImportedSymbolName(const Symbol* sym) const;
virtual bool isBundle() const;
virtual bool isDylib() const;
+ virtual bool isExecutable() const;
+ virtual bool isPositionIndependentExecutable() const;
virtual bool forceFlat() const;
- virtual uintptr_t doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context);
+ virtual bool participatesInCoalescing() const;
+ virtual const char* findClosestSymbol(const void* addr, const void** closestAddr) const = 0;
+ virtual void initializeCoalIterator(CoalIterator&, unsigned int loadOrder, unsigned) = 0;
+ virtual bool incrementCoalIterator(CoalIterator&) = 0;
+ virtual uintptr_t getAddressCoalIterator(CoalIterator&, const LinkContext& contex) = 0;
+ virtual void updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, unsigned targetIndex, const LinkContext& context) = 0;
+ virtual uintptr_t doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
+ virtual uintptr_t doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, void (*lock)(), void (*unlock)()) = 0;
virtual void doTermination(const LinkContext& context);
- virtual void doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]);
virtual bool needsInitialization();
- virtual bool hasImageNotification();
virtual bool getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length);
+ virtual void getUnwindInfo(dyld_unwind_sections* info);
virtual bool findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset);
virtual bool usablePrebinding(const LinkContext& context) const;
-
-
- static void printStatistics(unsigned int imageCount);
-
+ virtual unsigned int segmentCount() const;
+ virtual const char* segName(unsigned int) const;
+ virtual uintptr_t segSize(unsigned int) const;
+ virtual uintptr_t segFileSize(unsigned int) const;
+ virtual bool segHasTrailingZeroFill(unsigned int);
+ virtual uintptr_t segFileOffset(unsigned int) const;
+ virtual bool segReadable(unsigned int) const;
+ virtual bool segWriteable(unsigned int) const;
+ virtual bool segExecutable(unsigned int) const;
+ virtual bool segUnaccessible(unsigned int) const;
+ virtual bool segHasPreferredLoadAddress(unsigned int) const;
+ virtual uintptr_t segActualLoadAddress(unsigned int) const;
+ virtual uintptr_t segPreferredLoadAddress(unsigned int) const;
+ virtual uintptr_t segActualEndAddress(unsigned int) const;
+ virtual void registerInterposing();
+ virtual uint32_t sdkVersion() const;
+ virtual uint32_t minOSVersion() const;
+ virtual const char* libPath(unsigned int) const;
+ virtual bool notifyObjC() const { return fNotifyObjC; }
+
+ static void printStatisticsDetails(unsigned int imageCount, const InitializerTimingList&);
+ static uint32_t minOSVersion(const mach_header*);
+ static uint32_t sdkVersion(const mach_header* mh);
+ static intptr_t computeSlide(const mach_header* mh);
+ static bool findSection(const mach_header* mh, const char* segmentName, const char* sectionName, void** sectAddress, uintptr_t* sectSize);
+ static const dyld_info_command* findDyldInfoLoadCommand(const mach_header* mh);
+ static const char* findClosestSymbol(const mach_header* mh, const void* addr, const void** closestAddr);
+ static bool getLazyBindingInfo(uint32_t& lazyBindingInfoOffset, const uint8_t* lazyInfoStart, const uint8_t* lazyInfoEnd,
+ uint8_t* segIndex, uintptr_t* segOffset, int* ordinal, const char** symbolName, bool* doneAfterBind);
+ static uintptr_t segPreferredAddress(const mach_header* mh, unsigned segIndex);
+ static uintptr_t bindLocation(const LinkContext& context, uintptr_t location, uintptr_t value,
+ uint8_t type, const char* symbolName,
+ intptr_t addend, const char* inPath, const char* toPath, const char* msg);
+ virtual void rebase(const LinkContext& context, uintptr_t slide) = 0;
+
+
+
protected:
ImageLoaderMachO(const ImageLoaderMachO&);
+ ImageLoaderMachO(const macho_header* mh, const char* path, unsigned int segCount,
+ uint32_t segOffsets[], unsigned int libCount);
+ virtual ~ImageLoaderMachO() {}
+
void operator=(const ImageLoaderMachO&);
- virtual uint32_t doGetDependentLibraryCount();
- virtual void doGetDependentLibraries(DependentLibrary libs[]);
- virtual LibraryInfo doGetLibraryInfo();
+ virtual void setDyldInfo(const struct dyld_info_command*) = 0;
+ virtual void setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*) = 0;
+ virtual bool isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const = 0;
+ virtual bool hasSubLibrary(const LinkContext& context, const ImageLoader* child) const = 0;
+ virtual uint32_t* segmentCommandOffsets() const = 0;
+ virtual const ImageLoader::Symbol* findShallowExportedSymbol(const char* name, const ImageLoader** foundIn) const = 0;
+ virtual bool containsSymbol(const void* addr) const = 0;
+ virtual uintptr_t exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const = 0;
+ virtual bool exportedSymbolIsWeakDefintion(const Symbol* symbol) const = 0;
+ virtual const char* exportedSymbolName(const Symbol* symbol) const = 0;
+ virtual unsigned int exportedSymbolCount() const = 0;
+ virtual const ImageLoader::Symbol* exportedSymbolIndexed(unsigned int) const = 0;
+ virtual unsigned int importedSymbolCount() const = 0;
+ virtual const ImageLoader::Symbol* importedSymbolIndexed(unsigned int) const = 0;
+ virtual const char* importedSymbolName(const Symbol* symbol) const = 0;
+#if PREBOUND_IMAGE_SUPPORT
+ virtual void resetPreboundLazyPointers(const LinkContext& context) = 0;
+#endif
+
+
+ virtual void doGetDependentLibraries(DependentLibraryInfo libs[]);
+ virtual LibraryInfo doGetLibraryInfo(const LibraryInfo& requestorInfo);
+ virtual void getRPaths(const LinkContext& context, std::vector<const char*>&) const;
+ virtual bool getUUID(uuid_t) const;
virtual void doRebase(const LinkContext& context);
- virtual void doBind(const LinkContext& context, BindingLaziness bindness);
- virtual void doInitialization(const LinkContext& context);
- virtual void doPrebinding(const LinkContext& context, time_t timestamp, uint8_t* fileToPrebind);
+ virtual void doBind(const LinkContext& context, bool forceLazysBound) = 0;
+ virtual void doBindJustLazies(const LinkContext& context) = 0;
+ virtual bool doInitialization(const LinkContext& context);
+ virtual void doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs);
virtual bool needsTermination();
- virtual void instantiateSegments(const uint8_t* fileData);
virtual bool segmentsMustSlideTogether() const;
virtual bool segmentsCanSlide() const;
virtual void setSlide(intptr_t slide);
virtual bool usesTwoLevelNameSpace() const;
- virtual bool isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const;
- virtual bool hasSubLibrary(const LinkContext& context, const ImageLoader* child) const;
virtual bool isPrebindable() const;
- virtual void prebindUnmap(const LinkContext& context);
-
-#if !__LP64__ // split segs not supported for 64-bits
- virtual void mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
-#endif
-
-private:
- friend class SegmentMachO;
-
- void init();
- void parseLoadCmds();
- void doBindIndirectSymbolPointers(const LinkContext& context, BindingLaziness bindness, bool onlyCoalescedSymbols);
- void doBindExternalRelocations(const LinkContext& context, bool onlyCoalescedSymbols);
- uintptr_t resolveUndefined(const LinkContext& context, const struct macho_nlist* symbol, bool twoLevel, ImageLoader **foundIn);
- uintptr_t getRelocBase();
+
+protected:
+
+ void destroy();
+ static void sniffLoadCommands(const macho_header* mh, const char* path, bool inCache, bool* compressed,
+ unsigned int* segCount, unsigned int* libCount, const LinkContext& context,
+ const linkedit_data_command** codeSigCmd,
+ const encryption_info_command** encryptCmd);
+ static bool needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh);
+ void loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile, const LinkContext& context);
+ void validateFirstPages(const struct linkedit_data_command* codeSigCmd, int fd, const uint8_t *fileData, size_t lenFileData, off_t offsetInFat, const LinkContext& context);
+ const struct macho_segment_command* segLoadCommand(unsigned int segIndex) const;
+ void parseLoadCmds(const ImageLoader::LinkContext& context);
+ int crashIfInvalidCodeSignature();
+ bool segHasRebaseFixUps(unsigned int) const;
+ bool segHasBindFixUps(unsigned int) const;
+ void segProtect(unsigned int segIndex, const ImageLoader::LinkContext& context);
+ void segMakeWritable(unsigned int segIndex, const ImageLoader::LinkContext& context);
+#if __i386__
+ bool segIsReadOnlyImport(unsigned int) const;
+#endif
+ intptr_t assignSegmentAddresses(const LinkContext& context);
+ uintptr_t reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context);
+ bool reserveAddressRange(uintptr_t start, size_t length);
+ void mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
+ void mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context);
+ void UnmapSegments();
+ void __attribute__((noreturn)) throwSymbolNotFound(const LinkContext& context, const char* symbol,
+ const char* referencedFrom, const char* fromVersMismatch,
+ const char* expectedIn);
void doImageInit(const LinkContext& context);
void doModInitFunctions(const LinkContext& context);
- void setupLazyPointerHandler();
- void applyPrebindingToDATA(uint8_t* fileToPrebind);
- void applyPrebindingToLoadCommands(const LinkContext& context, uint8_t* fileToPrebind, time_t timestamp);
- void applyPrebindingToLinkEdit(const LinkContext& context, uint8_t* fileToPrebind);
-#if !__LP64__ // split segs not supported for 64-bits
- unsigned int getExtraZeroFillEntriesCount();
- int sharedRegionLoadFile(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
- int sharedRegionMapFile(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
- int sharedRegionMakePrivate(const LinkContext& context);
- int sharedRegionMapFilePrivate(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context, bool usemmap);
- int sharedRegionMapFilePrivateOutside(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
- void initMappingTable(uint64_t offsetInFat, sf_mapping *mappingTable, uintptr_t baseAddress);
- void initMappingTable(uint64_t offsetInFat, _shared_region_mapping_np *mappingTable);
-#endif
- bool needsCoalescing() const;
-
- static bool symbolRequiresCoalescing(const struct macho_nlist* symbol);
- static uintptr_t bindLazySymbol(const mach_header*, uintptr_t* lazyPointer);
- static const struct macho_nlist* binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount);
- static const struct macho_nlist* binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[],
- const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex);
-
- const uint8_t* fMachOData;
- const uint8_t* fLinkEditBase; // add any internal "offset" to this to get actual address
- const struct macho_nlist* fSymbolTable;
- const char* fStrings;
- const struct dysymtab_command* fDynamicInfo;
- uintptr_t fSlide;
- bool fIsSplitSeg;
- bool fHasSubLibraries;
- bool fHasSubUmbrella;
- bool fTextSegmentHasFixups;
- const struct macho_routines_command* fDashInit;
- const struct macho_section* fModInitSection;
- const struct macho_section* fModTermSection;
- const struct macho_section* fDATAdyld;
- const struct macho_section* fImageNotifySection;
- const struct twolevel_hints_command* fTwoLevelHints;
- const struct dylib_command* fDylibID;
- const char* fReExportThruFramework;
- SegmentMachO* fTextSegmentWithFixups; // NULL unless __TEXT segment has fixups
-
- static uint32_t fgHintedBinaryTreeSearchs;
- static uint32_t fgUnhintedBinaryTreeSearchs;
-};
+ void setupLazyPointerHandler(const LinkContext& context);
+ void lookupProgramVars(const LinkContext& context) const;
+ void makeTextSegmentWritable(const LinkContext& context, bool writeable);
+ void preFetchDATA(int fd, uint64_t offsetInFat, const LinkContext& context);
-class SegmentMachO : public Segment
-{
-public:
- SegmentMachO(const struct macho_segment_command* cmd, ImageLoaderMachO*, const uint8_t* fileData);
- virtual ~SegmentMachO();
-
- virtual const ImageLoader* getImage();
- virtual const char* getName();
- virtual uintptr_t getSize();
- virtual uintptr_t getFileSize();
- virtual uintptr_t getFileOffset();
- virtual bool readable();
- virtual bool writeable();
- virtual bool executable();
- virtual bool unaccessible();
- virtual bool hasFixUps();
- virtual uintptr_t getActualLoadAddress();
- virtual uintptr_t getPreferredLoadAddress();
- virtual void setUnMapWhenDestructed(bool unmap);
- virtual uint32_t crc32();
+ void doInterpose(const LinkContext& context) = 0;
+ bool hasReferencesToWeakSymbols() const;
+ uintptr_t getSymbolAddress(const Symbol* sym, const ImageLoader* requestor,
+ const LinkContext& context, bool runResolver) const;
+
+ static uintptr_t bindLazySymbol(const mach_header*, uintptr_t* lazyPointer);
protected:
- virtual bool hasPreferredLoadAddress();
-
-private:
- SegmentMachO(const SegmentMachO&);
- void operator=(const SegmentMachO&);
-
- friend class ImageLoaderMachO;
-
-
- ImageLoaderMachO* const fImage;
- char fName[18];
- const uintptr_t fSize;
- const uintptr_t fFileSize;
- const uintptr_t fFileOffset;
- const uintptr_t fPreferredLoadAddress;
- const uint16_t fVMProtection;
- bool fHasFixUps;
- bool fUnMapOnDestruction;
+ uint64_t fCoveredCodeLength;
+ const uint8_t* fMachOData;
+ const uint8_t* fLinkEditBase; // add any internal "offset" to this to get mapped address
+ uintptr_t fSlide;
+ uint32_t fEHFrameSectionOffset;
+ uint32_t fUnwindInfoSectionOffset;
+ uint32_t fDylibIDOffset;
+ uint32_t fSegmentsCount : 8,
+ fIsSplitSeg : 1,
+ fInSharedCache : 1,
+#if TEXT_RELOC_SUPPORT
+ fTextSegmentRebases : 1,
+ fTextSegmentBinds : 1,
+#endif
+#if __i386__
+ fReadOnlyImportSegment : 1,
+#endif
+ fHasSubLibraries : 1,
+ fHasSubUmbrella : 1,
+ fInUmbrella : 1,
+ fHasDOFSections : 1,
+ fHasDashInit : 1,
+ fHasInitializers : 1,
+ fHasTerminators : 1,
+ fNotifyObjC : 1,
+ fRetainForObjC : 1,
+ fRegisteredAsRequiresCoalescing : 1; // <rdar://problem/7886402> Loading MH_DYLIB_STUB causing coalescable miscount
+
+
+ static uint32_t fgSymbolTableBinarySearchs;
};