Assembly 无法将8位地址移动到16位寄存器
我正在尝试分配要注册的变量,代码如下:Assembly 无法将8位地址移动到16位寄存器,assembly,x86,x86-16,emu8086,Assembly,X86,X86 16,Emu8086,我正在尝试分配要注册的变量,代码如下: ORG 100h var1 DB 10 ; var2 DB 20 ; MOV BX,var1 ; error : operands do not match: 16 bit register and 8 bit address RET END 但如果将第四行替换为: MOV BL, var1; 它起作用了。所以我的问题是,为什么我不能将8位变量移动到更大的16位寄存器 我已经提到了O
ORG 100h
var1 DB 10 ;
var2 DB 20 ;
MOV BX,var1 ; error : operands do not match: 16 bit register and 8 bit address
RET
END
但如果将第四行替换为:
MOV BL, var1;
它起作用了。所以我的问题是,为什么我不能将8位变量移动到更大的16位寄存器
我已经提到了OP,但它没有回答我的问题
注意:
您使用的是一个汇编程序,它跟踪您如何声明符号,以确定要使用的操作数大小
var1
不是一个8位地址,它是一个16位地址(不包括段),指向两个8位变量中的第一个。因此,汇编程序错误消息措辞糟糕,令人困惑
NASM会照你说的做,然后进行16位加载。您可以在bl
中找到var1
,在bh
中找到var2
。大概您可以编写mov-bx、word[var1]
或word-ptr
或任何东西,以使汇编程序发出16位负载
(实际上,NASM会将mov BX,var1
组合成mov r16,imm16
,将地址放入寄存器。始终使用[]
围绕内存引用,以保持一致性,因为这适用于英特尔语法的NASM和MASM变体。不过,NASM不支持写入mov立即数形式的mov BX,offset var1
语法。)
为什么我不能将8位变量移到更大的16位寄存器中
因为机器代码MOV指令需要源操作数和目标操作数的大小相同。这是必需的,因为MOV
指令本身并不指定如何填充较大目标寄存器的剩余位
为了允许不同大小的移动操作,Intel在80386 CPU中添加了MOVZX
和MOVSX
,这允许较小的源操作数(目标始终是32位寄存器)-SX和-ZX后缀表示目标寄存器先前未使用的位应该填充什么
在16位英特尔处理器上,有一条指令CBW
(将字节转换为字),它的符号从8位扩展到16位。不幸的是,这只适用于累加器(寄存器AL/AX),因此您必须执行以下操作:
mov al,var1
cbw
mov bx,ax
cbw
进行符号扩展。如果您的var1
未签名,您可以这样做:
mov bl,var1
xor bh,bh ; equivalent to mov bh,0 but faster and only one byte opcode
或者,正如彼得·科尔德斯所说:
xor bx,bx ;clear the whole destination register
mov bl,var1 ;update the least significant byte of the register with the 8-bit value
您需要使用
movzx
或movsx
,如果可以分别使用零或符号扩展进行移动。它可能在8086中不可用,在这种情况下,您需要像您所做的那样进入BL
,然后自己将BH
归零。至于原因:因为他们是这样创建架构的:)@Jester:不是,只有cbw。我更新了标签wiki,其中有一个指向wikipedia的链接,其中有一个表格,列出了引入各种指令的时间。还有一篇关于在16位8086上学习asm是如何愚蠢的文章。但无论如何,一些主要的INSN8086缺失的是movzx/sx和bt*bit-manip.upvoting,这只是因为错误信息措辞糟糕且具有误导性。这里的答案并没有试图解释为什么这是一个错误,movzx在8086上也不起作用,但仍然存在。投票决定将其作为本文件的副本关闭,因为本文件有更详细的答案。xor bx,bx/mov bl,var1
会更好,因为它更像是您希望在32位或64位模式下使用的好习惯用法之一(在使用较小部分之前将整个寄存器归零)。它打破了对完整寄存器的旧内容的错误依赖,但将上半部分和下半部分分别归零则不行。另外,movs/zxr16,r/m8
是有效的。它对于64位dest reg也是有效的,但对于movzx
则不鼓励这样做,因为它与32位dest的movzx相同。有一个新的操作码用于movsx r64,r/m32
,但不用于movzx。另外,mov-bh,bh
是一个2字节指令,与mov-bh,0
的代码大小相同。如果你要写BH,mov实际上更适合现代CPU上的8位寄存器。(但这两种方法都不好,而将整个16位寄存器的xor归零,就像我之前的评论一样。)