为什么对象 (ELF) 文件中没有堆栈段?
Why is there no stack segment in an object (ELF) files?
我是 OS 的初学者。这个问题是我的教授提出的,让我很困惑。我希望我能在这里得到一些提示和帮助。
在我的记忆中,ELF文件可以link相互。这是 ELF 文件不能有堆栈段的原因吗?
非常感谢您的帮助!
这是因为stack不是需要以文件格式保存的东西,它完全是和runtime执行相关的。就像您的文件中不需要 "heap segment" 一样。
另一方面,堆栈属于一个执行线程,不是数据或函数,它没有固定大小。考虑一个递归函数:
int foo() {
printf("Stack Overflow!\n");
return foo();
}
每个递归在栈中都有自己的帧,没有属于foo()
自身的栈,仅供其执行。
当然你可以在你的文件中保留一个堆栈段,就像一大块静态内存一样,让%rsp
指针(x64)指向它。但是OS已经为你做好了,所以没有必要。
大多数 GNU/Linux ELF 程序确实有堆栈段,因为除了最近的体系结构外,程序头中的堆栈段用于将堆栈标记为 non-executable(这是一种形式安全强化)。
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 0x8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000ffd0c 0x00000000000ffd0c R E 0x200000
LOAD 0x0000000000100548 0x0000000000700548 0x0000000000700548
0x000000000000b6fc 0x0000000000015440 RW 0x200000
…
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000100548 0x0000000000700548 0x0000000000700548
0x0000000000002ab8 0x0000000000002ab8 R 0x1
在某些GNU/Linux架构(FDPIC)上,堆栈段的大小甚至被内核用来设置主线程的堆栈大小。
(有不同种类的程序段。并非所有程序段都从文件图像中加载位。)
我是 OS 的初学者。这个问题是我的教授提出的,让我很困惑。我希望我能在这里得到一些提示和帮助。
在我的记忆中,ELF文件可以link相互。这是 ELF 文件不能有堆栈段的原因吗?
非常感谢您的帮助!
这是因为stack不是需要以文件格式保存的东西,它完全是和runtime执行相关的。就像您的文件中不需要 "heap segment" 一样。
另一方面,堆栈属于一个执行线程,不是数据或函数,它没有固定大小。考虑一个递归函数:
int foo() {
printf("Stack Overflow!\n");
return foo();
}
每个递归在栈中都有自己的帧,没有属于foo()
自身的栈,仅供其执行。
当然你可以在你的文件中保留一个堆栈段,就像一大块静态内存一样,让%rsp
指针(x64)指向它。但是OS已经为你做好了,所以没有必要。
大多数 GNU/Linux ELF 程序确实有堆栈段,因为除了最近的体系结构外,程序头中的堆栈段用于将堆栈标记为 non-executable(这是一种形式安全强化)。
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 0x8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000ffd0c 0x00000000000ffd0c R E 0x200000
LOAD 0x0000000000100548 0x0000000000700548 0x0000000000700548
0x000000000000b6fc 0x0000000000015440 RW 0x200000
…
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000100548 0x0000000000700548 0x0000000000700548
0x0000000000002ab8 0x0000000000002ab8 R 0x1
在某些GNU/Linux架构(FDPIC)上,堆栈段的大小甚至被内核用来设置主线程的堆栈大小。
(有不同种类的程序段。并非所有程序段都从文件图像中加载位。)