X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/b2fa67a80bc53211e4d1ea81f23e9f953ee1dd6c..599556ff3dd31aab68bb9685f1ed7fc4867803e7:/src/ld/LinkEditClassic.hpp diff --git a/src/ld/LinkEditClassic.hpp b/src/ld/LinkEditClassic.hpp index 7fbc755..3389f5c 100644 --- a/src/ld/LinkEditClassic.hpp +++ b/src/ld/LinkEditClassic.hpp @@ -32,6 +32,7 @@ #include #include +#include #include "Options.h" #include "ld.hpp" @@ -49,8 +50,6 @@ public: // overrides of ld::Atom virtual ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char** nm) const - { return false; } virtual uint64_t objectAddress() const { return 0; } virtual void encode() = 0; @@ -92,13 +91,8 @@ public: uint32_t currentOffset(); private: - class CStringEquals - { - public: - bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } - }; enum { kBufferSize = 0x01000000 }; - typedef __gnu_cxx::hash_map, CStringEquals> StringToOffset; + typedef std::unordered_map StringToOffset; const uint32_t _pointerSize; std::vector _fullBuffers; @@ -230,7 +224,7 @@ private: uint32_t stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool); uint64_t valueForStab(const ld::relocatable::File::Stab& stab); uint8_t sectionIndexForStab(const ld::relocatable::File::Stab& stab); - + bool isAltEntry(const ld::Atom* atom); mutable std::vector > _globals; mutable std::vector > _locals; @@ -242,18 +236,44 @@ private: uint32_t _stabsIndexEnd; static ld::Section _s_section; + static int _s_anonNameIndex; + }; template ld::Section SymbolTableAtom::_s_section("__LINKEDIT", "__symbol_table", ld::Section::typeLinkEdit, true); +template +int SymbolTableAtom::_s_anonNameIndex = 1; + +template +bool SymbolTableAtom::isAltEntry(const ld::Atom* atom) +{ + // alt entries have a group subordinate reference to the previous atom + for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) { + if ( fit->kind == ld::Fixup::kindNoneGroupSubordinate ) { + if ( fit->binding == Fixup::bindingDirectlyBound ) { + const Atom* prevAtom = fit->u.target; + assert(prevAtom != NULL); + for (ld::Fixup::iterator fit2 = prevAtom->fixupsBegin(); fit2 != prevAtom->fixupsEnd(); ++fit2) { + if ( fit2->kind == ld::Fixup::kindNoneFollowOn ) { + if ( fit2->binding == Fixup::bindingDirectlyBound ) { + if ( fit2->u.target == atom ) + return true; + } + } + } + } + } + } + return false; +} template bool SymbolTableAtom::addLocal(const ld::Atom* atom, StringPoolAtom* pool) { macho_nlist

entry; - static int s_anonNameIndex = 1; assert(atom->symbolTableInclusion() != ld::Atom::symbolTableNotIn); // set n_strx @@ -264,7 +284,7 @@ bool SymbolTableAtom::addLocal(const ld::Atom* atom, StringPoolAtom* pool) if ( atom->combine() == ld::Atom::combineByNameAndContent ) { // don't use 'l' labels for x86_64 strings // x86_64 obj-c runtime confused when static lib is stripped - sprintf(anonName, "LC%u", s_anonNameIndex++); + sprintf(anonName, "LC%u", _s_anonNameIndex++); symbolName = anonName; } } @@ -279,7 +299,7 @@ bool SymbolTableAtom::addLocal(const ld::Atom* atom, StringPoolAtom* pool) } else if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) { // make auto-strip anonymous name for symbol - sprintf(anonName, "l%03u", s_anonNameIndex++); + sprintf(anonName, "l%03u", _s_anonNameIndex++); symbolName = anonName; } } @@ -315,6 +335,8 @@ bool SymbolTableAtom::addLocal(const ld::Atom* atom, StringPoolAtom* pool) desc |= N_WEAK_DEF; if ( atom->isThumb() ) desc |= N_ARM_THUMB_DEF; + if ( (this->_options.outputKind() == Options::kObjectFile) && this->_state.allObjectFilesScatterable && isAltEntry(atom) ) + desc |= N_ALT_ENTRY; entry.set_n_desc(desc); // set n_value ( address this symbol will be at if this executable is loaded at it preferred address ) @@ -335,7 +357,16 @@ void SymbolTableAtom::addGlobal(const ld::Atom* atom, StringPoolAtom* pool) macho_nlist

entry; // set n_strx - entry.set_n_strx(pool->add(atom->name())); + const char* symbolName = atom->name(); + char anonName[32]; + if ( this->_options.outputKind() == Options::kObjectFile ) { + if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) { + // make auto-strip anonymous name for symbol + sprintf(anonName, "l%03u", _s_anonNameIndex++); + symbolName = anonName; + } + } + entry.set_n_strx(pool->add(symbolName)); // set n_type if ( atom->definition() == ld::Atom::definitionAbsolute ) { @@ -356,8 +387,9 @@ void SymbolTableAtom::addGlobal(const ld::Atom* atom, StringPoolAtom* pool) entry.set_n_type(N_EXT | N_SECT | N_PEXT); } else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip) - && (atom->section().type() == ld::Section::typeMachHeader) ) { - // the __mh_execute_header is historical magic and must be an absolute symbol + && (atom->section().type() == ld::Section::typeMachHeader) + && !_options.positionIndependentExecutable() ) { + // the __mh_execute_header is historical magic in non-pie executabls and must be an absolute symbol entry.set_n_type(N_EXT | N_ABS); } } @@ -380,6 +412,8 @@ void SymbolTableAtom::addGlobal(const ld::Atom* atom, StringPoolAtom* pool) desc |= N_SYMBOL_RESOLVER; if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) ) desc |= N_NO_DEAD_STRIP; + if ( (this->_options.outputKind() == Options::kObjectFile) && this->_state.allObjectFilesScatterable && isAltEntry(atom) ) + desc |= N_ALT_ENTRY; if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) { desc |= N_WEAK_DEF; // support auto hidden weak symbols: .weak_def_can_be_hidden @@ -444,7 +478,13 @@ void SymbolTableAtom::addImport(const ld::Atom* atom, StringPoolAtom* pool) // set n_type if ( this->_options.outputKind() == Options::kObjectFile ) { - if ( (atom->scope() == ld::Atom::scopeLinkageUnit) + if ( atom->section().type() == ld::Section::typeTempAlias ) { + if ( atom->scope() == ld::Atom::scopeLinkageUnit ) + entry.set_n_type(N_INDR | N_EXT | N_PEXT); + else + entry.set_n_type(N_INDR | N_EXT); + } + else if ( (atom->scope() == ld::Atom::scopeLinkageUnit) && (atom->definition() == ld::Atom::definitionTentative) ) entry.set_n_type(N_UNDF | N_EXT | N_PEXT); else @@ -493,8 +533,24 @@ void SymbolTableAtom::addImport(const ld::Atom* atom, StringPoolAtom* pool) // set n_value, zero for import proxy and size for tentative definition if ( atom->definition() == ld::Atom::definitionTentative ) entry.set_n_value(atom->size()); - else + else if ( atom->section().type() != ld::Section::typeTempAlias ) entry.set_n_value(0); + else { + assert(atom->fixupsBegin() != atom->fixupsEnd()); + for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) { + assert(fit->kind == ld::Fixup::kindNoneFollowOn); + switch ( fit->binding ) { + case ld::Fixup::bindingByNameUnbound: + entry.set_n_value(pool->add(fit->u.name)); + break; + case ld::Fixup::bindingsIndirectlyBound: + entry.set_n_value(pool->add((_state.indirectBindingTable[fit->u.bindingIndex])->name())); + break; + default: + assert(0 && "internal error: unexpected alias binding"); + } + } + } // add to array _imports.push_back(entry); @@ -609,6 +665,7 @@ bool SymbolTableAtom::hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, return ( (_stabsIndexStart != _stabsIndexEnd) || (_stabsStringsOffsetStart != _stabsStringsOffsetEnd) ); } + template void SymbolTableAtom::encode() { @@ -616,6 +673,7 @@ void SymbolTableAtom::encode() // make nlist entries for all local symbols std::vector& localAtoms = this->_writer._localAtoms; + std::vector& globalAtoms = this->_writer._exportedAtoms; _locals.reserve(localAtoms.size()+this->_state.stabs.size()); this->_writer._localSymbolsStartIndex = 0; // make nlist entries for all debug notes @@ -642,7 +700,6 @@ void SymbolTableAtom::encode() // make nlist entries for all global symbols - std::vector& globalAtoms = this->_writer._exportedAtoms; _globals.reserve(globalAtoms.size()); this->_writer._globalSymbolsStartIndex = symbolIndex; for (std::vector::const_iterator it=globalAtoms.begin(); it != globalAtoms.end(); ++it) { @@ -767,13 +824,13 @@ uint64_t LocalRelocationsAtom::relocBaseAddress(ld::Internal& state) // for kext bundles the reloc base address starts at __TEXT segment return _options.baseAddress(); } - // for all other kinds, the x86_64 reloc base address starts at __DATA segment + // for all other kinds, the x86_64 reloc base address starts at first writable segment (usually __DATA) for (std::vector::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) { ld::Internal::FinalSection* sect = *sit; - if ( strcmp(sect->segmentName(), "__DATA") == 0 ) + if ( !sect->isSectionHidden() && _options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE ) return sect->address; } - throw "__DATA segment not found"; + throw "writable (__DATA) segment not found"; } template @@ -884,10 +941,10 @@ uint64_t ExternalRelocationsAtom::relocBaseAddress(ld::Internal& state) // for x86_64 the reloc base address starts at __DATA segment for (std::vector::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) { ld::Internal::FinalSection* sect = *sit; - if ( strcmp(sect->segmentName(), "__DATA") == 0 ) + if ( !sect->isSectionHidden() && _options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE ) return sect->address; } - throw "__DATA segment not found"; + throw "writable (__DATA) segment not found"; } template @@ -919,13 +976,22 @@ uint64_t ExternalRelocationsAtom::size() const return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info

); } +#if SUPPORT_ARCH_arm64 +template <> uint32_t ExternalRelocationsAtom::pointerReloc() { return ARM64_RELOC_UNSIGNED; } +#endif +#if SUPPORT_ARCH_arm_any template <> uint32_t ExternalRelocationsAtom::pointerReloc() { return ARM_RELOC_VANILLA; } +#endif template <> uint32_t ExternalRelocationsAtom::pointerReloc() { return GENERIC_RELOC_VANILLA; } template <> uint32_t ExternalRelocationsAtom::pointerReloc() { return X86_64_RELOC_UNSIGNED; } template <> uint32_t ExternalRelocationsAtom::callReloc() { return X86_64_RELOC_BRANCH; } template <> uint32_t ExternalRelocationsAtom::callReloc() { return GENERIC_RELOC_VANILLA; } +#if SUPPORT_ARCH_arm64 +template <> uint32_t ExternalRelocationsAtom::callReloc() { return ARM64_RELOC_BRANCH26; } +#endif + template uint32_t ExternalRelocationsAtom::callReloc() { @@ -1218,6 +1284,15 @@ void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSecti relocs.push_back(reloc1); } break; + case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_TLV); + relocs.push_back(reloc1); + break; default: assert(0 && "need to handle -r reloc"); @@ -1239,7 +1314,7 @@ uint32_t SectionRelocationsAtom::sectSymNum(bool external, const ld::Atom* ta } template <> -void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* sect, +void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* sect, const Entry& entry, std::vector >& relocs) { macho_relocation_info

reloc1; @@ -1255,8 +1330,7 @@ void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* fromExternal = entry.fromTargetUsesExternalReloc; fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget); } - - + switch ( entry.kind ) { case ld::Fixup::kindStoreX86PCRel32: case ld::Fixup::kindStoreX86BranchPCRel32: @@ -1363,8 +1437,8 @@ void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* } else { // regular pointer - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc is target offset is non-zero + if ( !external && (entry.toAddend != 0) && (entry.toTarget->symbolTableInclusion() != ld::Atom::symbolTableNotIn) ) { + // use scattered reloc if target offset is non-zero into named atom (5658046) sreloc1->set_r_scattered(true); sreloc1->set_r_pcrel(false); sreloc1->set_r_length(2); @@ -1383,6 +1457,17 @@ void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* relocs.push_back(reloc1); } break; + case ld::Fixup::kindStoreX86PCRel32TLVLoad: + case ld::Fixup::kindStoreX86Abs32TLVLoad: + case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(entry.kind == ld::Fixup::kindStoreX86PCRel32TLVLoad); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(GENERIC_RLEOC_TLV); + relocs.push_back(reloc1); + break; default: assert(0 && "need to handle -r reloc"); @@ -1390,6 +1475,8 @@ void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* } + +#if SUPPORT_ARCH_arm_any template <> void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* sect, const Entry& entry, std::vector >& relocs) @@ -1614,7 +1701,207 @@ void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* } } +#endif +#if SUPPORT_ARCH_arm64 +template <> +void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* sect, + const Entry& entry, std::vector >& relocs) +{ + macho_relocation_info

reloc1; + macho_relocation_info

reloc2; + uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address; + bool external = entry.toTargetUsesExternalReloc; + uint32_t symbolNum = sectSymNum(external, entry.toTarget); + bool fromExternal = false; + uint32_t fromSymbolNum = 0; + if ( entry.fromTarget != NULL ) { + fromExternal = entry.fromTargetUsesExternalReloc; + fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget); + } + + + switch ( entry.kind ) { + case ld::Fixup::kindStoreARM64Branch26: + if ( entry.toAddend != 0 ) { + assert(entry.toAddend < 0x400000); + reloc2.set_r_address(address); + reloc2.set_r_symbolnum(entry.toAddend); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(2); + reloc2.set_r_extern(false); + reloc2.set_r_type(ARM64_RELOC_ADDEND); + relocs.push_back(reloc2); + } + // fall into next case + case ld::Fixup::kindStoreTargetAddressARM64Branch26: + case ld::Fixup::kindStoreARM64DtraceCallSiteNop: + case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_BRANCH26); + relocs.push_back(reloc1); + break; + + case ld::Fixup::kindStoreARM64Page21: + if ( entry.toAddend != 0 ) { + assert(entry.toAddend < 0x400000); + reloc2.set_r_address(address); + reloc2.set_r_symbolnum(entry.toAddend); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(2); + reloc2.set_r_extern(false); + reloc2.set_r_type(ARM64_RELOC_ADDEND); + relocs.push_back(reloc2); + } + // fall into next case + case ld::Fixup::kindStoreTargetAddressARM64Page21: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_PAGE21); + relocs.push_back(reloc1); + break; + + case ld::Fixup::kindStoreARM64PageOff12: + if ( entry.toAddend != 0 ) { + assert(entry.toAddend < 0x400000); + reloc2.set_r_address(address); + reloc2.set_r_symbolnum(entry.toAddend); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(2); + reloc2.set_r_extern(false); + reloc2.set_r_type(ARM64_RELOC_ADDEND); + relocs.push_back(reloc2); + } + // fall into next case + case ld::Fixup::kindStoreTargetAddressARM64PageOff12: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_PAGEOFF12); + relocs.push_back(reloc1); + break; + + case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21: + case ld::Fixup::kindStoreARM64GOTLoadPage21: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGE21); + relocs.push_back(reloc1); + break; + + case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12: + case ld::Fixup::kindStoreARM64GOTLoadPageOff12: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGEOFF12); + relocs.push_back(reloc1); + break; + + + case ld::Fixup::kindStoreLittleEndian64: + case ld::Fixup::kindStoreTargetAddressLittleEndian64: + if ( entry.fromTarget != NULL ) { + // this is a pointer-diff + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(3); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_UNSIGNED); + reloc2.set_r_address(address); + reloc2.set_r_symbolnum(fromSymbolNum); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(3); + reloc2.set_r_extern(fromExternal); + reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR); + relocs.push_back(reloc2); + relocs.push_back(reloc1); + } + else { + // regular pointer + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(3); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_UNSIGNED); + relocs.push_back(reloc1); + } + break; + + case ld::Fixup::kindStoreLittleEndian32: + case ld::Fixup::kindStoreTargetAddressLittleEndian32: + if ( entry.fromTarget != NULL ) { + // this is a pointer-diff + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_UNSIGNED); + reloc2.set_r_address(address); + reloc2.set_r_symbolnum(fromSymbolNum); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(2); + reloc2.set_r_extern(fromExternal); + reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR); + relocs.push_back(reloc2); + relocs.push_back(reloc1); + } + else { + // regular pointer + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_UNSIGNED); + relocs.push_back(reloc1); + } + break; + + case ld::Fixup::kindStoreARM64PointerToGOT: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(3); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_POINTER_TO_GOT); + relocs.push_back(reloc1); + break; + + case ld::Fixup::kindStoreARM64PCRelToGOT: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(ARM64_RELOC_POINTER_TO_GOT); + relocs.push_back(reloc1); + break; + + default: + assert(0 && "need to handle arm64 -r reloc"); + + } + +} +#endif // SUPPORT_ARCH_arm64 template @@ -1866,14 +2153,18 @@ bool IndirectSymbolTableAtom::kextBundlesDontHaveIndirectSymbolTable() template void IndirectSymbolTableAtom::encode() { - // static executables should not have an indirect symbol table - if ( this->_options.outputKind() == Options::kStaticExecutable ) + // static executables should not have an indirect symbol table, unless PIE + if ( (this->_options.outputKind() == Options::kStaticExecutable) && !_options.positionIndependentExecutable() ) return; // x86_64 kext bundles should not have an indirect symbol table if ( (this->_options.outputKind() == Options::kKextBundle) && kextBundlesDontHaveIndirectSymbolTable() ) return; + // slidable static executables (-static -pie) should not have an indirect symbol table + if ( (this->_options.outputKind() == Options::kStaticExecutable) && this->_options.positionIndependentExecutable() ) + return; + // find all special sections that need a range of the indirect symbol table section for (std::vector::iterator sit = this->_state.sections.begin(); sit != this->_state.sections.end(); ++sit) { ld::Internal::FinalSection* sect = *sit;