程序被调用的流程可以总结如下:
参数传递
函数调用时,实际参数通过栈传递。参数从右到左入栈。
传递的参数包括实际参数和返回地址。
栈帧分配
为被调用函数的局部变量和形参分配存储空间。
分配的存储空间大小取决于局部变量的数量和类型。
控制转移
将控制转移到被调用函数的入口地址。
这通常通过一个跳转指令(如`CALL`)实现。
执行被调用函数
被调用函数从入口地址开始执行,直到遇到`RET`指令。
在执行过程中,被调用函数可能会使用局部变量、形参和寄存器。
返回结果
被调用函数执行完毕后,将返回结果保存到指定的位置(通常是`EAX`寄存器)。
然后执行`RET`指令,将控制返回到调用函数。
资源清理
释放被调用函数所占用的存储空间,包括局部变量和返回地址。
这通常通过`POP`指令将栈顶元素出栈并恢复其原始值。
示例代码分析
```csharp
class Program
{
static void Main()
{
char[] szBuff = "sfjdlskfjl".ToCharArray();
int nRet = TestFunction(szBuff, 32);
return;
}
static int TestFunction(char[] buffer, int size)
{
// 函数内部执行
return size;
}
}
```
参数传递
`szBuff`和`32`作为实际参数传递给`TestFunction`。
参数通过栈传递,从右到左入栈。
栈帧分配
为`TestFunction`的局部变量(如`buffer`和`size`)分配存储空间。
控制转移
`Main`函数中的`TestFunction(szBuff, 32)`调用将控制转移到`TestFunction`的入口地址。
执行被调用函数
`TestFunction`从入口地址开始执行,直到遇到`RET`指令。
在`TestFunction`中,执行`return size;`将返回值`32`保存到`EAX`寄存器。
返回结果
`TestFunction`执行完毕后,`RET`指令将控制返回到`Main`函数。
资源清理
`TestFunction`所占用的存储空间被释放。
通过这个示例,可以清晰地看到函数调用的整个流程,包括参数传递、栈帧分配、控制转移、执行被调用函数、返回结果和资源清理。