[lld] r219655 - [mach-o] Add Pass to create are shim Atoms for ARM interworking.
Shankar Easwaran
shankare at codeaurora.org
Sat Oct 18 20:13:05 PDT 2014
Hi Nick,
This patch doesnot seem to reuse shim's right ?
Are you planning to add this soon as well ?
Shankar Easwaran
On 10/13/2014 8:51 PM, Nick Kledzik wrote:
> Author: kledzik
> Date: Mon Oct 13 20:51:42 2014
> New Revision: 219655
>
> URL: http://llvm.org/viewvc/llvm-project?rev=219655&view=rev
> Log:
> [mach-o] Add Pass to create are shim Atoms for ARM interworking.
>
> Arm code has two instruction encodings "thumb" and "arm". When branching from
> one code encoding to another, you need to use an instruction that switches
> the instruction mode. Usually the transition only happens at call sites, and
> the linker can transform a BL instruction in BLX (or vice versa). But if the
> compiler did a tail call optimization and a function ends with a branch (not
> branch and link), there is no pc-rel BX instruction.
>
> The ShimPass looks for pc-rel B instructions that will need to switch mode.
> For those cases it synthesizes a shim which does the transition, then modifies
> the original atom with the B instruction to target to the shim atom.
>
> Added:
> lld/trunk/lib/ReaderWriter/MachO/ShimPass.cpp
> lld/trunk/test/mach-o/arm-shims.yaml
> Modified:
> lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
> lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h
> lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
> lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
> lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
> lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
> lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt
> lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
> lld/trunk/lib/ReaderWriter/MachO/MachOPasses.h
> lld/trunk/test/mach-o/arm-interworking.yaml
> lld/trunk/test/mach-o/parse-arm-relocs.yaml
>
> Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
> +++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Mon Oct 13 20:51:42 2014
> @@ -230,6 +230,9 @@ public:
> /// Pass to transform __compact_unwind into __unwind_info should be run.
> bool needsCompactUnwindPass() const;
>
> + /// Pass to add shims switching between thumb and arm mode.
> + bool needsShimPass() const;
> +
> /// Magic symbol name stubs will need to help lazy bind.
> StringRef binderSymbolName() const;
>
>
> Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h (original)
> +++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h Mon Oct 13 20:51:42 2014
> @@ -9,6 +9,7 @@
>
> #include "MachONormalizedFile.h"
> #include "Atoms.h"
> +#include "File.h"
>
> #include "lld/Core/LLVM.h"
> #include "lld/Core/Reference.h"
> @@ -50,6 +51,9 @@ public:
> return false;
> }
>
> + /// Used by ShimPass to insert shims in branches that switch mode.
> + virtual bool isNonCallBranch(const Reference &) = 0;
> +
> /// Used by GOTPass to update GOT References
> virtual void updateReferenceToGOT(const Reference *, bool targetIsNowGOT) {}
>
> @@ -182,6 +186,12 @@ public:
> /// Only relevant for 32-bit arm archs.
> virtual bool isThumbFunction(const DefinedAtom &atom) { return false; }
>
> + /// Only relevant for 32-bit arm archs.
> + virtual const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
> + const DefinedAtom &) {
> + llvm_unreachable("shims only support on arm");
> + }
> +
> struct ReferenceInfo {
> Reference::KindArch arch;
> uint16_t kind;
>
> Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp (original)
> +++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp Mon Oct 13 20:51:42 2014
> @@ -36,6 +36,7 @@ public:
> bool isCallSite(const Reference &) override;
> bool isPointer(const Reference &) override;
> bool isPairedReloc(const normalized::Relocation &) override;
> + bool isNonCallBranch(const Reference &) override;
>
> bool needsCompactUnwind() override {
> return false;
> @@ -106,8 +107,13 @@ public:
> }
>
> bool isThumbFunction(const DefinedAtom &atom) override;
> + const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
> + const DefinedAtom &) override;
>
> private:
> + friend class Thumb2ToArmShimAtom;
> + friend class ArmToThumbShimAtom;
> +
> static const Registry::KindStrings _sKindStrings[];
> static const StubInfo _sStubInfoArmPIC;
>
> @@ -119,12 +125,14 @@ private:
> modeData, /// Content starting at this offset is data.
>
> // Kinds found in mach-o .o files:
> - thumb_b22, /// ex: bl _foo
> + thumb_bl22, /// ex: bl _foo
> + thumb_b22, /// ex: b _foo
> thumb_movw, /// ex: movw r1, :lower16:_foo
> thumb_movt, /// ex: movt r1, :lower16:_foo
> thumb_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
> thumb_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
> - arm_b24, /// ex: bl _foo
> + arm_bl24, /// ex: bl _foo
> + arm_b24, /// ex: b _foo
> arm_movw, /// ex: movw r1, :lower16:_foo
> arm_movt, /// ex: movt r1, :lower16:_foo
> arm_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
> @@ -154,6 +162,7 @@ private:
> static uint32_t setWordFromThumbMov(uint32_t instruction, uint16_t word);
> static uint32_t setWordFromArmMov(uint32_t instruction, uint16_t word);
>
> + StringRef stubName(const DefinedAtom &);
> bool useExternalRelocationTo(const Atom &target);
>
> void applyFixupFinal(const Reference &ref, uint8_t *location,
> @@ -183,11 +192,13 @@ const Registry::KindStrings ArchHandler_
> LLD_KIND_STRING_ENTRY(modeThumbCode),
> LLD_KIND_STRING_ENTRY(modeArmCode),
> LLD_KIND_STRING_ENTRY(modeData),
> + LLD_KIND_STRING_ENTRY(thumb_bl22),
> LLD_KIND_STRING_ENTRY(thumb_b22),
> LLD_KIND_STRING_ENTRY(thumb_movw),
> LLD_KIND_STRING_ENTRY(thumb_movt),
> LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
> LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
> + LLD_KIND_STRING_ENTRY(arm_bl24),
> LLD_KIND_STRING_ENTRY(arm_b24),
> LLD_KIND_STRING_ENTRY(arm_movw),
> LLD_KIND_STRING_ENTRY(arm_movt),
> @@ -256,13 +267,31 @@ const ArchHandler::StubInfo &ArchHandler
> }
>
> bool ArchHandler_arm::isCallSite(const Reference &ref) {
> - return (ref.kindValue() == thumb_b22) || (ref.kindValue() == arm_b24);
> + switch (ref.kindValue()) {
> + case thumb_b22:
> + case thumb_bl22:
> + case arm_b24:
> + case arm_bl24:
> + return true;
> + default:
> + return false;
> + }
> }
>
> bool ArchHandler_arm::isPointer(const Reference &ref) {
> return (ref.kindValue() == pointer32);
> }
>
> +bool ArchHandler_arm::isNonCallBranch(const Reference &ref) {
> + switch (ref.kindValue()) {
> + case thumb_b22:
> + case arm_b24:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> bool ArchHandler_arm::isPairedReloc(const Relocation &reloc) {
> switch (reloc.type) {
> case ARM_RELOC_SECTDIFF:
> @@ -275,6 +304,23 @@ bool ArchHandler_arm::isPairedReloc(cons
> }
> }
>
> +/// Trace references from stub atom to lazy pointer to target and get its name.
> +StringRef ArchHandler_arm::stubName(const DefinedAtom &stubAtom) {
> + assert(stubAtom.contentType() == DefinedAtom::typeStub);
> + for (const Reference *ref : stubAtom) {
> + if (const DefinedAtom* lp = dyn_cast<DefinedAtom>(ref->target())) {
> + if (lp->contentType() != DefinedAtom::typeLazyPointer)
> + continue;
> + for (const Reference *ref2 : *lp) {
> + if (ref2->kindValue() != lazyPointer)
> + continue;
> + return ref2->target()->name();
> + }
> + }
> + }
> + return "stub";
> +}
> +
> /// Extract displacement from an ARM b/bl/blx instruction.
> int32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
> // Sign-extend imm24
> @@ -352,7 +398,7 @@ uint32_t ArchHandler_arm::setDisplacemen
> bool is_bl = ((instruction & 0xD000F800) == 0xD000F000);
> bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
> bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
> - uint32_t newInstruction = (instruction & 0xF800D000);
> + uint32_t newInstruction = (instruction & 0xD000F800);
> if (is_bl || is_blx) {
> if (targetIsThumb) {
> newInstruction = 0xD000F000; // Use bl
> @@ -363,7 +409,7 @@ uint32_t ArchHandler_arm::setDisplacemen
> displacement += 2;
> }
> } else if (is_b) {
> - assert(!targetIsThumb && "no pc-rel thumb branch instruction that "
> + assert(targetIsThumb && "no pc-rel thumb branch instruction that "
> "switches to arm mode");
> }
> else {
> @@ -461,7 +507,10 @@ std::error_code ArchHandler_arm::getRefe
> switch (relocPattern(reloc)) {
> case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
> // ex: bl _foo (and _foo is undefined)
> - *kind = thumb_b22;
> + if ((instruction & 0xD000F800) == 0x9000F000)
> + *kind = thumb_b22;
> + else
> + *kind = thumb_bl22;
> if (E ec = atomFromSymbolIndex(reloc.symbol, target))
> return ec;
> // Instruction contains branch to addend.
> @@ -470,13 +519,19 @@ std::error_code ArchHandler_arm::getRefe
> return std::error_code();
> case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
> // ex: bl _foo (and _foo is defined)
> - *kind = thumb_b22;
> + if ((instruction & 0xD000F800) == 0x9000F000)
> + *kind = thumb_b22;
> + else
> + *kind = thumb_bl22;
> displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
> targetAddress = fixupAddress + 4 + displacement;
> return atomFromAddress(reloc.symbol, targetAddress, target, addend);
> case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
> // ex: bl _foo+4 (and _foo is defined)
> - *kind = thumb_b22;
> + if ((instruction & 0xD000F800) == 0x9000F000)
> + *kind = thumb_b22;
> + else
> + *kind = thumb_bl22;
> displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
> targetAddress = fixupAddress + 4 + displacement;
> if (E ec = atomFromAddress(0, reloc.value, target, addend))
> @@ -487,7 +542,11 @@ std::error_code ArchHandler_arm::getRefe
> return std::error_code();
> case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
> // ex: bl _foo (and _foo is undefined)
> - *kind = arm_b24;
> + if (((instruction & 0x0F000000) == 0x0A000000)
> + && ((instruction & 0xF0000000) != 0xF0000000))
> + *kind = arm_b24;
> + else
> + *kind = arm_bl24;
> if (E ec = atomFromSymbolIndex(reloc.symbol, target))
> return ec;
> // Instruction contains branch to addend.
> @@ -496,13 +555,21 @@ std::error_code ArchHandler_arm::getRefe
> return std::error_code();
> case ARM_RELOC_BR24 | rPcRel | rLength4:
> // ex: bl _foo (and _foo is defined)
> - *kind = arm_b24;
> + if (((instruction & 0x0F000000) == 0x0A000000)
> + && ((instruction & 0xF0000000) != 0xF0000000))
> + *kind = arm_b24;
> + else
> + *kind = arm_bl24;
> displacement = getDisplacementFromArmBranch(instruction);
> targetAddress = fixupAddress + 8 + displacement;
> return atomFromAddress(reloc.symbol, targetAddress, target, addend);
> case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
> // ex: bl _foo+4 (and _foo is defined)
> - *kind = arm_b24;
> + if (((instruction & 0x0F000000) == 0x0A000000)
> + && ((instruction & 0xF0000000) != 0xF0000000))
> + *kind = arm_b24;
> + else
> + *kind = arm_bl24;
> displacement = getDisplacementFromArmBranch(instruction);
> targetAddress = fixupAddress + 8 + displacement;
> if (E ec = atomFromAddress(0, reloc.value, target, addend))
> @@ -836,6 +903,7 @@ void ArchHandler_arm::applyFixupFinal(co
> case modeData:
> break;
> case thumb_b22:
> + case thumb_bl22:
> assert(thumbMode);
> displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
> value32 = setDisplacementInThumbBranch(*loc32, fixupAddress, displacement,
> @@ -867,7 +935,8 @@ void ArchHandler_arm::applyFixupFinal(co
> write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
> break;
> case arm_b24:
> - assert(!thumbMode);
> + case arm_bl24:
> + assert(!thumbMode);
> displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
> value32 = setDisplacementInArmBranch(*loc32, displacement, targetIsThumb);
> write32(*loc32, _swap, value32);
> @@ -903,7 +972,10 @@ void ArchHandler_arm::applyFixupFinal(co
> write32(*loc32, _swap, targetAddress + ref.addend());
> break;
> case delta32:
> - write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend());
> + if (targetIsThumb)
> + write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend() + 1);
> + else
> + write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend());
> break;
> case lazyPointer:
> case lazyImmediateLocation:
> @@ -990,6 +1062,7 @@ void ArchHandler_arm::applyFixupRelocata
> case modeData:
> break;
> case thumb_b22:
> + case thumb_bl22:
> assert(thumbMode);
> if (useExternalReloc)
> displacement = (ref.addend() - (fixupAddress + 4));
> @@ -1026,6 +1099,7 @@ void ArchHandler_arm::applyFixupRelocata
> write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
> break;
> case arm_b24:
> + case arm_bl24:
> assert(!thumbMode);
> if (useExternalReloc)
> displacement = (ref.addend() - (fixupAddress + 8));
> @@ -1100,6 +1174,7 @@ void ArchHandler_arm::appendSectionReloc
> // Do nothing.
> break;
> case thumb_b22:
> + case thumb_bl22:
> if (useExternalReloc) {
> appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
> ARM_THUMB_RELOC_BR22 | rExtern | rPcRel | rLength4);
> @@ -1179,6 +1254,7 @@ void ArchHandler_arm::appendSectionReloc
> ARM_RELOC_PAIR | rScattered | rLenThmbHi);
> break;
> case arm_b24:
> + case arm_bl24:
> if (useExternalReloc) {
> appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
> ARM_RELOC_BR24 | rExtern | rPcRel | rLength4);
> @@ -1307,6 +1383,112 @@ bool ArchHandler_arm::isThumbFunction(co
> return false;
> }
>
> +
> +class Thumb2ToArmShimAtom : public SimpleDefinedAtom {
> +public:
> + Thumb2ToArmShimAtom(MachOFile &file, StringRef targetName,
> + const DefinedAtom &target)
> + : SimpleDefinedAtom(file) {
> + addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
> + ArchHandler_arm::modeThumbCode, 0, this, 0);
> + addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
> + ArchHandler_arm::delta32, 8, &target, 0);
> + std::string name = std::string(targetName) + "$shim";
> + StringRef tmp(name);
> + _name = tmp.copy(file.allocator());
> + }
> +
> + StringRef name() const override {
> + return _name;
> + }
> +
> + ContentType contentType() const override {
> + return DefinedAtom::typeCode;
> + }
> +
> + Alignment alignment() const override {
> + return Alignment(2);
> + }
> +
> + uint64_t size() const override {
> + return 12;
> + }
> +
> + ContentPermissions permissions() const override {
> + return DefinedAtom::permR_X;
> + }
> +
> + ArrayRef<uint8_t> rawContent() const override {
> + static const uint8_t bytes[] =
> + { 0xDF, 0xF8, 0x04, 0xC0, // ldr ip, pc + 4
> + 0xFF, 0x44, // add ip, pc, ip
> + 0x60, 0x47, // ldr pc, [ip]
> + 0x00, 0x00, 0x00, 0x00 }; // .long target - this
> + assert(sizeof(bytes) == size());
> + return llvm::makeArrayRef(bytes, sizeof(bytes));
> + }
> +private:
> + StringRef _name;
> +};
> +
> +
> +class ArmToThumbShimAtom : public SimpleDefinedAtom {
> +public:
> + ArmToThumbShimAtom(MachOFile &file, StringRef targetName,
> + const DefinedAtom &target)
> + : SimpleDefinedAtom(file) {
> + addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
> + ArchHandler_arm::delta32, 12, &target, 0);
> + std::string name = std::string(targetName) + "$shim";
> + StringRef tmp(name);
> + _name = tmp.copy(file.allocator());
> + }
> +
> + StringRef name() const override {
> + return _name;
> + }
> +
> + ContentType contentType() const override {
> + return DefinedAtom::typeCode;
> + }
> +
> + Alignment alignment() const override {
> + return Alignment(2);
> + }
> +
> + uint64_t size() const override {
> + return 16;
> + }
> +
> + ContentPermissions permissions() const override {
> + return DefinedAtom::permR_X;
> + }
> +
> + ArrayRef<uint8_t> rawContent() const override {
> + static const uint8_t bytes[] =
> + { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 4
> + 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
> + 0x1C, 0xFF, 0x2F, 0xE1, // ldr pc, [ip]
> + 0x00, 0x00, 0x00, 0x00 }; // .long target - this
> + assert(sizeof(bytes) == size());
> + return llvm::makeArrayRef(bytes, sizeof(bytes));
> + }
> +private:
> + StringRef _name;
> +};
> +
> +const DefinedAtom *ArchHandler_arm::createShim(MachOFile &file,
> + bool thumbToArm,
> + const DefinedAtom &target) {
> + bool isStub = (target.contentType() == DefinedAtom::typeStub);
> + StringRef targetName = isStub ? stubName(target) : target.name();
> + if (thumbToArm)
> + return new (file.allocator()) Thumb2ToArmShimAtom(file, targetName, target);
> + else
> + return new (file.allocator()) ArmToThumbShimAtom(file, targetName, target);
> +}
> +
> +
> std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
> return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
> }
>
> Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp (original)
> +++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp Mon Oct 13 20:51:42 2014
> @@ -74,6 +74,10 @@ public:
> const StubInfo &stubInfo() override { return _sStubInfo; }
>
> bool isCallSite(const Reference &) override;
> + bool isNonCallBranch(const Reference &) override {
> + return false;
> + }
> +
> bool isPointer(const Reference &) override;
> bool isPairedReloc(const normalized::Relocation &) override;
>
>
> Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp (original)
> +++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp Mon Oct 13 20:51:42 2014
> @@ -34,6 +34,10 @@ public:
>
> const StubInfo &stubInfo() override { return _sStubInfo; }
> bool isCallSite(const Reference &) override;
> + bool isNonCallBranch(const Reference &) override {
> + return false;
> + }
> +
> bool isPointer(const Reference &) override;
> bool isPairedReloc(const normalized::Relocation &) override;
>
>
> Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp (original)
> +++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp Mon Oct 13 20:51:42 2014
> @@ -86,6 +86,10 @@ public:
>
> const StubInfo &stubInfo() override { return _sStubInfo; }
>
> + bool isNonCallBranch(const Reference &) override {
> + return false;
> + }
> +
> bool isCallSite(const Reference &) override;
> bool isPointer(const Reference &) override;
> bool isPairedReloc(const normalized::Relocation &) override;
>
> Modified: lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt (original)
> +++ lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt Mon Oct 13 20:51:42 2014
> @@ -12,6 +12,7 @@ add_lld_library(lldMachO
> MachONormalizedFileFromAtoms.cpp
> MachONormalizedFileToAtoms.cpp
> MachONormalizedFileYAML.cpp
> + ShimPass.cpp
> StubsPass.cpp
> WriterMachO.cpp
> )
>
> Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
> +++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Mon Oct 13 20:51:42 2014
> @@ -324,6 +324,21 @@ bool MachOLinkingContext::needsCompactUn
> }
> }
>
> +bool MachOLinkingContext::needsShimPass() const {
> + // Shim pass only used in final executables.
> + if (_outputMachOType == MH_OBJECT)
> + return false;
> + // Only 32-bit arm arches use Shim pass.
> + switch (_arch) {
> + case arch_armv6:
> + case arch_armv7:
> + case arch_armv7s:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> StringRef MachOLinkingContext::binderSymbolName() const {
> return archHandler().stubInfo().binderSymbolName;
> }
> @@ -572,6 +587,8 @@ void MachOLinkingContext::addPasses(Pass
> mach_o::addCompactUnwindPass(pm, *this);
> if (needsGOTPass())
> mach_o::addGOTPass(pm, *this);
> + if (needsShimPass())
> + mach_o::addShimPass(pm, *this); // Shim pass must run after stubs pass.
> }
>
> Writer &MachOLinkingContext::writer() const {
>
> Modified: lld/trunk/lib/ReaderWriter/MachO/MachOPasses.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOPasses.h?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/MachO/MachOPasses.h (original)
> +++ lld/trunk/lib/ReaderWriter/MachO/MachOPasses.h Mon Oct 13 20:51:42 2014
> @@ -19,6 +19,7 @@ namespace mach_o {
> void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx);
> void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx);
> void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx);
> +void addShimPass(PassManager &pm, const MachOLinkingContext &ctx);
>
> } // namespace mach_o
> } // namespace lld
>
> Added: lld/trunk/lib/ReaderWriter/MachO/ShimPass.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ShimPass.cpp?rev=219655&view=auto
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/MachO/ShimPass.cpp (added)
> +++ lld/trunk/lib/ReaderWriter/MachO/ShimPass.cpp Mon Oct 13 20:51:42 2014
> @@ -0,0 +1,131 @@
> +//===- lib/ReaderWriter/MachO/ShimPass.cpp -------------------------------===//
> +//
> +// The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This linker pass updates branch-sites whose target is a different mode
> +// (thumb vs arm).
> +//
> +// Arm code has two instruction encodings thumb and arm. When branching from
> +// one code encoding to another, you need to use an instruction that switches
> +// the instruction mode. Usually the transition only happens at call sites, and
> +// the linker can transform a BL instruction in BLX (or vice versa). But if the
> +// compiler did a tail call optimization and a function ends with a branch (not
> +// branch and link), there is no pc-rel BX instruction.
> +//
> +// The ShimPass looks for pc-rel B instructions that will need to switch mode.
> +// For those cases it synthesizes a shim which does the transition, then
> +// modifies the original atom with the B instruction to target to the shim atom.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "ArchHandler.h"
> +#include "File.h"
> +#include "MachOPasses.h"
> +
> +#include "lld/Core/DefinedAtom.h"
> +#include "lld/Core/File.h"
> +#include "lld/Core/LLVM.h"
> +#include "lld/Core/Reference.h"
> +#include "lld/Core/Simple.h"
> +#include "lld/ReaderWriter/MachOLinkingContext.h"
> +
> +#include "llvm/ADT/DenseMap.h"
> +
> +
> +namespace lld {
> +namespace mach_o {
> +
> +class ShimPass : public Pass {
> +public:
> + ShimPass(const MachOLinkingContext &context)
> + : _context(context)
> + , _archHandler(_context.archHandler())
> + , _stubInfo(_archHandler.stubInfo())
> + , _file("<mach-o shim pass>") {
> + }
> +
> +
> + void perform(std::unique_ptr<MutableFile> &mergedFile) override {
> + // Scan all references in all atoms.
> + for (const DefinedAtom *atom : mergedFile->defined()) {
> + for (const Reference *ref : *atom) {
> + // Look at non-call branches.
> + if (!_archHandler.isNonCallBranch(*ref))
> + continue;
> + const Atom *target = ref->target();
> + assert(target != nullptr);
> + if (const lld::DefinedAtom *daTarget = dyn_cast<DefinedAtom>(target)) {
> + bool atomIsThumb = _archHandler.isThumbFunction(*atom);
> + bool targetIsThumb = _archHandler.isThumbFunction(*daTarget);
> + if (atomIsThumb != targetIsThumb)
> + updateBranchToUseShim(atomIsThumb, *daTarget, ref);
> + }
> + }
> + }
> + // Exit early if no shims needed.
> + if (_targetToShim.empty())
> + return;
> +
> + // Sort shim atoms so the layout order is stable.
> + std::vector<const DefinedAtom *> shims;
> + shims.reserve(_targetToShim.size());
> + for (auto element : _targetToShim) {
> + shims.push_back(element.second);
> + }
> + std::sort(shims.begin(), shims.end(),
> + [](const DefinedAtom *l, const DefinedAtom *r) {
> + return (l->name() < r->name());
> + });
> +
> + // Add all shims to master file.
> + for (const DefinedAtom *shim : shims) {
> + mergedFile->addAtom(*shim);
> + }
> + }
> +
> +private:
> +
> + void updateBranchToUseShim(bool thumbToArm, const DefinedAtom& target,
> + const Reference *ref) {
> + // Make file-format specific stub and other support atoms.
> + const DefinedAtom *shim = this->getShim(thumbToArm, target);
> + assert(shim != nullptr);
> + // Switch branch site to target shim atom.
> + const_cast<Reference *>(ref)->setTarget(shim);
> + }
> +
> + const DefinedAtom* getShim(bool thumbToArm, const DefinedAtom& target) {
> + auto pos = _targetToShim.find(&target);
> + if ( pos != _targetToShim.end() ) {
> + // Reuse an existing shim.
> + assert(pos->second != nullptr);
> + return pos->second;
> + } else {
> + // There is no existing shim, so create a new one.
> + const DefinedAtom *shim = _archHandler.createShim(_file, thumbToArm,
> + target);
> + _targetToShim[&target] = shim;
> + return shim;
> + }
> + }
> +
> + const MachOLinkingContext &_context;
> + mach_o::ArchHandler &_archHandler;
> + const ArchHandler::StubInfo &_stubInfo;
> + MachOFile _file;
> + llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToShim;
> +};
> +
> +
> +
> +void addShimPass(PassManager &pm, const MachOLinkingContext &ctx) {
> + pm.add(std::unique_ptr<Pass>(new ShimPass(ctx)));
> +}
> +
> +} // end namespace mach_o
> +} // end namespace lld
>
> Modified: lld/trunk/test/mach-o/arm-interworking.yaml
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/arm-interworking.yaml?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/test/mach-o/arm-interworking.yaml (original)
> +++ lld/trunk/test/mach-o/arm-interworking.yaml Mon Oct 13 20:51:42 2014
> @@ -237,28 +237,28 @@ undefined-symbols:
> # CHECK: - kind: modeThumbCode
> # CHECK: offset: 0
> # CHECK: target: _t1
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 0
> # CHECK: target: _a1
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 6
> # CHECK: target: _a2
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 12
> # CHECK: target: _a2
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 16
> # CHECK: target: _t1
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 22
> # CHECK: target: _t1
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 28
> # CHECK: target: _t2
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 34
> # CHECK: target: _t2
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 38
> # CHECK: target: _t3
> # CHECK: - name: _t2
> @@ -277,16 +277,16 @@ undefined-symbols:
> # CHECK: - name: _a1
> # CHECK: scope: global
> # CHECK: references:
> -# CHECK: - kind: arm_b24
> +# CHECK: - kind: arm_bl24
> # CHECK: offset: 0
> # CHECK: target: _a1
> -# CHECK: - kind: arm_b24
> +# CHECK: - kind: arm_bl24
> # CHECK: offset: 4
> # CHECK: target: _a2
> -# CHECK: - kind: arm_b24
> +# CHECK: - kind: arm_bl24
> # CHECK: offset: 8
> # CHECK: target: _t1
> -# CHECK: - kind: arm_b24
> +# CHECK: - kind: arm_bl24
> # CHECK: offset: 12
> # CHECK: target: _t2
> # CHECK: - name: _a2
>
> Added: lld/trunk/test/mach-o/arm-shims.yaml
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/arm-shims.yaml?rev=219655&view=auto
> ==============================================================================
> --- lld/trunk/test/mach-o/arm-shims.yaml (added)
> +++ lld/trunk/test/mach-o/arm-shims.yaml Mon Oct 13 20:51:42 2014
> @@ -0,0 +1,179 @@
> +# RUN: lld -flavor darwin -arch armv7 %s -dylib %p/Inputs/libSystem.yaml -o %t
> +# RUN: macho-dump --dump-section-data %t | FileCheck %s
> +#
> +# Test b from arm to thumb or vice versa has shims added.s
> +#
> +#
> +
> +--- !mach-o
> +arch: armv7
> +file-type: MH_OBJECT
> +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
> +sections:
> + - segment: __TEXT
> + section: __text
> + type: S_REGULAR
> + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
> + alignment: 2
> + address: 0x0000000000000000
> + content: [ 0x00, 0xBF, 0xFF, 0xF7, 0xFE, 0xEF, 0xFF, 0xF7,
> + 0xFB, 0xBF, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3,
> + 0xFA, 0xFF, 0xFF, 0xFA, 0xF9, 0xFF, 0xFF, 0xEA ]
> + relocations:
> + - offset: 0x00000014
> + type: ARM_RELOC_BR24
> + length: 2
> + pc-rel: true
> + extern: true
> + symbol: 3
> + - offset: 0x00000010
> + type: ARM_RELOC_BR24
> + length: 2
> + pc-rel: true
> + extern: true
> + symbol: 3
> + - offset: 0x00000006
> + type: ARM_THUMB_RELOC_BR22
> + length: 2
> + pc-rel: true
> + extern: true
> + symbol: 2
> + - offset: 0x00000002
> + type: ARM_THUMB_RELOC_BR22
> + length: 2
> + pc-rel: true
> + extern: true
> + symbol: 2
> +global-symbols:
> + - name: _a1
> + type: N_SECT
> + scope: [ N_EXT ]
> + sect: 1
> + value: 0x000000000000000C
> + - name: _t1
> + type: N_SECT
> + scope: [ N_EXT ]
> + sect: 1
> + desc: [ N_ARM_THUMB_DEF ]
> + value: 0x0000000000000000
> +undefined-symbols:
> + - name: _a2
> + type: N_UNDF
> + scope: [ N_EXT ]
> + value: 0x0000000000000000
> + - name: _t2
> + type: N_UNDF
> + scope: [ N_EXT ]
> + value: 0x0000000000000000
> +
> +
> +--- !mach-o
> +arch: armv7
> +file-type: MH_OBJECT
> +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
> +sections:
> + - segment: __TEXT
> + section: __text
> + type: S_REGULAR
> + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
> + alignment: 2
> + address: 0x0000000000000000
> + content: [ 0x00, 0xBF, 0xFF, 0xF7, 0xFE, 0xEF, 0xFF, 0xF7,
> + 0xFB, 0xBF, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3,
> + 0xFA, 0xFF, 0xFF, 0xFA, 0xF9, 0xFF, 0xFF, 0xEA ]
> + relocations:
> + - offset: 0x00000014
> + type: ARM_RELOC_BR24
> + length: 2
> + pc-rel: true
> + extern: true
> + symbol: 3
> + - offset: 0x00000010
> + type: ARM_RELOC_BR24
> + length: 2
> + pc-rel: true
> + extern: true
> + symbol: 3
> + - offset: 0x00000006
> + type: ARM_THUMB_RELOC_BR22
> + length: 2
> + pc-rel: true
> + extern: true
> + symbol: 2
> + - offset: 0x00000002
> + type: ARM_THUMB_RELOC_BR22
> + length: 2
> + pc-rel: true
> + extern: true
> + symbol: 2
> +global-symbols:
> + - name: _a2
> + type: N_SECT
> + scope: [ N_EXT ]
> + sect: 1
> + value: 0x000000000000000C
> + - name: _t2
> + type: N_SECT
> + scope: [ N_EXT ]
> + sect: 1
> + desc: [ N_ARM_THUMB_DEF ]
> + value: 0x0000000000000000
> +undefined-symbols:
> + - name: _a1
> + type: N_UNDF
> + scope: [ N_EXT ]
> + value: 0x0000000000000000
> + - name: _t1
> + type: N_UNDF
> + scope: [ N_EXT ]
> + value: 0x0000000000000000
> +
> +...
> +
> +
> +# CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
> +# CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
> +# CHECK: ('_section_data', '00bf00f0 10e800f0 19b80000 00f020e3 000000fa 0f0000ea 00bffff7 f8ef00f0 07b80000 00f020e3 f4fffffa 050000ea dff804c0 ff446047 d4ffffff dff804c0 ff446047 e0ffffff 04c09fe5 0cc08fe0 1cff2fe1 adffffff 04c09fe5 0cc08fe0 1cff2fe1 b5ffffff')
> +
> +# When we get a good mach-o disassembler the above __text section content check can be change to be symbolic.
> +
> +
> +# Input file one:
> +#
> +# .align 2
> +# .code 16
> +# .globl _t1
> +# .thumb_func _t1
> +#_t1:
> +# nop
> +# blx _a2
> +# b _a2
> +#
> +# .code 32
> +# .align 2
> +# .globl _a1
> +#_a1:
> +# nop
> +# blx _t2
> +# b _t2
> +
> +
> +
> +# Input file two:
> +#
> +# .align 2
> +# .code 16
> +# .globl _t2
> +# .thumb_func _t2
> +#_t2:
> +# nop
> +# blx _a1
> +# b _a1
> +#
> +# .code 32
> +# .align 2
> +# .globl _a2
> +#_a2:
> +# nop
> +# blx _t1
> +# b _t1
>
> Modified: lld/trunk/test/mach-o/parse-arm-relocs.yaml
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/parse-arm-relocs.yaml?rev=219655&r1=219654&r2=219655&view=diff
> ==============================================================================
> --- lld/trunk/test/mach-o/parse-arm-relocs.yaml (original)
> +++ lld/trunk/test/mach-o/parse-arm-relocs.yaml Mon Oct 13 20:51:42 2014
> @@ -572,19 +572,19 @@ undefined-symbols:
> # CHECK: references:
> # CHECK: - kind: modeThumbCode
> # CHECK: offset: 0
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 0
> # CHECK: target: _x
> # CHECK-NOT: addend:
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 4
> # CHECK: target: _x
> # CHECK: addend: 4
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 8
> # CHECK: target: _undef
> # CHECK-NOT: addend:
> -# CHECK: - kind: thumb_b22
> +# CHECK: - kind: thumb_bl22
> # CHECK: offset: 12
> # CHECK: target: _undef
> # CHECK: addend: 4
> @@ -660,19 +660,19 @@ undefined-symbols:
> # CHECK: - name: _foo_arm
> # CHECK: references:
> # CHECK-NOT: - kind: modeThumbCode
> -# CHECK: - kind: arm_b24
> +# CHECK: - kind: arm_bl24
> # CHECK: offset: 0
> # CHECK: target: _x
> # CHECK-NOT: addend:
> -# CHECK: - kind: arm_b24
> +# CHECK: - kind: arm_bl24
> # CHECK: offset: 4
> # CHECK: target: _x
> # CHECK: addend: 4
> -# CHECK: - kind: arm_b24
> +# CHECK: - kind: arm_bl24
> # CHECK: offset: 8
> # CHECK: target: _undef
> # CHECK-NOT: addend:
> -# CHECK: - kind: arm_b24
> +# CHECK: - kind: arm_bl24
> # CHECK: offset: 12
> # CHECK: target: _undef
> # CHECK: addend: 4
> @@ -739,11 +739,11 @@ undefined-symbols:
> # bl _undef
> # bl _undef+4
> # movw r1, :lower16:(_x-L1)
> -# movt r1, :upper16:(_x-L1)
> +# movt r1, :upper16:(_x-L1)
> # movw r2, :lower16:(_x+8-L1)
> -# movt r2, :upper16:(_x+8-L1)
> +# movt r2, :upper16:(_x+8-L1)
> # movw r1, :lower16:(_t1-L1)
> -# movt r1, :upper16:(_t1-L1)
> +# movt r1, :upper16:(_t1-L1)
> # add r1, pc
> #L1:
> # movw r3, :lower16:_x
> @@ -770,9 +770,9 @@ undefined-symbols:
> # bl _undef
> # bl _undef+4
> # movw r1, :lower16:(_x-L2)
> -# movt r1, :upper16:(_x-L2)
> +# movt r1, :upper16:(_x-L2)
> # movw r2, :lower16:(_x+8-L2)
> -# movt r2, :upper16:(_x+8-L2)
> +# movt r2, :upper16:(_x+8-L2)
> # add r1, pc
> #L2:
> # movw r3, :lower16:_x
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by the Linux Foundation
More information about the llvm-commits
mailing list