Skip to content
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
20 changes: 20 additions & 0 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2927,6 +2927,23 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocation from data to data\n");
}

static BinaryFunction *getInitFunctionIfStaticBinary(BinaryContext &BC) {
// Workaround for https://github.com/llvm/llvm-project/issues/100096
// ("[BOLT] GOT array pointer incorrectly rewritten"). In aarch64
// static glibc binaries, the .init section's _init function pointer can
// alias with a data pointer for the end of an array. GOT rewriting
// currently can't detect this and updates the data pointer to the
// moved _init, causing a runtime crash. Skipping _init on the other
// hand should be harmless.
if (!BC.IsStaticExecutable)
return nullptr;
const BinaryData *BD = BC.getBinaryDataByName("_init");
if (!BD || BD->getSectionName() != ".init")
return nullptr;
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: skip _init in for GOT workaround.\n");
return BC.getBinaryFunctionAtAddress(BD->getAddress());
}

void RewriteInstance::selectFunctionsToProcess() {
// Extend the list of functions to process or skip from a file.
auto populateFunctionNames = [](cl::opt<std::string> &FunctionNamesFile,
Expand Down Expand Up @@ -3047,6 +3064,9 @@ void RewriteInstance::selectFunctionsToProcess() {
return true;
};

if (BinaryFunction *Init = getInitFunctionIfStaticBinary(*BC))
Init->setIgnored();

for (auto &BFI : BC->getBinaryFunctions()) {
BinaryFunction &Function = BFI.second;

Expand Down
43 changes: 43 additions & 0 deletions bolt/test/AArch64/check-init-not-moved.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Regression test for https://github.com/llvm/llvm-project/issues/100096
# static glibc binaries crash on startup because _init is moved and
# shares its address with an array end pointer. The GOT rewriting can't
# tell the two pointers apart and incorrectly updates the _array_end
# address. Test checks that _init is not moved.

# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -static -Wl,--section-start=.data=0x1000 -Wl,--section-start=.init=0x1004
# RUN: llvm-bolt %t.exe -o %t.bolt
# RUN: llvm-nm %t.exe | FileCheck --check-prefix=CHECK-ORIGINAL %s
# RUN: llvm-nm %t.bolt | FileCheck --check-prefix=CHECK-BOLTED %s

.section .data
.globl _array_end
_array_start:
.word 0x0

_array_end:
.section .init,"ax",@progbits
.globl _init

# Check that bolt doesn't move _init.
#
# CHECK-ORIGINAL: 0000000000001004 T _init
# CHECK-BOLTED: 0000000000001004 T _init
_init:
ret

.section .text,"ax",@progbits
.globl _start

# Check that bolt is moving some other functions.
#
# CHECK-ORIGINAL: 0000000000001008 T _start
# CHECK-BOLTED-NOT: 0000000000001008 T _start
_start:
bl _init
adrp x0, #:got:_array_end
ldr x0, [x0, #:gotpage_lo15:_array_end]
adrp x0, #:got:_init
ldr x0, [x0, #:gotpage_lo15:_init]
ret