[lld] r219655 - [mach-o] Add Pass to create are shim Atoms for ARM interworking.
Nick Kledzik
kledzik at apple.com
Mon Oct 20 09:46:48 PDT 2014
On Oct 18, 2014, at 8:13 PM, Shankar Easwaran <shankare at codeaurora.org> wrote:
> Hi Nick,
>
> This patch doesnot seem to reuse shim's right ?
It does re-use them. The pass has used _targetToShim to maintain a map of shim atoms produced for each target atom. If two locations branch to the same target and both need a shim, the same shim is re-used.
-Nick
>
> 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