从IA-32中的程序集访问C++中的函数参数

Abi*_*n K 2 c++ 64-bit x86 assembly function

我一直在学习IA-32汇编编程.所以我想在汇编中编写一个函数并从C++中调用它.

我正在遵循的教程实际上是用于x64程序集.但我正在研究IA-32.在x64中,它表示函数参数存储在RCX,RDX,R8,R9等寄存器中.

但是在搜索一下,我可以理解在IA-32中,参数存储在堆栈中,而不是存储在寄存器中.

下面是我的C++代码:

#include <iostream>
#include <conio.h>

using namespace std;
extern "C" int PassParam(int a,int b);

int main()
{
    cout << "z is " << PassParam(15,13) << endl;
    _getch();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

下面是PassParam()函数的汇编代码(它只添加两个参数,这就是全部.它仅用于学习目的):

程序集中的PassParam():

.model C,flat
.code
PassParam proc
    mov eax,[ebp-212]
    add eax,[ebp-216]
    ret
PassParam endp
end
Run Code Online (Sandbox Code Playgroud)

在我的汇编代码中,您可以看到我将[ebp-212]中的第一个参数移动到eax.该值获得如下:

我在C++中编写了PassParam()函数并对其进行了反汇编.然后检查ebp在哪里以及存储第二个参数的位置(参数从右到左存储).我可以看到212的差异,所以这就是我获得这个价值的方式.然后像往常一样,第一个参数存储在4个字节之后.它工作正常.

题 :

这是从程序集访问参数的正确方法吗?我的意思是,它是否始终[ebp-212]存储参数?

如果没有,任何人都可以解释将参数从C++传递到汇编的正确方法吗?

注意 :

我正在使用Windows 7计算机上的Visual C++ 2010.

Nec*_*lis 8

在32位架构,这取决于调用约定,Windows为例如既有__fastcall__thiscall在使用寄存器和堆栈ARGS,并__cdecl__stdcall在使用堆栈ARGS,但谁做的清理不同.MSDN 在这里有一个很好的列表(或更多的面向程序集的版本).请注意,FPU/SSE操作也有自己的约定.

为了方便和简单,尝试使用__stdcall所有内容,这允许您使用堆栈帧来访问args MOV r32,[EBP+4+(arg_index * 4)],或者如果您不使用堆栈帧,您可以使用MOV r32,[ESP+local_stack_offset+(arg_index * 4)].带注释的C++ - > x86汇编例如这里应该有所帮助.


所以作为一个简单的例子,假设我们MulAdd在汇编中有函数,使用C++原型int __stdcall MulAdd(int base, int mul, int add),它看起来像:

MOV EAX,[ESP+4] //get the first arg('base') off the stack
MOV ECX,[ESP+8] //get the second arg('mul') off the stack
IMUL EAX,ECX //base * mul
MOV ECX,[ESP+12] //get arg 3 off the stack
ADD EAX,ECX
RETN 12 //cleanup the 3 args and return
Run Code Online (Sandbox Code Playgroud)

或者如果您使用堆栈框架:

PUSH EBP
MOV EBP,ESP //save the stack
MOV EAX,[EBP+8] //get the first arg('base') off the stack
MOV ECX,[EBP+12] //get the second arg('mul') off the stack
IMUL EAX,ECX //base * mul
MOV ECX,[EBP+16] //get arg 3 off the stack
ADD EAX,ECX
MOV ESP,EBP //restore the stack
POP EBP
RETN //return to caller
Run Code Online (Sandbox Code Playgroud)

使用堆栈帧避免了需要通过PUSH对局部变量进行的args,溢出或寄存器或堆栈分配来调整对堆栈所做的更改.它的缺点是它减少了你必须使用的寄存器数量.