|
15 | 15 | #include "llvm/ADT/StringExtras.h"
|
16 | 16 | #include "llvm/BinaryFormat/ELF.h"
|
17 | 17 | #include "llvm/ExecutionEngine/JITLink/JITLink.h"
|
| 18 | +#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h" |
18 | 19 | #include "llvm/Object/ELFObjectFile.h"
|
19 | 20 | #include "llvm/Support/Endian.h"
|
20 | 21 | #include "llvm/Support/ManagedStatic.h"
|
@@ -724,27 +725,127 @@ bool GOTBuilder::visitEdge(LinkGraph &G, Block *B, Edge &E) {
|
724 | 725 | return true;
|
725 | 726 | }
|
726 | 727 |
|
| 728 | +const uint8_t Armv7ABS[] = { |
| 729 | + 0x00, 0xc0, 0x00, 0xe3, // movw r12, #0x0000 ; lower 16-bit |
| 730 | + 0x00, 0xc0, 0x40, 0xe3, // movt r12, #0x0000 ; upper 16-bit |
| 731 | + 0x1c, 0xff, 0x2f, 0xe1 // bx r12 |
| 732 | +}; |
| 733 | + |
727 | 734 | const uint8_t Thumbv7ABS[] = {
|
728 | 735 | 0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit
|
729 | 736 | 0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit
|
730 | 737 | 0x60, 0x47 // bx r12
|
731 | 738 | };
|
732 | 739 |
|
733 |
| -Symbol &StubsManager_v7::createEntry(LinkGraph &G, Symbol &Target) { |
| 740 | +/// Create a new node in the link-graph for the given stub template. |
| 741 | +template <size_t Size> |
| 742 | +static Block &allocStub(LinkGraph &G, Section &S, const uint8_t (&Code)[Size]) { |
734 | 743 | constexpr uint64_t Alignment = 4;
|
735 |
| - Block &B = addStub(G, Thumbv7ABS, Alignment); |
736 |
| - LLVM_DEBUG({ |
737 |
| - const char *StubPtr = B.getContent().data(); |
738 |
| - HalfWords Reg12 = encodeRegMovtT1MovwT3(12); |
739 |
| - assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && |
740 |
| - checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && |
741 |
| - "Linker generated stubs may only corrupt register r12 (IP)"); |
742 |
| - }); |
| 744 | + ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size); |
| 745 | + return G.createContentBlock(S, Template, orc::ExecutorAddr(), Alignment, 0); |
| 746 | +} |
| 747 | + |
| 748 | +static Block &createStubThumbv7(LinkGraph &G, Section &S, Symbol &Target) { |
| 749 | + Block &B = allocStub(G, S, Thumbv7ABS); |
743 | 750 | B.addEdge(Thumb_MovwAbsNC, 0, Target, 0);
|
744 | 751 | B.addEdge(Thumb_MovtAbs, 4, Target, 0);
|
745 |
| - Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false); |
746 |
| - Stub.setTargetFlags(ThumbSymbol); |
747 |
| - return Stub; |
| 752 | + |
| 753 | + [[maybe_unused]] const char *StubPtr = B.getContent().data(); |
| 754 | + [[maybe_unused]] HalfWords Reg12 = encodeRegMovtT1MovwT3(12); |
| 755 | + assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && |
| 756 | + checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && |
| 757 | + "Linker generated stubs may only corrupt register r12 (IP)"); |
| 758 | + return B; |
| 759 | +} |
| 760 | + |
| 761 | +static Block &createStubArmv7(LinkGraph &G, Section &S, Symbol &Target) { |
| 762 | + Block &B = allocStub(G, S, Armv7ABS); |
| 763 | + B.addEdge(Arm_MovwAbsNC, 0, Target, 0); |
| 764 | + B.addEdge(Arm_MovtAbs, 4, Target, 0); |
| 765 | + |
| 766 | + [[maybe_unused]] const char *StubPtr = B.getContent().data(); |
| 767 | + [[maybe_unused]] uint32_t Reg12 = encodeRegMovtA1MovwA2(12); |
| 768 | + assert(checkRegister<Arm_MovwAbsNC>(StubPtr, Reg12) && |
| 769 | + checkRegister<Arm_MovtAbs>(StubPtr + 4, Reg12) && |
| 770 | + "Linker generated stubs may only corrupt register r12 (IP)"); |
| 771 | + return B; |
| 772 | +} |
| 773 | + |
| 774 | +static bool needsStub(const Edge &E) { |
| 775 | + Symbol &Target = E.getTarget(); |
| 776 | + |
| 777 | + // Create stubs for external branch targets. |
| 778 | + if (!Target.isDefined()) { |
| 779 | + switch (E.getKind()) { |
| 780 | + case Arm_Call: |
| 781 | + case Arm_Jump24: |
| 782 | + case Thumb_Call: |
| 783 | + case Thumb_Jump24: |
| 784 | + return true; |
| 785 | + default: |
| 786 | + return false; |
| 787 | + } |
| 788 | + } |
| 789 | + |
| 790 | + // For local targets, create interworking stubs if we switch Arm/Thumb with an |
| 791 | + // instruction that cannot switch the instruction set state natively. |
| 792 | + bool TargetIsThumb = Target.getTargetFlags() & ThumbSymbol; |
| 793 | + switch (E.getKind()) { |
| 794 | + case Arm_Jump24: |
| 795 | + return TargetIsThumb; // Branch to Thumb needs interworking stub |
| 796 | + case Thumb_Jump24: |
| 797 | + return !TargetIsThumb; // Branch to Arm needs interworking stub |
| 798 | + default: |
| 799 | + break; |
| 800 | + } |
| 801 | + |
| 802 | + return false; |
| 803 | +} |
| 804 | + |
| 805 | +bool StubsManager_v7::visitEdge(LinkGraph &G, Block *B, Edge &E) { |
| 806 | + if (!needsStub(E)) |
| 807 | + return false; |
| 808 | + |
| 809 | + // Stub Arm/Thumb follows instruction set state at relocation site. |
| 810 | + // TODO: We may reduce them at relaxation time and reuse freed slots. |
| 811 | + bool MakeThumb = (E.getKind() > LastArmRelocation); |
| 812 | + LLVM_DEBUG(dbgs() << " Preparing " << (MakeThumb ? "Thumb" : "Arm") |
| 813 | + << " stub for " << G.getEdgeKindName(E.getKind()) |
| 814 | + << " edge at " << B->getFixupAddress(E) << " (" |
| 815 | + << B->getAddress() << " + " |
| 816 | + << formatv("{0:x}", E.getOffset()) << ")\n"); |
| 817 | + |
| 818 | + Symbol &Target = E.getTarget(); |
| 819 | + assert(Target.hasName() && "Edge cannot point to anonymous target"); |
| 820 | + Symbol *&StubSymbol = getStubSymbolSlot(Target.getName(), MakeThumb); |
| 821 | + |
| 822 | + if (!StubSymbol) { |
| 823 | + if (!StubsSection) |
| 824 | + StubsSection = &G.createSection(getSectionName(), |
| 825 | + orc::MemProt::Read | orc::MemProt::Exec); |
| 826 | + Block &B = MakeThumb ? createStubThumbv7(G, *StubsSection, Target) |
| 827 | + : createStubArmv7(G, *StubsSection, Target); |
| 828 | + StubSymbol = &G.addAnonymousSymbol(B, 0, B.getSize(), true, false); |
| 829 | + if (MakeThumb) |
| 830 | + StubSymbol->setTargetFlags(ThumbSymbol); |
| 831 | + |
| 832 | + LLVM_DEBUG({ |
| 833 | + dbgs() << " Created " << (MakeThumb ? "Thumb" : "Arm") << " entry for " |
| 834 | + << Target.getName() << " in " << StubsSection->getName() << ": " |
| 835 | + << *StubSymbol << "\n"; |
| 836 | + }); |
| 837 | + } |
| 838 | + |
| 839 | + assert(MakeThumb == (StubSymbol->getTargetFlags() & ThumbSymbol) && |
| 840 | + "Instruction set states of stub and relocation site should be equal"); |
| 841 | + LLVM_DEBUG({ |
| 842 | + dbgs() << " Using " << (MakeThumb ? "Thumb" : "Arm") << " entry " |
| 843 | + << *StubSymbol << " in " |
| 844 | + << StubSymbol->getBlock().getSection().getName() << "\n"; |
| 845 | + }); |
| 846 | + |
| 847 | + E.setTarget(*StubSymbol); |
| 848 | + return true; |
748 | 849 | }
|
749 | 850 |
|
750 | 851 | const char *getEdgeKindName(Edge::Kind K) {
|
|
0 commit comments