Нужно ли добавлять длину сопоставления к указателю, возвращенному mmap с флагами MAP_GROWSDOWN и MAP_STACK? - PullRequest
1 голос
/ 30 июня 2019

Я создаю простой стек для загрузчика a.out, и я придумал это:

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

Однако я не уверен в этом.

Должен ли я добавить 65535 (размер отображения) к результирующему указателю, прежде чем переместить его в указатель стека, потому что я использовал флаги MAP_STACK и MAP_GROWSDOWN? Или я могу просто использовать его как есть?

Документация для этого не очень ясна, и я не смог ничего найти при поиске в Интернете.

В частности, это (из mmap (2)) смущает меня:

Адрес возврата на одну страницу меньше области памяти, которая фактически создается в виртуальном адресном пространстве процесса.

1 Ответ

1 голос
/ 04 июля 2019
  1. Да, вы должны добавить 65536 к результирующему указателю. Обратите внимание, не 65535. Большинство архитектур реализуют push (x) как * - sp = x; таким образом, имея sp выше , стек вполне подходит для начала. Что еще более важно это должно быть выровнено, и 65535 не.

  2. Документация неверна. Я думаю, что это означает "на одну страницу выше , чем ...". Это лучше согласуется с исходной реализацией и результатом небольшого примера программы ниже:


  #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;
  }

который печатает:

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

в моей системе:

$ 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
...