【问题标题】:x86 - addressing modes to access elements in arraysx86 - 访问数组中元素的寻址模式
【发布时间】:2023-12-29 03:26:01
【问题描述】:

我正在努力学习汇编语言。有人可以解释和/或举例说明如何使用寻址模式来访问以下每种数组类型中的元素吗?

  1. DWORD数组

  2. 结构数组,其中每个结构包含两个DWORDs

  3. 数组数组,其中每个数组有10个DWORDs

【问题讨论】:

    标签: arrays assembly x86 addressing-mode


    【解决方案1】:

    您没有提及您具体针对的是哪个处理器,但在 386+ 中这会起作用。我没有 MASM,但 MASM 使用 Intel 语法。

    1. 假设ebx 是基址寄存器,esi 是元素的索引寄存器。标准 32 位寄存器(eaxebxecxedxebpesiedi)对此处使用的寻址模式有效。 esp 可以用作基址寄存器,但不能用作索引寄存器。索引寄存器的值可以选择用 2、4 或 8 进行缩放。在此示例中,我们可以为 dword 数组使用缩放因子 4(在 386 个合法缩放因子中为 1、2、4 和 8)。

      将数组中的值读入eaxmov eax, [ebx+4*esi]eax 的值存储到数组中:mov [ebx+4*esi], eax

    2. 让我们保持ebx 作为基地址。对于每个结构由 2 个双字组成的结构数组,我们可以为 esi 使用比例因子 8。

      将第一个双字的值读入eaxmov eax, [ebx+8*esi]eax 的值存储到第一个 dword 中:mov [ebx+8*esi], eax

      将第二个dword的值读入eaxmov eax, [ebx+8*esi+4]eax 的值存储到第二个dword 中:mov [ebx+8*esi+4], eax

      如果索引不能被硬编码,您只需将 4 添加到 ebx(或用于存储基地址的任何寄存器)。如果你有硬编码的基地址,那么你可以使用例如。 esi 解决结构和例如。 ebx 来解决您想要的 dword。请注意,在 386+ 中,您不能在间接寻址中扩展多个寄存器(索引寄存器)。

    3. 我们仍然假设您事先不知道数组的基地址,您将在ebx 中拥有它,在esi 中拥有结构的索引,在edx 中拥有索引的双字。

      要获取结构体的地址,可以使用lea 乘法优化(10 = 8 + 2):

      编辑: 修正:lea esi,[4*esi](dword 为 4 个字节)

      lea edi,[ebx+8*esi]

      lea edi,[edi+2*esi]

      现在您在edi 中获得了结构的地址。您只需将 dword 的索引(本例中存储在 edx 中)乘以 4(因为每个 dword 为 4 个字节)。

      将dword的值读取到eaxmov eax,[edi+4*edx]

      eax 的值存储到双字中:mov [edi+4*edx],eax

    【讨论】:

    • 在 x86 上执行*10 的正常方式是*5*2,例如lea reg, [reg+reg*4]/add reg,reg。您可以通过将其设置为 *8 而不是 *2 来再扩展 4 个。所以对于案例 3:lea eax, [esi+esi*4]/lea eax, [ebx + esi*8](eax 保存内部数组/结构的地址)。然后mov eax, [eax + edx*4]。 (使用任何临时而不是 EAX,包括覆盖其中一个输入。)顺便说一句,shl esi, 2 会比 lea esi, [4*esi] 更有效,因为你不添加或复制。
    【解决方案2】:

    逻辑很简单。

    一维数组的第i个元素的地址就是数组(或第0个元素)的地址加上i * 元素大小.

    如果你有一个二维数组,你可以把它当作一维数组的一维数组,并把它简化为我刚刚描述的已经很熟悉的情况:i的地址 em>- 2-dim 数组的第 1-dim 子数组就是 2-dim 数组的地址加上 i * 子数组大小。在第 i 个子数组中,我们已经知道如何计算第 j 个元素地址。

    所以,二维数组的第(i,j)元素的地址就是数组的地址加上i * 子数组size + j * 元素大小 或者,等价地,数组的地址加上 (i * 元素个数在行中 + j) * 元素大小.

    你应该能够弄清楚如何用汇编语言做到这一点。

    【讨论】: