Chapter 4: Virtual Process Memory
The idea is to limit the maximal stack size to a fixedvalue. Since the stack is bounded, the region into
which memory mappings are installed can then be started immediately below the end of the stack. In
contrast to the classical approach, it now expandsfrom top to bottom. Since the heap is still located in the
lower region of the virtual address space and grows upward, both mmap region and heap can expand
until there is really no portion of the virtual address space left. To ensure that the stack does not collide
with the mmap region, a safety gap is installed between both.
4.2.2 Creating the Layout
The address space of a task is laid out when an ELF binary is loaded withload_elf_binary—recallthat
the function is used by theexecsystem call. Loading an ELF file is cluttered with numerous technical
details that are not interesting for our purposes, so the code flow diagram in Figure 4-3 concentrates on
the steps required to set up the virtual memory region.
Set PF_RANDOMIZE if required
load_elf_binary
arch_pick_mmap_layout
setup_arg_pages
Figure 4-3: Code flow diagram for
load_elf_binary.
Address space randomization is enabled if the global variablerandomize_va_spaceis set to 1. This is
usually the case, but is disabled for Transmeta CPUs because it has a negative speed impact on such
machines. Besides, the user can use/proc/sys/kernel/randomize_va_spaceto disable the feature.
The address space layout is selected inarch_pick_mmap_layout. If the architecture does not provide
a specific function, the kernel’s default routine sets up the address space as shown in Figure 4-1. It is,
however, more interesting to observe how IA-32 chooses between the classical and the new alternative:
arch/x86/mm/mmap_32.c
void arch_pick_mmap_layout(struct mm_struct *mm)
{
/*
* Fall back to the standard layout if the personality
* bit is set, or if the expected stack growth is unlimited:
*/
if (sysctl_legacy_va_layout ||
(current->personality & ADDR_COMPAT_LAYOUT) ||
current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
{
mm->mmap_base = TASK_UNMAPPED_BASE;
mm->get_unmapped_area = arch_get_unmapped_area;
mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base(mm);