1

I'm on a 64-bit system, but want to use mmap to allocate pages within the first 2GB of memory. On Linux, I can do this with the MAP_32BIT flag:

#include <sys/mman.h>
#include <stdio.h>

int main() {
    void *addr = mmap(
        NULL, // address hint
        4096, // size
        PROT_READ | PROT_WRITE, // permissions
        MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS, // flags
        -1, // file descriptor
        0 // offset
    );
    if (addr == MAP_FAILED)
        perror("mmap");
    else
        printf("%p", addr);
}

Godbolt link demonstrating that this works on Linux. As of version 10.15, MacOS also allegedly supports the MAP_32BIT flag. However, when I compile and run the program on my system (11.3), it fails with ENOMEM. The mapping does work when MAP_32BIT is removed.

I have a few potential explanations for why this doesn't work, but none of them are very compelling:

  • The permissions are wrong somehow (although removing either PROT_READ or PROT_WRITE didn't solve it).
  • I need to specify an address hint for this to work, for some reason.
  • MacOS (or my version of it) simply doesn't support MAP_32BIT for anonymous mappings.
Challenger5
  • 959
  • 6
  • 26

1 Answers1

1

The problem is the "zero page": on some 32-bit Unixes, the lowest page of memory is commonly configured to be inaccessible so that accesses to NULL can be detected and signal an error. On 64-bit systems, MacOS extends this to the entire first 4 GiB of memory by default. mmap therefore refuses to map addresses in this region, since they are already mapped to page zero.

This can be simply changed using a linker option:

$ cc -Wl,-pagezero_size,0x1000 test.c
$ ./a.out
0xb0e5000
Challenger5
  • 959
  • 6
  • 26