使用`esp*scale 时寻址内存时出错

use*_*761 1 x86 assembly nasm

内存寻址的一般形式(在这里找到)是:

[base + index*scale + disp]
Run Code Online (Sandbox Code Playgroud)

当我尝试汇编/编译以下代码时:

mov eax, [ebx + esp*4 + 2]
Run Code Online (Sandbox Code Playgroud)

NASM 给出以下错误:“错误:无效的有效地址”

但以下工作正常:

 mov eax, [ebx + esp + 2]
Run Code Online (Sandbox Code Playgroud)

以下也可以正常工作:

mov eax, [ebx + ecx*4 + 2]
Run Code Online (Sandbox Code Playgroud)

所以看起来使用scalewithesp作为索引寄存器会导致错误。

我对么?我在哪里可以阅读更多相关信息(英特尔手册除外,长达 4000 多页!)。

Cod*_*ray 5

此处的“规则”在英特尔 IA-32 架构手册中有很好的介绍。特别是,第 1 卷:基本架构包含以下信息:

3.7.5 指定偏移

内存地址的偏移部分可以直接指定为静态值(称为位移),也可以通过由以下一个或多个组件组成的地址计算来指定:

  • 位移— 8 位、16 位或 32 位值。
  • Base — 通用寄存器中的值。
  • 索引— 通用寄存器中的值。
  • 比例因子- 乘以索引值的 2、4 或 8 值。

添加这些组件所产生的偏移量称为有效地址。除了比例因子之外,这些组件中的每一个都可以具有正值或负值(2s 补码)。图 3-11 显示了可以组合这些组件以在所选段中创建有效地址的所有可能方式。


图 3-11。偏移(或有效地址)计算

将通用寄存器用作基址或索引组件受到以下方式的限制:

  • ESP 寄存器不能用作索引寄存器。
  • 当使用 ESP 或 EBP 寄存器作为基址时,SS 段为默认段。在所有其他情况下,DS 段是默认段。

基数、索引和位移分量可以任意组合使用,并且这些分量中的任何一个都可以为 NULL。仅当还使用索引时才可以使用比例因子。每种可能的组合对于程序员在高级语言和汇编语言中常用的数据结构都很有用。

以下寻址模式建议用于地址组件的常见组合。

  • 位移? 单独的位移表示对操作数的直接(未计算)偏移。因为位移是在指令中编码的,所以这种形式的地址有时称为绝对地址或静态地址。它通常用于访问静态分配的标量操作数。
  • 基地?单独的基数表示对操作数的间接偏移。由于基址寄存器中的值是可以改变的,因此可以用于变量和数据结构的动态存储。
  • 基础 + 位移? 基址寄存器和位移可以一起用于两个不同的目的:

    • 当元素大小不是 2、4 或 8 字节时作为数组的索引 - 位移分量将静态偏移量编码到数组的开头。基址寄存器保存计算结果,以确定数组中特定元素的偏移量。
    • 访问记录的字段:基址寄存器保存记录开头的地址,而位移是该字段的静态偏移量。

    这种组合的一个重要特例是访问过程激活记录中的参数。过程激活记录是进入过程时创建的堆栈帧。在这里,EBP 寄存器是基址寄存器的最佳选择,因为它会自动选择堆栈段。这是此通用功能的紧凑编码。

  • (指数?比例)+位移?当元素大小为 2、4 或 8 字节时,此地址模式提供了一种对静态数组进行索引的有效方法。位移定位数组的开头,索引寄存器保存所需数组元素的下标,处理器通过应用缩放因子自动将下标转换为索引。

  • 基础 + 指数 + 位移? 一起使用两个寄存器支持二维数组(位移保存数组开头的地址)或记录数组的多个实例之一(位移是记录中某个字段的偏移量)。
  • 基础+(指数?比例)+位移?当数组元素的大小为 2、4 或 8 字节时,将所有寻址组件一起使用可以有效地索引二维数组。

阅读并遵守这些规则,你会没事的。您不需要阅读所有 4000 页,但您确实应该足够熟悉手册的内容,以便您可以在需要时查找内容(例如当汇编器发出错误消息时)。在完全不熟悉微处理器的设计或编程模型的情况下对其进行编程是非常困难的。

mov eax, [ebx + esp*4 + 2]
Run Code Online (Sandbox Code Playgroud)

确实是一种无效的寻址模式,因为您正试图ESP用作索引。图 3-11 说你不能ESP用作索引,就像下面的第一个要点一样。这里的逻辑是,ESP小号粘性p ointer,它包含一个地址。

缩放地址没有意义。然而,从地址偏移确实有意义,这就是为什么ESP 可以用作基数。这就是为什么这很好:

mov eax, [ebx + esp + 2]
Run Code Online (Sandbox Code Playgroud)

这也很好:

mov eax, [ebx + ecx*4 + 2]
Run Code Online (Sandbox Code Playgroud)

因为ECX可以用作索引。

在评论中,您提供了以下说明:

mov eax, [ebx + esp + 2]
Run Code Online (Sandbox Code Playgroud)

正如罗斯岭已经回答说,这是合法的,因为你没有实际比例 ESP,所以汇编程序是足够聪明,在使用ESP作为基地,并EBX指数。换句话说,它已将其重新排序为:

mov eax, [2 + esp + ebx]
          ^    ^     ^
          |    |     |
displacement   |    index
              base
Run Code Online (Sandbox Code Playgroud)

使用隐式 1 作为比例因子。