所有PE节都加载到内存中的相同基地址吗?如果没有,PIC代码如何找到其他部分的数据?

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

所有PE节都加载到内存中的相同基地址吗?如果没有,PIC代码如何找到其他部分的数据?

例如,假设我有如下代码:

.text
   mov rax, myData
.data
   myData: ...

对于 PIC 代码,

mov
必须使用相对寻址。我明白这是如何工作的,如果
VA(.data) - FileOffset(.data) == VA(.text) - FileOffset(.text)
。 Windows PE 加载程序可以保证这一点吗?如果没有,像上面这样的 PIC 代码如何找到
myData
的相对地址?

assembly compilation linker memory-address portable-executable
1个回答
0
投票

在 Windows(或 UEFI)中加载 DLL 或 EXE 时,操作系统会为程序的内存映射选择一个“基地址”。程序中的所有内存地址(全局变量、函数)都相对于该基地址定位,在 Win32 文档中称为“图像基地址”。 PE 部分也以相对于该图像库的偏移量加载。以下是 Windows notepad.exe 中的示例,使用

dumpbin /headers

:

SECTION HEADER #2
  .rdata name
    92A8 virtual size
   26000 virtual address (0000000140026000 to 000000014002F2A7)
    9400 size of raw data
   24A00 file pointer to raw data (00024A00 to 0002DDFF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         Read Only

加载到内存中后,记事本 
.rdata

部分的内容将加载到

image_base + 0x26000
因为每个部分都相对于相同的图像基地址,所以加载图像中任意两点之间的距离始终是一个常数。

注意:同一图像中任意两点之间的距离恒定仅适用于

loaded

图像。在磁盘上,PE文件经常会省略空白区域,并且有对齐的考虑。 现在回到您的汇编代码。您编写的代码与位置无关。当您这样编写时,将会应用运行时修复(“重定位”)来使对

myData

的引用起作用。一个更好的例子是使用 x86-64 的 RIP 相对寻址模式:

.text
   lea rax, [myData]
.data
   myData: ...

这由汇编器翻译为 
lea rax, [rip + ???]

。链接器用 ??? 填充此内容。成为

myData
lea
指令之间的距离(实际上是紧随其后的指令的地址)。
因为这样的距离是恒定的,所以 DLL 中的这条指令会被硬编码,不需要重新定位。

现代操作系统的程序加载器都是这样工作的,但有特定于操作系统的怪癖。

© www.soinside.com 2019 - 2024. All rights reserved.