将变量移动到cl并使用内联汇编执行shr

时间:2016-11-22 22:24:46

标签: c assembly x86 intel 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行中获得大小操作数错误。 我怎样才能实现正确的转变?

1 个答案:

答案 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 指令要求两个操作数具有相同的大小。

MOVMOVZX是这个规则的明显例外,操作数类型必须匹配单个指令。这些指令分别对一个较小的值进行零扩展或符号扩展,以便它可以存储到更大的寄存器中。)

但是,在这种情况下,您甚至不需要需要 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位,允许您使用MOVBL寄存器,这些寄存器为8位,因此与BH的大小相匹配。在上面的代码中,我假设您只想要低8位,所以我使用了resp

另请注意,我已使用BLBYTE PTR规范。这些在MASM(或Visual Studio的内联汇编程序)中并不是绝对必要的,因为它可以从变量类型中推断出类型的大小。但是,我认为它增加了可读性,通常是一种推荐的做法。 DWORD PTR表示32位;它与DWORD和32位寄存器(int)的大小相同。 E*X表示16位;它与WORD和16位寄存器(short)的大小相同。 *X表示8位;它的大小与BYTE和8位寄存器(char*L)相同。