Skip to content

Commit 80b41c2

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 llvm#100096.
1 parent 0ccc389 commit 80b41c2

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

bolt/lib/Rewrite/RewriteInstance.cpp

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

2930+
static BinaryFunction *getInitFunctionIfStaticBinary(BinaryContext &BC) {
2931+
// Workaround for https://github.com/llvm/llvm-project/issues/100096
2932+
// ("[BOLT] GOT array pointer incorrectly rewritten"). In aarch64
2933+
// static glibc binaries, the .init section's _init function pointer can
2934+
// alias with a data pointer for the end of an array. GOT rewriting
2935+
// currently can't detect this and updates the data pointer to the
2936+
// moved _init, causing a runtime crash. Skipping _init on the other
2937+
// hand should be harmless.
2938+
if (!BC.IsStaticExecutable)
2939+
return nullptr;
2940+
const BinaryData *BD = BC.getBinaryDataByName("_init");
2941+
if (!BD || BD->getSectionName() != ".init")
2942+
return nullptr;
2943+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: skip _init in for GOT workaround.\n");
2944+
return BC.getBinaryFunctionAtAddress(BD->getAddress());
2945+
}
2946+
29302947
void RewriteInstance::selectFunctionsToProcess() {
29312948
// Extend the list of functions to process or skip from a file.
29322949
auto populateFunctionNames = [](cl::opt<std::string> &FunctionNamesFile,
@@ -3047,6 +3064,10 @@ void RewriteInstance::selectFunctionsToProcess() {
30473064
return true;
30483065
};
30493066

3067+
if (auto *InitBD = BC->getBinaryDataByName("_init"))
3068+
if (BinaryFunction *Init = getInitFunctionIfStaticBinary(*BC))
3069+
Init->setIgnored();
3070+
30503071
for (auto &BFI : BC->getBinaryFunctions()) {
30513072
BinaryFunction &Function = BFI.second;
30523073

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)