将变量移动到 cl 并使用内联汇编执行 shr
Move variable to cl and perform shr using inline assembly
所以我正在尝试将以下赋值从 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 行遇到大小操作数错误。
我怎样才能实现正确的转变?
E*X
寄存器是32位,而*L
寄存器是8位。同样,在Windows上,int
类型是32位宽,而char
类型是8位宽。您不能在一条指令中任意混合这些大小。
因此,在您的第一段代码中:
sub cl, numB // Line 5
这是错误的,因为 cl
寄存器存储一个 8 位值,而 numB
变量是 int
类型,它存储一个 32 位值。您不能从 8 位值中减去 32 位值; SUB
指令的两个操作数必须大小相同。
同样,在你的第二段代码中:
mov cl, ecx // Line 5
您正在尝试将 ECX 中的 32 位值移动到 8 位 CL 寄存器中。没有某种截断就不会发生这种情况,因此您必须明确指出。 MOV
指令要求它的两个操作数具有相同的大小。
(MOVZX
和 MOVSX
是此规则的明显例外,即操作数类型必须与单个指令匹配。这些指令分别对较小的值进行零扩展或符号扩展,因此它可以存储到更大的寄存器中。)
但是,在这种情况下,您甚至不需要 MOV 指令。请记住,CL 只是完整的 32 位 ECX 寄存器的低 8 位。因此,设置 ECX 也会隐式设置 CL。如果你只需要低 8 位,你可以在后续指令中使用 CL。因此,您的代码变为:
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
对于上面讨论的相同操作数大小匹配问题,我还不得不更改最后的 MOV
指令。您不能将存储在 32 位寄存器中的值直接移动到 8 位变量中。您必须移动低 8 位或高 8 位,从而允许您使用 BL
或 BH
寄存器,它们是 8 位,因此匹配 resp
的大小.在上面的代码中,我假设您只需要低 8 位,所以我使用了 BL
.
另请注意,我使用了 BYTE PTR
和 DWORD PTR
规范。这些在 MASM(或 Visual Studio 的内联汇编程序)中并不是绝对必要的,因为它可以从变量的类型中推断出类型的大小。但是,我认为它增加了可读性,并且通常是推荐的做法。 DWORD
表示32位;它的大小与 int
和一个 32 位寄存器 (E*X
) 相同。 WORD
表示16位;它的大小与 short
和一个 16 位寄存器 (*X
) 相同。 BYTE
表示8位;它与 char
和一个 8 位寄存器(*L
或 *H
)的大小相同。
所以我正在尝试将以下赋值从 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 行遇到大小操作数错误。 我怎样才能实现正确的转变?
E*X
寄存器是32位,而*L
寄存器是8位。同样,在Windows上,int
类型是32位宽,而char
类型是8位宽。您不能在一条指令中任意混合这些大小。
因此,在您的第一段代码中:
sub cl, numB // Line 5
这是错误的,因为 cl
寄存器存储一个 8 位值,而 numB
变量是 int
类型,它存储一个 32 位值。您不能从 8 位值中减去 32 位值; SUB
指令的两个操作数必须大小相同。
同样,在你的第二段代码中:
mov cl, ecx // Line 5
您正在尝试将 ECX 中的 32 位值移动到 8 位 CL 寄存器中。没有某种截断就不会发生这种情况,因此您必须明确指出。 MOV
指令要求它的两个操作数具有相同的大小。
(MOVZX
和 MOVSX
是此规则的明显例外,即操作数类型必须与单个指令匹配。这些指令分别对较小的值进行零扩展或符号扩展,因此它可以存储到更大的寄存器中。)
但是,在这种情况下,您甚至不需要 MOV 指令。请记住,CL 只是完整的 32 位 ECX 寄存器的低 8 位。因此,设置 ECX 也会隐式设置 CL。如果你只需要低 8 位,你可以在后续指令中使用 CL。因此,您的代码变为:
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
对于上面讨论的相同操作数大小匹配问题,我还不得不更改最后的 MOV
指令。您不能将存储在 32 位寄存器中的值直接移动到 8 位变量中。您必须移动低 8 位或高 8 位,从而允许您使用 BL
或 BH
寄存器,它们是 8 位,因此匹配 resp
的大小.在上面的代码中,我假设您只需要低 8 位,所以我使用了 BL
.
另请注意,我使用了 BYTE PTR
和 DWORD PTR
规范。这些在 MASM(或 Visual Studio 的内联汇编程序)中并不是绝对必要的,因为它可以从变量的类型中推断出类型的大小。但是,我认为它增加了可读性,并且通常是推荐的做法。 DWORD
表示32位;它的大小与 int
和一个 32 位寄存器 (E*X
) 相同。 WORD
表示16位;它的大小与 short
和一个 16 位寄存器 (*X
) 相同。 BYTE
表示8位;它与 char
和一个 8 位寄存器(*L
或 *H
)的大小相同。