cranelift: Add a flag for preserving frame pointers (#4469)

Preserving frame pointers -- even inside leaf functions -- makes it easy to
capture the stack of a running program, without requiring any side tables or
metadata (like `.eh_frame` sections). Many sampling profilers and similar tools
walk frame pointers to capture stacks. Enabling this option will play nice with
those tools.
This commit is contained in:
Nick Fitzgerald
2022-07-20 08:02:21 -07:00
committed by GitHub
parent 6e099720af
commit 22d91a7c84
8 changed files with 96 additions and 7 deletions

View File

@@ -237,6 +237,19 @@ pub(crate) fn define() -> SettingGroup {
true,
);
settings.add_bool(
"preserve_frame_pointers",
"Preserve frame pointers",
r#"
Preserving frame pointers -- even inside leaf functions -- makes it
easy to capture the stack of a running program, without requiring any
side tables or metadata (like `.eh_frame` sections). Many sampling
profilers and similar tools walk frame pointers to capture stacks.
Enabling this option will play nice with those tools.
"#,
false,
);
settings.add_bool(
"machine_code_cfg_info",
"Generate CFG metadata for machine code.",
@@ -324,7 +337,7 @@ pub(crate) fn define() -> SettingGroup {
for the out-of-bounds case, a misspeculation of that conditional
branch (falsely predicted in-bounds) will select an in-bounds
index to load on the speculative path.
This option is enabled by default because it is highly
recommended for secure sandboxing. The embedder should consider
the security implications carefully before disabling this option.

View File

@@ -1410,12 +1410,13 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
if !self.call_conv.extends_baldrdash() {
self.fixed_frame_storage_size += total_stacksize;
self.setup_frame = M::is_frame_setup_needed(
self.is_leaf,
self.stack_args_size(),
clobbered_callee_saves.len(),
self.fixed_frame_storage_size,
);
self.setup_frame = self.flags.preserve_frame_pointers()
|| M::is_frame_setup_needed(
self.is_leaf,
self.stack_args_size(),
clobbered_callee_saves.len(),
self.fixed_frame_storage_size,
);
insts.extend(
M::gen_debug_frame_info(self.call_conv, &self.flags, &self.isa_flags).into_iter(),

View File

@@ -541,6 +541,7 @@ enable_atomics = true
enable_safepoints = false
enable_llvm_abi_extensions = false
unwind_info = true
preserve_frame_pointers = false
machine_code_cfg_info = false
emit_all_ones_funcaddrs = false
enable_probestack = true

View File

@@ -0,0 +1,15 @@
;; Test compilation of leaf functions without preserving frame pointers.
test compile precise-output
set unwind_info=false
set preserve_frame_pointers=false
target aarch64
function %leaf(i64) -> i64 {
block0(v0: i64):
return v0
}
; block0:
; ret

View File

@@ -0,0 +1,18 @@
;; Test compilation of leaf functions while preserving frame pointers.
test compile precise-output
set unwind_info=false
set preserve_frame_pointers=true
target aarch64
function %leaf(i64) -> i64 {
block0(v0: i64):
return v0
}
; stp fp, lr, [sp, #-16]!
; mov fp, sp
; block0:
; ldp fp, lr, [sp], #16
; ret

View File

@@ -0,0 +1,20 @@
;; Test compilation of leaf functions without preserving frame pointers.
test compile precise-output
set unwind_info=false
set preserve_frame_pointers=false
target x86_64
function %leaf(i64) -> i64 {
block0(v0: i64):
return v0
}
; pushq %rbp
; movq %rsp, %rbp
; block0:
; movq %rdi, %rax
; movq %rbp, %rsp
; popq %rbp
; ret

View File

@@ -0,0 +1,20 @@
;; Test compilation of leaf functions while preserving frame pointers.
test compile precise-output
set unwind_info=false
set preserve_frame_pointers=true
target x86_64
function %leaf(i64) -> i64 {
block0(v0: i64):
return v0
}
; pushq %rbp
; movq %rsp, %rbp
; block0:
; movq %rdi, %rax
; movq %rbp, %rsp
; popq %rbp
; ret

View File

@@ -393,6 +393,7 @@ impl Engine {
| "machine_code_cfg_info"
| "tls_model" // wasmtime doesn't use tls right now
| "opt_level" // opt level doesn't change semantics
| "preserve_frame_pointers" // we don't currently rely on frame pointers
| "enable_alias_analysis" // alias analysis-based opts don't change semantics
| "probestack_func_adjusts_sp" // probestack above asserted disabled
| "probestack_size_log2" // probestack above asserted disabled