[llvm] 95dcb8b - [llvm-jitlink] Support plain AArch32 stubs in jitlink-check's stub_addr() expressions (#73268)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 24 12:41:05 PST 2023
Author: Stefan Gränitz
Date: 2023-11-24T21:41:00+01:00
New Revision: 95dcb8b49dd3bb0fcb9f020fe931632a0ddf4994
URL: https://github.com/llvm/llvm-project/commit/95dcb8b49dd3bb0fcb9f020fe931632a0ddf4994
DIFF: https://github.com/llvm/llvm-project/commit/95dcb8b49dd3bb0fcb9f020fe931632a0ddf4994.diff
LOG: [llvm-jitlink] Support plain AArch32 stubs in jitlink-check's stub_addr() expressions (#73268)
We want to use regular `stub_addr()` expressions in `jitlink-check` lines to test the generation of stubs in AArch32, but we don't want this to require a standardized GOT-based PLT implementation. In terms of performance and binary size it doesn't seem beneficial. And in terms of patching branch targets, we should be able to handle range-extension- and interworking-stubs without a lot of extra logic.
In order to allow such AArch32 stubs we add a separate path for `stub_addr()` expressions in `llvm-jitlink-elf`. The relocations in our stubs are not pointing to the GOT, but to the external symbol directly. Thus, we have to avoid access to the block of the edge target. Instead we only return the symbol name, which is enough to use `stub_addr()` expressions in tests.
The name of the AArch32 stubs section differs from the conventional `$__STUBS` on purpose. It allows to add a regular PLT/GOT implementation as an orthogonal feature in the future. In order to also allow decoding of stub target addresses in the future, we mention the stub flavor in the section name as well.
Added:
llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s
Modified:
llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 94669e0bceb836d..ec28db415c04625 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -295,7 +295,7 @@ class StubsManager : public TableManager<StubsManager<Flavor>> {
StubsManager() = default;
/// Name of the object file section that will contain all our stubs.
- static StringRef getSectionName() { return "__llvm_jitlink_STUBS"; }
+ static StringRef getSectionName();
/// Implements link-graph traversal via visitExistingEdges().
bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
@@ -345,6 +345,10 @@ class StubsManager : public TableManager<StubsManager<Flavor>> {
template <>
Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target);
+template <> inline StringRef StubsManager<Thumbv7>::getSectionName() {
+ return "__llvm_jitlink_aarch32_STUBS_Thumbv7";
+}
+
} // namespace aarch32
} // namespace jitlink
} // namespace llvm
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s
new file mode 100644
index 000000000000000..bd95c375279246a
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s
@@ -0,0 +1,45 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=thumbv7-linux-gnueabi -arm-add-build-attributes \
+# RUN: -filetype=obj -filetype=obj -o %t/elf_stubs.o %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
+# RUN: -slab-allocate 10Kb -slab-page-size 4096 \
+# RUN: -abs external_func=0x76bbe880 \
+# RUN: -check %s %t/elf_stubs.o
+
+ .text
+ .syntax unified
+
+# Check that calls/jumps to external functions trigger the generation of
+# branch-range extension stubs. These stubs don't follow the default PLT model
+# where the branch-target address is loaded from a GOT entry. Instead, they
+# hard-code it in the immediate field.
+#
+# jitlink-check: decode_operand(test_external_call, 2) = stub_addr(elf_stubs.o, external_func) - next_pc(test_external_call)
+# jitlink-check: decode_operand(test_external_jump, 0) = stub_addr(elf_stubs.o, external_func) - next_pc(test_external_jump)
+ .globl test_external_call
+ .type test_external_call,%function
+ .p2align 1
+ .code 16
+ .thumb_func
+test_external_call:
+ bl external_func
+ .size test_external_call, .-test_external_call
+
+ .globl test_external_jump
+ .type test_external_call,%function
+ .p2align 1
+ .code 16
+ .thumb_func
+test_external_jump:
+ b external_func
+ .size test_external_jump, .-test_external_jump
+
+# Empty main function for jitlink to be happy
+ .globl main
+ .type main,%function
+ .p2align 1
+ .code 16
+ .thumb_func
+main:
+ bx lr
+ .size main, .-main
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
index 4b7b3f9be701785..a02468758b33f68 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
@@ -24,6 +24,10 @@ static bool isELFGOTSection(Section &S) { return S.getName() == "$__GOT"; }
static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
+static bool isELFAArch32StubsSection(Section &S) {
+ return S.getName().starts_with("__llvm_jitlink_aarch32_STUBS_");
+}
+
static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
auto EItr =
llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
@@ -68,6 +72,15 @@ static Expected<Symbol &> getELFStubTarget(LinkGraph &G, Block &B) {
return getELFGOTTarget(G, GOTSym.getBlock());
}
+static Expected<std::string> getELFAArch32StubTargetName(LinkGraph &G,
+ Block &B) {
+ auto E = getFirstRelocationEdge(G, B);
+ if (!E)
+ return E.takeError();
+ Symbol &StubTarget = E->getTarget();
+ return StubTarget.getName().str();
+}
+
namespace llvm {
Error registerELFGraphInfo(Session &S, LinkGraph &G) {
@@ -102,6 +115,7 @@ Error registerELFGraphInfo(Session &S, LinkGraph &G) {
bool isGOTSection = isELFGOTSection(Sec);
bool isStubsSection = isELFStubsSection(Sec);
+ bool isAArch32StubsSection = isELFAArch32StubsSection(Sec);
bool SectionContainsContent = false;
bool SectionContainsZeroFill = false;
@@ -142,6 +156,18 @@ Error registerELFGraphInfo(Session &S, LinkGraph &G) {
else
return TS.takeError();
SectionContainsContent = true;
+ } else if (isAArch32StubsSection) {
+ if (Sym->isSymbolZeroFill())
+ return make_error<StringError>("zero-fill atom in Stub section",
+ inconvertibleErrorCode());
+
+ if (auto Name = getELFAArch32StubTargetName(G, Sym->getBlock()))
+ FileInfo.StubInfos[*Name] = {Sym->getSymbolContent(),
+ Sym->getAddress().getValue(),
+ Sym->getTargetFlags()};
+ else
+ return Name.takeError();
+ SectionContainsContent = true;
}
if (Sym->hasName()) {
More information about the llvm-commits
mailing list