Skip to content

Commit f2c50f9

Browse files
authored
[BOLT] Support restartable sequences in tcmalloc (#167195)
Add `RSeqRewriter` to detect code references from `__rseq_cs` section and ignore function referenced from that section. Code references are detected via relocations (static or dynamic). Note that the abort handler is preceded by a 4-byte signature byte sequence and we cannot relocate the handler without that the signature, otherwise the application may crash. Thus we are ignoring the function, i.e. making sure it's not separated from its signature.
1 parent 4023beb commit f2c50f9

File tree

5 files changed

+117
-2
lines changed

5 files changed

+117
-2
lines changed

bolt/include/bolt/Rewrite/MetadataRewriters.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ class BinaryContext;
1919

2020
// The list of rewriter build functions.
2121

22-
std::unique_ptr<MetadataRewriter> createLinuxKernelRewriter(BinaryContext &);
23-
2422
std::unique_ptr<MetadataRewriter> createBuildIDRewriter(BinaryContext &);
2523

24+
std::unique_ptr<MetadataRewriter> createLinuxKernelRewriter(BinaryContext &);
25+
2626
std::unique_ptr<MetadataRewriter> createPseudoProbeRewriter(BinaryContext &);
2727

28+
std::unique_ptr<MetadataRewriter> createRSeqRewriter(BinaryContext &);
29+
2830
std::unique_ptr<MetadataRewriter> createSDTRewriter(BinaryContext &);
2931

3032
std::unique_ptr<MetadataRewriter> createGNUPropertyRewriter(BinaryContext &);

bolt/lib/Rewrite/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ add_llvm_library(LLVMBOLTRewrite
2424
BuildIDRewriter.cpp
2525
PseudoProbeRewriter.cpp
2626
RewriteInstance.cpp
27+
RSeqRewriter.cpp
2728
SDTRewriter.cpp
2829
GNUPropertyRewriter.cpp
2930

bolt/lib/Rewrite/RSeqRewriter.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//===- bolt/Rewrite/RSeqRewriter.cpp --------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Basic support for restartable sequences used by tcmalloc. Prevent critical
10+
// section overrides by ignoring optimizations in containing functions.
11+
//
12+
// References:
13+
// * https://google.github.io/tcmalloc/rseq.html
14+
// * tcmalloc/internal/percpu_rseq_x86_64.S
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#include "bolt/Core/BinaryFunction.h"
19+
#include "bolt/Rewrite/MetadataRewriter.h"
20+
#include "bolt/Rewrite/MetadataRewriters.h"
21+
#include "llvm/Support/Errc.h"
22+
23+
using namespace llvm;
24+
using namespace bolt;
25+
26+
namespace {
27+
28+
class RSeqRewriter final : public MetadataRewriter {
29+
public:
30+
RSeqRewriter(StringRef Name, BinaryContext &BC)
31+
: MetadataRewriter(Name, BC) {}
32+
33+
Error preCFGInitializer() override {
34+
for (const BinarySection &Section : BC.allocatableSections()) {
35+
if (Section.getName() != "__rseq_cs")
36+
continue;
37+
38+
auto handleRelocation = [&](const Relocation &Rel, bool IsDynamic) {
39+
BinaryFunction *BF = nullptr;
40+
if (Rel.Symbol)
41+
BF = BC.getFunctionForSymbol(Rel.Symbol);
42+
else if (Relocation::isRelative(Rel.Type))
43+
BF = BC.getBinaryFunctionContainingAddress(Rel.Addend);
44+
45+
if (!BF) {
46+
BC.errs() << "BOLT-WARNING: no function found matching "
47+
<< (IsDynamic ? "dynamic " : "")
48+
<< "relocation in __rseq_cs\n";
49+
} else if (!BF->isIgnored()) {
50+
BC.outs() << "BOLT-INFO: restartable sequence reference detected in "
51+
<< *BF << ". Function will not be optimized\n";
52+
BF->setIgnored();
53+
}
54+
};
55+
56+
for (const Relocation &Rel : Section.dynamicRelocations())
57+
handleRelocation(Rel, /*IsDynamic*/ true);
58+
59+
for (const Relocation &Rel : Section.relocations())
60+
handleRelocation(Rel, /*IsDynamic*/ false);
61+
}
62+
63+
return Error::success();
64+
}
65+
};
66+
67+
} // namespace
68+
69+
std::unique_ptr<MetadataRewriter>
70+
llvm::bolt::createRSeqRewriter(BinaryContext &BC) {
71+
return std::make_unique<RSeqRewriter>("rseq-cs-rewriter", BC);
72+
}

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3346,6 +3346,8 @@ void RewriteInstance::initializeMetadataManager() {
33463346

33473347
MetadataManager.registerRewriter(createPseudoProbeRewriter(*BC));
33483348

3349+
MetadataManager.registerRewriter(createRSeqRewriter(*BC));
3350+
33493351
MetadataManager.registerRewriter(createSDTRewriter(*BC));
33503352

33513353
MetadataManager.registerRewriter(createGNUPropertyRewriter(*BC));

bolt/test/X86/rseq.s

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## Check that llvm-bolt avoids optimization of functions referenced from
2+
## __rseq_cs section, i.e. containing critical sections and abort handlers used
3+
## by restartable sequences in tcmalloc.
4+
5+
# RUN: %clang %cflags %s -o %t -nostdlib -no-pie -Wl,-q
6+
# RUN: llvm-bolt %t -o %t.bolt --print-cfg 2>&1 | FileCheck %s
7+
# RUN: %clang %cflags %s -o %t.pie -nostdlib -pie -Wl,-q
8+
# RUN: llvm-bolt %t.pie -o %t.pie.bolt 2>&1 | FileCheck %s
9+
10+
# CHECK: restartable sequence reference detected in _start
11+
# CHECK: restartable sequence reference detected in __rseq_abort
12+
13+
## Force relocations against .text
14+
.text
15+
.reloc 0, R_X86_64_NONE
16+
17+
.global _start
18+
.type _start, %function
19+
_start:
20+
pushq %rbp
21+
mov %rsp, %rbp
22+
.L1:
23+
pop %rbp
24+
.L2:
25+
retq
26+
.size _start, .-_start
27+
28+
.section __rseq_abort, "ax"
29+
## Signature for rseq abort IP. Unmarked in the symbol table.
30+
.byte 0x0f, 0x1f, 0x05
31+
.long 0x42424242
32+
.L3:
33+
jmp .L2
34+
35+
.section __rseq_cs, "aw"
36+
.balign 32
37+
.quad .L1
38+
.quad .L3

0 commit comments

Comments
 (0)