From 3c0907ce51f51bbedeb63b482041e4a8e1239364 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 13 Sep 2018 19:43:15 +0200 Subject: [PATCH 1/8] add -Z emit-stack-sizes --- src/librustc/session/config.rs | 2 ++ src/librustc_codegen_llvm/back/write.rs | 2 ++ src/librustc_codegen_llvm/llvm/ffi.rs | 3 ++- src/rustllvm/PassWrapper.cpp | 5 ++++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8fa15d48a5dc9..eb779e6382f4b 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1385,6 +1385,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "run the self profiler"), profile_json: bool = (false, parse_bool, [UNTRACKED], "output a json file with profiler results"), + emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], + "emits a section containing stack size metadata"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 447b505e79c62..02ef690b94233 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -196,6 +196,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool) let features = CString::new(features).unwrap(); let is_pie_binary = !find_features && is_pie_binary(sess); let trap_unreachable = sess.target.target.options.trap_unreachable; + let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; let asm_comments = sess.asm_comments(); @@ -213,6 +214,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool) trap_unreachable, singlethread, asm_comments, + emit_stack_size_section, ) }; diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index a5f4137c62b14..845f2fa9f45a6 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1460,7 +1460,8 @@ extern "C" { DataSections: bool, TrapUnreachable: bool, Singlethread: bool, - AsmComments: bool) + AsmComments: bool, + EmitStackSizeSection: bool) -> Option<&'static mut TargetMachine>; pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine); pub fn LLVMRustAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>, M: &'a Module); diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 5c4bb61781ed1..06f75d981e3d6 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -373,7 +373,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( bool DataSections, bool TrapUnreachable, bool Singlethread, - bool AsmComments) { + bool AsmComments, + bool EmitStackSizeSection) { auto OptLevel = fromRust(RustOptLevel); auto RM = fromRust(RustReloc); @@ -411,6 +412,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( } #if LLVM_VERSION_GE(6, 0) + Options.EmitStackSizeSection = EmitStackSizeSection; + Optional CM; #else CodeModel::Model CM = CodeModel::Model::Default; From 39afcd0673cb8fc04944ede0402dd2479bb57300 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 13 Sep 2018 19:46:52 +0200 Subject: [PATCH 2/8] document this feature in the unstable book --- .../src/compiler-flags/emit-stack-sizes.md | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md diff --git a/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md b/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md new file mode 100644 index 0000000000000..56cb6409201e4 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md @@ -0,0 +1,153 @@ +# `emit-stack-sizes` + +The tracking issue for this feature is: [#54192] + +[#54192]: https://github.com/rust-lang/rust/issues/54192 + +------------------------ + +The rustc flag `-Z emit-stack-sizes` makes LLVM emit stack size metadata. + +Consider this crate: + +``` +#![crate_type = "lib"] + +use std::ptr; + +pub fn foo() { + // this function doesn't use the stack +} + +pub fn bar() { + let xs = [0u32; 2]; + + // force LLVM to allocate `xs` on the stack + unsafe { ptr::read_volatile(&xs.as_ptr()); } +} +``` + +Using the `-Z emit-stack-sizes` flag produces extra linker sections in the +output *object file*. + +``` console +$ rustc -C opt-level=3 --emit=obj foo.rs + +$ size -A foo.o +foo.o : +section size addr +.text 0 0 +.text._ZN3foo3foo17he211d7b4a3a0c16eE 1 0 +.text._ZN3foo3bar17h1acb594305f70c2eE 22 0 +.note.GNU-stack 0 0 +.eh_frame 72 0 +Total 95 + +$ rustc -C opt-level=3 --emit=obj -Z emit-stack-sizes foo.rs + +$ size -A foo.o +foo.o : +section size addr +.text 0 0 +.text._ZN3foo3foo17he211d7b4a3a0c16eE 1 0 +.stack_sizes 9 0 +.text._ZN3foo3bar17h1acb594305f70c2eE 22 0 +.stack_sizes 9 0 +.note.GNU-stack 0 0 +.eh_frame 72 0 +Total 113 +``` + +As of LLVM 7.0 the data will be written into a section named `.stack_sizes` and +the format is "an array of pairs of function symbol values (pointer size) and +stack sizes (unsigned LEB128)". + +``` console +$ objdump -d foo.o + +foo.o: file format elf64-x86-64 + +Disassembly of section .text._ZN3foo3foo17he211d7b4a3a0c16eE: + +0000000000000000 <_ZN3foo3foo17he211d7b4a3a0c16eE>: + 0: c3 retq + +Disassembly of section .text._ZN3foo3bar17h1acb594305f70c2eE: + +0000000000000000 <_ZN3foo3bar17h1acb594305f70c2eE>: + 0: 48 83 ec 10 sub $0x10,%rsp + 4: 48 8d 44 24 08 lea 0x8(%rsp),%rax + 9: 48 89 04 24 mov %rax,(%rsp) + d: 48 8b 04 24 mov (%rsp),%rax + 11: 48 83 c4 10 add $0x10,%rsp + 15: c3 retq + +$ objdump -s -j .stack_sizes foo.o + +foo.o: file format elf64-x86-64 + +Contents of section .stack_sizes: + 0000 00000000 00000000 00 ......... +Contents of section .stack_sizes: + 0000 00000000 00000000 10 ......... +``` + +It's important to note that linkers will discard this linker section by default. +To preserve the section you can use a linker script like the one shown below. + +``` text +/* file: keep-stack-sizes.x */ +SECTIONS +{ + .stack_sizes : + { + KEEP(*(.stack_sizes)); + } +} +``` + +The linker script must be passed to the linker using a rustc flag like `-C +link-arg`. + +``` +// file: src/main.rs +use std::ptr; + +#[inline(never)] +fn main() { + let xs = [0u32; 2]; + + // force LLVM to allocate `xs` on the stack + unsafe { ptr::read_volatile(&xs.as_ptr()); } +} +``` + +``` console +$ RUSTFLAGS="-Z emit-stack-sizes" cargo build --release + +$ size -A target/release/hello | grep stack_sizes || echo section was not found +section was not found + +$ RUSTFLAGS="-Z emit-stack-sizes" cargo rustc --release -- \ + -C link-arg=-Wl,-Tkeep-stack-sizes.x \ + -C link-arg=-N + +$ size -A target/release/hello | grep stack_sizes +.stack_sizes 90 205368 + +$ objdump -s -j .stack_sizes target/release/hello + +target/release/hello: file format elf64-x86-64 + +Contents of section .stack_sizes: + 32238 c0040000 00000000 08f00400 00000000 ................ + 32248 00080005 00000000 00000810 05000000 ................ + 32258 00000000 20050000 00000000 10400500 .... ........@.. + 32268 00000000 00087005 00000000 00000080 ......p......... + 32278 05000000 00000000 90050000 00000000 ................ + 32288 00a00500 00000000 0000 .......... +``` + +> Author note: I'm not entirely sure why, in *this* case, `-N` is required in +> addition to `-Tkeep-stack-sizes.x`. For example, it's not required when +> producing statically linked files for the ARM Cortex-M architecture. From f5bc6782554b7d55678d0ed4256cba4586be4208 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 13 Sep 2018 20:25:58 +0200 Subject: [PATCH 3/8] add run-make test --- .../run-make-fulldeps/emit-stack-sizes/Makefile | 12 ++++++++++++ src/test/run-make-fulldeps/emit-stack-sizes/foo.rs | 13 +++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/run-make-fulldeps/emit-stack-sizes/Makefile create mode 100644 src/test/run-make-fulldeps/emit-stack-sizes/foo.rs diff --git a/src/test/run-make-fulldeps/emit-stack-sizes/Makefile b/src/test/run-make-fulldeps/emit-stack-sizes/Makefile new file mode 100644 index 0000000000000..b6b8113633d6e --- /dev/null +++ b/src/test/run-make-fulldeps/emit-stack-sizes/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +ifdef IS_WINDOWS +# Do nothing on MSVC. +all: + exit 0 +else +# check that the .stack_sizes section is generated +all: + $(RUSTC) -C opt-level=3 -Z emit-stack-sizes --emit=obj foo.rs + size -A $(TMPDIR)/foo.o | $(CGREP) .stack_sizes +endif diff --git a/src/test/run-make-fulldeps/emit-stack-sizes/foo.rs b/src/test/run-make-fulldeps/emit-stack-sizes/foo.rs new file mode 100644 index 0000000000000..6c81b63963a1c --- /dev/null +++ b/src/test/run-make-fulldeps/emit-stack-sizes/foo.rs @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +pub fn foo() {} From 5362752a1ef8698112d98efe40de6c39aa4480d9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 15 Sep 2018 23:19:07 +0200 Subject: [PATCH 4/8] run test only if LLVM version is >= 6.0.0 --- .../run-make-fulldeps/emit-stack-sizes/Makefile | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/run-make-fulldeps/emit-stack-sizes/Makefile b/src/test/run-make-fulldeps/emit-stack-sizes/Makefile index b6b8113633d6e..efe15f89c816b 100644 --- a/src/test/run-make-fulldeps/emit-stack-sizes/Makefile +++ b/src/test/run-make-fulldeps/emit-stack-sizes/Makefile @@ -6,7 +6,20 @@ all: exit 0 else # check that the .stack_sizes section is generated +# this test requires LLVM >= 6.0.0 +vers = $(shell llvm-ar -version) +ifneq (,$(findstring version 3,$(vers))) +all: + exit 0 +else ifneq (,$(findstring version 4,$(vers))) +all: + exit 0 +else ifneq (,$(findstring version 5,$(vers))) +all: + exit 0 +else all: $(RUSTC) -C opt-level=3 -Z emit-stack-sizes --emit=obj foo.rs size -A $(TMPDIR)/foo.o | $(CGREP) .stack_sizes endif +endif From 7d2bb283ce077059663a40588105cd0ce09182df Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 16 Sep 2018 21:29:57 +0200 Subject: [PATCH 5/8] use `rustc -Vv` in the run-make test --- src/test/run-make-fulldeps/emit-stack-sizes/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/run-make-fulldeps/emit-stack-sizes/Makefile b/src/test/run-make-fulldeps/emit-stack-sizes/Makefile index efe15f89c816b..6ed9b6c4314c6 100644 --- a/src/test/run-make-fulldeps/emit-stack-sizes/Makefile +++ b/src/test/run-make-fulldeps/emit-stack-sizes/Makefile @@ -7,14 +7,14 @@ all: else # check that the .stack_sizes section is generated # this test requires LLVM >= 6.0.0 -vers = $(shell llvm-ar -version) -ifneq (,$(findstring version 3,$(vers))) +vers = $(shell $(RUSTC) -Vv) +ifneq (,$(findstring LLVM version: 3,$(vers))) all: exit 0 -else ifneq (,$(findstring version 4,$(vers))) +else ifneq (,$(findstring LLVM version: 4,$(vers))) all: exit 0 -else ifneq (,$(findstring version 5,$(vers))) +else ifneq (,$(findstring LLVM version: 5,$(vers))) all: exit 0 else From 5e686b210477de8679820d063e1736857e55d923 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 16 Sep 2018 21:43:33 +0200 Subject: [PATCH 6/8] unstable-book: recommend an INFO section that makes the output .stack_sizes section non-allocatable when linking with either GNU LD or LLD --- .../src/compiler-flags/emit-stack-sizes.md | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md b/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md index 56cb6409201e4..b5456f9ba39ae 100644 --- a/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md +++ b/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md @@ -99,7 +99,8 @@ To preserve the section you can use a linker script like the one shown below. /* file: keep-stack-sizes.x */ SECTIONS { - .stack_sizes : + /* `INFO` makes the section not allocatable so it won't be loaded into memory */ + .stack_sizes (INFO) : { KEEP(*(.stack_sizes)); } @@ -133,19 +134,28 @@ $ RUSTFLAGS="-Z emit-stack-sizes" cargo rustc --release -- \ -C link-arg=-N $ size -A target/release/hello | grep stack_sizes -.stack_sizes 90 205368 +.stack_sizes 90 176272 + +$ # non-allocatable section (flags don't contain the "A" (alloc) flag) +$ readelf -S target/release/hello +Section Headers: + [Nr] Name Type Address Offset + Size EntSize Flags Link Info Align +(..) + [1031] .stack_sizes PROGBITS 000000000002b090 0002b0f0 + 000000000000005a 0000000000000000 L 5 0 1 $ objdump -s -j .stack_sizes target/release/hello target/release/hello: file format elf64-x86-64 Contents of section .stack_sizes: - 32238 c0040000 00000000 08f00400 00000000 ................ - 32248 00080005 00000000 00000810 05000000 ................ - 32258 00000000 20050000 00000000 10400500 .... ........@.. - 32268 00000000 00087005 00000000 00000080 ......p......... - 32278 05000000 00000000 90050000 00000000 ................ - 32288 00a00500 00000000 0000 .......... + 2b090 c0040000 00000000 08f00400 00000000 ................ + 2b0a0 00080005 00000000 00000810 05000000 ................ + 2b0b0 00000000 20050000 00000000 10400500 .... ........@.. + 2b0c0 00000000 00087005 00000000 00000080 ......p......... + 2b0d0 05000000 00000000 90050000 00000000 ................ + 2b0e0 00a00500 00000000 0000 .......... ``` > Author note: I'm not entirely sure why, in *this* case, `-N` is required in From 234e7c4d2efe249f1c38e23cf12ae84e65ee7e08 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 26 Sep 2018 15:25:57 +0200 Subject: [PATCH 7/8] docs: this llvm feature only supports the ELF object format --- src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md b/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md index b5456f9ba39ae..47f45a0b91f85 100644 --- a/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md +++ b/src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md @@ -8,6 +8,10 @@ The tracking issue for this feature is: [#54192] The rustc flag `-Z emit-stack-sizes` makes LLVM emit stack size metadata. +> **NOTE**: This LLVM feature only supports the ELF object format as of LLVM +> 8.0. Using this flag with targets that use other object formats (e.g. macOS +> and Windows) will result in it being ignored. + Consider this crate: ``` From 531e3566504f2bab929eaf57c4ba84838857933f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 26 Sep 2018 16:22:52 +0200 Subject: [PATCH 8/8] don't run the test on macOS --- src/test/run-make-fulldeps/emit-stack-sizes/Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/run-make-fulldeps/emit-stack-sizes/Makefile b/src/test/run-make-fulldeps/emit-stack-sizes/Makefile index 6ed9b6c4314c6..c2f643ce24c41 100644 --- a/src/test/run-make-fulldeps/emit-stack-sizes/Makefile +++ b/src/test/run-make-fulldeps/emit-stack-sizes/Makefile @@ -1,7 +1,13 @@ -include ../tools.mk +# This feature only works when the output object format is ELF so we ignore +# macOS and Windows ifdef IS_WINDOWS -# Do nothing on MSVC. +# Do nothing on Windows. +all: + exit 0 +else ifneq (,$(filter $(TARGET),i686-apple-darwin x86_64-apple-darwin)) +# Do nothing on macOS. all: exit 0 else