2

I'm currently trying to figure out how to add the first byte in memory pointed to by the pointer register SI to the current contents of the AX register.

So if SI holds some address, and the values in memory at that address are: 00 and 01, I'm looking to add just 00 to the AX register.

The first instruction my assembly-noobish self tried was add ax, byte ptr [SI] but of course, no dice, as I'm trying to add operands of different sizes.

My current workaround is

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

But this is incredibly wasteful and really hurts my executed instructions count (this is part of a subroutine that runs many times).

I'm limited to the 8086 instruction set so this question/answer by Peter Cordes which suggests movzx to condense my first two lines is unfortunately not viable.

4

1 回答 1

2

正如你所说,如果你可以假设一个兼容 386 的 CPU,一个不错的选择(特别是对于现代 CPU)是movzx dx, byte ptr [mem]/ add ax, dx。如果不是,我想我们可以假装我们正在调整一个真正的 8086,其中以字节为单位的代码大小通常比指令计数更重要。(特别是在具有 8 位总线的 8088 上。)因此,如果您无法完全避免归零指令,您肯定希望使用xor dx, dxDX 归零(2 个字节而不是 3 个字节)。mov reg, imm16

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

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


另一种选择是 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 根本不需要任何额外的寄存器。


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

xchg ax, reg只有 1 个字节,但如果您需要两次交换,如果您实际上必须在 AX 中返回,而不是在其他一些寄存器中返回,它可能不会为自己买单。

于 2021-07-06T05:22:45.483 回答