【问题标题】:What does "[V+ECX*2-2]" refer to in memory exactly?“[V+ECX*2-2]”在内存中到底指的是什么?
【发布时间】:2019-08-16 09:50:08
【问题描述】:

所以我有这个练习要解决:“给定一个 x 16 位整数的向量 V,检查向量是否只包含偶数。如果是这种情况,EAX 将等于 1,否则为 0。x 保存在地址为 n,有 16 位。解决方法如下:

    MOVZX ECX, WORD [n]
    XOR EAX, EAX
bcle:
    TEST WORD [V+ECX*2-2], 1
    LOOPZ bcle
    JNZ sinon
    INC EAX
sinon:

现在我被困在 [V+ECX*2-2]...也许我错了,但我相信此时的 ECX 寄存器包含一个数字,我们正在检查它是否偶数...如果那就是为什么我们要在内存中寻找那个地址呢?我在许多网站和书籍上查找了内存寻址的工作原理,但我永远无法应用于练习,也许如果这里有人可以用一个简单的例子向我解释我会很感激......

【问题讨论】:

  • 这个循环有很多错过的优化...test byte [v+ecx*2-2], 1 将节省 2 个字节并避免 Intel CPU 上的 LCP 解码停滞。 (test r/m16, imm8 不存在,只有 imm16 版本。在 32 位模式下具有 16 位立即数的指令可能会停止,因为操作数大小前缀会更改指令其余部分的长度。)此外,loop 是英特尔 CPU 速度慢;将test/jnz 作为dec/jnz 循环内的循环体确实会更快。但是这个循环无法优化性能代码大小。此外,索引寻址模式将在 Intel 上解压。
  • 另外,如果您的数组是静态的,通常大小可以是汇编时常量,而不是存储在内存中。就像在 V 定义之后的 n equ $ - V 一样。我知道这些都不是你要问的,但是这个优化不完善的循环让我很困扰。

标签: x86 nasm addressing-mode


【解决方案1】:

ECX 这里包含V 数组中当前数字的索引(更准确地说是索引+1),而不是数字本身。它是索引+1,因为ECXMOVZX ECX, WORD [n] 中是用n 初始化的(如在基于1 的数组中,而不是在n-1 中如在基于0 的数组中)。

[V+ECX*2-2] - 正在计算由ECX索引的数字的地址:

  • V - 是数组的地址,
  • ECX*2 - 计算数组内存中ECX'th 元素的偏移量,*2 - 因为我们处理的是 2 字节数字(16 位)
  • -2 - 将基于 1 的数组索引更改为基于 0 的数组索引,因为偏移量必须基于 0,同样-2 因为我们使用的是 2 字节数字
  • [...] - 通过括号内的地址取值
  • WORD - 取一个 2 字节的值

值得注意的是,V+...-2 是允许的,因为V - 是编译时常量,因此编译器可以将V-2 计算为另一个常量并将其放入编译后的二进制文件中。如果V 是动态值[V+...-2] 将无法放入单个指令中,并且需要单独计算地址。

【讨论】:

  • 实际上,如果将 V 替换为 32 位 GPR,则可以将其编码为例如 word [eax + ecx*2 - 2] 在这种情况下,只有常数 -2 将用于位移。
猜你喜欢
  • 2018-01-19
  • 1970-01-01
  • 1970-01-01
  • 2019-01-08
  • 2015-09-20
  • 1970-01-01
  • 1970-01-01
  • 2021-05-09
  • 1970-01-01
相关资源
最近更新 更多