函数返回值
int Count()
{
  int i,j;
  i=100;
  j=200;
  return i+j;
}
测试函数:
void Test()
{
int k=Count();
printf("\n k[%d]\n");
}
C/C++的函数返回值一般是放在寄存器eax里的,而不是在栈里。
你的这一句int k = Count()的汇编语句就是这样:
mov [esp - 4], eax //eax里是300,esp - 4是局部变量k的位置
你可以在vc里做个实验:
int  add(int a, int b)
{
__asm {
  mov eax,a // 把参数1存入eax
  add eax,b // eax += 参数2, 结果在eax里
}
}
int main()
{
printf("%d\n", add(3, 4));
return 0;
}
楼主需要了解下寄存器这一概念,我就不把C/C++函数的汇编代码给发出来了。
还有在汇编层面来看,函数的返回值根本就没有定论,函数可以通过多种方式返回。保存返回值在eax里只是C/C++的一个约定而已。
返回值可以放在栈里,但你在C的语言层面上可能做不到,其实随着函数的结束,mov esp, ebp这条指令过后,函数内部的局部变量就报废了。如果你之后没改变过栈的内容,你可以用栈来存返回值,但比起用寄存器来存储,存储和读取要慢的多。
自己突发奇想在vc下试了下用栈“返回”值,写了段代码:
#include <stdio.h>
void __declspec(naked) __stdcall return_a_value()
{
int local;
local = 1990; // 栈空间
__asm ret
}
printf函数返回值
int main()
{
int local = 1;
return_a_value(); // 用栈返回值
printf("%d\n", local);
return 0;
}
汇编看c之一,简单函数调用
简单的函数调用,通过简单的函数调用反汇编可以清楚了解如下
1.栈到底是什么,如何操纵栈的?
2.参数和临时变量是以什么形式在哪存放?
3.如何传递返回值?
 
举例:
#include <stdio.h>
 
int add(int a,int b)
{
    int c=0;
    c=a+b;
    return c;
}
int main(void)
{
    int x=0;
    int y=3;
    int z=4;
    x=add(y,z);
    return 0;
}
这是一个简单的通过调用函数计算两数之和的程序
VC6.0生成的汇编代码如下:
add函数
{

0040D750  push        ebp
//main函数的ebp压栈,ebp=1000,esp=896
0040D751  mov        ebp,esp
//得到栈基址,这里的新的意思是每个函数访问属于自己的一块栈区域,其实是相邻的内存区域,或者说栈只有一个。ebp=896esp=896
0040D753  sub        esp,44h
//ebp=896esp=828
0040D756  push        ebx
0040D757  push        esi
0040D758  push        edi
//ebp=896esp=816
0040D759  lea        edi,[ebp-44h]
0040D75C  mov        ecx,11h
0040D761  mov        eax,0CCCCCCCCh
0040D766  rep stos    dword ptr [edi]
//初始化内部变量区
5:        int c=0;
0040D768  mov        dword ptr [ebp-4],0
//c放入栈基址
6:        c=a+b;
0040D76F  mov        eax,dword ptr [ebp+8]
0040D772  add        eax,dword ptr [ebp+0Ch]
//因为栈基地址就是栈顶地址,所以通过ebp访问传过来的参数,ebp+8ebp+c是因为ebp上方的8字节用于存储调用函数的调用地址和堆栈基地址了。
0040D775  mov        dword ptr [ebp-4],eax
//运算结果放入c
7:        return c;
0040D778  mov        eax,dword ptr [ebp-4]
//用寄存器eax返回结果
8:    }
0040D77B  pop        edi
0040D77C  pop        esi
0040D77D  pop        ebx
//恢复寄存器的值,ebp=896esp=828
0040D77E  mov        esp,ebp
//恢复栈顶地址,ebp=896esp=896,此函数堆栈被释放!
0040D780  pop        ebp
//恢复栈基地址,ebp=1000esp=900,此时恢复到调用前的栈基地址和顶地址
0040D781  ret
//返回调用点,ebp=1000,esp=904,调用点地址被弹出,返回到调用点
 
main函数
{
0040D790  push        ebp
0040D791  mov        ebp,esp
//用栈顶地址作为栈基地址,目的是不和调用前栈空间冲突,为了叙述方便假设此时的栈基址ebp=1000esp=1000
0040D793  sub        esp,4Ch
//esp下移,开辟出0x4C字节的空间,这个空间是留给内部参数用的,这个空间的大小随内部变量多少由编译器决定。ebp=1000esp=1000-0x4C=924
0040D796  push        ebx
0040D797  push        esi
0040D798  push        edi
//保护 ebxesiedi的值,ebp=1000esp=924-12=912
0040D799  lea        edi,[ebp-4Ch]
0040D79C  mov        ecx,13h
0040D7A1  mov        eax,0CCCCCCCCh
0040D7A6  rep stos    dword ptr [edi]
//把内部参数占用的空间每个字节都初始化为0xCC这个是为了在DUBUG程序的方便,编译器加入的,如果不在DEBUG状态下,这个区域是没有被初始化的,也就是说是随机值。
12:      int x=0;
0040D7A8  mov        dword ptr [ebp-4],0
13:      int y=3;
0040D7AF  mov        dword ptr [ebp-8],3
14:      int z=4;
0040D7B6  mov        dword ptr [ebp-0Ch],4
//内部变量放入刚才被初始化为0xCC的内部变量区,x占用四字节在地址9996-9999yz一次类推
15:      x=add(y,z);
0040D7BD  mov        eax,dword ptr [ebp-0Ch]
0040D7C0  push        eax
0040D7C1  mov        ecx,dword ptr [ebp-8]
0040D7C4  push        ecx
//把参数按照stdcall方式从右到左压栈,ebp=1000esp=912-8=904z首先入栈在908-911y904-907
0040D7C5  call        @ILT+15(_add) (00401014)
//把返回下一行代码即 add esp,8 的地址压栈,转向add函数,ebp=1000esp=900add函数
0040D7CA  add        esp,8

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。