I’m allocating memory using mmap
Linux syscall.
mov x5, 0 ; offset is zero mov x4, -1 ; no file descriptor mov x3, 0x22 ; MAP_PRIVATE + MAP_ANONYMOUS mov x2, 3 ; PROT_READ + PROT_WRITE mov x1, 4096 ; initial region size in bytes mov x0, 0 ; let Linux choose region address mov x8, 222 ; mmap svc 0
Is it possible to increase the size of allocated memory region preserving its start address and contents? How to do it properly?
Advertisement
Answer
On Linux, use the mremap(2)
Linux-specific system call without MREMAP_MAYMOVE
to extend the existing mapping, without considering the option of remapping those physical pages to a different virtual address where there’s enough room for the larger mapping.
It will return an error if some other mapping already exists for the pages you want to grow into. (Unlike mmap(MAP_FIXED)
which will silently replace those mappings.)
If you’re writing in asm, portability to non-Linux is barely relevant; other OSes will have different call numbers and maybe ABIs, so just look up __NR_mremap
in asm/unistd.h
, and get the flags
patterns from sys/mman.h
.
With just portable POSIX calls, mmap()
with a non-NULL hint address = right after you existing mapping, but without MAP_FIXED
; it will pick that address if the pages are free (and as @datenwolf says, merge with the earlier mapping into one long extent). Otherwise it will pick somewhere else. (Then you have to munmap
that mapping that ended up not where you wanted it.)
There is a Linux-specific mmap
option: MAP_FIXED_NOREPLACE
will return an error instead of mapping at an address different from the hint. Kernels older than 4.17 don’t know about that flag and will typically treat it as if you used no other flags besides MAP_ANONYMOUS
, so you should check the return value against the hint.
Do not use MAP_FIXED_NOREPLACE | MAP_FIXED
; that would act as MAP_FIXED
on old kernels, and maybe also on new kernels that do know about MAP_FIXED_NOREPLACE
.
Assuming you know the start of the mapping you want to extend, and the desired new total size, mremap
is a better choice than mmap(MAP_FIXED_NOREPLACE)
. It’s been supported since at least Linux 2.4, i.e. decades, and keeps the existing mapping flags and permissions automatically (e.g. MAP_PRIVATE, PROT_READ|PROT_WRITE)
If you only knew the end address of the existing mapping, mmap(MAP_FIXED_NOREPLACE)
might be a good choice.