2

when I run vmmap for a process the regions start with the __TEXT entry rather than __PAGEZERO as in sample output at documentation

otool -l also shows

Load command 0
      cmd LC_SEGMENT_64
  cmdsize 72
  segname __PAGEZERO
   vmaddr 0x0000000000000000
   vmsize 0x0000000100000000
  fileoff 0
 filesize 0
  maxprot 0x00000000
 initprot 0x00000000
   nsects 0
    flags 0x0

uname -mrsvp output is:

Darwin 21.2.0 Darwin Kernel Version 21.2.0: Sun Nov 28 20:28:54 PST 2021; root:xnu-8019.61.5~1/RELEASE_X86_64 x86_64 i386

Why is it so?

1 Answer 1

2

It is because that memory region is not listed as allocated by the process.

Basically vmmap traverses a list of virtual memory regions allocated by the process and displays them in a human-readable format. As it does not display the __PAGEZERO region - it is because it is not in the list.

You can confirm that this is not a bug in vmmap, or a change in how it outputs allocations, by listing the regions with a different tool. For example use Instruments.app from Xcode, add the VM Tracker from the Library and you'll see that it displays the same list of regions.

The purpose of the __PAGEZERO region was for processes to list a portion of memory at the beginning of the address space as "out of limits". I.e. these are memory addresses that cannot be read and cannot be written to during the execution of the process. Traditionally, you wanted to guard a bit of memory space around the NULL pointer (address 0), so that bugs that triggered reads or writes of the NULL pointer would terminate the program instead of modifying important state.

Later on with the introduction of the 64-bit address space, it was common to have a very large __PAGEZERO region - effectively blocking out all access to address 0x0 to 0x100000000. The reason for that is that it blocks access to all addresses that a 32-bit pointer can express. Often programs would have been originally written for a 32-bit environment and then later ported to a 64-bit environment. If the programmer wasn't careful, it is possible to do data conversions on pointers that effectively restrict them to 32-bits.

On a 32-bit system that is "safe" in that it doesn't actually harm anything in practice. However when the same code is run on a 64-bit system, this means that the program would try to access a completely different part of memory than intended. Therefore __PAGEZERO was extended to block all of the 32-bit pointers to prevent bugs like these from corrupting memory and instead make them very visible as program crashes.

Note that some programs didn't have the large __PAGEZERO region as for example 32-bit programs wouldn't work with such as a region (obviously). Similarly for some 64-bit programs, it would be a choice to leave it out in certain special situations - for example a program such as WINE that could essentially run 32-bit applications within a 64-bit environment.

Today, on recent macOS systems, 32-bit programs are no longer supported. The kernel is therefore free to enforce a so called "hard pagezero", meaning that this large address space is always blocked for all running programs. No matter if the program actually specifies such a region or not, all programs get the protection that comes with it. This is doable since 32-bits program are no longer supported and are no longer allowed to be executed.

As the hard pagezero is now directly enforced by the kernel for ordinary user-space processes, it is no longer necessary to explicitly include it in memory region lists. This is why it is no longer printed out by a tool such as vmmap.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .