Skip to content
Advertisement

How to increase the size of memory region allocated with mmap()

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.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement