0

I need to find a way to use mmap instead of malloc. How is this possible? (I am not using libc only syscalls) And yes brk() is possible. I used sbrk() but realized its not sys-call... (x86 inline assembly)

I've been looking around and saw this: How to use mmap to allocate a memory in heap? But it didn't help for me, because I had a segfault.

Basically, all I want to do a create 3 slabs of memory for storing characters.

Say,

char * x = malloc(1000);
char * y = malloc(2000);
char * z = malloc(3000);

How is this possible with mmap and how to free it later with munmap?

Community
  • 1
  • 1
Kalon
  • 111
  • 1
  • 10
  • http://www.kernel.org/doc/man-pages/online/pages/man2/sbrk.2.html is a syscall, but a deprecated one. – Basile Starynkevitch Feb 09 '13 at 09:25
  • 1
    the glibc `malloc` uses `mmap` if appropriate (for example, if the amount of bytes to allocate is beyond a certain threshold) – Andreas Grapentin Feb 09 '13 at 09:25
  • 1
    taken from the malloc man page: Normally, malloc() allocates memory from the heap, and adjusts the size of the heap as required, using sbrk(2). When allocating blocks of memory larger than MMAP_THRESHOLD bytes, the glibc malloc() implementation allocates the memory as a private anonymous mapping using mmap(2). MAP_THRESHOLD is 128 kB by default, but is adjustable using mallopt(3). Allocations performed using mmap(2) are unaffected by the RLIMIT_DATA resource limit (see getrlimit(2)). – Andreas Grapentin Feb 09 '13 at 09:27
  • How are you not using libc? mmap and malloc are libc calls. – LtWorf Feb 09 '13 at 10:46
  • 1
    @LtWorf: `malloc` is indeed a standard `libc` function, but `mmap` is a system call, that can be called without any library.... like Flexo's answer shows.... – Basile Starynkevitch Feb 09 '13 at 11:24

2 Answers2

11

Did you carefully read the mmap(2) man page? I recommend reading it several times.

Notice that you can only ask the kernel [thru mmap etc...] to manage memory aligned to and multiple of the page size sysconf(_SC_PAGE_SIZE) which is often 4096 bytes (and I am supposing that in my answer).

Then you might do:

  size_t page_size =  sysconf(_SC_PAGE_SIZE);
  assert (page_size == 4096); // otherwise this code is wrong

  // 1000 bytes fit into 1*4096
  char *x = mmap (NULL, page_size, PROT_READ|PROT_WRITE, 
                  MAP_ANONYMOUS, -1, (off_t)0);
  if (x == MMAP_FAILED) perror("mmap x"), exit (EXIT_FAILURE);

  // 2000 bytes fit into 1*4096
  char *y = mmap (NULL, page_size, PROT_READ|PROT_WRITE, 
                  MAP_ANONYMOUS, -1, (off_t)0);
  if (y == MMAP_FAILED) perror("mmap y"), exit (EXIT_FAILURE);

later to free the memory, use

  if (munmap(x, page_size))
     perror("munmap x"), exit(EXIT_FAILURE);

etc

If you want to allocate 5Kbytes, you'll need two pages (because 5Kbytes < 2*4096 and 5Kbytes > 1*4096) i.e. mmap(NULL, 2*page_size, ...

Actually, all of your x, y, z takes only 8000 bytes and could fit into two, not three, pages... But then you could only munmap that memory together.

Be aware that mmap is a system call which might be quite expensive. malloc implementations take care to avoid calling it too often, that is why they manage previously free-d zones to reuse them later (in further malloc-s) without any syscall. In practice, most malloc implementations manage differently big allocations (e.g. more than a megabyte), which are often mmap-ed at malloc and munmap-ed at free time.... You could study the source code of some malloc. The one from MUSL Libc might be easier to read than the Glibc malloc.

BTW, the file /proc/1234/maps is showing you the memory map of process of pid 1234. Try also cat /proc/self/maps in a terminal, it shows the memory map of that cat process.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
4

You can call mmap to make an anonymous mapping in x86 asm with something like:

    mov eax, 192    ; mmap
    xor ebx, ebx    ; addr   = NULL
    mov ecx, 4096   ; len    = 4096
    mov edx, $7     ; prot   = PROT_READ|PROT_WRITE|PROT_EXEC
    mov esi, $22    ; flags  = MAP_PRIVATE|MAP_ANONYMOUS
    mov edi, -1     ; fd     = -1 (Ignored for MAP_ANONYMOUS)
    xor ebp, ebp    ; offset = 0 (4096*0) (Ignored for MAP_ANONYMOUS)
    int $80         ; make call (There are other ways to do this too)
Flexo
  • 87,323
  • 22
  • 191
  • 272