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

Error addressing memory when using`esp*scale

内存寻址的一般形式(找到了here)是:

[base + index*scale + disp]

当我尝试assemble/compile以下代码时:

mov eax, [ebx + esp*4 + 2]

NASM 给出以下错误:"error: invalid effective address".

但以下工作正常:

 mov eax, [ebx + esp + 2]

以下也可以正常工作:

mov eax, [ebx + ecx*4 + 2]

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

我说的对吗?我在哪里可以阅读更多相关信息(英特尔手册除外,它有 4000 多页!)。

这里的"rules"都很好的覆盖了Intel IA-32 Architecture manuals. In particular, Volume 1: Basic Architecture包含以下信息:

3.7.5 Specifying an Offset

The offset part of a memory address can be specified directly as a static value (called a displacement) or through an address computation made up of one or more of the following components:

  • Displacement — An 8-, 16-, or 32-bit value.
  • Base — The value in a general-purpose register.
  • Index — The value in a general-purpose register.
  • Scale factor — A value of 2, 4, or 8 that is multiplied by the index value.

The offset which results from adding these components is called an effective address. Each of these components can have either a positive or negative (2s complement) value, with the exception of the scaling factor. Figure 3-11 shows all the possible ways that these components can be combined to create an effective address in the selected segment.


Figure 3-11. Offset (or Effective Address) Computation

The uses of general-purpose registers as base or index components are restricted in the following manner:

  • The ESP register cannot be used as an index register.
  • When the ESP or EBP register is used as the base, the SS segment is the default segment. In all other cases, the DS segment is the default segment.

The base, index, and displacement components can be used in any combination, and any of these components can be NULL. A scale factor may be used only when an index also is used. Each possible combination is useful for data structures commonly used by programmers in high-level languages and assembly language.

The following addressing modes suggest uses for common combinations of address components.

  • Displacement ⎯ A displacement alone represents a direct (uncomputed) offset to the operand. Because the displacement is encoded in the instruction, this form of an address is sometimes called an absolute or static address. It is commonly used to access a statically allocated scalar operand.
  • Base ⎯ A base alone represents an indirect offset to the operand. Since the value in the base register can change, it can be used for dynamic storage of variables and data structures.
  • Base + Displacement ⎯ A base register and a displacement can be used together for two distinct purposes:

    • As an index into an array when the element size is not 2, 4, or 8 bytes—The displacement component encodes the static offset to the beginning of the array. The base register holds the results of a calculation to determine the offset to a specific element within the array.
    • To access a field of a record: the base register holds the address of the beginning of the record, while the displacement is a static offset to the field.

    An important special case of this combination is access to parameters in a procedure activation record. A procedure activation record is the stack frame created when a procedure is entered. Here, the EBP register is the best choice for the base register, because it automatically selects the stack segment. This is a compact encoding for this common function.

  • (Index ∗ Scale) + Displacement ⎯ This address mode offers an efficient way to index into a static array when the element size is 2, 4, or 8 bytes. The displacement locates the beginning of the array, the index register holds the subscript of the desired array element, and the processor automatically converts the subscript into an index by applying the scaling factor.

  • Base + Index + Displacement ⎯ Using two registers together supports either a two-dimensional array (the displacement holds the address of the beginning of the array) or one of several instances of an array of records (the displacement is an offset to a field within the record).
  • Base + (Index ∗ Scale) + Displacement ⎯ Using all the addressing components together allows efficient indexing of a two-dimensional array when the elements of the array are 2, 4, or 8 bytes in size.

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

mov eax, [ebx + esp*4 + 2]

确实是一种无效的寻址模式,因为您正试图使用​​ ESP 作为索引。图 3-11 表示您不能使用 ESP 作为索引,正下方的第一个要点也是如此。这里的逻辑是 ESPstack pointer,它包含一个地址。

缩放地址没有意义。但是,从地址 offset 确实有意义,这就是为什么 ESP can 可以用作基础的原因。这就是为什么这样很好:

mov eax, [ebx + esp + 2]

这个也可以:

mov eax, [ebx + ecx*4 + 2]

因为ECX可以作为索引

在评论中,您给出了这条指令:

mov eax, [ebx + esp + 2]

正如 Ross Ridge 已经回复的那样,这是合法的,因为您实际上并没有 缩放 ESP,所以汇编程序足够聪明,可以使用 ESP作为 baseEBX 作为 index。换句话说,它已将其重新排序为:

mov eax, [2 + esp + ebx]
          ^    ^     ^
          |    |     |
displacement   |    index
              base

隐式 1 作为比例因子。