X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/d425e3882ca60fabae080ddb890789ef2e73a66b..fb9a160cc46cd88a41dda5ab61012c5572e56f33:/src/ld/ld.hpp diff --git a/src/ld/ld.hpp b/src/ld/ld.hpp index 7be00a3..e297036 100644 --- a/src/ld/ld.hpp +++ b/src/ld/ld.hpp @@ -31,12 +31,19 @@ #include #include -#include #include +#include +#include +#include +#include +#include "configure.h" namespace ld { +// Forward declaration for bitcode support +class Bitcode; + // // ld::File // @@ -51,7 +58,9 @@ namespace ld { class File { public: - enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, objcConstraintRetainReleaseOrGC, objcConstraintGC }; + enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, + objcConstraintRetainReleaseOrGC, objcConstraintGC, + objcConstraintRetainReleaseForSimulator }; class AtomHandler { public: @@ -84,7 +93,7 @@ public: Ordinal (uint64_t ordinal) : _ordinal(ordinal) {} - enum { ArgListPartition=0, IndirectDylibPartition=1, LTOPartition = 2, InvalidParition=0xffff }; + enum { kArgListPartition=0, kIndirectDylibPartition=1, kLTOPartition = 2, kLinkerOptionPartition = 2, InvalidParition=0xffff }; Ordinal(uint16_t partition, uint16_t majorIndex, uint16_t minorIndex, uint16_t counter) { _ordinal = ((uint64_t)partition<<48) | ((uint64_t)majorIndex<<32) | ((uint64_t)minorIndex<<16) | ((uint64_t)counter<<0); } @@ -115,16 +124,21 @@ public: // The minorIndex is used for files pulled in by a file list and the value is the index of the file in the file list. // The counter is used for .a files and the value is the index of the object in the archive. // Thus, an object pulled in from a .a that was listed in a file list could use all three fields. - static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(ArgListPartition, argIndex, 0, 0); }; + static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(kArgListPartition, argIndex, 0, 0); }; const Ordinal nextFileListOrdinal() const { return nextMinorIndex(); } - const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(ArgListPartition, majorIndex(), minorIndex(), index); } + const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(kArgListPartition, majorIndex(), minorIndex(), index); } // For indirect libraries the partition is IndirectDylibPartition and the counter is used or order the libraries. - static const ld::File::Ordinal indirectDylibBase() { return Ordinal(IndirectDylibPartition, 0, 0, 0); } + static const ld::File::Ordinal indirectDylibBase() { return Ordinal(kIndirectDylibPartition, 0, 0, 0); } const Ordinal nextIndirectDylibOrdinal() const { return nextCounter(); } // For the LTO mach-o the partition is LTOPartition. As there is only one LTO file no other fields are needed. - static const ld::File::Ordinal LTOOrdinal() { return Ordinal(LTOPartition, 0, 0, 0); } + static const ld::File::Ordinal LTOOrdinal() { return Ordinal(kLTOPartition, 0, 0, 0); } + + // For linker options embedded in object files + static const ld::File::Ordinal linkeOptionBase() { return Ordinal(kIndirectDylibPartition, 1, 0, 0); } + const Ordinal nextLinkerOptionOrdinal() { nextCounter(); return *this; }; + }; typedef enum { Reloc, Dylib, Archive, Other } Type; @@ -138,10 +152,14 @@ public: virtual bool forEachAtom(AtomHandler&) const = 0; virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const = 0; virtual ObjcConstraint objCConstraint() const { return objcConstraintNone; } + virtual uint8_t swiftVersion() const { return 0; } virtual uint32_t cpuSubType() const { return 0; } virtual uint32_t subFileCount() const { return 1; } + virtual uint32_t minOSVersion() const { return 0; } + virtual uint32_t platformLoadCommand() const { return 0; } bool fileExists() const { return _modTime != 0; } Type type() const { return _type; } + virtual Bitcode* getBitcode() const { return NULL; } private: const char* _path; time_t _modTime; @@ -155,11 +173,14 @@ private: // enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, mac10_6=0x000A0600, mac10_7=0x000A0700, mac10_8=0x000A0800, - mac10_Future=0x10000000 }; + mac10_9=0x000A0900, mac10_Future=0x10000000 }; enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100, iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000, - iOS_6_0=0x00060000, iOS_Future=0x10000000}; - + iOS_6_0=0x00060000, iOS_7_0=0x00070000, iOS_8_0=0x00080000, + iOS_9_0=0x00090000, iOS_Future=0x10000000}; +enum WatchOSVersionMin { wOSVersionUnset=0, wOS_1_0=0x00010000, wOS_2_0=0x00020000 }; + + namespace relocatable { // // ld::relocatable::File @@ -181,6 +202,7 @@ namespace relocatable { { public: enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 }; + enum SourceKind { kSourceUnknown=0, kSourceObj, kSourceLTO, kSourceArchive, kSourceCompilerArchive }; struct Stab { const class Atom* atom; uint8_t type; @@ -189,6 +211,7 @@ namespace relocatable { uint32_t value; const char* string; }; + typedef const std::vector< std::vector > LinkerOptionsList; File(const char* pth, time_t modTime, Ordinal ord) : ld::File(pth, modTime, ord, Reloc) { } @@ -199,6 +222,8 @@ namespace relocatable { virtual const std::vector* stabs() const = 0; virtual bool canScatterAtoms() const = 0; virtual bool hasLongBranchStubs() { return false; } + virtual LinkerOptionsList* linkerOptions() const = 0; + virtual SourceKind sourceKind() const { return kSourceUnknown; } }; } // namespace relocatable @@ -257,8 +282,15 @@ namespace dylib { virtual bool hasWeakDefinition(const char* name) const = 0; virtual bool hasPublicInstallName() const = 0; virtual bool allSymbolsAreWeakImported() const = 0; - virtual const void* codeSignatureDR() const = 0; + virtual bool installPathVersionSpecific() const { return false; } + virtual bool appExtensionSafe() const = 0; + protected: + struct ReExportChain { ReExportChain* prev; const File* file; }; + virtual std::pair hasWeakDefinitionImpl(const char* name) const = 0; + virtual bool containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& defAddress) const = 0; + virtual void assertNoReExportCycles(ReExportChain*) const = 0; + const char* _dylibInstallPath; uint32_t _dylibTimeStamp; uint32_t _dylibCurrentVersion; @@ -298,14 +330,14 @@ class Section { public: enum Type { typeUnclassified, typeCode, typePageZero, typeImportProxies, typeLinkEdit, typeMachHeader, typeStack, - typeLiteral4, typeLiteral8, typeLiteral16, typeConstants, typeTempLTO, + typeLiteral4, typeLiteral8, typeLiteral16, typeConstants, typeTempLTO, typeTempAlias, typeCString, typeNonStdCString, typeCStringPointer, typeUTF16Strings, typeCFString, typeObjC1Classes, typeCFI, typeLSDA, typeDtraceDOF, typeUnwindInfo, typeObjCClassRefs, typeObjC2CategoryList, typeZeroFill, typeTentativeDefs, typeLazyPointer, typeStub, typeNonLazyPointer, typeDyldInfo, typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers, typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols, typeTLVDefs, typeTLVZeroFill, typeTLVInitialValues, typeTLVInitializerPointers, typeTLVPointers, - typeFirstSection, typeLastSection, typeDebug }; + typeFirstSection, typeLastSection, typeDebug, typeSectCreate }; Section(const char* sgName, const char* sctName, @@ -391,16 +423,31 @@ struct Fixup kindStoreARMLoad12, kindStoreARMLow16, kindStoreARMHigh16, kindStoreThumbLow16, kindStoreThumbHigh16, +#if SUPPORT_ARCH_arm64 + // ARM64 specific store kinds + kindStoreARM64Branch26, + kindStoreARM64Page21, kindStoreARM64PageOff12, + kindStoreARM64GOTLoadPage21, kindStoreARM64GOTLoadPageOff12, + kindStoreARM64GOTLeaPage21, kindStoreARM64GOTLeaPageOff12, + kindStoreARM64TLVPLoadPage21, kindStoreARM64TLVPLoadPageOff12, + kindStoreARM64TLVPLoadNowLeaPage21, kindStoreARM64TLVPLoadNowLeaPageOff12, + kindStoreARM64PointerToGOT, kindStoreARM64PCRelToGOT, +#endif // dtrace probes kindDtraceExtra, kindStoreX86DtraceCallSiteNop, kindStoreX86DtraceIsEnableSiteClear, kindStoreARMDtraceCallSiteNop, kindStoreARMDtraceIsEnableSiteClear, + kindStoreARM64DtraceCallSiteNop, kindStoreARM64DtraceIsEnableSiteClear, kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear, // lazy binding kindLazyTarget, kindSetLazyOffset, + // islands + kindIslandTarget, // data-in-code markers kindDataInCodeStartData, kindDataInCodeStartJT8, kindDataInCodeStartJT16, kindDataInCodeStartJT32, kindDataInCodeStartJTA32, kindDataInCodeEnd, + // linker optimzation hints + kindLinkerOptimizationHint, // pointer store combinations kindStoreTargetAddressLittleEndian32, // kindSetTargetAddress + kindStoreLittleEndian32 kindStoreTargetAddressLittleEndian64, // kindSetTargetAddress + kindStoreLittleEndian64 @@ -421,6 +468,20 @@ struct Fixup kindStoreTargetAddressARMBranch24, // kindSetTargetAddress + kindStoreARMBranch24 kindStoreTargetAddressThumbBranch22, // kindSetTargetAddress + kindStoreThumbBranch22 kindStoreTargetAddressARMLoad12, // kindSetTargetAddress + kindStoreARMLoad12 +#if SUPPORT_ARCH_arm64 + // ARM64 value calculation and store combinations + kindStoreTargetAddressARM64Branch26, // kindSetTargetAddress + kindStoreARM64Branch26 + kindStoreTargetAddressARM64Page21, // kindSetTargetAddress + kindStoreARM64Page21 + kindStoreTargetAddressARM64PageOff12, // kindSetTargetAddress + kindStoreARM64PageOff12 + kindStoreTargetAddressARM64GOTLoadPage21, // kindSetTargetAddress + kindStoreARM64GOTLoadPage21 + kindStoreTargetAddressARM64GOTLoadPageOff12,// kindSetTargetAddress + kindStoreARM64GOTLoadPageOff12 + kindStoreTargetAddressARM64GOTLeaPage21, // kindSetTargetAddress + kindStoreARM64GOTLeaPage21 + kindStoreTargetAddressARM64GOTLeaPageOff12, // kindSetTargetAddress + kindStoreARM64GOTLeaPageOff12 + kindStoreTargetAddressARM64TLVPLoadPage21, // kindSetTargetAddress + kindStoreARM64TLVPLoadPage21 + kindStoreTargetAddressARM64TLVPLoadPageOff12,// kindSetTargetAddress + kindStoreARM64TLVPLoadPageOff12 + kindStoreTargetAddressARM64TLVPLoadNowLeaPage21, // kindSetTargetAddress + kindStoreARM64TLVPLoadNowLeaPage21 + kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12, // kindSetTargetAddress + kindStoreARM64TLVPLoadNowLeaPageOff12 +#endif }; union { @@ -436,54 +497,70 @@ struct Fixup TargetBinding binding : 3; bool contentAddendOnly : 1; bool contentDetlaToAddendOnly : 1; + bool contentIgnoresAddend : 1; typedef Fixup* iterator; Fixup() : offsetInAtom(0), kind(kindNone), clusterSize(k1of1), weakImport(false), binding(bindingNone), - contentAddendOnly(false), contentDetlaToAddendOnly(false) { u.target = NULL; } + contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { u.target = NULL; } Fixup(Kind k, Atom* targetAtom) : offsetInAtom(0), kind(k), clusterSize(k1of1), weakImport(false), binding(Fixup::bindingDirectlyBound), - contentAddendOnly(false), contentDetlaToAddendOnly(false) + contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { assert(targetAtom != NULL); u.target = targetAtom; } Fixup(uint32_t off, Cluster c, Kind k) : offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(Fixup::bindingNone), - contentAddendOnly(false), contentDetlaToAddendOnly(false) + contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { u.addend = 0; } Fixup(uint32_t off, Cluster c, Kind k, bool weakIm, const char* name) : offsetInAtom(off), kind(k), clusterSize(c), weakImport(weakIm), binding(Fixup::bindingByNameUnbound), - contentAddendOnly(false), contentDetlaToAddendOnly(false) + contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { assert(name != NULL); u.name = name; } Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const char* name) : offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b), - contentAddendOnly(false), contentDetlaToAddendOnly(false) + contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { assert(name != NULL); u.name = name; } Fixup(uint32_t off, Cluster c, Kind k, const Atom* targetAtom) : offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(Fixup::bindingDirectlyBound), - contentAddendOnly(false), contentDetlaToAddendOnly(false) + contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { assert(targetAtom != NULL); u.target = targetAtom; } Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const Atom* targetAtom) : offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b), - contentAddendOnly(false), contentDetlaToAddendOnly(false) + contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { assert(targetAtom != NULL); u.target = targetAtom; } Fixup(uint32_t off, Cluster c, Kind k, uint64_t addend) : offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(Fixup::bindingNone), - contentAddendOnly(false), contentDetlaToAddendOnly(false) + contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { u.addend = addend; } + Fixup(Kind k, uint32_t lohKind, uint32_t off1, uint32_t off2) : + offsetInAtom(off1), kind(k), clusterSize(k1of1), + weakImport(false), binding(Fixup::bindingNone), contentAddendOnly(false), + contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { + assert(k == kindLinkerOptimizationHint); + LOH_arm64 extra; + extra.addend = 0; + extra.info.kind = lohKind; + extra.info.count = 1; + extra.info.delta1 = 0; + extra.info.delta2 = (off2 - off1) >> 2; + u.addend = extra.addend; + } + + bool firstInCluster() const { switch (clusterSize) { case k1of1: @@ -512,6 +589,18 @@ struct Fixup return false; } + union LOH_arm64 { + uint64_t addend; + struct { + unsigned kind : 6, + count : 2, // 00 => 1 addr, 11 => 4 addrs + delta1 : 14, // 16-bit delta, low 2 bits assumed zero + delta2 : 14, + delta3 : 14, + delta4 : 14; + } info; + }; + }; // @@ -570,7 +659,7 @@ public: typeSectionEnd, typeBranchIsland, typeLazyPointer, typeStub, typeNonLazyPointer, typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers, typeLTOtemporary, typeResolver, - typeTLV, typeTLVZeroFill, typeTLVInitialValue, typeTLVInitializerPointers }; + typeTLV, typeTLVZeroFill, typeTLVInitialValue, typeTLVInitializerPointers, typeTLVPointer }; enum SymbolTableInclusion { symbolTableNotIn, symbolTableNotInFinalLinkedImages, symbolTableIn, symbolTableInAndNeverStrip, symbolTableInAsAbsolute, @@ -605,13 +694,14 @@ public: _contentType(ct), _symbolTableInclusion(i), _scope(s), _mode(modeSectionOffset), _overridesADylibsWeakDef(false), _coalescedAway(false), - _live(false), _machoSection(0), _weakImportState(weakImportUnset) + _live(false), _dontDeadStripIfRefLive(false), + _machoSection(0), _weakImportState(weakImportUnset) { #ifndef NDEBUG switch ( _combine ) { case combineByNameAndContent: case combineByNameAndReferences: - assert(_symbolTableInclusion == symbolTableNotIn); + assert(_symbolTableInclusion != symbolTableIn); assert(_scope != scopeGlobal); break; case combineByName: @@ -629,6 +719,7 @@ public: ContentType contentType() const { return _contentType; } SymbolTableInclusion symbolTableInclusion() const{ return _symbolTableInclusion; } bool dontDeadStrip() const { return _dontDeadStrip; } + bool dontDeadStripIfReferencesLive() const { return _dontDeadStripIfRefLive; } bool isThumb() const { return _thumb; } bool isAlias() const { return _alias; } Alignment alignment() const { return Alignment(_alignmentPowerOf2, _alignmentModulus); } @@ -648,6 +739,7 @@ public: void setCoalescedAway() { _coalescedAway = true; } void setWeakImportState(bool w) { assert(_definition == definitionProxy); _weakImportState = ( w ? weakImportTrue : weakImportFalse); } void setAutoHide() { _autoHide = true; } + void setDontDeadStripIfReferencesLive() { _dontDeadStripIfRefLive = true; } void setLive() { _live = true; } void setLive(bool value) { _live = value; } void setMachoSection(unsigned x) { assert(x != 0); assert(x < 256); _machoSection = x; } @@ -675,15 +767,13 @@ public: } return false; } + virtual void setFile(const File* f) { } virtual UnwindInfo::iterator beginUnwind() const { return NULL; } virtual UnwindInfo::iterator endUnwind() const { return NULL; } virtual LineInfo::iterator beginLineInfo() const { return NULL; } virtual LineInfo::iterator endLineInfo() const { return NULL; } -protected: - enum AddressMode { modeSectionOffset, modeFinalAddress }; - void setAttributesFromAtom(const Atom& a) { _section = a._section; _alignmentModulus = a._alignmentModulus; @@ -692,7 +782,6 @@ protected: _combine = a._combine; _dontDeadStrip = a._dontDeadStrip; _thumb = a._thumb; - _alias = a._alias; _autoHide = a._autoHide; _contentType = a._contentType; _symbolTableInclusion = a._symbolTableInclusion; @@ -703,6 +792,9 @@ protected: _weakImportState = a._weakImportState; } +protected: + enum AddressMode { modeSectionOffset, modeFinalAddress }; + const Section * _section; uint64_t _address; uint16_t _alignmentModulus; @@ -720,6 +812,7 @@ protected: bool _overridesADylibsWeakDef : 1; bool _coalescedAway : 1; bool _live : 1; + bool _dontDeadStripIfRefLive : 1; unsigned _machoSection : 8; WeakImportState _weakImportState : 2; }; @@ -733,6 +826,24 @@ public: }; + +// utility classes for using std::unordered_map with c-strings +struct CStringHash { + size_t operator()(const char* __s) const { + size_t __h = 0; + for ( ; *__s; ++__s) + __h = 5 * __h + *__s; + return __h; + }; +}; +struct CStringEquals +{ + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } +}; + +typedef std::unordered_set CStringSet; + + class Internal { public: @@ -757,6 +868,10 @@ public: bool hasExternalRelocs; }; + typedef std::map AtomToSection; + + virtual uint64_t assignFileOffsets() = 0; + virtual void setSectionSizesAndAlignments() = 0; virtual ld::Internal::FinalSection* addAtom(const Atom&) = 0; virtual ld::Internal::FinalSection* getFinalSection(const ld::Section& inputSection) = 0; virtual ~Internal() {} @@ -765,14 +880,23 @@ public: lazyBindingHelper(NULL), compressedFastBinderProxy(NULL), objcObjectConstraint(ld::File::objcConstraintNone), objcDylibConstraint(ld::File::objcConstraintNone), - cpuSubType(0), + swiftVersion(0), cpuSubType(0), minOSVersion(0), + objectFileFoundWithNoVersion(false), allObjectFilesScatterable(true), - someObjectFileHasDwarf(false), usingHugeSections(false) { } - + someObjectFileHasDwarf(false), usingHugeSections(false), + hasThreadLocalVariableDefinitions(false), + hasWeakExternalSymbols(false), + someObjectHasOptimizationHints(false), + dropAllBitcode(false), embedMarkerOnly(false) { } + std::vector sections; std::vector dylibs; std::vector stabs; + AtomToSection atomToSection; + CStringSet linkerOptionLibraries; + CStringSet linkerOptionFrameworks; std::vector indirectBindingTable; + std::vector filesWithBitcode; const ld::dylib::File* bundleLoader; const Atom* entryPoint; const Atom* classicBindingHelper; @@ -780,33 +904,24 @@ public: const Atom* compressedFastBinderProxy; ld::File::ObjcConstraint objcObjectConstraint; ld::File::ObjcConstraint objcDylibConstraint; + uint8_t swiftVersion; uint32_t cpuSubType; + uint32_t minOSVersion; + uint32_t derivedPlatformLoadCommand; + bool objectFileFoundWithNoVersion; bool allObjectFilesScatterable; bool someObjectFileHasDwarf; bool usingHugeSections; + bool hasThreadLocalVariableDefinitions; + bool hasWeakExternalSymbols; + bool someObjectHasOptimizationHints; + bool dropAllBitcode; + bool embedMarkerOnly; + std::string ltoBitcodePath; }; - -// utility classes for using std::unordered_map with c-strings -struct CStringHash { - size_t operator()(const char* __s) const { - size_t __h = 0; - for ( ; *__s; ++__s) - __h = 5 * __h + *__s; - return __h; - }; -}; -struct CStringEquals -{ - bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } -}; - - - - -