所以我试图将以下赋值从C转换为内联汇编
resp = (0x1F)&(letter >> (3 - numB));
假设变量的声明如下
unsigned char resp;
unsigned char letter;
int numB;
所以我尝试了以下内容:
_asm {
mov ebx, 01fh
movzx edx, letter
mov cl,3
sub cl, numB // Line 5
shr edx, cl
and ebx, edx
mov resp, ebx
}
或以下
_asm {
mov ebx, 01fh
movzx edx, letter
mov ecx,3
sub ecx, numB
mov cl, ecx // Line 5
shr edx, cl
and ebx, edx
mov resp, ebx
}
在这两种情况下,我都会在第5行中获得大小操作数错误。 我怎样才能实现正确的转变?
答案 0 :(得分:1)
E*X
寄存器为32位,而*L
寄存器为8位。同样,在Windows上,int
类型为32位宽,而char
类型为8位宽。您不能在一条指令中任意混合这些大小。
所以,在你的第一段代码中:
sub cl, numB // Line 5
这是错误的,因为cl
寄存器存储了8位值,而numB
变量的类型为int
,存储了32位值。您不能从8位值中减去32位值; <{1}}指令的两个操作数必须大小相同。
同样,在你的第二段代码中:
SUB
您正试图将ECX中的32位值移入8位CL寄存器。如果没有某种截断,这是不可能发生的,所以你必须明确地指出它。 mov cl, ecx // Line 5
指令要求两个操作数具有相同的大小。
(MOV
和MOVZX
是这个规则的明显例外,操作数类型必须匹配单个指令。这些指令分别对一个较小的值进行零扩展或符号扩展,以便它可以存储到更大的寄存器中。)
但是,在这种情况下,您甚至不需要需要 MOV指令。请记住,CL只是完整32位ECX寄存器的低8位。因此,设置ECX也隐式设置CL。如果只需要低8位,则可以在后续指令中使用CL。因此,您的代码变为:
MOVSX
对于上面讨论的相同操作数大小匹配问题,我还必须更改最终的 mov ebx, 01fh ; move constant into 32-bit EBX
movzx edx, BYTE PTR letter ; zero-extended move of 8-bit variable into 32-bit EDX
mov ecx, 3 ; move constant into ECX
sub ecx, DWORD PTR numB ; subtract 32-bit variable from ECX
shr edx, cl ; shift EDX right by the lower 8 bits of ECX
and ebx, edx ; bitwise AND of EDX and EBX, leaving result in EBX
mov BYTE PTR resp, bl ; move lower 8 bits of EBX into 8-bit variable
指令。您不能将存储在32位寄存器中的值直接移动到8位变量中。您必须移动低8位或高8位,允许您使用MOV
或BL
寄存器,这些寄存器为8位,因此与BH
的大小相匹配。在上面的代码中,我假设您只想要低8位,所以我使用了resp
。
另请注意,我已使用BL
和BYTE PTR
规范。这些在MASM(或Visual Studio的内联汇编程序)中并不是绝对必要的,因为它可以从变量类型中推断出类型的大小。但是,我认为它增加了可读性,通常是一种推荐的做法。 DWORD PTR
表示32位;它与DWORD
和32位寄存器(int
)的大小相同。 E*X
表示16位;它与WORD
和16位寄存器(short
)的大小相同。 *X
表示8位;它的大小与BYTE
和8位寄存器(char
或*L
)相同。