stack-sizes
Tools to print stack usage information emitted by LLVM in human readable format
Background information
Since nightly-2018-09-27
rustc
has a (nightly only) -Z emit-stack-sizes
flag to (make LLVM) emit stack usage information about functions.
NOTE: This feature only works when the output artifact has the ELF object format.
The stack-sizes
tool parses the metadata emitted by that flag and prints it in
human readable format.
The cargo stack-sizes
subcommand does something similar but first it builds
the whole dependency graph with -Z emit-stack-sizes
.
Metadata format
The tools expect the object file to contain a .stack_sizes
section with stack
usage information emitted by LLVM (-stack-size-section
). For convenience,
the documentation about -stack-size-section
is copied below:
A section containing metadata on function stack sizes will be emitted when TargetLoweringObjectFile::StackSizesSection is not null, and TargetOptions::EmitStackSizeSection is set (-stack-size-section). The section will contain an array of pairs of function symbol values (pointer size) and stack sizes (unsigned LEB128). The stack size values only include the space allocated in the function prologue. Functions with dynamic stack allocations are not included.
Installation
$ cargo +stable install stack-sizes
Example usage
The recommended way to analyze your program is to use the cargo stack-sizes
subcommand.
Most targets will discard .stack_sizes
information at link time so the linking
process needs to be tweaked to keep the information in the final binary.
Consider a Cargo project named hello
with the following src/main.rs
file:
use ;
We'll use this linker script to preserve the
.stack_sizes
information. Place that linker script in the root of the Cargo
project.
$ cat keep-stack-sizes.x
SECTIONS
{
.stack_sizes (INFO) :
{
KEEP(*(.stack_sizes));
}
}
Now we can build the project. cargo stack-sizes
has a similar CLI to cargo rustc
. Flags after --
will be passed to the top rustc
invocation. We'll
use those flags to pass the linker script to the linker.
$ cargo +nightly stack-sizes \
--bin hello \
--release \
-v \
-- -C link-arg=-Wl,-Tkeep-stack-sizes.x -C link-arg=-N
RUSTC=stack-sizes-rustc "cargo" "rustc" "--bin" "hello" "--release" "--" "-C" "link-arg=-Wl,-Tkeep-stack-sizes.x" "-C" "link-arg=-N"
(..)
Finished release [optimized] target(s) in 0.63s
"stack-sizes" "target/release/hello"
address stack name
0x0000000000000550 24 hello::stack::hebd29682aa7dd994
0x00000000000004d0 8 std::rt::lang_start::h272a86063047800b
0x0000000000000500 8 std::rt::lang_start::{{closure}}::h22007b5ddf658a64
0x0000000000000510 8 core::ops::function::FnOnce::call_once::hb7bafcf111f236ed
0x0000000000000530 8 hello::main::hb36271094cf69f90
0x0000000000000590 8 main
0x00000000000004c0 0 core::array::<impl core::iter::traits::IntoIterator for &'a [T; _]>::into_iter::h63e320078b8d6e5b
0x0000000000000520 0 core::ptr::drop_in_place::h6545f3e9027cd0b3
0x0000000000000540 0 hello::registers::h16b8b9c5d4e45cf5
0x00000000000005c0 0 __rust_alloc
0x00000000000005d0 0 __rust_dealloc
0x00000000000005e0 0 __rust_realloc
0x00000000000005f0 0 __rust_alloc_zeroed
Library
This crate can also be used as a library to parse .stack_sizes
information.
The API documentation can be found here. It's
recommended to disable the default tool
feature of this crate, which builds
the tools, when using it as a library.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.