Skip to content

[llvm-jitlink] Support plain AArch32 range extension stubs in jitlink-check's stub_addr() expressions #73268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
45 changes: 45 additions & 0 deletions llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s
Original file line number Diff line number Diff line change
@@ -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
26 changes: 26 additions & 0 deletions llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(); });
Expand Down Expand Up @@ -64,6 +68,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) {
Expand Down Expand Up @@ -98,6 +111,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;
Expand Down Expand Up @@ -138,6 +152,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()) {
Expand Down