我是否必须将映射的长度添加到带有 MAP_GROWSDOWN 和 MAP_STACK 标志的 mmap 返回的指针?
Do I have to add the length of the mapping to a pointer returned by mmap with the MAP_GROWSDOWN and MAP_STACK flags?
我正在为 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))让我感到困惑:
The return address is one page lower than the memory area that is actually created in the process's virtual address space.
是的,您必须将 65536 添加到结果指针。注意,不是 65535。大多数架构将 push(x) 实现为 *--sp = x;所以让 sp above 堆栈就可以开始了。更重要的是它必须对齐,而65535不是。
文档似乎有误。我认为它打算 "is one page higher than the..."。这更好地与源实现以及下面的小示例程序的结果保持一致:
#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
我正在为 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))让我感到困惑:
The return address is one page lower than the memory area that is actually created in the process's virtual address space.
是的,您必须将 65536 添加到结果指针。注意,不是 65535。大多数架构将 push(x) 实现为 *--sp = x;所以让 sp above 堆栈就可以开始了。更重要的是它必须对齐,而65535不是。
文档似乎有误。我认为它打算 "is one page higher than the..."。这更好地与源实现以及下面的小示例程序的结果保持一致:
#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