运行时打印的变量地址与可执行文件中的变量地址为何不一致?
运行时打印的变量地址与可执行文件中的变量地址为何不一致?
嗨,这个问题其实戳中了现代操作系统里虚拟内存和程序加载的核心逻辑,我给你一步步捋清楚:
首先得明确你看到的两个地址本质上是啥:
- 用
objdump看到的0000000000004010是相对虚拟地址(RVA),简单说就是这个变量在程序里的「偏移位置」——相对于程序被加载到虚拟内存时的起始基址的偏移量。 - 运行时
printf输出的0x555555558010是完整的虚拟地址,它是「加载基址 + 偏移量」算出来的结果。
那这个加载基址是怎么来的?
在Linux系统里,默认情况下ELF可执行文件会被加载到用户虚拟地址空间的0x555555554000附近(哪怕你关了ASLR,这个基址也是固定的)。你可以自己算一下:0x555555558010 - 0x4010 = 0x555555554000,正好对上这个默认基址。
你可以用readelf -l 你的可执行文件名验证这个点,查看输出里的LOAD段信息:
- 比如
.data段(你的静态变量testInt就存在这个段里)的虚拟起始地址是0x555555558000,而它在可执行文件中的偏移是0x4000,testInt在.data段里的偏移是0x10,加起来就是0x555555558010,和你打印的地址完全一致。
再补充两个关键点:
- 你关闭ASLR只是取消了加载基址的随机化,但基址本身不会消失——因为用户空间和内核空间的虚拟地址是严格分隔的,加载器必须把程序放到用户空间的专属区域,这个区域的起始就是固定基址(ASLR关闭时)。
- 你猜的没错,不管是哪个地址都不是物理地址,操作系统靠MMU(内存管理单元)把虚拟地址映射到物理地址,用户程序根本碰不到物理地址,只能操作虚拟地址。
你的测试代码:
#include <unistd.h> #include <stdio.h> static int testInt = 5; int main() { printf("address of testInt: %p\n", (void*)&testInt); return 0; }
备注:内容来源于stack exchange,提问作者Enderhippo
相关产品推荐
相关产品推荐

