二进制程序中的内存地址如何在运行时指向内存中的正确位置?

问题描述 投票:0回答:2

根据我对编译程序(例如C程序)的理解,编译器将获取您的代码并以二进制(即目标拱的机器代码)格式输出可执行程序。

在此二进制文件中,您将具有指向内存中地址的指令,以从程序其他部分加载数据/指令。

鉴于此程序将在任意位置加载到内存中,该程序如何知道这些内存地址是什么?他们是如何设置/计算的,这是谁的工作?

[[例如,二进制文件是否仅具有占位符,表示操作系统首次将其加载到内存中时所取代的内存位置?

如果它需要动态加载共享库,它将如何计算出该存储库的位置?

“虚拟记忆”如何发挥作用? (如果有的话)

memory compilation operating-system executable machine-code
2个回答
0
投票
程序如何知道这些内存地址是什么?
程序(及其作者)不知道

what内存地址在加载到计算机内存中时的地址,它仅相对于段的开头知道

where占位符。这就是为什么编译器为每个此类占位符随附relocation record。重定位是一条信息,告诉操作系统或链接器

重定位地址在哪里(它在代码或数据段中的偏移量)
    它在哪个段中
  1. 它指的是哪个段或符号
  2. 该地址应采用哪种搬迁方式
  • 请考虑以下Windows Portable可执行程序的简单代码或源代码:
  • [.text] Main:NOP LEA ESI,[Mem] ; more instructions [.data] DB "Some data" Mem: DB "Other data"

    将转换为机器指令和存储器数据:

    |[.text]                   |[.text]
    |00000000:90               |Main:NOP
    |00000001:8D35[09000000]   |     LEA ESI,[Mem]
    |00000007:                 |     ; more instructions
    |[.data]                   |[.data]
    |00000000:536F6D6520646174~|     DB "Some data"
    |00000009:4F74686572206461~|Mem: DB "Other data"
    

    编译器不知道Mem的虚拟地址,它只知道它位于0x00000009段的开头的.data个字节,因此它将这个临时编号放入LEA ESI,[Mem]的操作代码中并创建相对于段.text的占位符的重定位(位于段0x00000003中的偏移.data处)。

    在链接时,链接程序决定将.text段加载到虚拟地址0x00401000,将其加载到VA .data0x00402000段。然后,链接器读取重定位记录并通过添加0x00402000来修改占位符。然后,链接的可执行文件中的指令LEA ESI,[Mem]将为8D3509204000,这是Mem的最终固定虚拟地址。我们将能够在运行时在调试器中看到该地址。

    在链接的可执行文件(16位DOS MZ或Windows PE)中也存在重定位,以防无法在链接时假定的虚拟映像库地址处加载重定位。在Linux中链接SO库更加复杂,请参见http://www.skyfree.org/linux/references/ELF_Format.pdf中的

    2动态链接章


  • 0
    投票
    © www.soinside.com 2019 - 2024. All rights reserved.