c-为什么将4字节的参数传递给期望2字节参数的函数有效



查看这段使用VC++2003/2005编译的C代码。

#include <stdio.h>
#include <windows.h>
void WINAPI SomeFunction(WORD a, WORD b)
{
printf("%d + %d = %dn", a, b, a + b);
}
int main()
{
__asm {
MOV EAX, 5
MOV EBX, 6
PUSH EBX
PUSH EAX
CALL SomeFunction
}
return 0;
}

在这段ASM代码中,我将两个DWORD(4字节)参数(据我所知,默认情况下)传递给SomeFunction()函数,该函数需要两个WORD(2字节)参数,并且工作正常(输出5 + 6 = 11)。

1) 为什么这样有效?

知道该函数需要两个WORD参数,我将执行以下操作:

__asm {
MOV WORD PTR [EAX], 5
MOV WORD PTR [EBX], 6
PUSH EBX
PUSH EAX
CALL SomeFunction
}

在调试时,它抛出一个Segmentation错误。

2) 为什么不起作用

提前感谢!

第一个有效,因为Win32 ABI规定,任何大小小于或等于4字节的参数都将作为4字节传递,必要时进行填充。因此,16位字实际上是作为32位传递的。这就是你正在做的。

第二个不起作用,因为它做了一件不同的事情:

MOV WORD PTR [EAX], 5

该行将5移动到从EAX所指向的存储器位置开始的16位字中。但是EAX之前没有加载有效的存储器地址。此外,您正在按下指针(WORD*?)。

为了在堆栈中传递16位值,您可以使用:

MOV AX, 5
MOV BX, 6
PUSH AX
PUSH BX

但这与Win32 ABI相反,因为堆栈总是以32位对齐。

有趣的是,如果您通过值传递此结构(未经测试),这将起作用:

struct WW
{
WORD a, b;
};
void WINAPI SomeFunction(WW w)
{
printf("%d + %d = %dn", w.a, w.b, w.a + w.b);
}
int main()
{
__asm {
MOV BX, 6 // the parameters are reversed, methinks
MOV AX, 5
PUSH BX
PUSH AX
CALL SomeFunction
}
return 0;
}

这是因为结构的字段被打包在4个字节(sizeof(WW)==4)中,所以这就是复制到堆栈中的内容。

当然,玩16位寄存器并不有趣。这样做可能更好:

MOV EAX 0x00060005
PUSH EAX

并一次性复制整个32位结构。

相关内容

最新更新