从内存中添加一个字节到 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 而不是其他寄存器,那么它可能无法收回成本。
我目前正在尝试弄清楚如何将指针寄存器 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 而不是其他寄存器,那么它可能无法收回成本。