Skip to content

Commit 0776fc3

Browse files
author
yavtuk
committed
[BOLT] Search section based on relocation symbol
We need to search referenced section based on relocations symbol section to properly match end section symbols. For example on some binaries we can observe that init_array_end/fini_array_end might be "placed" in to the gap and since no section could be found for address the relocation would be skipped resulting in wrong ADRP imm after emitting new text resulting in binary sigsegv. Credits for the test to Vladislav Khmelevskii aka yota9.
1 parent 268249f commit 0776fc3

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2457,8 +2457,21 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
24572457
if (BinaryData *BD = BC->getBinaryDataByName(SymbolName))
24582458
ReferencedSymbol = BD->getSymbol();
24592459

2460-
ErrorOr<BinarySection &> ReferencedSection =
2461-
BC->getSectionForAddress(SymbolAddress);
2460+
ErrorOr<BinarySection &> ReferencedSection{std::errc::bad_address};
2461+
symbol_iterator SymbolIter = Rel.getSymbol();
2462+
if (SymbolIter != InputFile->symbol_end()) {
2463+
SymbolRef Symbol = *SymbolIter;
2464+
section_iterator Section =
2465+
cantFail(Symbol.getSection(), "cannot get symbol section");
2466+
if (Section != InputFile->section_end()) {
2467+
Expected<StringRef> SectionName = Section->getName();
2468+
if (SectionName && !SectionName->empty())
2469+
ReferencedSection = BC->getUniqueSectionByName(*SectionName);
2470+
}
2471+
}
2472+
2473+
if (!ReferencedSection)
2474+
ReferencedSection = BC->getSectionForAddress(SymbolAddress);
24622475

24632476
const bool IsToCode = ReferencedSection && ReferencedSection->isText();
24642477

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
SECTIONS {
2+
.fini_array :
3+
{
4+
PROVIDE_HIDDEN (__fini_array_start = .);
5+
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
6+
PROVIDE_HIDDEN (__fini_array_end = .);
7+
}
8+
9+
. = . + 128;
10+
11+
.text : { *(.text) }
12+
}

bolt/test/AArch64/array_end.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Test checks that bolt properly finds end section label.
2+
// Linker script contains gap after destructor array, so
3+
// __init_array_end address would not be owned by any section.
4+
5+
// REQUIRES: system-linux
6+
// RUN: %clang %cflags -no-pie %s -o %t.exe -Wl,-q \
7+
// RUN: -Wl,-T %S/Inputs/array_end.lld_script
8+
// RUN: llvm-bolt %t.exe -o %t.bolt --print-disasm \
9+
// RUN: --print-only="callFini" | FileCheck %s
10+
11+
// CHECK: adr [[REG:x[0-28]+]], "__fini_array_end/1"
12+
13+
__attribute__((destructor)) void destr() {}
14+
15+
__attribute__((noinline)) void callFini() {
16+
extern void (*__fini_array_start[])();
17+
extern void (*__fini_array_end[])();
18+
unsigned long Count = __fini_array_end - __fini_array_start;
19+
for (unsigned long I = 0; I < Count; ++I)
20+
(*__fini_array_start[I])();
21+
}
22+
23+
void _start() { callFini(); }

0 commit comments

Comments
 (0)