所以我之前问过这个问题,但细节要少得多。问题标题准确地描述了问题:我在C ++中有一个方法,我试图从具有参数和返回值的程序集(x86)调用。我充分理解了汇编和对C ++的相当深刻的理解(否则我不会承担这个问题)。就代码而言,这就是我所拥有的:
// methodAddr is a pointer to the method address
void* methodAddr = method->Address;
// buffer is an int array of parameter values. The parameters can be anything (of any type)
// but are copied into an int array so they can be pushed onto the stack in reverse order
// 4 bytes at a time (as in push (int)). I know there's an issue here that is irrelevent to my baseline testing, in that if any parameter is over 4 bytes it will be broken and
// reversed (which is not good) but for basic testing this isn't an issue, so overlook this.
for (int index = bufferElementCount - 1; index >= 0; index--)
{
int val = buffer[index];
__asm
{
push val
}
}
int returnValueCount = 0;
// if there is a return value, allocate some space for it and push that onto the stack after
// the parameters have been pushed on
if (method->HasReturnValue)
{
*returnSize = method->ReturnValueSize;
outVal = new char[*returnSize];
returnValueCount = (*returnSize / 4) + (*returnSize % 4 != 0 ? 1 : 0);
memset(outVal, 0, *returnSize);
for (int index = returnValueCount - 1; index >= 0; index--)
{
char* addr = ((char*)outVal) + (index * 4);
__asm
{
push addr
}
}
}
// calculate the stack pointer offset so after the call we can pop the parameters and return value
int espOffset = (bufferElementCount + returnValueCount) * 4;
// call the method
__asm
{
call methodAddr;
add esp, espOffset
};
对于我的基本测试,我使用的方法具有以下签名:
Person MyMethod3( int, char, int );
问题是:当省略方法签名的返回值时,所有参数值都被正确传递。但是当我按原样保留方法时,传递的参数数据不正确但返回的值是正确的。所以我的问题显然是错的?我已经尝试在参数之前将返回值空间推送到堆栈。人员结构如下:
class Person
{
public:
Text Name;
int Age;
float Cash;
ICollection<Person*>* Friends;
};
非常感谢任何帮助。谢谢!
我正在使用Visual Studio 2013和2013年11月的C ++ CTP编译器,目标是x86。
因为它与反汇编有关,这是直接的方法调用:
int one = 876;
char two = 'X';
int three = 9738;
Person p = MyMethod3(one, two, three);
以下是反汇编:
00CB0A20 mov dword ptr [one],36Ch
char two = 'X';
00CB0A27 mov byte ptr [two],58h
int three = 9738;
00CB0A2B mov dword ptr [three],260Ah
Person p = MyMethod3(one, two, three);
00CB0A32 push 10h
00CB0A34 lea ecx,[p]
00CB0A37 call Person::__autoclassinit2 (0C6AA2Ch)
00CB0A3C mov eax,dword ptr [three]
00CB0A3F push eax
00CB0A40 movzx ecx,byte ptr [two]
00CB0A44 push ecx
00CB0A45 mov edx,dword ptr [one]
00CB0A48 push edx
00CB0A49 lea eax,[p]
00CB0A4C push eax
00CB0A4D call MyMethod3 (0C6B783h)
00CB0A52 add esp,10h
00CB0A55 mov dword ptr [ebp-4],0
我对此的解释如下:
执行局部变量的赋值。然后创建输出寄存器。然后将参数放在特定的寄存器中(此处的顺序恰好是eax
,ecx
和edx
,这是有意义的(eax
和ebx
是例如,ecx
用于两个,edx
和其他一些寄存器用于最后一个参数?))。然后调用LEA
(加载有效地址),我不明白但已理解为MOV
。然后它以地址作为参数调用方法?然后移动堆栈指针以弹出参数并返回值。
任何进一步的解释都值得赞赏,因为我确信我的理解存在一些缺陷。