参数和返回值是函数的两个重要组成部分,可以通过参数向函数传入信息,通过返回值使函数传出信息。看一段C语言代码:
#include <stdio.h>
int function(int a, int b)
{
if (a > b)
{
return a;
}
else
{
return b;
}
}
int main()
{
function(1, 2);
return 0;
} 这里定义了一个函数function(),参数是两个整型变量,返回值也是整型变量,当a的值大于b时返回a,否则返回b,很明显这个函数返回的是两个数中的较大数,然后在主函数中调用了这个函数,参数分别为1、2。编译后使用IDA进行分析,主函数的反汇编代码如下:
.text:00401020 push ebp
.text:00401021 mov ebp, esp
.text:00401023 push 2 ; b
.text:00401025 push 1 ; a
.text:00401027 call ?function@@YAHHH@Z ; function(int,int)
这里向栈中压入数据2和1,然后调用函数function(int,int)。可以猜想这样向堆栈里压入2和1就是在给被调用的过程传递参数了。这里要注意,传递参数的时候是反着来的,C语言里调用的时候是function(1, 2),等到反汇编的时候就变成先压入2,再压入1这样的了。
.
text:0040102C add esp, 8
这一句代码用来抬高栈顶,抬高栈顶是为了平衡栈桢,前面为了给被调用过程传递参数向栈中压入了两个四字节的int型变量,这里把栈顶抬高八个字节就是为了销毁传递参数的痕迹。
.text:0040102F xor eax, eax
.text:00401031 pop ebp
.text:00401032 retn 下面是function()函数在IDA中的分析结果:
.text:00401000 ; Attributes: bp-based frame
.text:00401000
.text:00401000 ; int __cdecl function(int a, int b)
.text:00401000 ?function@@YAHHH@Z proc near ; CODE XREF: _main+7 p
.text:00401000
.text:00401000 a = dword ptr 8
.text:00401000 b = dword ptr 0Ch
.text:00401000这里是对function()函数的参数、返回值、调用方式等信息的分析。这里说明了function()函数的调用方式为__cdecl,返回值是int型,两个参数a、b与ebp对应的偏移分别为0x08和0x0C。
.text:00401000 push ebp
.text:00401001 mov ebp, esp
.text:00401003 mov eax, [ebp+a]
.text:00401006 cmp eax, [ebp+b]
.text:00401009 jle short loc_401012
.text:0040100B mov eax, [ebp+a]
.text:0040100E jmp short loc_401015
.text:00401010 jmp short loc_401015
.text:00401012 mov eax, [ebp+b]
.text:00401015 pop ebp
.text:00401016 retn
.text:00401016 ?function@@YAHHH@Z endp 一般来说过程返回的结果都是储存在eax里的。这个函数比较两个参数a、b,如果参数a大于参数b则把参数a放到eax,跳到最后返回,如果参数a不大于参数b则把参数b放到eax中返回。

本文通过一个C语言示例介绍了如何通过参数向函数传递信息,并通过返回值从函数传出信息。具体分析了函数调用过程中参数的传递方式及栈帧的变化。
84

被折叠的 条评论
为什么被折叠?



