Assembly 基底与位移的差异

Assembly 基底与位移的差异,assembly,x86,intel,addressing-mode,Assembly,X86,Intel,Addressing Mode,我在理解我遇到的两个说明时遇到一些问题。 第一个是: imul eax,DWORD PTR [esi+ebx*4-0x4] 此指令是否意味着=>将括号之间计算的地址处的值乘以eax,并将其存储在同一寄存器(eax)中? 如果是这样的话,我们会这样计算括号中的地址吗 ebx*4 esi+操作1的结果 从结果中减去4 转到地址(结果)并获取其中的值 我发出解码的第二条指令是这条 jmp DWORD PTR [eax*4+0x80497e8] -eax*4是否等同于索引*刻度? -0x8

我在理解我遇到的两个说明时遇到一些问题。
第一个是:

imul   eax,DWORD PTR [esi+ebx*4-0x4]
此指令是否意味着=>将括号之间计算的地址处的值乘以eax,并将其存储在同一寄存器(eax)中? 如果是这样的话,我们会这样计算括号中的地址吗

  • ebx*4
  • esi+操作1的结果
  • 从结果中减去4
  • 转到地址(结果)并获取其中的值
  • 我发出解码的第二条指令是这条

    jmp    DWORD PTR [eax*4+0x80497e8]
    
    -eax*4是否等同于索引*刻度?
    -0x80497e8是否为位移

    所以要把地址放在括号里,这是我们应该遵循的顺序吗

  • eax*4
  • 将结果添加到1中。发送到地址0x80497e8
  • 跳转到那个地址
  • 据我所知,[base+index*scales]用于获取数组内部的值。 基是指向数组中第一个元素的指针。 索引实际上就是存储我们想要的值的索引 比例是数组包含的日期的大小

    我的问题是当你在方程中加入位移时,位移的作用是什么?
    当位移为负值时,这意味着什么

    不要被术语所愚弄。“base”具有特定的技术含义,寻址模式的“base”组件不必是数组的开始。e、 g.
    [esp+16+esi*4]
    可以索引从
    esp+16
    开始的本地数组,即使
    esp
    是基寄存器

    类似地,
    [esi+ebx*4-0x4]
    最明显的解释是
    array[i-1]
    ,其中
    i
    位于ebx中,
    esi
    持有数组的起始地址。编译器将
    -1
    折叠到寻址模式,而不是在另一个寄存器中计算
    ebx-1
    并将其用作索引,这显然是一种优化

    当位移为负值时,这意味着什么

    它没有任何“意义”。硬件只进行二进制加法,并使用结果。由程序员(或编译器)使用寻址模式访问所需的字节

    我的答案中有一些例子,说明了什么时候可以使用所有可能的寻址模式进行数组索引,可以使用指向数组的指针,也可以使用静态数组(因此可以将数组的起始地址硬编码为绝对位移)


    在技术x86寻址模式术语中:

    • 位移:地址的+常量部分,用扩展的
      disp8
      disp32
      补码编码。(在64位寻址模式中,
      disp32
      符号扩展为64位)
    • 偏移量:esi+ebx*4-0x4计算的结果:相对于段基的偏移量。(在基址为0的普通平面内存模型中,偏移量=整个地址)

      人们经常使用“偏移量”来描述位移,通常不会产生混淆,因为从上下文中可以清楚地看出,他们谈论的是恒定偏移量(使用英语单词offset的意思不是x86
      seg:off
      ),但我喜欢使用“偏移量”来描述位移

    • 基址:寻址模式的非索引寄存器组件(如果有)。(改为“无基址寄存器”的编码意味着存在一个
      disp32
      ,您可以将其视为一个基址。它意味着DS段。)

      这包括只有索引而没有基址寄存器的情况:
      [esi*4]
      只能编码为
      [dword 0+esi*4]


    是,
    eax*=内存源操作数

    是的,你的地址计算是正确的。基+缩放索引+有符号位移,生成虚拟地址1

    “转到地址(结果)并获取其中的值”是一种奇怪的描述方式。“go to”通常意味着控制传输,将字节作为代码获取。但事实并非如此,这只是来自该地址的数据加载,完全由硬件处理

    现代x86 CPU(例如Intel Skylake)将
    imul eax、[esi+ebx*4-4]
    解码为两个UOP:一个imul ALU操作和一个加载。ALU操作必须等待加载结果。(有趣的事实:对于大多数管道,这两个微操作实际上是微融合到一个uop中的,除了在无序调度程序中。有关更多信息,请参阅。)

    当load uop运行时,地址生成单元(AGU)获得2个寄存器输入、索引比例因子(左移2)和即时位移(
    -4
    )。AGU中的shift和add硬件计算加载地址

    加载执行单元内的下一步是使用该地址从L1d缓存加载(基本上内置了第一级L1dTLB虚拟->物理缓存。L1d是虚拟索引的,因此TLB查找可以与从L1d缓存中获取8个标记+数据集并行进行)。假设L1dTLB和L1d缓存中有命中,负载执行单元在5个周期后收到负载结果

    加载结果作为源操作数转发给ALU执行单元。ALU不关心它是imul eax、ebx还是内存源操作数;只要两个输入操作数都准备好,乘法uop就被分派到ALU


    是,
    eax*4
    是缩放索引

    是,
    0x80497e8
    是disp32位移。在这种情况下,寻址模式的位移分量可能被用作静态跳转表的地址。您可以将其视为此寻址模式的基础

    跳转到那个地址

    否,从该地址加载新的EIP值。这对我来说是个挑战
    imul   eax,DWORD PTR [esi+ebx*4-0x4]
    
    jmp    DWORD PTR [eax*4+0x80497e8]
    
    lea   eax, [eax*4+0x80497e8]       ; address calc
    jmp   eax                          ; jump to code at that address