栈中最后一个可访问地址之上的内存区域存储了什么?
用户栈顶部空白区域与起始地址疑问
之前我询问为何栈并非从0x7fff...c开始,得到的答复是通常0x800...及以上地址属于内核空间,命令行参数(cli args)和环境变量位于用户栈的顶部,因此栈起始地址低于0x7fff...c。但我最近通过测试发现了一些细节,想进一步探究:
C程序遍历栈字符串测试
我用以下程序尝试遍历栈上的所有字符串:
#include <stdio.h> #include <string.h> int main(int argc, const char **argv) { const char *ptr = argv[0]; while (1) { printf("%p: %s\n", ptr, ptr); size_t len = strlen(ptr); ptr = (void *)ptr + len + 1; } }
将程序编译为./t并运行,在显示完所有环境变量后,得到如下输出:
0x7ffc19f84fa0: <final env variable string> 0x7ffc19f84fee: _=./t 0x7ffc19f84ff4: ./t 0x7ffc19f84ff8: 0x7ffc19f84ff9: 0x7ffc19f84ffa: 0x7ffc19f84ffb: 0x7ffc19f84ffc: 0x7ffc19f84ffd: 0x7ffc19f84ffe: 0x7ffc19f84fff:
可以看到,./t字符串(地址范围0x7ffc19f84ff4~0x7ffc19f84ff7)的空终止符之后还有一个额外的空字节,随后程序触发段错误——我猜测此处就是栈的基址。那在内核内存开始前的这段“空白”区域中实际存储了什么?
汇编程序验证栈起始地址
我还尝试了以下汇编代码:
global _start extern print_hex, fgets, puts, print, exit section .text _start: pop rdi mov rcx, 0 _start_loop: mov rdi, rsp call print_hex pop rdi call puts jmp _start_loop mov rdi, 0 call exit
其中print_hex是我自行编写的十六进制地址打印例程,运行后输出如下:
0x00007ffcd272de28 ./bin/main 0x00007ffcd272de30 abc 0x00007ffcd272de38 def 0x00007ffcd272de40 ghi 0x00007ffcd272de48 make: *** [Makefile:47: run] Segmentation fault
看起来即使在_start入口处,栈也并非从0x7fff...开头的地址开始。
内容的提问来源于stack exchange,提问作者Pack Yak1
相关产品推荐
相关产品推荐

