编译出来的一个完整可以执行的可执行文件,用objdump -t 看其中子函数对应的符号地址(称作地址1),其与该程序在linux系统上运行后,打印出该子函数的地址(称作地址2),这两个地址为什么不一样?具体是什么原因?背后的原理是什么?

2024-04-21by@ansonlkz&@GPT-4.Model: GPT-3.5
ansonlkz

编译出来的一个完整可以执行的可执行文件,用objdump -t 看其中子函数对应的符号地址(称作地址1),其与该程序在linux系统上运行后,打印出该子函数的地址(称作地址2),这两个地址为什么不一样?具体是什么原因?背后的原理是什么?

Avatar
Avatar

地址1是编译器编译时生成的符号地址,而地址2是程序在运行时加载到内存中的实际地址。这两个地址不一样的原因是因为程序在运行时会被加载到内存中的某个地址空间中,这个地址空间是由操作系统动态分配的,因此与编译时生成的符号地址不一样。

具体原因是因为在Linux系统中,程序在运行时会被加载到虚拟内存中,而虚拟内存是由操作系统动态管理的,因此程序的实际地址是在运行时被动态分配的。而编译器在编译时生成的符号地址是相对的静态地址,只有在程序被加载到内存中后才会被映射到实际的物理地址上。

因此,编译器生成的符号地址和程序在运行时的实际地址不一样是因为程序在运行时被加载到内存中的地址空间是动态分配的,而不是固定的。

ansonlkz

但是,在实验的结果中,地址1是0x000000000000129f,地址2是0x564487ea729f,这两者之间,为什么最后面三位数是相同的?它们两个之间有什么关系?

Avatar
Avatar

在地址1和地址2中,最后面三位数(0x129f和0x729f)是相同的,这是因为在Linux系统中,虚拟内存地址的布局规则。在Linux系统中,虚拟内存地址通常会被分为不同的区域,比如代码段、数据段、堆、栈等。这些区域通常会以固定的偏移量进行对齐和分配。

在地址1中,0x000000000000129f是编译器编译生成的符号地址,而在地址2中,0x564487ea729f是程序在运行时被加载到内存中的实际地址。由于Linux系统的虚拟内存地址布局规则,这两个地址中的最后三位数是相同的,表示它们都属于同一个区域或者段。

因此,这两个地址的最后三位数相同,但是整体的地址不同,是因为它们分别表示了编译时生成的符号地址和程序运行时加载到内存中的实际地址,且都位于同一个区域或段中。