我已经在你的程序中添加了/proc/self/maps
解析器(与@AndrewHenle建议的方法相同,但我是在程序启动时执行的,并且不调用pmap
):
char* get_stack_bounds() {
FILE* maps = fopen("/proc/self/maps", "r");
static char line[256];
while(!feof(maps)) {
fgets(line, 255, maps);
if(strstr(line, "[stack]")) {
char* space = strchr(line, ' ');
*space = '\0';
fclose(maps);
return line;
}
}
fclose(maps);
return NULL;
}
unsigned long get_stack_right() {
char* bounds = get_stack_bounds();
bounds = strchr(bounds, '-') + 1;
return strtol(bounds, NULL, 16);
}
在 main()
开始时候输出一些信息:
printf("&result: %p delta: %ld\n", &result,
get_stack_right() - ((unsigned long) &result));
这里是一些结果:
> ./a.out 104747
&result: 0x7fff3347c7f8 delta: 6152
0
> ./a.out 174580
&result: 0x7fffe43c9b38 delta: 5320
0
> ./a.out 174580
&result: 0x7fff26ad2b28 delta: 9432
Segmentation fault (core dumped)
> ./a.out 174580
&result: 0x7fff145aa5a8 delta: 6744
0
> ./a.out 174580
&result: 0x7fff74fff0b8 delta: 12104
Segmentation fault (core dumped)
我认为
delta
(即
result
地址和栈基地址之间的差异)与段错误之间的相关性是显而易见的。
你应该注意,
main()
不是程序中运行的第一个函数,实际的入口点将是来自crt1.o(或其他文件)的
_start()
,因此初始堆栈大小可能会有所不同。
实际问题是
地址空间布局随机化。这里是来自
fs/binfmt_elf_fdpic.c
的注释,关于它的用法:
/* In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
* by the processes running on the same package. One thing we can do is
* to shuffle the initial stack for them, so we give the architecture
* an opportunity to do so here.
*/
sp = arch_align_stack(bprm->p);
这里是x86上
arch_align_stack()
的实现:
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
sp -= get_random_int() % 8192;
return sp & ~0xf;
}
printf
中的%EAX
。 - Marcus Müller%EAX
。 - Barmar