http://blog.csdn.net/wishfly/article/details/5022008

 
简单的函数调用,通过简单的函数调用反汇编可以清楚了解如下

1.栈到底是什么,如何操纵栈的?

2.参数和临时变量是以什么形式在哪存放?

3.如何传递返回值?

测试代码如下(这是一个简单的通过调用函数计算两数之和的程序):

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
#include <stdio.h>

int add(int a, int b)
{
    ;
    c = a + b;
    return c;
}

int main(void)
{
    ;
    x = add(y, z);
    ;
}

 
 
解释如下
 

 ASM Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
 
add函数
{
;ebp=1000,esp=900
    0040D750   push        ebp

;把main函数的ebp压栈,ebp=1000,esp=896
    0040D751   mov         ebp, esp

;得到“新”栈基址,这里的新的意思是每个函数访问属于自己的一块栈区域,其实是相邻的内存区域,或者说栈只有一个
    ;ebp=896,esp=896
    0040D753   sub         esp, 44h

;ebp=896,esp=828
    0040D756   push        ebx
    0040D757   push        esi
    0040D758   push        edi

;ebp=896,esp=816
    0040D759   lea         edi, [ebp - 44h]
    0040D75C   mov         ecx, 11h
    0040D761   mov         eax, 0CCCCCCCCh
    0040D766   ]
    0040D772   :  }
0040D77B   pop         edi
0040D77C   pop         esi
0040D77D   pop         ebx

;恢复“旧”栈顶地址,ebp=896,esp=896,此函数堆栈被释放!
0040D77E   mov         esp, ebp

;恢复“旧”栈基地址,ebp=1000,esp=900,此时恢复到调用前的栈基地址和顶地址
0040D780   pop         ebp

;返回调用点,ebp=1000,esp=904,调用点地址被弹出,返回到调用点
0040D781   ret

main函数

{
;用栈顶地址作为栈基地址,目的是不和调用前栈空间冲突
    ;为了叙述方便假设原 ebp=1004,esp=1004
    ;执行完下面两行汇编语句后 ebp=1000,esp=1000
    0040D790   push        ebp
    0040D791   mov         ebp, esp

;esp下移,开辟出0x4C字节的空间,这个空间是留给内部参数用的,这个空间的大小随内部变量多少由编译器决定。
    ;ebp=1000,esp=1000-0x4C=924
    0040D793   sub         esp, 4Ch

;保存 ebx,esi,edi的值,ebp=1000,esp=924-12=912
    0040D796   push        ebx
    0040D797   push        esi
    0040D798   push        edi

;把内部参数占用的空间每个字节都初始化为0xCC,这个是为了在DUBUG程序的方便,编译器加入的
    ;如果不在DEBUG状态下,这个区域是没有被初始化的,也就是说是随机值。
    0040D799   lea         edi, [ebp - 4Ch]
    0040D79C   mov         ecx, 13h
    0040D7A1   mov         eax, 0CCCCCCCCh

0040D7A6   : x = add(y, z);
    0040D7BD   mov         eax, dword ptr [ebp - 0Ch]
    0040D7C0   push        eax
    0040D7C1   ]
    0040D7C4   : }

 
main函数堆栈变化示意图:
add函数堆栈变化示意图:

现在来总结开始提出的三个问题

1.栈到底是什么,如何操纵栈的?

栈是操作系统分配给程序运行的一块内存区域,有以下特点:

1.1、改变堆栈用push, pop,用的esp栈顶指针,而读指针则用ebp栈基指针灵活访问

1.2、每当一个函数跳转到另一个函数时,会在上一个函数用到的栈空间下方开辟空间

2.参数和临时变量是以什么形式在哪存放?

2.1、参数放在旧栈的返回地址和旧栈基地址的上方,而临时变量则在新栈的最上方处,变量名会被编译器连接一个地址,程序在被编译成汇编以后,变量名就是虚无了。

3.如何传递返回值?

3.1、传递一个值的情况下,通过eax传递

可以看出,栈溢出是由于编译器没有检查栈是否还有空间。

 

附件列表

汇编看C函数调用的更多相关文章

  1. 利用汇编查看C++函数调用

    这篇文章的内容是一个老生常谈的问题----> 函数是如何被调用的. 本文用汇编代码研究函数调用的过程,参数调用的方式,函数值的返回. 1. 函数是如何实现调用的 函数的调用是用call 和 re ...

  2. 从汇编看c++成员函数指针(三)

    前面的从汇编看c++中成员函数指针(一)和从汇编看c++成员函数指针(二)讨论的要么是单一类,要么是普通的多重继承,没有讨论虚拟继承,下面就来看一看,当引入虚拟继承之后,成员函数指针会有什么变化. 下 ...

  3. 从汇编看c++中指向成员变量的指针(二)

    在从汇编看c++中指向成员变量的指针(一)中讨论的情形没有虚拟继承,下面来看看,当加入了虚拟继承的时候,指向成员变量的指针有什么变化. 下面是c++源码: #include <iostream& ...

  4. 从汇编看c++成员函数指针(二)

    下面先看一段c++源码: #include <cstdio> using namespace std; class X { public: virtual int get1() { ; } ...

  5. 从汇编看c++中的虚拟继承及内存布局(二)

    下面是c++源码: class Top {//虚基类 public: int i; Top(int ii) { i = ii; } virtual int getTop() { cout <&l ...

  6. 从汇编看c++的虚拟继承以及其内存布局(一)

    先看第一种最简单的情形,所有类中没有任何虚函数的菱形继承. 下面是c++源码: class Top {//虚基类 public: int i; Top(int ii) { i = ii; } }; c ...

  7. 从汇编看c++中的多态

    http://www.cnblogs.com/chaoguo1234/archive/2013/05/19/3079078.html 在c++中,当一个类含有虚函数的时候,类就具有了多态性.构造函数的 ...

  8. 从汇编看c++的new和delete

    下面是c++源码: class X { private: int _x; public: X() : _x(xx) {} ~X() {} }; int main() { X* xp = new X; ...

  9. 从汇编看c++中成员函数指针(一)

    下面先来看c++的源码: #include <cstdio> using namespace std; class X { public: int get1() { ; } virtual ...

随机推荐

  1. interface思考练习一

    参考了这篇文章,博主超级优秀,看他的最好,我只是写了点自己看他的博文学到的东西.CSDNzdwzzu2006 接口这东西认真学是在第一次构建工程的时候,很晕菜,原来学SE时不扎实,导致东西都不会用,看 ...

  2. BZOJ1053:反素数(数学)

    题目链接 对于任意的正整数\(x\),记其约数的个数为\(g(x)\).现在定义反素数:对于\(0<i<x\),都有\(g(x)>g(i)\),那么就称x为反素数. 现在给定一个数N ...

  3. 字符串化#、拼接字符##和可变参数宏(...和_ _VA_ARGS_ _)

    宏定义的使用与注意事项 ##是一个连接符号,用于把参数连在一起 #是“字符串化”的意思.出现在宏定义中的#是把跟在后面的参数转换成一个字符串#define paster( n ) printf( &q ...

  4. Jenkins和Gitblit集成实现提交后自动构建

    Gitblit是一个纯Java基于git的解决方案.它属于Apache Allura等伪造软件之一,它将票务系统与web ui结合在一起.我经历了一个设置过程,我想我可以帮助新用户避免痛点. 使用场景 ...

  5. java.lang.NoClassDefFoundError: org/hibernate/service/ServiceRegistry] 类似问题

    使用Hibernate时出现以上错误,在Java Project中运行无误,但是来到Dynamic Web Project中却出现了如下错误: hibernate 报错:java.lang.NoCla ...

  6. MyEclipse和Eclipse中jsp、html格式化自动排版问题

    一.myeclipse的漂亮排版设置 步骤: 在左侧快捷 “搜索” 框里面输入 html . 点击选中左侧HTML Source . line - width 是设置当前行里面有多少字符时,就换行.这 ...

  7. Git之修复Bug流程

    场景描述 当一个项目已经上线,同时又在原有基础上新增功能模块,于是乎就要在原有代码的基础上进行开发,在新增模块功能的开发的过程中,项目发现了一个紧急Bug,需要修复.应对这种情况,有以下两种解决方案: ...

  8. android studio run得时候 选择开启对话框

    一个项目run 调试得时候,在Android studio3.0默认得设置是运行在上一个device上,我们通过改变设置,废话不多说,上图: 然后点击这个edit config 在miscellane ...

  9. 解除单个文件的与svn服务器的关联

    有些文件和个人开发环境有关不需要和svn服务器做同步,可以取消其和svn服务的关联. 右键选中要取消关联的文件,右键菜单 Tortoise SVN  --->   unversion and a ...

  10. 【CodeForces】961 F. k-substrings 字符串哈希+二分

    [题目]F. k-substrings [题意]给定长度为n的串S,对于S的每个k-子串$s_ks_{k+1}...s_{n-k+1},k\in[1,\left \lceil \frac{n}{2} ...