Skip to content

Commit e2f1a95

Browse files
authored
[BOLT][AArch64] Handle IFUNCS properly (#71104)
Currently we were testing only the binaries compiled with O0, which results in indirect call to the IFUNC trampoline and the trampoline has associated IFUNC symbol with it. Compile with O3 results in direct calling the IFUNC trampoline and no symbols are associated with it, the IFUNC symbol address becomes the same as IFUNC resolver address. Since no symbol was associated the BF was not created before PLT analyze and be the algorithm we're going to analyze target relocation. As we're expecting the JUMP relocation we're also expecting the associated symbol with it to be presented. But for IFUNC relocation the IRELATIVE relocation is used and no symbol is associated with it, the addend value is pointing on the target symbol, so we need to find BF using it and use it's symbol in this situation. Currently this is checked only for AArch64 platform, so I've limited it in code to use this logic only for this platform, although I wouldn't be surprised if other platforms needs to activate this logic too.
1 parent 485075c commit e2f1a95

File tree

5 files changed

+77
-7
lines changed

5 files changed

+77
-7
lines changed

bolt/include/bolt/Core/Relocation.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ struct Relocation {
124124
/// otherwise.
125125
bool isRelative() const { return isRelative(Type); }
126126

127+
/// Return true if this relocation is R_*_IRELATIVE type. Return false
128+
/// otherwise.
129+
bool isIRelative() const { return isIRelative(Type); }
130+
127131
/// Emit relocation at a current \p Streamer' position. The caller is
128132
/// responsible for setting the position correctly.
129133
size_t emit(MCStreamer *Streamer) const;

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,24 +1344,41 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
13441344

13451345
BinaryFunction *BF = BC->getBinaryFunctionAtAddress(EntryAddress);
13461346
if (BF && BC->isAArch64()) {
1347-
// Handle IFUNC trampoline
1347+
// Handle IFUNC trampoline with symbol
13481348
setPLTSymbol(BF, BF->getOneName());
13491349
return;
13501350
}
13511351

13521352
const Relocation *Rel = BC->getDynamicRelocationAt(TargetAddress);
1353-
if (!Rel || !Rel->Symbol)
1353+
if (!Rel)
13541354
return;
13551355

1356+
MCSymbol *Symbol = Rel->Symbol;
1357+
if (!Symbol) {
1358+
if (!BC->isAArch64() || !Rel->Addend || !Rel->isIRelative())
1359+
return;
1360+
1361+
// IFUNC trampoline without symbol
1362+
BinaryFunction *TargetBF = BC->getBinaryFunctionAtAddress(Rel->Addend);
1363+
if (!TargetBF) {
1364+
errs()
1365+
<< "BOLT-WARNING: Expected BF to be presented as IFUNC resolver at "
1366+
<< Twine::utohexstr(Rel->Addend) << ", skipping\n";
1367+
return;
1368+
}
1369+
1370+
Symbol = TargetBF->getSymbol();
1371+
}
1372+
13561373
ErrorOr<BinarySection &> Section = BC->getSectionForAddress(EntryAddress);
13571374
assert(Section && "cannot get section for address");
13581375
if (!BF)
1359-
BF = BC->createBinaryFunction(Rel->Symbol->getName().str() + "@PLT",
1360-
*Section, EntryAddress, 0, EntrySize,
1376+
BF = BC->createBinaryFunction(Symbol->getName().str() + "@PLT", *Section,
1377+
EntryAddress, 0, EntrySize,
13611378
Section->getAlignment());
13621379
else
1363-
BF->addAlternativeName(Rel->Symbol->getName().str() + "@PLT");
1364-
setPLTSymbol(BF, Rel->Symbol->getName());
1380+
BF->addAlternativeName(Symbol->getName().str() + "@PLT");
1381+
setPLTSymbol(BF, Symbol->getName());
13651382
}
13661383

13671384
void RewriteInstance::disassemblePLTSectionAArch64(BinarySection &Section) {

bolt/test/AArch64/Inputs/iplt.ld

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SECTIONS {
2+
.plt : ALIGN(16) { *(.plt) *(.iplt) }
3+
}

bolt/test/AArch64/ifunc.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// This test checks that IFUNC trampoline is properly recognised by BOLT
2+
3+
// With -O0 indirect call is performed on IPLT trampoline. IPLT trampoline
4+
// has IFUNC symbol.
5+
// RUN: %clang %cflags -nostdlib -O0 -no-pie %s -fuse-ld=lld \
6+
// RUN: -o %t.O0.exe -Wl,-q
7+
// RUN: llvm-bolt %t.O0.exe -o %t.O0.bolt.exe \
8+
// RUN: --print-disasm --print-only=_start | \
9+
// RUN: FileCheck --check-prefix=O0_CHECK %s
10+
11+
// With -O3 direct call is performed on IPLT trampoline. IPLT trampoline
12+
// doesn't have associated symbol. The ifunc symbol has the same address as
13+
// IFUNC resolver function.
14+
// RUN: %clang %cflags -nostdlib -O3 %s -fuse-ld=lld -fPIC -pie \
15+
// RUN: -o %t.O3_pie.exe -Wl,-q
16+
// RUN: llvm-bolt %t.O3_pie.exe -o %t.O3_pie.bolt.exe \
17+
// RUN: --print-disasm --print-only=_start | \
18+
// RUN: FileCheck --check-prefix=O3_CHECK %s
19+
20+
// Check that IPLT trampoline located in .plt section are normally handled by
21+
// BOLT. The gnu-ld linker doesn't use separate .iplt section.
22+
// RUN: %clang %cflags -nostdlib -O3 %s -fuse-ld=lld -fPIC -pie \
23+
// RUN: -T %p/Inputs/iplt.ld -o %t.iplt_O3_pie.exe -Wl,-q
24+
// RUN: llvm-bolt %t.iplt_O3_pie.exe -o %t.iplt_O3_pie.bolt.exe \
25+
// RUN: --print-disasm --print-only=_start | \
26+
// RUN: FileCheck --check-prefix=O3_CHECK %s
27+
28+
// O0_CHECK: adr x{{[0-9]+}}, ifoo
29+
// O3_CHECK: b "{{resolver_foo|ifoo}}{{.*}}@PLT"
30+
31+
#include <stdio.h>
32+
#include <string.h>
33+
34+
static void foo() {}
35+
36+
static void *resolver_foo(void) { return foo; }
37+
38+
__attribute__((ifunc("resolver_foo"))) void ifoo();
39+
40+
void _start() { ifoo(); }

bolt/test/runtime/iplt.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
// This test checks that the ifuncs works after bolt.
2+
// Compiling with 00 results in IFUNC indirect calling.
23

3-
// RUN: %clang %cflags -no-pie %s -fuse-ld=lld \
4+
// RUN: %clang %cflags -O0 -no-pie %s -fuse-ld=lld \
45
// RUN: -o %t.exe -Wl,-q
56
// RUN: llvm-bolt %t.exe -o %t.bolt.exe --use-old-text=0 --lite=0
67
// RUN: %t.bolt.exe | FileCheck %s
78

9+
// RUN: %clang %cflags -O3 -no-pie %s -fuse-ld=lld \
10+
// RUN: -o %t.O3.exe -Wl,-q
11+
// RUN: llvm-bolt %t.O3.exe -o %t.O3.bolt.exe --use-old-text=0 --lite=0
12+
// RUN: %t.O3.bolt.exe | FileCheck %s
13+
814
// CHECK: foo
915

1016
#include <stdio.h>

0 commit comments

Comments
 (0)