为什么内存用户 space 顶部的指令地址与 linux 进程内存布局相反?
Why are instructions addresses on the top of the memory user space contrary to the linux process memory layout?
#include <stdio.h>
void func() {}
int main() {
printf("%p", &func);
return 0;
}
这个程序输出了0x55c4cda9464a
假设func
会被存储在.text
段,根据这个图,从CS:APP
:
我想 func
的地址应该在 .text
部分的起始地址附近,但这个地址在中间的某个地方。为什么会这样?存储在堆栈上的局部变量的地址接近 2^48 - 1,但我试图反汇编不同的 C 代码,指令总是位于该 0x55...
地址附近的某个位置。
gcc
,当配置 --enable-default-pie
1(默认)时,默认生成 Position Independent Executables(PIE). Which means the load address isn't same as what linker specified at compile-time (0x400000 for x86_64). This is a security mechanism so that Address Space Layout Randomization (ASLR) 2 can be enabled. That is, gcc compiles with -pie
选项。
如果你用-no-pie
选项编译(gcc -no-pie file.c
),那么你可以看到func
的地址更接近0x400000。
在我的系统上,我得到:
$ gcc -no-pie t.c
$ ./a.out
0x401132
你也可以用readelf
查看加载地址:
$ readelf -Wl a.out | grep LOAD
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x000478 0x000478 R 0x1000
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x0001f5 0x0001f5 R E 0x1000
LOAD 0x002000 0x0000000000402000 0x0000000000402000 0x000158 0x000158 R 0x1000
LOAD 0x002e10 0x0000000000403e10 0x0000000000403e10 0x000228 0x000230 RW 0x1000
1 你可以用 gcc --verbose
.
检查这个
2 您可能还会注意到您的程序打印的地址在每个 运行 中都是不同的。那是因为 ASLR。您可以通过以下方式禁用它:
$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
ASLR 默认在 Linux 上启用。
#include <stdio.h>
void func() {}
int main() {
printf("%p", &func);
return 0;
}
这个程序输出了0x55c4cda9464a
假设func
会被存储在.text
段,根据这个图,从CS:APP
:func
的地址应该在 .text
部分的起始地址附近,但这个地址在中间的某个地方。为什么会这样?存储在堆栈上的局部变量的地址接近 2^48 - 1,但我试图反汇编不同的 C 代码,指令总是位于该 0x55...
地址附近的某个位置。
gcc
,当配置 --enable-default-pie
1(默认)时,默认生成 Position Independent Executables(PIE). Which means the load address isn't same as what linker specified at compile-time (0x400000 for x86_64). This is a security mechanism so that Address Space Layout Randomization (ASLR) 2 can be enabled. That is, gcc compiles with -pie
选项。
如果你用-no-pie
选项编译(gcc -no-pie file.c
),那么你可以看到func
的地址更接近0x400000。
在我的系统上,我得到:
$ gcc -no-pie t.c
$ ./a.out
0x401132
你也可以用readelf
查看加载地址:
$ readelf -Wl a.out | grep LOAD
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x000478 0x000478 R 0x1000
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x0001f5 0x0001f5 R E 0x1000
LOAD 0x002000 0x0000000000402000 0x0000000000402000 0x000158 0x000158 R 0x1000
LOAD 0x002e10 0x0000000000403e10 0x0000000000403e10 0x000228 0x000230 RW 0x1000
1 你可以用 gcc --verbose
.
2 您可能还会注意到您的程序打印的地址在每个 运行 中都是不同的。那是因为 ASLR。您可以通过以下方式禁用它:
$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
ASLR 默认在 Linux 上启用。