我正在为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
标志,在将其移动到堆栈指针之前,是否必须添加(映射的大小)?还是我可以按原样使用它?
关于此的文档还不是很清楚,并且在搜索Internet时我什么也找不到。
具体来说,这(来自mmap(2))使我感到困惑:
返回地址比在进程的虚拟地址空间中实际创建的内存区域低一页。
是的,您必须将65536添加到结果指针。注意,不是65535。大多数体系结构将push(x)实现为*-sp = x; 因此,将sp 置于堆栈上方是可以的。更重要的是,它必须对齐,而不是65535。
该文档似乎是错误的。我认为打算“ 比... 高一页”。这样可以更好地与源代码实现以及下面的小示例程序的结果保持一致:
#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
你为什么要注释掉
MAP_UNINITIALIZED
?我的Linux没有启用该功能[请参阅:stackoverflow.com/questions/42784442/…最后评论]
真?我在3.18上启用了它(
asm/mman.h
虽然我使用)。/usr/local/include/asm-generic/mman-common.h: # define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be uninitialized */
这是安全的事情,这就是为什么我认为ubuntu拒绝它的原因。请注意,glibc可以过滤掉您的选项,因此可以指定规格。如果将其作为strace -e trace = mmap ./a.out运行,则可能在args中看不到您的选项。