x86指令“call dword ptr ds:[00923030h]”是什么意思?

10

以下x86汇编指令的作用是什么?

call dword ptr ds:[00923030h]

我猜这是一次间接调用,但它是如何计算调用地址的呢?

4个回答

17

[编辑] 更新

每当您看到类似 ds:0x00923030 的内存操作数时,那就是一种 段相对 寻址方式。实际的地址是相对于 ds 段寄存器基地址的线性地址 0x00923030。

x86 架构中的内存分段有些令人困惑,我认为 维基百科 解释得很好。

基本上,x86 有一些特殊的 寄存器:cs代码段)、ds数据段)、esfsgsss段)。每个内存访问都与某个段寄存器关联。通常情况下,您不需要指定段寄存器,取决于内存访问的方式,会使用默认的段寄存器。例如,cs 寄存器用于读取指令。

每个段寄存器都有一个特定的 基地址 和一个 限制。基地址确定与线性地址 0x00000000 对应的物理地址,限制确定该段的最大允许线性地址。例如,如果基地址为 0x00040000,限制为 0x0000FFFF,则仅有效的线性地址为 0x00000000 到 0x0000FFFF,并且相应的物理地址为 0x00040000 到 0x0004FFFF。

因此,调用子程序所在的物理地址由存储在 ds 段寄存器中的基地址加上 0x00923030 给出。但是我们还没结束——指令中有一个单词 ptr。这增加了一层间接寻址,因此子程序的实际目标是存储在位置 ds:0x00923030 上的地址。

在 AT&T 语法(被 GNU 汇编器接受)中,该指令将如下编写:

lcall *ds:0x00923030

如果想了解指令的全部细节,请参考80386参考手册。这个指令的特定变体是"CALL r/m16"(调用近距离寄存器间接/内存间接)。


不太对,我认为存在一个间接性。因此,被调用的子程序所在的物理地址由存储在DS段寄存器中的基址加上0x00923030的值给出。 - Knut Arne Vedaa
1
一个段选择器并不像你所说的指向物理地址,而是指向线性地址。当逻辑地址已经被解析为线性地址时,物理地址才在最后一步获得。 - newgre
是的,分段 -> 线性,然后虚拟 -> 物理。 - Peter Cordes
此外,x86中的所有内存访问都是相对于某个段的。ds:是数据寻址模式的默认值,除了以ebpesp为基址寄存器的情况。这个答案似乎也暗示着call ds:1234会有更少的间接级别,即它可能会执行EIP=1234,而不是从内存地址ds:1234加载新的EIP值。但这毫无意义;在ds:1234中的ds:已经意味着它是一个(数据)内存源操作数。 - Peter Cordes
不,这是call r/m32,而不是16dword是32位,word是16位。大多数这些错误都很小,而且它们之间有一个相当好的答案,但链接的重复答案已经非常好了。 - Peter Cordes

10

这个特定的操作码通过逻辑地址ds:[00923030h]指向的虚拟地址(32位)进行调用。
逻辑地址由两个组件组成:

  1. 一个16位段选择器,本例中为ds,基本上是操作系统管理的(全局/本地)描述符表中的索引。这样的选择器还保存给定段的访问权限信息,该信息在访问时进行检查(当前特权级、CPL
  2. 一个32位的偏移量
    然后计算最终地址如下:从选择器中获取的基址+偏移量

请注意,上述计算表示线性地址,而不是物理地址(参见英特尔手册第3a卷,图2.2),然后通过4KB分页的标准机制进行转换,即地址包括页目录、页表的索引以及所选页内的偏移量。但请记住,所有主流操作系统都使用所谓的平坦内存模型,这意味着所有段选择器都指向地址0x00000000,限制设置为0xFFFFFFFF,这就是可以在所有段之间进行转换并最终导致(容易)利用缓冲区溢出的原因。

给出的汇编指令很可能是通过可执行文件的导入地址表进行调用(有关详细信息,请参见这篇精彩文章),即这很不可能是序数子程序调用。
编译器会生成这样的代码,是因为外部dll导入函数的最终虚拟地址通常在编译时无法确定(由于dll的重新定位)。使用这种调用结构,操作系统加载程序可以将正确的虚拟地址插入到逻辑地址指向的地址指针中,编译器无需关心最终函数的地址是什么。


2

call dword ptr ds:[00923030h]的意思是,在数据段中调用指针00923939h处的某个值。


1

据我所知,它获取DS寄存器的值(并将其左移4位),加上给定的立即值,从生成的内存位置获取一个双字值,该值成为要调用的地址。(编辑:这适用于16位实模式,对于保护模式,请参见其他答案。)


这是错误的,偏移量没有添加到ds寄存器的值上。实际上这是一个逻辑地址。 - newgre
这不是实模式,因为它使用DWORD操作数大小来表示新地址(并且它不是远程调用)。在实模式下,它只能是“word ptr”函数指针。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接