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 000000000000..56cb6409201e --- /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.