diff options
-rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler.cpp | 38 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler.h | 44 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp | 88 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp | 209 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 234 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp | 101 | ||||
-rw-r--r-- | lld/test/mach-o/parse-data-relocs-x86_64.yaml | 10 | ||||
-rw-r--r-- | lld/test/mach-o/parse-relocs-x86.yaml | 11 | ||||
-rw-r--r-- | lld/test/mach-o/parse-text-relocs-x86_64.yaml | 10 |
9 files changed, 638 insertions, 107 deletions
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler.cpp index 8dfafc6478b..f5fdb1baa46 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler.cpp @@ -86,6 +86,44 @@ ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) { return result; } +normalized::Relocation +ArchHandler::relocFromPattern(ArchHandler::RelocPattern pattern) { + normalized::Relocation result; + result.offset = 0; + result.scattered = (pattern & rScattered); + result.type = (RelocationInfoType)(pattern & 0xF); + result.pcRel = (pattern & rPcRel); + result.isExtern = (pattern & rExtern); + result.value = 0; + result.symbol = 0; + switch (pattern & 0x300) { + case rLength1: + result.length = 0; + break; + case rLength2: + result.length = 1; + break; + case rLength4: + result.length = 2; + break; + case rLength8: + result.length = 3; + break; + } + return result; +} + +void ArchHandler::appendReloc(normalized::Relocations &relocs, uint32_t offset, + uint32_t symbol, uint32_t value, + RelocPattern pattern) { + normalized::Relocation reloc = relocFromPattern(pattern); + reloc.offset = offset; + reloc.symbol = symbol; + reloc.value = value; + relocs.push_back(reloc); +} + + int16_t ArchHandler::readS16(bool swap, const uint8_t *addr) { return read16(swap, *reinterpret_cast<const uint16_t*>(addr)); } diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.h b/lld/lib/ReaderWriter/MachO/ArchHandler.h index 8a097a024e0..cf479c83a00 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler.h +++ b/lld/lib/ReaderWriter/MachO/ArchHandler.h @@ -105,11 +105,37 @@ public: const lld::Atom **target, Reference::Addend *addend) = 0; - /// Fixup an atom when generating a final linked binary. - virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, - Reference::KindValue kindValue, uint64_t addend, - uint8_t *location, uint64_t fixupAddress, - uint64_t targetAddress, uint64_t inAtomAddress) = 0; + /// Prototype for a helper function. Given an atom, finds the symbol table + /// index for it in the output file. + typedef std::function<uint32_t (const Atom &atom)> FindSymbolIndexForAtom; + + /// Prototype for a helper function. Given an atom, finds the index + /// of the section that will contain the atom. + typedef std::function<uint32_t (const Atom &atom)> FindSectionIndexForAtom; + + /// Prototype for a helper function. Given an atom, finds the address + /// assigned to it in the output file. + typedef std::function<uint64_t (const Atom &atom)> FindAddressForAtom; + + /// Some architectures require local symbols on anonymous atoms. + virtual bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) { + return false; + } + + /// Copy raw content then apply all fixup References on an Atom. + virtual void generateAtomContent(const DefinedAtom &atom, bool relocatable, + FindAddressForAtom findAddress, + uint8_t *atomContentBuffer) = 0; + + /// Used in -r mode to convert a Reference to a mach-o relocation. + virtual void appendSectionRelocations(const DefinedAtom &atom, + uint64_t atomSectionOffset, + const Reference &ref, + FindSymbolIndexForAtom, + FindSectionIndexForAtom, + FindAddressForAtom, + normalized::Relocations&) = 0; + struct ReferenceInfo { Reference::KindArch arch; @@ -161,7 +187,15 @@ protected: rLength4 = 0x0200, rLength8 = 0x0300 }; + /// Extract RelocPattern from normalized mach-o relocation. static RelocPattern relocPattern(const normalized::Relocation &reloc); + /// Create normalized Relocation initialized from pattern. + static normalized::Relocation relocFromPattern(RelocPattern pattern); + /// One liner to add a relocation. + static void appendReloc(normalized::Relocations &relocs, uint32_t offset, + uint32_t symbol, uint32_t value, + RelocPattern pattern); + static int16_t readS16(bool swap, const uint8_t *addr); static int32_t readS32(bool swap, const uint8_t *addr); diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp index a1e6b83c83d..16088589b14 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp @@ -57,11 +57,18 @@ public: const lld::Atom **target, Reference::Addend *addend) override; - void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, - Reference::KindValue kindValue, uint64_t addend, - uint8_t *location, uint64_t fixupAddress, - uint64_t targetAddress, uint64_t inAtomAddress) - override; + void generateAtomContent(const DefinedAtom &atom, bool relocatable, + FindAddressForAtom findAddress, + uint8_t *atomContentBuffer) override; + + void appendSectionRelocations(const DefinedAtom &atom, + uint64_t atomSectionOffset, + const Reference &ref, + FindSymbolIndexForAtom, + FindSectionIndexForAtom, + FindAddressForAtom, + normalized::Relocations &) override; + private: static const Registry::KindStrings _sKindStrings[]; @@ -96,6 +103,14 @@ private: uint32_t clearThumbBit(uint32_t value, const Atom *target); uint32_t setDisplacementInArmBranch(uint32_t instruction, int32_t disp); + void applyFixupFinal(const Reference &ref, uint8_t *location, + uint64_t fixupAddress, uint64_t targetAddress, + uint64_t inAtomAddress); + + void applyFixupRelocatable(const Reference &ref, uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress); const bool _swap; }; @@ -594,19 +609,17 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, return std::error_code(); } -void ArchHandler_arm::applyFixup(Reference::KindNamespace ns, - Reference::KindArch arch, - Reference::KindValue kindValue, - uint64_t addend, uint8_t *location, - uint64_t fixupAddress, uint64_t targetAddress, - uint64_t inAtomAddress) { - if (ns != Reference::KindNamespace::mach_o) +void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress) { + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return; - assert(arch == Reference::KindArch::ARM); + assert(ref.kindArch() == Reference::KindArch::ARM); int32_t *loc32 = reinterpret_cast<int32_t *>(location); int32_t displacement; // FIXME: these writes may need a swap. - switch (kindValue) { + switch (ref.kindValue()) { case thumb_b22: // FIXME break; @@ -623,7 +636,7 @@ void ArchHandler_arm::applyFixup(Reference::KindNamespace ns, // FIXME break; case arm_b24: - displacement = (targetAddress - (fixupAddress + 8)) + addend; + displacement = (targetAddress - (fixupAddress + 8)) + ref.addend(); *loc32 = setDisplacementInArmBranch(*loc32, displacement); break; case arm_movw: @@ -654,6 +667,51 @@ void ArchHandler_arm::applyFixup(Reference::KindNamespace ns, } } +void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom, + bool relocatable, + FindAddressForAtom findAddress, + uint8_t *atomContentBuffer) { + // Copy raw bytes. + memcpy(atomContentBuffer, atom.rawContent().data(), atom.size()); + // Apply fix-ups. + for (const Reference *ref : atom) { + uint32_t offset = ref->offsetInAtom(); + const Atom *target = ref->target(); + uint64_t targetAddress = 0; + if (isa<DefinedAtom>(target)) + targetAddress = findAddress(*target); + uint64_t atomAddress = findAddress(atom); + uint64_t fixupAddress = atomAddress + offset; + if (relocatable) { + applyFixupRelocatable(*ref, &atomContentBuffer[offset], + fixupAddress, targetAddress, + atomAddress); + } else { + applyFixupFinal(*ref, &atomContentBuffer[offset], + fixupAddress, targetAddress, + atomAddress); + } + } +} + +void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, + uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress) { + // FIXME: to do +} + +void ArchHandler_arm::appendSectionRelocations(const DefinedAtom &atom, + uint64_t atomSectionOffset, + const Reference &ref, + FindSymbolIndexForAtom, + FindSectionIndexForAtom, + FindAddressForAtom, + normalized::Relocations &) { + // FIXME: to do +} + std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() { return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm()); } diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp index db7d03648ca..4cb043ec8eb 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp @@ -57,11 +57,17 @@ public: const lld::Atom **target, Reference::Addend *addend) override; - void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, - Reference::KindValue kindValue, uint64_t addend, - uint8_t *location, uint64_t fixupAddress, - uint64_t targetAddress, uint64_t inAtomAddress) - override; + void generateAtomContent(const DefinedAtom &atom, bool relocatable, + FindAddressForAtom findAddress, + uint8_t *atomContentBuffer) override; + + void appendSectionRelocations(const DefinedAtom &atom, + uint64_t atomSectionOffset, + const Reference &ref, + FindSymbolIndexForAtom symbolIndexForAtom, + FindSectionIndexForAtom sectionIndexForAtom, + FindAddressForAtom addressForAtom, + normalized::Relocations &relocs) override; private: static const Registry::KindStrings _sKindStrings[]; @@ -83,6 +89,17 @@ private: lazyImmediateLocation, /// Location contains immediate value used in stub. }; + static bool useExternalRelocationTo(const Atom &target); + + void applyFixupFinal(const Reference &ref, uint8_t *location, + uint64_t fixupAddress, uint64_t targetAddress, + uint64_t inAtomAddress); + + void applyFixupRelocatable(const Reference &ref, uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress); + const bool _swap; }; @@ -246,12 +263,10 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, Reference::Addend offsetInTo; Reference::Addend offsetInFrom; switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) { - case((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 | - GENERIC_RELOC_PAIR | rScattered | rLength4) - : - case((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 | - GENERIC_RELOC_PAIR | rScattered | rLength4) - : + case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 | + GENERIC_RELOC_PAIR | rScattered | rLength4): + case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 | + GENERIC_RELOC_PAIR | rScattered | rLength4): toAddress = reloc1.value; fromAddress = reloc2.value; value = readS32(swap, fixupContent); @@ -285,33 +300,58 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, } } -void ArchHandler_x86::applyFixup(Reference::KindNamespace ns, - Reference::KindArch arch, - Reference::KindValue kindValue, - uint64_t addend, uint8_t *location, - uint64_t fixupAddress, uint64_t targetAddress, - uint64_t inAtomAddress) { - if (ns != Reference::KindNamespace::mach_o) +void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom, + bool relocatable, + FindAddressForAtom findAddress, + uint8_t *atomContentBuffer) { + // Copy raw bytes. + memcpy(atomContentBuffer, atom.rawContent().data(), atom.size()); + // Apply fix-ups. + for (const Reference *ref : atom) { + uint32_t offset = ref->offsetInAtom(); + const Atom *target = ref->target(); + uint64_t targetAddress = 0; + if (isa<DefinedAtom>(target)) + targetAddress = findAddress(*target); + uint64_t atomAddress = findAddress(atom); + uint64_t fixupAddress = atomAddress + offset; + if (relocatable) { + applyFixupRelocatable(*ref, &atomContentBuffer[offset], + fixupAddress, targetAddress, + atomAddress); + } else { + applyFixupFinal(*ref, &atomContentBuffer[offset], + fixupAddress, targetAddress, + atomAddress); + } + } +} + +void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress) { + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return; - assert(arch == Reference::KindArch::x86); + assert(ref.kindArch() == Reference::KindArch::x86); int32_t *loc32 = reinterpret_cast<int32_t *>(location); int16_t *loc16 = reinterpret_cast<int16_t *>(location); - switch (kindValue) { + switch (ref.kindValue()) { case branch32: - write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend); + write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + ref.addend()); break; case branch16: - write16(*loc16, _swap, (targetAddress - (fixupAddress + 4)) + addend); + write16(*loc16, _swap, (targetAddress - (fixupAddress + 2)) + ref.addend()); break; case pointer32: case abs32: - write32(*loc32, _swap, targetAddress + addend); + write32(*loc32, _swap, targetAddress + ref.addend()); break; case funcRel32: - write32(*loc32, _swap, targetAddress - inAtomAddress + addend); // FIXME + write32(*loc32, _swap, targetAddress - inAtomAddress + ref.addend()); break; case delta32: - write32(*loc32, _swap, targetAddress - fixupAddress + addend); + write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend()); break; case lazyPointer: case lazyImmediateLocation: @@ -323,6 +363,125 @@ void ArchHandler_x86::applyFixup(Reference::KindNamespace ns, } } +void ArchHandler_x86::applyFixupRelocatable(const Reference &ref, + uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress) { + int32_t *loc32 = reinterpret_cast<int32_t *>(location); + int16_t *loc16 = reinterpret_cast<int16_t *>(location); + switch (ref.kindValue()) { + case branch32: + write32(*loc32, _swap, ref.addend() - (fixupAddress + 4)); + break; + case branch16: + write16(*loc16, _swap, ref.addend() - (fixupAddress + 2)); + break; + case pointer32: + case abs32: + write32(*loc32, _swap, targetAddress + ref.addend()); + break; + case funcRel32: + write32(*loc32, _swap, targetAddress - inAtomAddress + ref.addend()); // FIXME + break; + case delta32: + write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend()); + break; + case lazyPointer: + case lazyImmediateLocation: + // do nothing + break; + default: + llvm_unreachable("invalid x86 Reference Kind"); + break; + } +} + +bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) { + // Undefined symbols are referenced via external relocations. + if (isa<UndefinedAtom>(&target)) + return true; + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) { + switch (defAtom->merge()) { + case DefinedAtom::mergeAsTentative: + // Tentative definitions are referenced via external relocations. + return true; + case DefinedAtom::mergeAsWeak: + case DefinedAtom::mergeAsWeakAndAddressUsed: + // Global weak-defs are referenced via external relocations. + return (defAtom->scope() == DefinedAtom::scopeGlobal); + default: + break; + } + } + // Everything else is reference via an internal relocation. + return false; +} + + +void ArchHandler_x86::appendSectionRelocations( + const DefinedAtom &atom, + uint64_t atomSectionOffset, + const Reference &ref, + FindSymbolIndexForAtom symbolIndexForAtom, + FindSectionIndexForAtom sectionIndexForAtom, + FindAddressForAtom addressForAtom, + normalized::Relocations &relocs) { + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return; + assert(ref.kindArch() == Reference::KindArch::x86); + uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom(); + bool useExternalReloc = useExternalRelocationTo(*ref.target()); + switch (ref.kindValue()) { + case branch32: + if (useExternalReloc) + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4); + else + appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, + GENERIC_RELOC_VANILLA | rPcRel | rLength4); + break; + case branch16: + if (useExternalReloc) + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2); + else + appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, + GENERIC_RELOC_VANILLA | rPcRel | rLength2); + break; + case pointer32: + case abs32: + if (useExternalReloc) + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + GENERIC_RELOC_VANILLA | rExtern | rLength4); + else + appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, + GENERIC_RELOC_VANILLA | rLength4); + break; + case funcRel32: + appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()), + GENERIC_RELOC_SECTDIFF | rScattered | rLength4); + appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(), + GENERIC_RELOC_PAIR | rScattered | rLength4); + break; + case delta32: + appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()), + GENERIC_RELOC_SECTDIFF | rScattered | rLength4); + appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) + ref.offsetInAtom(), + GENERIC_RELOC_PAIR | rScattered | rLength4); + break; + case lazyPointer: + case lazyImmediateLocation: + llvm_unreachable("lazy reference kind implies Stubs pass was run"); + break; + default: + llvm_unreachable("unknown x86 Reference Kind"); + break; + + } +} + + std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() { return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86()); } diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp index 5f1cddb4ef9..4fc8000797b 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -84,12 +84,22 @@ public: Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) override; - - virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, - Reference::KindValue kindValue, uint64_t addend, - uint8_t *location, uint64_t fixupAddress, - uint64_t targetAddress, uint64_t inAtomAddress) - override; + + virtual bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) { + return (atom->contentType() == DefinedAtom::typeCString); + } + + void generateAtomContent(const DefinedAtom &atom, bool relocatable, + FindAddressForAtom findAddress, + uint8_t *atomContentBuffer) override; + + void appendSectionRelocations(const DefinedAtom &atom, + uint64_t atomSectionOffset, + const Reference &ref, + FindSymbolIndexForAtom symbolIndexForAtom, + FindSectionIndexForAtom sectionIndexForAtom, + FindAddressForAtom addressForAtom, + normalized::Relocations &relocs) override; private: static const Registry::KindStrings _sKindStrings[]; @@ -126,6 +136,15 @@ private: Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2); + void applyFixupFinal(const Reference &ref, uint8_t *location, + uint64_t fixupAddress, uint64_t targetAddress, + uint64_t inAtomAddress); + + void applyFixupRelocatable(const Reference &ref, uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress); + const bool _swap; }; @@ -357,51 +376,76 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, } } -void ArchHandler_x86_64::applyFixup(Reference::KindNamespace ns, - Reference::KindArch arch, - Reference::KindValue kindValue, - uint64_t addend, uint8_t *location, - uint64_t fixupAddress, - uint64_t targetAddress, - uint64_t inAtomAddress) { - if (ns != Reference::KindNamespace::mach_o) +void ArchHandler_x86_64::generateAtomContent(const DefinedAtom &atom, + bool relocatable, + FindAddressForAtom findAddress, + uint8_t *atomContentBuffer) { + // Copy raw bytes. + memcpy(atomContentBuffer, atom.rawContent().data(), atom.size()); + // Apply fix-ups. + for (const Reference *ref : atom) { + uint32_t offset = ref->offsetInAtom(); + const Atom *target = ref->target(); + uint64_t targetAddress = 0; + if (isa<DefinedAtom>(target)) + targetAddress = findAddress(*target); + uint64_t atomAddress = findAddress(atom); + uint64_t fixupAddress = atomAddress + offset; + if (relocatable) { + applyFixupRelocatable(*ref, &atomContentBuffer[offset], + fixupAddress, targetAddress, + atomAddress); + } else { + applyFixupFinal(*ref, &atomContentBuffer[offset], + fixupAddress, targetAddress, + atomAddress); + } + } +} + +void ArchHandler_x86_64::applyFixupFinal(const Reference &ref, + uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress) { + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return; - assert(arch == Reference::KindArch::x86_64); + assert(ref.kindArch() == Reference::KindArch::x86_64); int32_t *loc32 = reinterpret_cast<int32_t *>(location); uint64_t *loc64 = reinterpret_cast<uint64_t *>(location); - switch (kindValue) { + switch (ref.kindValue()) { case branch32: case ripRel32: case ripRel32Got: case ripRel32GotLoad: - write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend); + write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + ref.addend()); break; case pointer64: case pointer64Anon: - write64(*loc64, _swap, targetAddress + addend); + write64(*loc64, _swap, targetAddress + ref.addend()); break; case ripRel32Minus1: - write32(*loc32, _swap, (targetAddress - (fixupAddress + 5)) + addend); + write32(*loc32, _swap, (targetAddress - (fixupAddress + 5)) + ref.addend()); break; case ripRel32Minus2: - write32(*loc32, _swap, (targetAddress - (fixupAddress + 6)) + addend); + write32(*loc32, _swap, (targetAddress - (fixupAddress + 6)) + ref.addend()); break; case ripRel32Minus4: - write32(*loc32, _swap, (targetAddress - (fixupAddress + 8)) + addend); + write32(*loc32, _swap, (targetAddress - (fixupAddress + 8)) + ref.addend()); break; case delta32: case delta32Anon: - write32(*loc32, _swap, (targetAddress - fixupAddress) + addend); + write32(*loc32, _swap, (targetAddress - fixupAddress) + ref.addend()); break; case delta64: case delta64Anon: - write64(*loc64, _swap, (targetAddress - fixupAddress) + addend); + write64(*loc64, _swap, (targetAddress - fixupAddress) + ref.addend()); break; case ripRel32GotLoadNowLea: // Change MOVQ to LEA assert(location[-2] == 0x8B); location[-2] = 0x8D; - write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend); + write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + ref.addend()); break; case lazyPointer: case lazyImmediateLocation: @@ -413,6 +457,148 @@ void ArchHandler_x86_64::applyFixup(Reference::KindNamespace ns, } } + +void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, + uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress) { + int32_t *loc32 = reinterpret_cast<int32_t *>(location); + uint64_t *loc64 = reinterpret_cast<uint64_t *>(location); + switch (ref.kindValue()) { + case branch32: + case ripRel32: + case ripRel32Got: + case ripRel32GotLoad: + write32(*loc32, _swap, ref.addend()); + break; + case pointer64: + write64(*loc64, _swap, ref.addend()); + break; + case pointer64Anon: + write64(*loc64, _swap, targetAddress + ref.addend()); + break; + case ripRel32Minus1: + write32(*loc32, _swap, ref.addend() - 1); + break; + case ripRel32Minus2: + write32(*loc32, _swap, ref.addend() - 2); + break; + case ripRel32Minus4: + write32(*loc32, _swap, ref.addend() - 4); + break; + case delta32: + write32(*loc32, _swap, ref.addend() + inAtomAddress - fixupAddress); + break; + case delta32Anon: + write32(*loc32, _swap, (targetAddress - fixupAddress) + ref.addend()); + break; + case delta64: + write64(*loc64, _swap, ref.addend() + inAtomAddress - fixupAddress); + break; + case delta64Anon: + write64(*loc64, _swap, (targetAddress - fixupAddress) + ref.addend()); + break; + case ripRel32GotLoadNowLea: + llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run"); + break; + case lazyPointer: + case lazyImmediateLocation: + llvm_unreachable("lazy reference kind implies Stubs pass was run"); + break; + default: + llvm_unreachable("unknown x86_64 Reference Kind"); + break; + } +} + +void ArchHandler_x86_64::appendSectionRelocations( + const DefinedAtom &atom, + uint64_t atomSectionOffset, + const Reference &ref, + FindSymbolIndexForAtom symbolIndexForAtom, + FindSectionIndexForAtom sectionIndexForAtom, + FindAddressForAtom addressForAtom, + normalized::Relocations &relocs) { + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return; + assert(ref.kindArch() == Reference::KindArch::x86_64); + uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom(); + switch (ref.kindValue()) { + case branch32: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4); + break; + case ripRel32: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4 ); + break; + case ripRel32Got: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_GOT | rPcRel | rExtern | rLength4 ); + break; + case ripRel32GotLoad: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 ); + break; + case pointer64: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_UNSIGNED | rExtern | rLength8); + break; + case pointer64Anon: + appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, + X86_64_RELOC_UNSIGNED | rLength8); + break; + case ripRel32Minus1: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 ); + break; + case ripRel32Minus2: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 ); + break; + case ripRel32Minus4: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 ); + break; + case delta32: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, + X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 ); + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_UNSIGNED | rExtern | rLength4 ); + break; + case delta32Anon: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, + X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 ); + appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, + X86_64_RELOC_UNSIGNED | rLength4 ); + break; + case delta64: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, + X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 ); + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_UNSIGNED | rExtern | rLength8 ); + break; + case delta64Anon: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, + X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 ); + appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, + X86_64_RELOC_UNSIGNED | rLength8 ); + break; + case ripRel32GotLoadNowLea: + llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run"); + break; + case lazyPointer: + case lazyImmediateLocation: + llvm_unreachable("lazy reference kind implies Stubs pass was run"); + break; + default: + llvm_unreachable("unknown x86_64 Reference Kind"); + break; + } +} + + std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() { return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64()); } diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index 0a306800001..17dc4701ca1 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -88,7 +88,8 @@ SegmentInfo::SegmentInfo(StringRef n) class Util { public: - Util(const MachOLinkingContext &ctxt) : _context(ctxt), _entryAtom(nullptr) {} + Util(const MachOLinkingContext &ctxt) : _context(ctxt), + _archHandler(ctxt.archHandler()), _entryAtom(nullptr) {} void assignAtomsToSections(const lld::File &atomFile); void organizeSections(); @@ -128,8 +129,7 @@ private: const Atom *targetOfStub(const DefinedAtom *stubAtom); bool belongsInGlobalSymbolsSection(const DefinedAtom* atom); void appendSection(SectionInfo *si, NormalizedFile &file); - void appendReloc(const DefinedAtom *atom, const Reference *ref, - Relocations &relocations); + uint32_t sectionIndexForAtom(const Atom *atom); static uint64_t alignTo(uint64_t value, uint8_t align2); typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex; @@ -147,6 +147,7 @@ private: }; const MachOLinkingContext &_context; + mach_o::ArchHandler &_archHandler; llvm::BumpPtrAllocator _allocator; std::vector<SectionInfo*> _sectionInfos; std::vector<SegmentInfo*> _segmentInfos; @@ -509,6 +510,14 @@ void Util::copySegmentInfo(NormalizedFile &file) { void Util::appendSection(SectionInfo *si, NormalizedFile &file) { const bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT); + + // Utility function for ArchHandler to find address of atom in output file. + auto addrForAtom = [&] (const Atom &atom) -> uint64_t { + auto pos = _atomToAddress.find(&atom); + assert(pos != _atomToAddress.end()); + return pos->second; + }; + // Add new empty section to end of file.sections. Section temp; file.sections.push_back(std::move(temp)); @@ -528,28 +537,9 @@ void Util::appendSection(SectionInfo *si, NormalizedFile &file) { uint8_t *sectionContent = file.ownedAllocations.Allocate<uint8_t>(si->size); normSect->content = llvm::makeArrayRef(sectionContent, si->size); for (AtomInfo &ai : si->atomsAndOffsets) { - // Copy raw bytes. uint8_t *atomContent = reinterpret_cast<uint8_t*> (§ionContent[ai.offsetInSection]); - memcpy(atomContent, ai.atom->rawContent().data(), ai.atom->size()); - // Apply fix-ups. - for (const Reference *ref : *ai.atom) { - uint32_t offset = ref->offsetInAtom(); - uint64_t targetAddress = 0; - if ( ref->target() != nullptr ) - targetAddress = _atomToAddress[ref->target()]; - uint64_t atomAddress = _atomToAddress[ai.atom]; - uint64_t fixupAddress = atomAddress + offset; - if ( rMode ) { - // FIXME: Need a handler method to update content for .o file - // output and any needed section relocations. - } else { - _context.archHandler().applyFixup( - ref->kindNamespace(), ref->kindArch(), ref->kindValue(), - ref->addend(), &atomContent[offset], fixupAddress, targetAddress, - atomAddress); - } - } + _archHandler.generateAtomContent(*ai.atom, rMode, addrForAtom, atomContent); } } @@ -647,6 +637,7 @@ bool Util::belongsInGlobalSymbolsSection(const DefinedAtom* atom) { } void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) { + bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT); // Mach-O symbol table has three regions: locals, globals, undefs. // Add all local (non-global) symbols in address order @@ -667,14 +658,31 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) { sym.sect = sect->finalSectionIndex; sym.desc = 0; sym.value = _atomToAddress[atom]; + _atomToSymbolIndex[atom] = file.localSymbols.size(); file.localSymbols.push_back(sym); } + } else if (rMode && _archHandler.needsLocalSymbolInRelocatableFile(atom)){ + // Create 'Lxxx' labels for anonymous atoms if archHandler says so. + static unsigned tempNum = 1; + char tmpName[16]; + sprintf(tmpName, "L%04u", tempNum++); + StringRef tempRef(tmpName); + Symbol sym; + sym.name = tempRef.copy(file.ownedAllocations); + sym.type = N_SECT; + sym.scope = 0; + sym.sect = sect->finalSectionIndex; + sym.desc = 0; + sym.value = _atomToAddress[atom]; + _atomToSymbolIndex[atom] = file.localSymbols.size(); + file.localSymbols.push_back(sym); } } } // Sort global symbol alphabetically, then add to symbol table. std::sort(globals.begin(), globals.end(), AtomSorter()); + const uint32_t globalStartIndex = file.localSymbols.size(); for (AtomAndIndex &ai : globals) { Symbol sym; sym.name = ai.atom->name(); @@ -683,6 +691,7 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) { sym.sect = ai.index; sym.desc = descBits(static_cast<const DefinedAtom*>(ai.atom)); sym.value = _atomToAddress[ai.atom]; + _atomToSymbolIndex[ai.atom] = globalStartIndex + file.globalSymbols.size(); file.globalSymbols.push_back(sym); } @@ -715,7 +724,7 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) { const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) { for (const Reference *ref : *lpAtom) { - if (_context.archHandler().isLazyPointer(*ref)) { + if (_archHandler.isLazyPointer(*ref)) { return ref->target(); } } @@ -838,21 +847,51 @@ void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex, } -void Util::appendReloc(const DefinedAtom *atom, const Reference *ref, - Relocations &relocations) { - // TODO: convert Reference to normalized relocation +uint32_t Util::sectionIndexForAtom(const Atom *atom) { + uint64_t address = _atomToAddress[atom]; + uint32_t index = 1; + for (const SectionInfo *si : _sectionInfos) { + if ((si->address <= address) && (address < si->address+si->size)) + return index; + ++index; + } + llvm_unreachable("atom not in any section"); } void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) { if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) return; + + // Utility function for ArchHandler to find symbol index for an atom. + auto symIndexForAtom = [&] (const Atom &atom) -> uint32_t { + auto pos = _atomToSymbolIndex.find(&atom); + assert(pos != _atomToSymbolIndex.end()); + return pos->second; + }; + + // Utility function for ArchHandler to find section index for an atom. + auto sectIndexForAtom = [&] (const Atom &atom) -> uint32_t { + return sectionIndexForAtom(&atom); + }; + + // Utility function for ArchHandler to find address of atom in output file. + auto addressForAtom = [&] (const Atom &atom) -> uint64_t { + auto pos = _atomToAddress.find(&atom); + assert(pos != _atomToAddress.end()); + return pos->second; + }; + for (SectionInfo *si : _sectionInfos) { Section &normSect = file.sections[si->normalizedSectionIndex]; for (const AtomInfo &info : si->atomsAndOffsets) { const DefinedAtom *atom = info.atom; for (const Reference *ref : *atom) { - appendReloc(atom, ref, normSect.relocations); + _archHandler.appendSectionRelocations(*atom, info.offsetInSection, *ref, + symIndexForAtom, + sectIndexForAtom, + addressForAtom, + normSect.relocations); } } } @@ -873,7 +912,7 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile, uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom() - segmentStartAddr; const Atom* targ = ref->target(); - if (_context.archHandler().isPointer(*ref)) { + if (_archHandler.isPointer(*ref)) { // A pointer to a DefinedAtom requires rebasing. if (dyn_cast<DefinedAtom>(targ)) { RebaseLocation rebase; @@ -895,13 +934,13 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile, nFile.bindingInfo.push_back(bind); } } - if (_context.archHandler().isLazyPointer(*ref)) { + if (_archHandler.isLazyPointer(*ref)) { BindLocation bind; bind.segIndex = segmentIndex; bind.segOffset = segmentOffset; bind.kind = llvm::MachO::BIND_TYPE_POINTER; bind.canBeNull = false; //sa->canBeNullAtRuntime(); - bind.ordinal = 1; + bind.ordinal = 1; // FIXME bind.symbolName = targ->name(); bind.addend = ref->addend(); nFile.lazyBindingInfo.push_back(bind); diff --git a/lld/test/mach-o/parse-data-relocs-x86_64.yaml b/lld/test/mach-o/parse-data-relocs-x86_64.yaml index ffc9e4777cf..6ba2e48d285 100644 --- a/lld/test/mach-o/parse-data-relocs-x86_64.yaml +++ b/lld/test/mach-o/parse-data-relocs-x86_64.yaml @@ -1,6 +1,12 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s \ +# RUN: && lld -flavor darwin -arch x86_64 %t -r -print_atoms -o %t2 | FileCheck %s # -# Test parsing of x86_64 data relocations. +# Test parsing and writing of x86_64 text relocations. +# +# The first step tests if the supplied mach-o file is parsed into the correct +# set of references. The second step verifies relocations can be round-tripped +# by writing to a new .o file, then parsing that file which should result in +# the same references. # #_foo: # ret diff --git a/lld/test/mach-o/parse-relocs-x86.yaml b/lld/test/mach-o/parse-relocs-x86.yaml index c9feb244d75..546a9e9a07d 100644 --- a/lld/test/mach-o/parse-relocs-x86.yaml +++ b/lld/test/mach-o/parse-relocs-x86.yaml @@ -1,9 +1,14 @@ -# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s +# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s \ +# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s # -# Test parsing of x86 relocations. +# Test parsing and writing of x86 relocations. # -# .text +# The first step tests if the supplied mach-o file is parsed into the correct +# set of references. The second step verifies relocations can be round-tripped +# by writing to a new .o file, then parsing that file which should result in +# the same references. # +# .text #_test: # call _undef # call _undef+2 diff --git a/lld/test/mach-o/parse-text-relocs-x86_64.yaml b/lld/test/mach-o/parse-text-relocs-x86_64.yaml index e3b9cf292de..b2a3d5de016 100644 --- a/lld/test/mach-o/parse-text-relocs-x86_64.yaml +++ b/lld/test/mach-o/parse-text-relocs-x86_64.yaml @@ -1,6 +1,12 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \ +# RUN: && lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s # -# Test parsing of x86_64 text relocations. +# Test parsing and writing of x86_64 text relocations. +# +# The first step tests if the supplied mach-o file is parsed into the correct +# set of references. The second step verifies relocations can be round-tripped +# by writing to a new .o file, then parsing that file which should result in +# the same references. # #_test: # call _foo |