我试图创建MAP_GROWSDOWN映射,并期望它能够自动增长。如手册页所述:
MAP_GROWSDOWN 这个标志用于堆叠。它向内核虚拟内存系统表明,映射应该向下扩展到内存中。返回地址比在进程虚拟地址空间中实际创建的内存区域低一页。触摸映射下面的“守护”页面中的地址将导致映射由页面增长。这种增长可以重复,直到映射增长到下一个较低映射的高端的一个页面内,此时触摸“保护”页面将产生一个
SIGSEGV信号。
因此,我编写了下面的示例来测试映射的增长:
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/mman.h>
#include <stdio.h>
int main(void){
char *mapped_ptr = mmap(NULL, 4096,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK | MAP_GROWSDOWN,
-1, 0);
if(mapped_ptr == MAP_FAILED){
int error_code = errno;
fprintf(stderr, "Cannot do MAP_FIXED mapping."
"Error code = %d, details = %s\n", error_code, strerror(error_code));
exit(EXIT_FAILURE);
}
volatile char *c_ptr_1 = mapped_ptr; //address returned by mmap
*c_ptr_1 = 'a'; //fine
volatile char *c_ptr_2 = mapped_ptr - 4095; //1 page below the guard
*c_ptr_2 = 'b'; //crashes with SEGV
}因此,我得到了SEGV,而不是增长映射。在这里生长是什么意思?
发布于 2020-07-02 18:02:09
我知道OP已经接受了其中一个答案,但不幸的是,它并没有解释为什么MAP_GROWSDOWN有时会工作。由于这个堆栈溢出问题是搜索引擎中的第一个热门问题之一,让我为其他人添加我的答案。
MAP_GROWSDOWN的文档需要更新。特别是:
这种增长可以重复,直到映射增长到下一个较低映射的高端的一个页面内,此时触摸“保护”页面将产生SIGSEGV信号。
实际上,内核不允许MAP_GROWSDOWN映射比stack_guard_gap页面离前面的映射更近。默认值是256,但可以在内核命令行中重写它。由于您的代码没有为映射指定任何所需的地址,所以内核会自动选择一个地址,但是很可能在现有映射结束后256页内结束。
编辑
此外,v5.0之前的内核拒绝访问堆栈指针下面超过64k+256字节的地址。详情请参见这个内核提交。
这个程序可以在x86上工作,即使使用的是5.0前内核:
#include <sys/mman.h>
#include <stdint.h>
#include <stdio.h>
#define PAGE_SIZE 4096UL
#define GAP 512 * PAGE_SIZE
static void print_maps(void)
{
FILE *f = fopen("/proc/self/maps", "r");
if (f) {
char buf[1024];
size_t sz;
while ( (sz = fread(buf, 1, sizeof buf, f)) > 0)
fwrite(buf, 1, sz, stdout);
fclose(f);
}
}
int main()
{
char *p;
void *stack_ptr;
/* Choose an address well below the default process stack. */
asm volatile ("mov %%rsp,%[sp]"
: [sp] "=g" (stack_ptr));
stack_ptr -= (intptr_t)stack_ptr & (PAGE_SIZE - 1);
stack_ptr -= GAP;
printf("Ask for a page at %p\n", stack_ptr);
p = mmap(stack_ptr, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_STACK | MAP_ANONYMOUS | MAP_GROWSDOWN,
-1, 0);
printf("Mapped at %p\n", p);
print_maps();
getchar();
/* One page is already mapped: stack pointer does not matter. */
*p = 'A';
printf("Set content of that page to \"%s\"\n", p);
print_maps();
getchar();
/* Expand down by one page. */
asm volatile (
"mov %%rsp,%[sp]" "\n\t"
"mov %[ptr],%%rsp" "\n\t"
"movb $'B',-1(%%rsp)" "\n\t"
"mov %[sp],%%rsp"
: [sp] "+&g" (stack_ptr)
: [ptr] "g" (p)
: "memory");
printf("Set end of guard page to \"%s\"\n", p - 1);
print_maps();
getchar();
return 0;
}https://stackoverflow.com/questions/56888725
复制相似问题