将无符号字符存储在寄存器中(x86 程序集)

Storing an unsigned char in register (x86 assembly)

我正在编写一个传递了 3 个参数的函数。

void function(unsigned char* one, int two, unsigned char three) {
    __asm 
    {
            mov eax, one
            mov ebx, two
            mov ecx, three //Having issues storing this variable in a register

但是我得到 "three" 的编译错误 "operand size conflict"。其他两个商店就好了。我想弄清楚为什么...如果我使用 lea ecx, three,它会编译。但是存储的值是错误的。

附带问题。我是否正确理解第一个参数向我传递了该变量的内存位置?

谢谢!

大多数 x86 指令要求所有参数的大小相同。在这种情况下,three 是一个 8 位参数,因此使用带有 8 位目标的 mov 来加载它,例如 mov cl, three

有一些类似于 mov 的指令允许 扩展 从较小的源到较大的目的地。例如,您可以使用 movzx ecx, three(使用零扩展移动)将字节加载到 ecx 并将前三个字节归零。

我建议不要通过 "mov" 指令将参数显式移动到寄存器中,因为如果您将项目编译为 "Register" 调用约定,那么 "one"、"two" 和 "three" 只是寄存器的别名,你可以覆盖你需要的数据,你只需在你的代码中插入不必要的 "mov" 指令。只需考虑哪些参数来自哪些寄存器并立即使用这些参数。但要小心大小小于寄存器大小的参数。高位可能未定义(丢弃)。

这取决于特定的调用约定,但最有可能的是,对于 32 位寄存器调用约定,调用在 EAX 中传递第一个参数,在 EDX 中传递第二个参数,在 ECX 中传递第三个参数。结果以 EAX(32 位)或 EAX:EDX 对(64 位)返回。有关详细信息,请参阅 http://docwiki.embarcadero.com/RADStudio/Seattle/en/Program_Control#Register_Convention

在你的例子中,"unsigned char three" 立即出现在 ECX 中,"two" 出现在 EDX 中,"one" 出现在 EAX 中,你不需要做任何移动,但是因为 "three" 只是一个字符(8 位)而 ECX 是双字(32 位),ECX 的第 8-31 位可能包含垃圾。您不应依赖这些位为零的假设。

对于64位调用约定,第一个参数在RCX中传递,第二个-RDX,第三个R8,第四个-R9,结果在RAX中返回。有关 64 位的详细信息,请参阅 https://msdn.microsoft.com/en-us/library/ms235286.aspx