从内存中添加一个字节到 AX 寄存器

Adding a byte from memory to the AX register

我目前正在尝试弄清楚如何将指针寄存器 SI 指向的内存中的第一个字节添加到 AX 寄存器的当前内容中。

因此,如果 SI 持有某个地址,并且该地址在内存中的值是:00 和 01,我希望将 00 添加到 AX 寄存器。

我的汇编菜鸟自己尝试的第一个指令是 add ax, byte ptr [SI] 但当然,没有骰子,因为我正在尝试添加不同大小的操作数。

我目前的解决方法是

mov dx,0000h             ;empty the contents of dx
mov dl,byte ptr [si]     ;get the value of the first byte in a register
add ax,dx                ;perform the originally desired addition

但这非常浪费,并且真的会影响我执行的指令数(这是运行多次的子例程的一部分)。

我受限于 8086 指令集,所以 不幸的是,这表明 movzx 压缩我的前两行是不可行的。

正如您所说,如果您可以假设一个 386 兼容的 CPU,一个不错的选择(尤其是对于现代 CPUs)是 movzx dx, byte ptr [mem] / add ax, dx。如果不是,我想我们可以假装我们正在为真正的 8086 进行调整,where code size in bytes is often more important than instruction count。 (特别是在 8088 上,它有 8 位总线。)所以你肯定想使用 xor dx, dx 来清零 DX(2 个字节而不是 mov reg, imm16 的 3 个字节),如果你不能避免清零指令一共

将 DX(或 DH)的归零提升到任何循环之外,所以你只需 mov dl, [mem] / add ax, dx。如果函数只执行一次,您可能需要(手动) 将函数内联在循环调用它的调用站点中,如果它足够小以至于有意义的话。或者选择一个寄存器,调用者负责将上半部分设为零。

正如 Raymond 所说,您可以选择任何其他寄存器,您知道其高半部分在函数的那个​​点为零。也许你可以 mov cx, 4 而不是 mov cl, 4 如果你之前碰巧需要 CL=4 来做其他事情,但是当你需要添加到 AX 时你已经完成了 CX。 mov cx, 4 仅长 1 个字节,因此您只需 1 个额外字节的代码大小即可将 CH 归零。 (对比 xor cx, cx 花费 2 个字节)


另一个选项是 byte add/adc,但这对于代码大小来说并不理想。 (或稍后 CPU 秒的表现。)

  add al, [mem]      ; 2 bytes + extra depending on addr mode
  adc ah, 0          ; 3 bytes

所以这比你已经有一个备用的上零寄存器多了 1 个字节:

  mov  dl, [mem]     ; 2 bytes (+ optional displacement)
  add  ax, dx        ; 2 bytes

但从好的方面来说,add/adc根本不需要任何额外的寄存器。


有了 SI 中的指针,如果您真的要优化代码大小,就值得寻找利用 lodsb 的方法。那会 mov al, [si] / inc si(或者如果 DF=1 则 dec si),但不会影响 FLAGS。所以你想添加到不同的寄存器中。

xchg ax, reg 只有 1 个字节,但是如果您需要两次交换,如果您实际上必须在 AX 中 return 而不是其他寄存器,那么它可能无法收回成本。