Skip to content

Commit 95dcb8b

Browse files
[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.
1 parent 20f634f commit 95dcb8b

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ class StubsManager : public TableManager<StubsManager<Flavor>> {
295295
StubsManager() = default;
296296

297297
/// Name of the object file section that will contain all our stubs.
298-
static StringRef getSectionName() { return "__llvm_jitlink_STUBS"; }
298+
static StringRef getSectionName();
299299

300300
/// Implements link-graph traversal via visitExistingEdges().
301301
bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
@@ -345,6 +345,10 @@ class StubsManager : public TableManager<StubsManager<Flavor>> {
345345
template <>
346346
Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target);
347347

348+
template <> inline StringRef StubsManager<Thumbv7>::getSectionName() {
349+
return "__llvm_jitlink_aarch32_STUBS_Thumbv7";
350+
}
351+
348352
} // namespace aarch32
349353
} // namespace jitlink
350354
} // namespace llvm
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# RUN: rm -rf %t && mkdir -p %t
2+
# RUN: llvm-mc -triple=thumbv7-linux-gnueabi -arm-add-build-attributes \
3+
# RUN: -filetype=obj -filetype=obj -o %t/elf_stubs.o %s
4+
# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
5+
# RUN: -slab-allocate 10Kb -slab-page-size 4096 \
6+
# RUN: -abs external_func=0x76bbe880 \
7+
# RUN: -check %s %t/elf_stubs.o
8+
9+
.text
10+
.syntax unified
11+
12+
# Check that calls/jumps to external functions trigger the generation of
13+
# branch-range extension stubs. These stubs don't follow the default PLT model
14+
# where the branch-target address is loaded from a GOT entry. Instead, they
15+
# hard-code it in the immediate field.
16+
#
17+
# jitlink-check: decode_operand(test_external_call, 2) = stub_addr(elf_stubs.o, external_func) - next_pc(test_external_call)
18+
# jitlink-check: decode_operand(test_external_jump, 0) = stub_addr(elf_stubs.o, external_func) - next_pc(test_external_jump)
19+
.globl test_external_call
20+
.type test_external_call,%function
21+
.p2align 1
22+
.code 16
23+
.thumb_func
24+
test_external_call:
25+
bl external_func
26+
.size test_external_call, .-test_external_call
27+
28+
.globl test_external_jump
29+
.type test_external_call,%function
30+
.p2align 1
31+
.code 16
32+
.thumb_func
33+
test_external_jump:
34+
b external_func
35+
.size test_external_jump, .-test_external_jump
36+
37+
# Empty main function for jitlink to be happy
38+
.globl main
39+
.type main,%function
40+
.p2align 1
41+
.code 16
42+
.thumb_func
43+
main:
44+
bx lr
45+
.size main, .-main

llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ static bool isELFGOTSection(Section &S) { return S.getName() == "$__GOT"; }
2424

2525
static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
2626

27+
static bool isELFAArch32StubsSection(Section &S) {
28+
return S.getName().starts_with("__llvm_jitlink_aarch32_STUBS_");
29+
}
30+
2731
static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
2832
auto EItr =
2933
llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
@@ -68,6 +72,15 @@ static Expected<Symbol &> getELFStubTarget(LinkGraph &G, Block &B) {
6872
return getELFGOTTarget(G, GOTSym.getBlock());
6973
}
7074

75+
static Expected<std::string> getELFAArch32StubTargetName(LinkGraph &G,
76+
Block &B) {
77+
auto E = getFirstRelocationEdge(G, B);
78+
if (!E)
79+
return E.takeError();
80+
Symbol &StubTarget = E->getTarget();
81+
return StubTarget.getName().str();
82+
}
83+
7184
namespace llvm {
7285

7386
Error registerELFGraphInfo(Session &S, LinkGraph &G) {
@@ -102,6 +115,7 @@ Error registerELFGraphInfo(Session &S, LinkGraph &G) {
102115

103116
bool isGOTSection = isELFGOTSection(Sec);
104117
bool isStubsSection = isELFStubsSection(Sec);
118+
bool isAArch32StubsSection = isELFAArch32StubsSection(Sec);
105119

106120
bool SectionContainsContent = false;
107121
bool SectionContainsZeroFill = false;
@@ -142,6 +156,18 @@ Error registerELFGraphInfo(Session &S, LinkGraph &G) {
142156
else
143157
return TS.takeError();
144158
SectionContainsContent = true;
159+
} else if (isAArch32StubsSection) {
160+
if (Sym->isSymbolZeroFill())
161+
return make_error<StringError>("zero-fill atom in Stub section",
162+
inconvertibleErrorCode());
163+
164+
if (auto Name = getELFAArch32StubTargetName(G, Sym->getBlock()))
165+
FileInfo.StubInfos[*Name] = {Sym->getSymbolContent(),
166+
Sym->getAddress().getValue(),
167+
Sym->getTargetFlags()};
168+
else
169+
return Name.takeError();
170+
SectionContainsContent = true;
145171
}
146172

147173
if (Sym->hasName()) {

0 commit comments

Comments
 (0)