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

为何每次在GDB中反汇编函数都会得到相同的指令及常量地址?

为什么GDB反汇编的地址每次都一模一样?

这事儿其实很好理解,核心原因和可执行文件的编译链接方式、系统的地址随机化机制直接相关,咱们一步步说:

1. 你编译出的是「固定地址」的可执行文件

当你执行gcc -o hello hello.c -ggdb时,在大多数Linux发行版的默认配置下,编译器会生成一个非位置无关可执行文件(non-PIE)。这类文件在链接阶段,链接器会直接给代码段(.text,存汇编指令)、只读数据段(.rodata,存常量字符串这类内容)分配固定的虚拟内存地址——比如x86_64架构下通常从0x400000开始。

这些固定地址会被明确写入最终生成的ELF可执行文件里的程序头表和节头表中。GDB加载这个文件时,会严格按照文件里记录的地址来映射内存区域,所以不管你重启多少次GDB,反汇编出来的指令、常量地址都不会变。

2. 地址空间布局随机化(ASLR)没起作用?

现在大部分Linux系统默认开启了ASLR(地址空间布局随机化),但它只对**位置无关可执行文件(PIE)**和共享库生效。对于non-PIE的可执行文件,ASLR不会去随机化它的代码段、数据段地址——因为这类程序的代码是基于固定地址编写的,随便改地址会直接导致程序崩溃。

如果你想验证这一点,可以试试用gcc -o hello hello.c -ggdb -fPIE -pie编译生成PIE可执行文件,之后每次启动GDB反汇编main,你会发现地址完全不一样了。

可执行文件里真的包含地址信息吗?

没错,你的hello文件确实存着指令和常量的地址相关信息:

  • ELF文件的节头表会记录每个段(比如.text、.rodata)的起始虚拟地址,以及段内每个内容的偏移量
  • 每条汇编指令在.text段里的偏移是固定的,段起始地址加上这个偏移,就是指令最终加载到内存里的地址
  • 常量(比如你代码里的字符串)存在.rodata段,同样通过「段起始地址+偏移」来确定最终内存地址

GDB就是靠读取这些文件里的信息,再结合内存映射的实际情况,才能准确显示出指令和常量的地址。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:38:03