You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用GCC编译各段具有不同PIE偏移的PIE ELF程序?

实现多段独立随机偏移的PIE程序(x86_64 Linux)

要让程序中不同段(如.my_data和.text/.bss)每次运行时的相对偏移随机,需要打破默认PIE程序的全局基址共享机制,让每个可加载段(PT_LOAD)被动态链接器独立随机化加载。以下是具体实现步骤:

1. 修改链接脚本(l.lds)

显式定义所有段的内存区域,确保.my_data和其他段分属不同的MEMORY区域,且链接器为每个段生成独立的PT_LOAD条目:

ENTRY(start)

MEMORY
{
  main_region (rwxai) : ORIGIN = 0x300000, LENGTH = 0x100000  /* 3M - 4M */
  my_data_region (rwxai) : ORIGIN = 0x500000, LENGTH = 0x100000 /* 5M - 6M */
}

SECTIONS
{
  /* 处理代码段 */
  .text : {
    *(.text)
    *(.text.*)
  } >main_region

  /* 处理只读数据段 */
  .rodata : {
    *(.rodata)
    *(.rodata.*)
  } >main_region

  /* 处理已初始化数据段 */
  .data : {
    *(.data)
    *(.data.*)
  } >main_region

  /* 处理未初始化数据段 */
  .bss : {
    *(.bss)
    *(.bss.*)
    *(COMMON)
  } >main_region

  /* 自定义数据段,放到独立内存区域 */
  .my_data : {
    *(.my_data)
  } >my_data_region =0x9090
}

2. 更新编译/链接选项(Makefile)

添加-fPIC确保代码完全位置无关,链接时启用-z separate-loadable-segments让链接器生成独立PT_LOAD段:

CFLAGS = -fPIE -fPIC
ASFLAGS = -fPIE

a: a.o l.lds
    ld -pie -z separate-loadable-segments --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -T l.lds -o $@ a.o

clean:
    rm -f *.o a

3. 启用内核段级ASLR

Linux默认的ASLR级别(kernel.randomize_va_space=2)支持段级独立随机化,执行以下命令启用:

sudo sysctl kernel.randomize_va_space=2

该设置会让动态链接器为每个PT_LOAD段计算独立的随机加载地址,而非共享全局基址。

原理说明

  • 默认PIE程序的所有PT_LOAD段共享同一个基址偏移,段间相对偏移固定;-z separate-loadable-segments让链接器为每个段生成独立的PT_LOAD条目。
  • 内核ASLR级别2会对每个PT_LOAD段单独应用随机偏移,实现段间相对地址的随机化。
  • -fPIE/-fPIC确保编译器生成位置无关代码,全局变量(如my_array)通过GOT表访问,动态链接器加载时会重定位GOT条目到实际随机地址。

验证效果

编译后运行程序,多次打印&my_array、&start、&normal_array的地址,会观察到各段的相对偏移每次运行都不同,符合预期效果。

内容的提问来源于stack exchange,提问作者Eric Stdlib

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:07:33