diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.h b/lld/lib/ReaderWriter/MachO/ArchHandler.h index b15462b4da6f..6fb8211dcea6 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler.h +++ b/lld/lib/ReaderWriter/MachO/ArchHandler.h @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "MachONormalizedFile.h" +#include "Atoms.h" #include "lld/Core/LLVM.h" #include "lld/Core/Reference.h" @@ -136,6 +137,11 @@ public: FindAddressForAtom, normalized::Relocations&) = 0; + /// Add arch-specific References. + virtual void addAdditionalReferences(MachODefinedAtom &atom) { } + + /// Only relevant for 32-bit arm archs. + virtual bool isThumbFunction(const DefinedAtom &atom) { return false; } struct ReferenceInfo { Reference::KindArch arch; diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp index 035313d3885b..01d4343e9fac 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp @@ -69,6 +69,9 @@ public: FindAddressForAtom, normalized::Relocations &) override; + void addAdditionalReferences(MachODefinedAtom &atom) override; + + bool isThumbFunction(const DefinedAtom &atom) override; private: static const Registry::KindStrings _sKindStrings[]; @@ -77,6 +80,9 @@ private: enum : Reference::KindValue { invalid, /// for error condition + modeThumbCode, /// Content starting at this offset is thumb. + modeArmCode, /// Content starting at this offset is arm. + // Kinds found in mach-o .o files: thumb_b22, /// ex: bl _foo thumb_movw, /// ex: movw r1, :lower16:_foo @@ -115,12 +121,12 @@ private: void applyFixupFinal(const Reference &ref, uint8_t *location, uint64_t fixupAddress, uint64_t targetAddress, - uint64_t inAtomAddress); + uint64_t inAtomAddress, bool &thumbMode); void applyFixupRelocatable(const Reference &ref, uint8_t *location, uint64_t fixupAddress, uint64_t targetAddress, - uint64_t inAtomAddress); + uint64_t inAtomAddress, bool &thumbMode); const bool _swap; }; @@ -135,6 +141,8 @@ ArchHandler_arm::ArchHandler_arm() : ArchHandler_arm::~ArchHandler_arm() { } const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = { + LLD_KIND_STRING_ENTRY(modeThumbCode), + LLD_KIND_STRING_ENTRY(modeArmCode), LLD_KIND_STRING_ENTRY(thumb_b22), LLD_KIND_STRING_ENTRY(thumb_movw), LLD_KIND_STRING_ENTRY(thumb_movt), @@ -712,7 +720,8 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *location, uint64_t fixupAddress, uint64_t targetAddress, - uint64_t inAtomAddress) { + uint64_t inAtomAddress, + bool &thumbMode) { if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return; assert(ref.kindArch() == Reference::KindArch::ARM); @@ -720,43 +729,59 @@ void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *location, int32_t displacement; uint16_t value16; switch (ref.kindValue()) { + case modeThumbCode: + thumbMode = true; + break; + case modeArmCode: + thumbMode = false; + break; case thumb_b22: + assert(thumbMode); displacement = (targetAddress - (fixupAddress + 4)) + ref.addend(); write32(*loc32, _swap, setDisplacementInThumbBranch(*loc32, displacement)); break; case thumb_movw: + assert(thumbMode); value16 = (targetAddress + ref.addend()) & 0xFFFF; write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16)); break; case thumb_movt: + assert(thumbMode); value16 = (targetAddress + ref.addend()) >> 16; write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16)); break; case thumb_movw_funcRel: + assert(thumbMode); value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF; write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16)); break; case thumb_movt_funcRel: + assert(thumbMode); value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16; write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16)); break; case arm_b24: + assert(!thumbMode); displacement = (targetAddress - (fixupAddress + 8)) + ref.addend(); *loc32 = setDisplacementInArmBranch(*loc32, displacement); break; case arm_movw: + assert(!thumbMode); value16 = (targetAddress + ref.addend()) & 0xFFFF; write32(*loc32, _swap, setWordFromArmMov(*loc32, value16)); break; case arm_movt: + assert(!thumbMode); value16 = (targetAddress + ref.addend()) >> 16; write32(*loc32, _swap, setWordFromArmMov(*loc32, value16)); break; case arm_movw_funcRel: + assert(!thumbMode); value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF; write32(*loc32, _swap, setWordFromArmMov(*loc32, value16)); break; case arm_movt_funcRel: + assert(!thumbMode); value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16; write32(*loc32, _swap, setWordFromArmMov(*loc32, value16)); break; @@ -783,6 +808,7 @@ void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom, // Copy raw bytes. memcpy(atomContentBuffer, atom.rawContent().data(), atom.size()); // Apply fix-ups. + bool thumbMode = false; for (const Reference *ref : atom) { uint32_t offset = ref->offsetInAtom(); const Atom *target = ref->target(); @@ -794,11 +820,11 @@ void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom, if (relocatable) { applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress, targetAddress, - atomAddress); + atomAddress, thumbMode); } else { applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress, targetAddress, - atomAddress); + atomAddress, thumbMode); } } } @@ -829,13 +855,21 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, uint8_t *location, uint64_t fixupAddress, uint64_t targetAddress, - uint64_t inAtomAddress) { + uint64_t inAtomAddress, + bool &thumbMode) { bool useExternalReloc = useExternalRelocationTo(*ref.target()); int32_t *loc32 = reinterpret_cast(location); int32_t displacement; uint16_t value16; switch (ref.kindValue()) { + case modeThumbCode: + thumbMode = true; + break; + case modeArmCode: + thumbMode = false; + break; case thumb_b22: + assert(thumbMode); if (useExternalReloc) displacement = (ref.addend() - (fixupAddress + 4)); else @@ -843,6 +877,7 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, write32(*loc32, _swap, setDisplacementInThumbBranch(*loc32, displacement)); break; case thumb_movw: + assert(thumbMode); if (useExternalReloc) value16 = ref.addend() & 0xFFFF; else @@ -850,6 +885,7 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16)); break; case thumb_movt: + assert(thumbMode); if (useExternalReloc) value16 = ref.addend() >> 16; else @@ -857,14 +893,17 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16)); break; case thumb_movw_funcRel: + assert(thumbMode); value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF; write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16)); break; case thumb_movt_funcRel: + assert(thumbMode); value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16; write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16)); break; case arm_b24: + assert(!thumbMode); if (useExternalReloc) displacement = (ref.addend() - (fixupAddress + 8)); else @@ -872,6 +911,7 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, write32(*loc32, _swap, setDisplacementInArmBranch(*loc32, displacement)); break; case arm_movw: + assert(!thumbMode); if (useExternalReloc) value16 = ref.addend() & 0xFFFF; else @@ -879,6 +919,7 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, write32(*loc32, _swap, setWordFromArmMov(*loc32, value16)); break; case arm_movt: + assert(!thumbMode); if (useExternalReloc) value16 = ref.addend() >> 16; else @@ -886,10 +927,12 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, write32(*loc32, _swap, setWordFromArmMov(*loc32, value16)); break; case arm_movw_funcRel: + assert(!thumbMode); value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF; write32(*loc32, _swap, setWordFromArmMov(*loc32, value16)); break; case arm_movt_funcRel: + assert(!thumbMode); value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16; write32(*loc32, _swap, setWordFromArmMov(*loc32, value16)); break; @@ -926,6 +969,10 @@ void ArchHandler_arm::appendSectionRelocations( uint32_t fromAtomAddress; uint16_t other16; switch (ref.kindValue()) { + case modeThumbCode: + case modeArmCode: + // Do nothing. + break; case thumb_b22: if (useExternalReloc) { appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, @@ -1115,6 +1162,25 @@ void ArchHandler_arm::appendSectionRelocations( } } +void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) { + if (atom.isThumb()) { + atom.addReference(0, modeThumbCode, &atom, 0, Reference::KindArch::ARM); + } +} + +bool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) { + for (const Reference *ref : atom) { + if (ref->offsetInAtom() != 0) + return false; + if (ref->kindNamespace() != Reference::KindNamespace::mach_o) + continue; + assert(ref->kindArch() == Reference::KindArch::ARM); + if (ref->kindValue() == modeThumbCode) + return true; + } + return false; +} + std::unique_ptr ArchHandler::create_arm() { return std::unique_ptr(new ArchHandler_arm()); } diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index dffc14952b6d..df9be71c18cd 100644 --- a/lld/lib/ReaderWriter/MachO/File.h +++ b/lld/lib/ReaderWriter/MachO/File.h @@ -139,6 +139,16 @@ public: return pos->second; } + typedef std::function DefinedAtomVisitor; + + void eachDefinedAtom(DefinedAtomVisitor vistor) { + for (auto §AndAtoms : _sectionAtoms) { + for (auto &offAndAtom : sectAndAtoms.second) { + vistor(offAndAtom.atom); + } + } + } + llvm::BumpPtrAllocator &allocator() { return _allocator; } private: diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index 9879e2d04ed5..bedfe6d351cc 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -617,6 +617,8 @@ uint16_t Util::descBits(const DefinedAtom* atom) { } if (atom->contentType() == lld::DefinedAtom::typeResolver) desc |= N_SYMBOL_RESOLVER; + if (_archHandler.isThumbFunction(*atom)) + desc |= N_ARM_THUMB_DEF; return desc; } @@ -656,7 +658,7 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) { sym.type = N_SECT; sym.scope = scopeBits(atom); sym.sect = sect->finalSectionIndex; - sym.desc = 0; + sym.desc = descBits(atom); sym.value = _atomToAddress[atom]; _atomToSymbolIndex[atom] = file.localSymbols.size(); file.localSymbols.push_back(sym); diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index ef6f49f79318..437c8d1281ab 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -562,6 +562,7 @@ std::error_code convertRelocs(const Section §ion, handler.kindArch()); } } + return std::error_code(); } @@ -606,6 +607,11 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path, return ec; } + // Add additional arch-specific References + file->eachDefinedAtom([&](MachODefinedAtom* atom) -> void { + handler->addAdditionalReferences(*atom); + }); + // Sort references in each atom to their canonical order. for (const DefinedAtom* defAtom : file->defined()) { reinterpret_cast(defAtom)->sortReferences(); diff --git a/lld/test/mach-o/parse-arm-relocs.yaml b/lld/test/mach-o/parse-arm-relocs.yaml index 1f6c4e03714d..507d8e787525 100644 --- a/lld/test/mach-o/parse-arm-relocs.yaml +++ b/lld/test/mach-o/parse-arm-relocs.yaml @@ -570,6 +570,8 @@ undefined-symbols: # CHECK: addend: 4 # CHECK: - name: _foo_thumb # CHECK: references: +# CHECK: - kind: modeThumbCode +# CHECK: offset: 0 # CHECK: - kind: thumb_b22 # CHECK: offset: 0 # CHECK: target: _x @@ -652,8 +654,12 @@ undefined-symbols: # CHECK: addend: 8 # CHECK: - name: _t1 # CHECK: content: [ C0, 46 ] +# CHECK: references: +# CHECK: - kind: modeThumbCode +# CHECK: offset: 0 # CHECK: - name: _foo_arm # CHECK: references: +# CHECK-NOT: - kind: modeThumbCode # CHECK: - kind: arm_b24 # CHECK: offset: 0 # CHECK: target: _x