如何让GCC也实现Clang 15+版本中可执行文件起始地址的随机化效果?
嗨,这个问题我之前也帮别人排查过,其实核心是GCC和Clang 15+的默认编译/链接选项差异,再结合系统的地址空间随机化(ASLR)配置,我给你拆解清楚怎么搞定:
首先先看你用到的测试代码:
#include <stdio.h> extern long __executable_start; // symbol provided by the linker script int main() { printf("Executable start %p\n", &__executable_start); return 0; }
你之前遇到的情况是:GCC和Clang 15之前的版本编译后,__executable_start固定输出0x400000,但Clang 15+之后每次运行的地址都是高地址段的随机值——这是因为Clang 15+默认开启了**位置无关可执行文件(PIE)**的相关选项,而GCC默认还没开启,所以要让GCC实现同样效果,你需要做这几步:
编译时手动开启PIE选项
GCC默认不会生成PIE可执行文件,你需要在编译命令里加上-fPIE -pie两个选项,比如:gcc -fPIE -pie your_code.c -o your_exec这两个选项的作用是:
-fPIE让编译器生成位置无关的代码,-pie让链接器生成可以加载到任意地址的可执行文件,这是实现地址随机化的基础。确认系统ASLR处于全随机模式
即使生成了PIE可执行文件,还要确保系统的ASLR是开启的。在Linux系统下,你可以通过以下命令查看当前配置:cat /proc/sys/kernel/randomize_va_space如果返回值是
2,说明已经是全地址空间随机化模式(正是我们需要的);如果是0或1,你需要用root权限开启全随机:echo 2 | sudo tee /proc/sys/kernel/randomize_va_space可选:添加强化安全的链接选项
要是你想进一步确保随机化的效果,还可以加上链接器的安全选项:gcc -fPIE -pie -Wl,-z,relro,-z,now your_code.c -o your_exec-z relro和-z now会增强可执行文件的安全属性,同时确保链接器正确应用随机基地址的配置。
做完这些之后,你多次运行生成的可执行文件,就会看到__executable_start的地址每次都是不同的高地址随机值,和Clang 15+的效果完全一致了。
简单说下原因:早期编译器默认不开启PIE是因为担心一点点性能损耗,但现在安全优先级更高,Clang 15+直接把PIE设为了默认选项,而GCC还需要我们手动指定这些参数来达到同样的效果。
内容来源于stack exchange

