]> git.lizzy.rs Git - rust.git/blob - src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md
Rollup merge of #85663 - fee1-dead:document-arc-from, r=m-ou-se
[rust.git] / src / doc / unstable-book / src / compiler-flags / emit-stack-sizes.md
1 # `emit-stack-sizes`
2
3 The tracking issue for this feature is: [#54192]
4
5 [#54192]: https://github.com/rust-lang/rust/issues/54192
6
7 ------------------------
8
9 The rustc flag `-Z emit-stack-sizes` makes LLVM emit stack size metadata.
10
11 > **NOTE**: This LLVM feature only supports the ELF object format as of LLVM
12 > 8.0. Using this flag with targets that use other object formats (e.g. macOS
13 > and Windows) will result in it being ignored.
14
15 Consider this crate:
16
17 ```
18 #![crate_type = "lib"]
19
20 use std::ptr;
21
22 pub fn foo() {
23     // this function doesn't use the stack
24 }
25
26 pub fn bar() {
27     let xs = [0u32; 2];
28
29     // force LLVM to allocate `xs` on the stack
30     unsafe { ptr::read_volatile(&xs.as_ptr()); }
31 }
32 ```
33
34 Using the `-Z emit-stack-sizes` flag produces extra linker sections in the
35 output *object file*.
36
37 ``` console
38 $ rustc -C opt-level=3 --emit=obj foo.rs
39
40 $ size -A foo.o
41 foo.o  :
42 section                                 size   addr
43 .text                                      0      0
44 .text._ZN3foo3foo17he211d7b4a3a0c16eE      1      0
45 .text._ZN3foo3bar17h1acb594305f70c2eE     22      0
46 .note.GNU-stack                            0      0
47 .eh_frame                                 72      0
48 Total                                     95
49
50 $ rustc -C opt-level=3 --emit=obj -Z emit-stack-sizes foo.rs
51
52 $ size -A foo.o
53 foo.o  :
54 section                                 size   addr
55 .text                                      0      0
56 .text._ZN3foo3foo17he211d7b4a3a0c16eE      1      0
57 .stack_sizes                               9      0
58 .text._ZN3foo3bar17h1acb594305f70c2eE     22      0
59 .stack_sizes                               9      0
60 .note.GNU-stack                            0      0
61 .eh_frame                                 72      0
62 Total                                    113
63 ```
64
65 As of LLVM 7.0 the data will be written into a section named `.stack_sizes` and
66 the format is "an array of pairs of function symbol values (pointer size) and
67 stack sizes (unsigned LEB128)".
68
69 ``` console
70 $ objdump -d foo.o
71
72 foo.o:     file format elf64-x86-64
73
74 Disassembly of section .text._ZN3foo3foo17he211d7b4a3a0c16eE:
75
76 0000000000000000 <_ZN3foo3foo17he211d7b4a3a0c16eE>:
77    0:   c3                      retq
78
79 Disassembly of section .text._ZN3foo3bar17h1acb594305f70c2eE:
80
81 0000000000000000 <_ZN3foo3bar17h1acb594305f70c2eE>:
82    0:   48 83 ec 10             sub    $0x10,%rsp
83    4:   48 8d 44 24 08          lea    0x8(%rsp),%rax
84    9:   48 89 04 24             mov    %rax,(%rsp)
85    d:   48 8b 04 24             mov    (%rsp),%rax
86   11:   48 83 c4 10             add    $0x10,%rsp
87   15:   c3                      retq
88
89 $ objdump -s -j .stack_sizes foo.o
90
91 foo.o:     file format elf64-x86-64
92
93 Contents of section .stack_sizes:
94  0000 00000000 00000000 00                 .........
95 Contents of section .stack_sizes:
96  0000 00000000 00000000 10                 .........
97 ```
98
99 It's important to note that linkers will discard this linker section by default.
100 To preserve the section you can use a linker script like the one shown below.
101
102 ``` text
103 /* file: keep-stack-sizes.x */
104 SECTIONS
105 {
106   /* `INFO` makes the section not allocatable so it won't be loaded into memory */
107   .stack_sizes (INFO) :
108   {
109     KEEP(*(.stack_sizes));
110   }
111 }
112 ```
113
114 The linker script must be passed to the linker using a rustc flag like `-C
115 link-arg`.
116
117 ```
118 // file: src/main.rs
119 use std::ptr;
120
121 #[inline(never)]
122 fn main() {
123     let xs = [0u32; 2];
124
125     // force LLVM to allocate `xs` on the stack
126     unsafe { ptr::read_volatile(&xs.as_ptr()); }
127 }
128 ```
129
130 ``` console
131 $ RUSTFLAGS="-Z emit-stack-sizes" cargo build --release
132
133 $ size -A target/release/hello | grep stack_sizes || echo section was not found
134 section was not found
135
136 $ RUSTFLAGS="-Z emit-stack-sizes" cargo rustc --release -- \
137     -C link-arg=-Wl,-Tkeep-stack-sizes.x \
138     -C link-arg=-N
139
140 $ size -A target/release/hello | grep stack_sizes
141 .stack_sizes                               90   176272
142
143 $ # non-allocatable section (flags don't contain the "A" (alloc) flag)
144 $ readelf -S target/release/hello
145 Section Headers:
146   [Nr]   Name              Type             Address           Offset
147        Size              EntSize            Flags  Link  Info  Align
148 (..)
149   [1031] .stack_sizes      PROGBITS         000000000002b090  0002b0f0
150        000000000000005a  0000000000000000   L       5     0     1
151
152 $ objdump -s -j .stack_sizes target/release/hello
153
154 target/release/hello:     file format elf64-x86-64
155
156 Contents of section .stack_sizes:
157  2b090 c0040000 00000000 08f00400 00000000  ................
158  2b0a0 00080005 00000000 00000810 05000000  ................
159  2b0b0 00000000 20050000 00000000 10400500  .... ........@..
160  2b0c0 00000000 00087005 00000000 00000080  ......p.........
161  2b0d0 05000000 00000000 90050000 00000000  ................
162  2b0e0 00a00500 00000000 0000               ..........
163 ```
164
165 > Author note: I'm not entirely sure why, in *this* case, `-N` is required in
166 > addition to `-Tkeep-stack-sizes.x`. For example, it's not required when
167 > producing statically linked files for the ARM Cortex-M architecture.