Skip to content

Commit 7b60ba8

Browse files
[BOLT] Skip _init; avoiding GOT breakage for static binaries
_init is used during startup of binaires. Unfortunately, its address can be shared (at least on AArch64 glibc static binaries) with a data reference that lives in the GOT. The GOT rewriting is currently unable to distinguish between data addresses and function addresses. This leads to the data address being incorrectly rewritten, causing a crash on startup of the binary: Unexpected reloc type in static binary. To avoid this, don't consider _init for being moved, by skipping it. For now, skip _init for static binaries on any architecture; we could add further conditions to narrow the skipped case for known crashes, but as a straw man I thought it'd be best to keep the condition as simple as possible and see if there any objections to this. Updates #100096.
1 parent 0ccc389 commit 7b60ba8

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2927,6 +2927,24 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
29272927
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocation from data to data\n");
29282928
}
29292929

2930+
static bool isStaticInitFunction(const BinaryContext &BC,
2931+
const BinaryFunction &Function) {
2932+
// Workaround for https://github.com/llvm/llvm-project/issues/100096
2933+
// ("[BOLT] GOT array pointer incorrectly rewritten"). In aarch64
2934+
// static glibc binaries, the .init section's _init function pointer can
2935+
// alias with a data pointer for the end of an array. GOT rewriting
2936+
// currently can't detect this and updates the data pointer to the
2937+
// moved _init, causing a runtime crash. Skipping _init on the other
2938+
// hand should be harmless.
2939+
if (!BC.IsStaticExecutable)
2940+
return false;
2941+
bool ShouldSkip =
2942+
Function.hasName("_init") && Function.getOriginSectionName() == ".init";
2943+
if (ShouldSkip)
2944+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: skip _init in for GOT workaround.\n");
2945+
return ShouldSkip;
2946+
}
2947+
29302948
void RewriteInstance::selectFunctionsToProcess() {
29312949
// Extend the list of functions to process or skip from a file.
29322950
auto populateFunctionNames = [](cl::opt<std::string> &FunctionNamesFile,
@@ -3061,7 +3079,9 @@ void RewriteInstance::selectFunctionsToProcess() {
30613079
if (Function.isFragment())
30623080
continue;
30633081

3064-
if (!shouldProcess(Function)) {
3082+
if (isStaticInitFunction(*BC, Function)) {
3083+
Function.setIgnored();
3084+
} else if (!shouldProcess(Function)) {
30653085
if (opts::Verbosity >= 1) {
30663086
BC->outs() << "BOLT-INFO: skipping processing " << Function
30673087
<< " per user request\n";
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Regression test for https://github.com/llvm/llvm-project/issues/100096
2+
# static glibc binaries crash on startup because _init is moved and
3+
# shares its address with an array end pointer. The GOT rewriting can't
4+
# tell the two pointers apart and incorrectly updates the _array_end
5+
# address. Test checks that _init is not moved.
6+
7+
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
8+
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -static -Wl,--section-start=.data=0x1000 -Wl,--section-start=.init=0x1004
9+
# RUN: llvm-bolt %t.exe -o %t.bolt
10+
# RUN: llvm-nm %t.exe | FileCheck --check-prefix=CHECK-ORIGINAL %s
11+
# RUN: llvm-nm %t.bolt | FileCheck --check-prefix=CHECK-BOLTED %s
12+
13+
.section .data
14+
.globl _array_end
15+
_array_start:
16+
.word 0x0
17+
18+
_array_end:
19+
.section .init,"ax",@progbits
20+
.globl _init
21+
22+
# Check that bolt doesn't move _init.
23+
#
24+
# CHECK-ORIGINAL: 0000000000001004 T _init
25+
# CHECK-BOLTED: 0000000000001004 T _init
26+
_init:
27+
ret
28+
29+
.section .text,"ax",@progbits
30+
.globl _start
31+
32+
# Check that bolt is moving some other functions.
33+
#
34+
# CHECK-ORIGINAL: 0000000000001008 T _start
35+
# CHECK-BOLTED-NOT: 0000000000001008 T _start
36+
_start:
37+
bl _init
38+
adrp x0, #:got:_array_end
39+
ldr x0, [x0, #:gotpage_lo15:_array_end]
40+
adrp x0, #:got:_init
41+
ldr x0, [x0, #:gotpage_lo15:_init]
42+
ret
43+

0 commit comments

Comments
 (0)