| STACK(7) | Miscellaneous Information Manual | STACK(7) | 
stack —
The stack grows from the base, where information of the outermost procedure call is stored, fixed at program start, to the stack pointer, a CPU register that points to information used by the current procedure call, varying during execution as procedures are called.
On most architectures, the stack base is at higher-numbered virtual addresses and the stack pointer is at lower-numbered virtual addresses — on these architectures, the stack grows down. On some other architectures, notably HP PA-RISC (‘hppa’), the stack base is at lower-numbered virtual addresses and the stack pointer is at higher-numbered virtual addresses, so on those architectures the stack grows up.
In the kernel, the C preprocessor macro
    __HAVE_MACHINE_STACK_GROWS_UP is defined in
    <machine/types.h> on
    architectures where the stack grows up.
+--------------------+ USRSTACK | stack gap | +--------------------+ stack base | accessible pages | | . | | . | <-- stack pointer (varies during execution) | . | +--------------------+ (stack base) - (soft stack rlimit) | inaccessible pages | +--------------------+ (stack base) - (hard stack rlimit) | guard/redzone | +--------------------+ USRSTACK - MAXSSIZ
On architectures where the stack grows up, the layout is:
+--------------------+ USRSTACK + MAXSSIZ | guard/redzone | +--------------------+ (stack base) + (hard stack rlimit) | inaccessible pages | +--------------------+ (stack base) + (soft stack rlimit) | . | | . | <-- stack pointer (varies during execution) | . | | accessible pages | +--------------------+ stack base | stack gap | +--------------------+ USRSTACK
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 vm.guard_size
      sysctl(7) knob.
    The stack guard is also sometimes known as the ‘redzone’ or ‘red zone’, although the term ‘red zone’ is also sometimes used to mean a fixed space 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 ABI of some architectures; see also sigaltstack(2) to specify an alternate stack base for the kernel to use when invoking signal handlers on signal delivery.
SIGSEGV to
      the process, but they can be made accessible by changing the soft stack
      rlimit with
    setrlimit(2).All of the boundaries — USRSTACK,
    the stack base, and the boundaries between the accessible, inaccessible, and
    guard pages — 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.
The stack base is exposed to programs via the
    AT_STACKBASE
    elf(5) auxiliary info vector
    entry.
The per-architecture constants USRSTACK
    and MAXSSIZ are defined in
    <machine/vmparam.h>.
+--------------------+ stack base = stackaddr + stacksize + guardsize | stack | | . | | . | <-- stack pointer (varies during execution) | . | +--------------------+ stackaddr | guard/redzone | +--------------------+ stackaddr - guardsize
On architectures where the stack grows up, the layout is:
+--------------------+ stackaddr + stacksize + guardsize | guard/redzone | +--------------------+ stackaddr + stacksize | . | | . | <-- stack pointer (varies during execution) | . | | stack | +--------------------+ stack base = stackaddr
The parameters stackaddr, stacksize, and guardsize can be obtained from an existing thread using pthread_getattr_np(3), pthread_attr_getguardsize(3), and the pthread_attr_getstack(3) family of functions.
When creating a thread, the stack can be manually allocated and
    the parameters can be set using
    pthread_attr_setguardsize(3)
    and the
    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
    vm.thread_guard_size
    sysctl(7) knob.
For the main thread,
    pthread_getattr_np(3)
    returns a 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
    vm.guard_size
    sysctl(7) knob at the time of
    program startup. (Note that this means the
    pthread(3) view of the main
    thread's stack guard may not coincide with the actual stack guard —
    it may overlap with, or lie entirely in, the inaccessible pages of the stack
    reserved on program start.) However, if the program changes its soft stack
    rlimit with setrlimit(2),
    this snapshot may become stale.
There is a race between the kernel's access of
    vm.guard_size at exec time, and userland's access of
    vm.guard_size in
    pthread(3)
  initialization.
| November 23, 2023 | NetBSD 10.1 |