I try to figure out the range of the shared memory segment i.e. the memory mapping segment in the memory layout of a process, from two sources below.
From https://manybutfinite.com/post/anatomy-of-a-program-in-memory/, I found a diagram of memory layout of a process
Do memory mapping segment and heap grow until they meet each other?
Or is there a limit for each of the two segments to grow up to, similar to RLIMIT_STACK for the stack segement?
From The Linux Programming Interface
To allow space for heap and stack growth, shared
memory segments are attached starting at the virtual address 0x40000000 . Mapped
mappings (Chapter 49) and shared libraries (Chapters 41 and 42) are also placed in
this area. (There is some variation in the default location at which shared memory
mappings and memory segments are placed, depending on the kernel versions and
the setting of the process’s RLIMIT_STACK resource limit.)
The address 0x40000000 is defined as the kernel constant TASK_UNMAPPED_BASE.
Does the shared memory segment start at TASK_UNMAPPED_BASE and grow upward?
Note that the previous diagram shows the shared memory segment grow downward, so does it grow upward or downward?
Thanks.
Best Answer
There are a couple of limits which apply to the
mmap
segment and the heap segment.RLIMIT_AS
determines the available address space, overall; this covers all the memory allocations that a program can make.RLIMIT_DATA
determines the maximum size of the data segment.The kernel checks stack expansion,
mmap
, andbrk
(heap allocation) against these limits. It also checks allocations against potentially conflicting segments, so the segments never end up overwriting each other (see for example the checks performed for heap allocation withbrk
). If an allocation is impossible, the program is “informed” as appropriate: the C library returns anENOMEM
error forbrk
, the kernel kills the program with aSIGSEGV
if the stack can’t be expanded...How the shared memory segment (strictly speaking from the kernel perspective, virtual memory area) grows depends on the memory layout, which can very from one process to another. On most architectures, “legacy” memory maps result in bottom-up allocation, starting from
TASK_UNMAPPED_BASE
; non-legacy memory maps result in top-down allocation. Seearch_pick_mmap_layout()
andmmap_is_legacy()
in the x86 architecture for an example. You can switch to the legacy memory map usingsetarch
’s-L
flag (see below for an example).In practice, you can see how the segment grows by looking at
/proc/$$/maps
and checking the addresses of the loaded shared libraries (if any), v. their load order. The dynamic linker is always loaded first; if it has a lower address than other libraries, then allocation is bottom-up, otherwise it’s top-down. Compare the output ofcat /proc/self/maps
andsetarch x86_64 -L cat /proc/self/maps
on a 64-bit x86 system.