|
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"
|
@@ -678,28 +679,145 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
|
678 | 679 | }
|
679 | 680 | }
|
680 | 681 |
|
| 682 | +const uint8_t Armv7ABS[] = { |
| 683 | + 0x00, 0xc0, 0x00, 0xe3, // movw r12, #0x0000 ; lower 16-bit |
| 684 | + 0x00, 0xc0, 0x40, 0xe3, // movt r12, #0x0000 ; upper 16-bit |
| 685 | + 0x1c, 0xff, 0x2f, 0xe1 // bx r12 |
| 686 | +}; |
| 687 | + |
681 | 688 | const uint8_t Thumbv7ABS[] = {
|
682 | 689 | 0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit
|
683 | 690 | 0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit
|
684 | 691 | 0x60, 0x47 // bx r12
|
685 | 692 | };
|
686 | 693 |
|
687 |
| -template <> |
688 |
| -Symbol &StubsManager<StubsFlavor::v7>::createEntry(LinkGraph &G, Symbol &Target) { |
| 694 | +/// Create a new node in the link-graph for the given stub template. |
| 695 | +template <size_t Size> |
| 696 | +static Block &allocStub(LinkGraph &G, Section &S, const uint8_t (&Code)[Size]) { |
689 | 697 | constexpr uint64_t Alignment = 4;
|
690 |
| - Block &B = addStub(G, Thumbv7ABS, Alignment); |
691 |
| - LLVM_DEBUG({ |
692 |
| - const char *StubPtr = B.getContent().data(); |
693 |
| - HalfWords Reg12 = encodeRegMovtT1MovwT3(12); |
694 |
| - assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && |
695 |
| - checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && |
696 |
| - "Linker generated stubs may only corrupt register r12 (IP)"); |
697 |
| - }); |
| 698 | + ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size); |
| 699 | + return G.createContentBlock(S, Template, orc::ExecutorAddr(), Alignment, 0); |
| 700 | +} |
| 701 | + |
| 702 | +static Block &createStubThumbv7(LinkGraph &G, Section &S, Symbol &Target) { |
| 703 | + Block &B = allocStub(G, S, Thumbv7ABS); |
698 | 704 | B.addEdge(Thumb_MovwAbsNC, 0, Target, 0);
|
699 | 705 | B.addEdge(Thumb_MovtAbs, 4, Target, 0);
|
700 |
| - Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false); |
701 |
| - Stub.setTargetFlags(ThumbSymbol); |
702 |
| - return Stub; |
| 706 | + |
| 707 | + [[maybe_unused]] const char *StubPtr = B.getContent().data(); |
| 708 | + [[maybe_unused]] HalfWords Reg12 = encodeRegMovtT1MovwT3(12); |
| 709 | + assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && |
| 710 | + checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && |
| 711 | + "Linker generated stubs may only corrupt register r12 (IP)"); |
| 712 | + return B; |
| 713 | +} |
| 714 | + |
| 715 | +static Block &createStubArmv7(LinkGraph &G, Section &S, Symbol &Target) { |
| 716 | + Block &B = allocStub(G, S, Armv7ABS); |
| 717 | + B.addEdge(Arm_MovwAbsNC, 0, Target, 0); |
| 718 | + B.addEdge(Arm_MovtAbs, 4, Target, 0); |
| 719 | + |
| 720 | + [[maybe_unused]] const char *StubPtr = B.getContent().data(); |
| 721 | + [[maybe_unused]] uint32_t Reg12 = encodeRegMovtA1MovwA2(12); |
| 722 | + assert(checkRegister<Arm_MovwAbsNC>(StubPtr, Reg12) && |
| 723 | + checkRegister<Arm_MovtAbs>(StubPtr + 4, Reg12) && |
| 724 | + "Linker generated stubs may only corrupt register r12 (IP)"); |
| 725 | + return B; |
| 726 | +} |
| 727 | + |
| 728 | +Symbol *StubsManager_v7::selectStub(const StubMapEntry &Candidates, |
| 729 | + ThumbStatePreference ThumbState) { |
| 730 | + Symbol *StubSymbol = nullptr; |
| 731 | + for (auto [StubIsThumb, Sym] : Candidates) { |
| 732 | + if (StubIsThumb) { |
| 733 | + if (ThumbState == Avoid) |
| 734 | + continue; // No match |
| 735 | + StubSymbol = Sym; |
| 736 | + break; // Best match |
| 737 | + } |
| 738 | + if (ThumbState == Avoid) { |
| 739 | + StubSymbol = Sym; |
| 740 | + break; // Best match |
| 741 | + } |
| 742 | + if (ThumbState == Prefer) { |
| 743 | + StubSymbol = Sym; |
| 744 | + continue; // Acceptable match |
| 745 | + } |
| 746 | + } |
| 747 | + return StubSymbol; |
| 748 | +} |
| 749 | + |
| 750 | +bool StubsManager_v7::visitEdge(LinkGraph &G, Block *B, Edge &E) { |
| 751 | + ThumbStatePreference ThumbState = Undefined; |
| 752 | + switch (E.getKind()) { |
| 753 | + case Arm_Call: |
| 754 | + case Arm_Jump24: |
| 755 | + ThumbState = Avoid; |
| 756 | + break; |
| 757 | + case Thumb_Call: |
| 758 | + ThumbState = Prefer; |
| 759 | + break; |
| 760 | + case Thumb_Jump24: |
| 761 | + ThumbState = Force; |
| 762 | + break; |
| 763 | + default: |
| 764 | + return false; |
| 765 | + } |
| 766 | + |
| 767 | + assert(ThumbState != Undefined && "Define Thumb state preference"); |
| 768 | + |
| 769 | + // Stubs are usually created only for external targets. |
| 770 | + Symbol &Target = E.getTarget(); |
| 771 | + if (Target.isDefined()) { |
| 772 | + bool TargetIsThumb = Target.getTargetFlags() & ThumbSymbol; |
| 773 | + bool InterworkingStub = ThumbState == Force && !TargetIsThumb; |
| 774 | + if (!InterworkingStub) |
| 775 | + return false; |
| 776 | + } |
| 777 | + |
| 778 | + LLVM_DEBUG(dbgs() << " Preparing stub with thumb-state '" |
| 779 | + << (ThumbState == Avoid ? "Avoid" : "") |
| 780 | + << (ThumbState == Prefer ? "Prefer" : "") |
| 781 | + << (ThumbState == Force ? "Force" : "") << "' for " |
| 782 | + << G.getEdgeKindName(E.getKind()) << " edge at " |
| 783 | + << B->getFixupAddress(E) << " (" << B->getAddress() << " + " |
| 784 | + << formatv("{0:x}", E.getOffset()) << ")\n"); |
| 785 | + |
| 786 | + assert(Target.hasName() && "Edge cannot point to anonymous target"); |
| 787 | + auto TargetEntry = StubMap.try_emplace(Target.getName()).first; |
| 788 | + |
| 789 | + Symbol *StubSymbol = selectStub(TargetEntry->second, ThumbState); |
| 790 | + if (!StubSymbol) { |
| 791 | + if (!StubsSection) |
| 792 | + StubsSection = &G.createSection(getSectionName(), |
| 793 | + orc::MemProt::Read | orc::MemProt::Exec); |
| 794 | + |
| 795 | + bool MakeThumb = ThumbState >= Prefer; |
| 796 | + Block &B = MakeThumb ? createStubThumbv7(G, *StubsSection, Target) |
| 797 | + : createStubArmv7(G, *StubsSection, Target); |
| 798 | + |
| 799 | + StubSymbol = &G.addAnonymousSymbol(B, 0, B.getSize(), true, false); |
| 800 | + if (MakeThumb) |
| 801 | + StubSymbol->setTargetFlags(ThumbSymbol); |
| 802 | + |
| 803 | + LLVM_DEBUG({ |
| 804 | + dbgs() << " Created " << (MakeThumb ? "Thumb" : "Arm") << " entry for " |
| 805 | + << Target.getName() << " in " << StubsSection->getName() << ": " |
| 806 | + << *StubSymbol << "\n"; |
| 807 | + }); |
| 808 | + |
| 809 | + TargetEntry->second.emplace_back(MakeThumb, StubSymbol); |
| 810 | + } |
| 811 | + |
| 812 | + LLVM_DEBUG({ |
| 813 | + bool StubIsThumb = StubSymbol->getTargetFlags() & ThumbSymbol; |
| 814 | + dbgs() << " Using " << (StubIsThumb ? "Thumb" : "Arm") << " entry " |
| 815 | + << *StubSymbol << " in " |
| 816 | + << StubSymbol->getBlock().getSection().getName() << "\n"; |
| 817 | + }); |
| 818 | + |
| 819 | + E.setTarget(*StubSymbol); |
| 820 | + return true; |
703 | 821 | }
|
704 | 822 |
|
705 | 823 | const char *getEdgeKindName(Edge::Kind K) {
|
|
0 commit comments