Warm tip: This article is reproduced from stackoverflow.com, please click
c linux mmap

Do I have to add the length of the mapping to a pointer returned by mmap with the MAP_GROWSDOWN and

发布于 2020-03-27 10:26:02

I'm creating a simple stack for an a.out loader and I've come up with this:

stack = (char *)mmap(NULL,
                     65535,
                     PROT_READ | PROT_WRITE,
                     MAP_PRIVATE | MAP_STACK |
                       MAP_GROWSDOWN | MAP_UNINITIALIZED |
                       MAP_ANONYMOUS,
                     -1,
                     0);

However, I'm not sure about this.

Do I have to add 65535 (the size of the mapping) to the resulting pointer before I move it to the stack pointer because I used the MAP_STACK and MAP_GROWSDOWN flags? Or can I just use it as it is?

The documentation for this hasn't been very clear, and I haven't been able to find anything when searching the Internet.

Specifically, this (from mmap(2)) confuses me:

The return address is one page lower than the memory area that is actually created in the process's virtual address space.

Questioner
S.S. Anne
Viewed
109
11.5k 2019-07-04 23:53
  1. Yes, you have to add 65536 to the resulting pointer. Note, not 65535. Most architectures implement push(x) as *--sp = x; so having the sp above the stack is ok to start with. More importantly it has to be aligned, and 65535 is not.

  2. The documentation appears to be wrong. I think it intends "is one page higher than the...". That better aligns with the source implementation, and the result of the little sample program below:


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

  volatile int sp;

  void segv(int signo) {
          char buf[80];
          int n = snprintf(buf, 80, "(%d): sp = %#x\n", signo, sp);
          write(1, buf, n);
           _exit(1);
  }

  int main(void) {
          int N = 65535;
          signal(SIGSEGV, segv);
          signal(SIGBUS, segv);
          char *stack = (char *)mmap(NULL,
                       N,
                       PROT_READ | PROT_WRITE,
                       MAP_PRIVATE | MAP_STACK |
                         MAP_GROWSDOWN | /*MAP_UNINITIALIZED |*/
                         MAP_ANONYMOUS,
                       -1,
                       0);
          printf("stack %p\n", stack);
          for (sp = 0; sp < N; sp += 4096) {
                  if (stack[sp]) {
                          printf("stack[%d] = %x\n", sp, stack[sp]);
                  }
          }
          for (sp = 0; sp > -N; sp -= 4096) {
                  if (stack[sp]) {
                          printf("stack[%d] = %x\n", sp, stack[sp]);
                  }
          }
          return 0;
  }

which prints out:

$ ./a.out
stack 0x7f805c5fb000
(11): sp = -4096

on my system:

$ uname -a
Linux u2 4.15.0-42-generic #45-Ubuntu SMP Thu Nov 15 19:32:57 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux