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

时间:2017-07-03 20:48:55

标签: assembly x86 nasm

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

[base + index*scale + disp]

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

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

NASM出现以下错误:"错误:无效的有效地址"

但以下工作正常:

 mov eax, [ebx + esp + 2]

以下工作正常:

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

所以看起来使用带有scale的{​​{1}}作为索引寄存器会导致错误。

我说错了吗?我在哪里可以阅读更多相关信息(英特尔手册除外,长度超过4000页!)。

1 个答案:

答案 0 :(得分:4)

"规则"这里涵盖Intel IA-32 Architecture manuals。特别是,Volume 1: Basic Architecture包含以下信息:

  

3.7.5指定偏移量

     

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

     
      
  • 置换 - 8位,16位或32位值。
  •   
  • 基础 - 通用寄存器中的值。
  •   
  • 索引 - 通用寄存器中的值。
  •   
  • 比例因子 - 值为2,4或8,乘以指数值。
  •   
     

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

     


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

     

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

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

base,index和displacement组件可以任意组合使用,并且这些组件中的任何组件都可以为NULL。只有在使用索引时才可以使用比例因子。每种可能的组合对于高级语言和汇编语言中程序员常用的数据结构都很有用。

     

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

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

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

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

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

  •   
  • 基础+索引+位移⎯一起使用两个寄存器支持二维数组(位移保存数组开头的地址)或记录数组的几个实例之一(位移是记录中字段的偏移量。)
  •   
  • Base +(Index * Scale)+ Displacement ⎯将所有寻址组件放在一起可以在数组元素为2,4或8字节时对二维数组进行高效索引。大小
  •   

阅读并遵守这些规则,你会没事的。你不需要来阅读所有4000页,但你真的应该熟悉手册的内容,你可以在需要的时候查看内容(比如当汇编程序咳嗽时)错误信息)。在不熟悉其设计或编程模型的情况下编程微处理器非常困难。

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

确实是无效的寻址模式,因为您尝试使用ESP作为索引。图3-11表示您不能使用ESP作为索引,紧接在下面的第一个项目符号点也是如此。这里的逻辑是ESP s 大头钉 p ointer,它包含一个地址。

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

mov eax, [ebx + esp + 2]

这也没关系:

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

因为ECX可以用作索引。

在评论中,您提出以下指示:

mov eax, [ebx + esp + 2]

正如Ross Ridge已经回答的那样,这是合法的,因为你实际上并没有扩展 ESP,因此汇编程序足够聪明,可以使用ESP作为< em> base 和EBX作为索引。换句话说,它已将其重新排序为:

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

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