1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
|
.\" $NetBSD: stack.7,v 1.8 2026/04/23 20:09:46 uwe Exp $
.\"
.\" Copyright (c) 2023 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd April 23, 2026
.Dt STACK 7
.Os
.Sh NAME
.Nm stack
.Nd layout of program execution stack memory
.Sh DESCRIPTION
When executing a program, with the
.Xr execve 2
or
.Xr posix_spawn 3
families of system calls,
.Nx
reserves a region in the new program image's virtual address space for
the
.Em stack ,
which stores return addresses and local variables for nested procedure
calls in program execution.
Similarly, threads created with
.Xr pthread_create 3
have regions allocated for per-thread stacks.
.Pp
The stack grows from the
.Em base ,
where information of the outermost procedure call is stored, fixed at
program start, to the
.Em stack pointer ,
a
.Tn CPU
register that points to information used by the current procedure call,
varying during execution as procedures are called.
.Pp
On most architectures, the stack base is at higher-numbered virtual
addresses and the stack pointer is at lower-numbered virtual addresses
\(em on these architectures,
.Em the stack grows down .
On some other architectures, notably
.Tn HP PA-RISC
.Pq Sq hppa ,
the stack base is at lower-numbered virtual addresses and the stack
pointer is at higher-numbered virtual addresses, so on those
architectures
.Em the stack grows up .
.Pp
In the kernel, the C preprocessor macro
.Dv __HAVE_MACHINE_STACK_GROWS_UP
is defined in
.In machine/types.h
on architectures where the stack grows up.
.Ss Main thread
For single-threaded programs, and for the main thread of multi-threaded
programs,
.Nx
reserves virtual addresses as follows on architectures where the stack
grows
.Em down :
.Bd -literal -offset indent
+--------------------+ USRSTACK
| ASLR stack gap |
+--------------------+ stack base
| accessible pages |
| . |
| . | <-- stack pointer
| . | (varies during execution)
| V |
+--------------------+ (stack base) - (soft stack rlimit)
| inaccessible pages |
+--------------------+ (stack base) - (hard stack rlimit)
| guard/redzone |
+--------------------+ USRSTACK - MAXSSIZ
.Ed
.Pp
On architectures where the stack grows
.Em up ,
the layout is:
.Bd -literal -offset indent
+--------------------+ USRSTACK + MAXSSIZ
| guard/redzone |
+--------------------+ (stack base) + (hard stack rlimit)
| inaccessible pages |
+--------------------+ (stack base) + (soft stack rlimit)
| \(ha |
| . | <-- stack pointer
| . | (varies during execution)
| . |
| accessible pages |
+--------------------+ stack base
| ASLR stack gap |
+--------------------+ USRSTACK
.Ed
.Bl -bullet
.It
The
.Em stack guard
is allocated so that any access \(em read, write, or execute \(em will
deliver
.Dv SIGSEGV
to the process.
This serves to detect stack overflow and crash rather than silently
overwrite other memory in the program's virtual address space.
The size of the stack guard is tuned by the
.Li vm.guard_size
.Xr sysctl 7
knob.
.Pp
The stack guard is also sometimes known as the
.Sq redzone
or
.Sq red zone ,
although the term
.Sq red zone
is also sometimes used to mean a fixed space
.Em above
the stack pointer (in the direction of stack growth) that the system
guarantees it will not overwrite when calling a signal handler in the
.Tn ABI
of some architectures; see also
.Xr sigaltstack 2
to specify an alternate stack base for the kernel to use when invoking
signal handlers on signal delivery.
.It
The
.Em inaccessible pages
of the stack region are allocated so that any access will also deliver
.Dv SIGSEGV
to the process, but they can be made accessible by changing the soft
stack rlimit with
.Xr setrlimit 2 .
.It
The
.Em accessible pages
of the stack region are allocated with read/write access permitted, and
are used to store the actual data in the program stack.
.It
When
.Tn PaX ASLR ,
address space layout randomization, is enabled, the
.Em stack gap
is an
.Em unallocated
space of a size chosen unpredictably at random at program startup time.
When
.Tn PaX ASLR
is disabled, the stack gap is empty.
.El
.Pp
All of the boundaries \(em
.Dv USRSTACK ,
the stack base, and the boundaries between the accessible,
inaccessible, and guard pages \(em are page-aligned, or rounded to be
page-aligned even if the rlimits are not themselves page-aligned,
rounding so that the sizes of the regions do not exceed the rlimits.
.Pp
The stack base is exposed to programs via the
.Dv AT_STACKBASE
.Xr elf 5
auxiliary info vector entry.
.Pp
The per-architecture constants
.Dv USRSTACK
and
.Dv MAXSSIZ
are defined in
.In machine/vmparam.h .
.Ss Non-main threads
Threads created with
.Xr pthread_create 3
have stacks allocated at dynamically chosen addresses outside the main
thread's stack region by default, and their stacks cannot be resized
after creation.
On architectures where the stack grows
.Em down ,
the layout is:
.Bd -literal -offset indent
+--------------------+ stack base = stackaddr + stacksize
| stack |
| . |
| . | <-- stack pointer
| . | (varies during execution)
| V |
+--------------------+ stackaddr
| guard/redzone |
+--------------------+ stackaddr - guardsize
.Ed
.Pp
On architectures where the stack grows
.Em up ,
the layout is:
.Bd -literal -offset indent
+--------------------+ stackaddr + stacksize + guardsize
| guard/redzone |
+--------------------+ stackaddr + stacksize
| \(ha |
| . | <-- stack pointer
| . | (varies during execution)
| . |
| stack |
+--------------------+ stack base = stackaddr
.Ed
.Pp
The parameters stackaddr, stacksize, and guardsize can be obtained from
an existing thread using
.Xr pthread_getattr_np 3 ,
.Xr pthread_attr_getguardsize 3 ,
and the
.Xr pthread_attr_getstack 3
family of functions.
.Pp
When creating a thread, the stack can be manually allocated and the
parameters can be set using
.Xr pthread_attr_setguardsize 3
and the
.Xr pthread_attr_setstack 3
family of functions.
However, the stack parameters cannot be changed after thread creation.
The default guard size is tuned by the
.Li vm.thread_guard_size
.Xr sysctl 7
knob.
.Pp
For the main thread,
.Xr pthread_getattr_np 3
returns a
.Em snapshot
of the parameters as they existed at program startup, so that stackaddr
and stacksize reflect the current accessible pages of the stack, and
guardsize is the value of the
.Li vm.guard_size
.Xr sysctl 7
knob at the time of program startup.
.Po
Note that this means the
.Xr pthread 3
view of the main thread's stack guard may not coincide with the actual
stack guard \(em it may overlap with, or lie entirely in, the
inaccessible pages of the stack reserved on program start.
.Pc
However, if the program changes its soft stack rlimit with
.Xr setrlimit 2 ,
this snapshot may become stale.
.Sh SEE ALSO
.Xr execve 2 ,
.Xr mmap 2 ,
.Xr mprotect 2 ,
.Xr sigaltstack 2 ,
.Xr ucontext 2 ,
.Xr posix_spawn 3 ,
.Xr pthread 3 ,
.Xr security 7 ,
.Xr sysctl 7 ,
.Xr paxctl 8
.Sh BUGS
.Tn PaX ASLR
doesn't actually guarantee an accessible stack reservation of length
equal to the soft stack rlimit \(em owing to a bug (XXX which PR
number?),
.Nx
may sometimes reserve less space than the soft rlimit, in which case
the accessible pages of the stack cannot be extended.
.Pp
There is a race between the kernel's access of
.Li vm.guard_size
at exec time, and userland's access of
.Li vm.guard_size
in
.Xr pthread 3
initialization.
|