C语言函数调用参数传递栈详解

合集下载

C语言中函数参数传递

C语言中函数参数传递

C语⾔中函数参数传递C语⾔中函数参数传递的三种⽅式(1)值传递,就是把你的变量的值传递给函数的形式参数,实际就是⽤变量的值来新⽣成⼀个形式参数,因⽽在函数⾥对形参的改变不会影响到函数外的变量的值。

(2)地址传递,就是把变量的地址赋给函数⾥形式参数的指针,使指针指向真实的变量的地址,因为对指针所指地址的内容的改变能反映到函数外,能改变函数外的变量的值。

(3)引⽤传递,实际是通过指针来实现的,能达到使⽤的效果如传址,可是使⽤⽅式如传值。

说⼏点建议:如果传值的话,会⽣成新的对象,花费时间和空间,⽽在退出函数的时候,⼜会销毁该对象,花费时间和空间。

因⽽如果int,char等固有类型,⽽是你⾃⼰定义的类或结构等,都建议传指针或引⽤,因为他们不会创建新的对象。

例1:下⾯这段代码的输出结果为:#include<stdio.h>void change(int*a, int&b, int c){c=*a;b=30;*a=20;}int main ( ){int a=10, b=20, c=30;change(&a,b,c);printf(“%d,%d,%d,”,a,b,c);return 0;}结果:20 30 30解析:1,指针传参 -> 将变量的地址直接传⼊函数,函数中可以对其值进⾏修改。

2,引⽤传参 -> 将变量的引⽤传⼊函数,效果和指针相同,同样函数中可以对其值进⾏修改。

3,值传参 -> 在传参过程中,⾸先将c的值复制给函数c变量,然后在函数中修改的即是函数的c变量,然后函数返回时,系统⾃动释放变量c。

⽽对main函数的c没有影响。

例2:#include<stdio.h>void myswap(int x, int y){int t;t=x;x=y;y=t;}int main(){int a, b;printf("请输⼊待交换的两个整数:");scanf("%d %d", &a, &b);myswap(a,b); //作为对⽐,直接交换两个整数,显然不⾏printf("调⽤交换函数后的结果是:%d 和 %d\n", a, b);return 0;}#include<stdio.h>void myswap(int *p1, int *p2){int t;t=*p1;*p1=*p2;*p2=t;}int main(){int a, b;printf("请输⼊待交换的两个整数:");scanf("%d %d", &a, &b);myswap(&a,&b); //交换两个整数的地址printf("调⽤交换函数后的结果是:%d 和 %d\n", a, b);return 0;}#include<stdio.h>void myswap(int &x, int &y){int t;t=x;x=y;y=t;}int main(){int a, b;printf("请输⼊待交换的两个整数:");scanf("%d %d", &a, &b);myswap(a,b); //直接以变量a和b作为实参交换printf("调⽤交换函数后的结果是:%d 和 %d\n", a, b);return 0;}第⼀个的运⾏结果:输⼊2 3,输出2 3第⼆个的运⾏结果:输⼊2 3,输出3 2第三个的运⾏结果:输⼊2 3,输出3 2解析:在第⼀个程序中,传值不成功的原因是指在形参上改变了数值,没有在实参上改变数值。

_stdcall介绍

_stdcall介绍

stdcall调用约定:stdcall很多时候被称为pascal调用约定,因为pascal是早期很常见的一种教学用计算机程序设计语言,其语法严谨,使用的函数调用约定就是stdcall。

在Microsoft C++系列的C/C++编译器中,常常用PASCAL宏来声明这个调用约定,类似的宏还有WINAPI和CALLBACK。

stdcall调用约定声明的语法为(以前文的那个函数为例):int __stdcall function(int a,int b)stdcall的调用约定意味着:1)参数从右向左压入堆栈,2)函数自身修改堆栈 3)函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸。

以上述这个函数为例,参数b首先被压栈,然后是参数a,函数调用function(1,2)调用处翻译成汇编语言将变成:push 2 第二个参数入栈push 1 第一个参数入栈call function 调用参数,注意此时自动把cs:eip入栈而对于函数自身,则可以翻译为:push ebp 保存ebp寄存器,该寄存器将用来保存堆栈的栈顶指针,可以在函数退出时恢复mov ebp,esp 保存堆栈指针mov eax,[ebp + 8H] 堆栈中ebp指向位置之前依次保存有ebp,cs:eip,a,b,ebp +8指向aadd eax,[ebp + 0CH] 堆栈中ebp + 12处保存了bmov esp,ebp 恢复esppop ebpret 8而在编译时,这个函数的名字被翻译成_function@8注意不同编译器会插入自己的汇编代码以提供编译的通用性,但是大体代码如此。

其中在函数开始处保留esp到ebp中,在函数结束恢复是编译器常用的方法。

从函数调用看,2和1依次被push进堆栈,而在函数中又通过相对于ebp(即刚进函数时的堆栈指针)的偏移量存取参数。

函数结束后,ret 8表示清理8个字节的堆栈,函数自己恢复了堆栈。

C语言函数调用的底层机制

C语言函数调用的底层机制

C语言函数调用的底层机制1.函数栈帧的创建和销毁:函数栈帧是在函数被调用时在内存中创建的,用于存储函数的局部变量、参数以及返回地址等信息。

栈帧的创建一般包括以下步骤:(1)将函数的返回地址、参数、局部变量的值等数据压栈。

(2)分配存储局部变量的空间。

(3)保存当前栈指针,并将栈指针指向新分配的栈帧。

函数执行完毕后,会执行相应的销毁操作,包括恢复堆栈指针、释放局部变量占用的内存等。

2.参数传递:(1)按值传递:将实参的值拷贝到栈帧中的参数位置,函数对参数的修改不会影响到实参。

(2)按地址传递:将实参的地址传递给函数,函数可以通过地址访问实参,其修改会影响到实参。

3.返回值的处理:C语言函数的返回值一般通过寄存器来处理。

在函数调用前,调用者会保存返回地址和一些寄存器的值等信息,然后调用函数。

函数执行完成后,会将返回值存储在指定的寄存器中,并将栈帧中保存的返回地址恢复到程序计数器中,从而实现函数调用后的返回操作。

4.函数的跳转和返回:函数的跳转和返回一般由CALL和RET指令来实现。

在函数调用时,通过CALL指令将函数的地址压栈并跳转到指定的函数入口地址。

函数执行完成后,通过RET指令将栈顶的返回地址弹出到程序计数器中,从而返回到函数调用的地方。

5.函数调用的栈帧布局:函数调用时的栈帧布局一般包括局部变量、参数、返回地址和上一级栈帧指针等信息。

栈帧的布局在编译器中是预先定义好的,根据平台的不同会有所不同。

总结起来,C语言函数调用的底层机制主要涉及函数栈帧的创建和销毁、参数传递、返回值的处理以及函数的跳转和返回等。

这些机制通过栈的操作实现函数的调用和返回,保证了函数的正确执行和数据的传递。

了解这些底层机制对于理解函数调用过程以及编写高效的函数调用代码非常重要。

C语言教程十一函数参数的传递和值返回

C语言教程十一函数参数的传递和值返回

C语言教程十一、函数参数的传递和值返回前面我们说的都是无参数无返回值的函数,实际程序中,我们经常使用到带参数有返回值的函数。

一、函数参数传递1.形式参数和实际参数函数的调用值把一些表达式作为参数传递给函数。

函数定义中的参数是形式参数,函数的调用者提供给函数的参数叫实际参数。

在函数调用之前,实际参数的值将被拷贝到这些形式参数中。

2.参数传递先看一个例子:void a(int); /*注意函数声明的形式*/main(){int num;scanf(%d,&num);a(num); /*注意调用形式*/}void a(int num_back) /*注意定义形式*/{printf(%d\n,num_back);}在主函数中,先定义一个变量,然后输入一个值,在a()这个函数中输出。

当程序运行a(num);这一步时,把num的值赋值给num_back,在运行程序过程中,把实际参数的值传给形式参数,这就是函数参数的传递。

形参和实参可能不只一个,如果多于一个时,函数声明、调用、定义的形式都要一一对应,不仅个数要对应,参数的数据类型也要对应。

void a(int,float);main(){int num1;float num2;scanf(%d,&num1);scanf(%f,&num2);a(num1,num2);}void a(int num1_back,float num2_back){printf(%d,%f\n,num1_back,num2_back);}上面的例子中,函数有两个参数,一个是整型,一个是浮点型,那么在声明、调用、定义的时候,不仅个数要一样,类型也要对应。

如果不对应,有可能使的编译错误,即使没错误,也有可能让数据传递过程中出现错误。

再看一个例子:void a(int);main(){int num;scanf(%d,&num);a(num);}void a(int num){printf(%d\n,num);}看上面的例子,形式参数和实际参数的标识符都是num,程序把实际参数num 的值传递给形式参数num。

c语言函数多个参数传递

c语言函数多个参数传递

c语言函数多个参数传递摘要:1.引言2.C 语言函数参数传递的方式3.多个参数的传递4.传递参数的注意事项5.结论正文:【引言】C 语言是一种广泛使用的编程语言,它具有简洁、高效的特点。

在C 语言程序设计中,函数的使用是必不可少的。

函数可以实现代码的模块化,使程序更加清晰易懂。

在函数调用时,参数的传递是一个重要的环节。

本篇文章主要介绍C 语言函数多个参数的传递方法及其注意事项。

【C 语言函数参数传递的方式】C 语言函数参数传递方式主要有两种:值传递和指针传递。

1.值传递:函数在调用时,会将实参的值复制到形参中。

这意味着形参和实参是两个独立的变量,它们之间互不影响。

值传递适用于基本数据类型,如int、float 等。

2.指针传递:函数在调用时,会将实参的地址传递给形参。

这意味着形参和实参共享同一内存空间,对形参的修改将影响实参。

指针传递适用于数组和结构体等复合数据类型。

【多个参数的传递】在实际编程中,函数可能需要接收多个参数。

C 语言中,多个参数的传递可以通过以下方式实现:1.按顺序传递:将多个参数按照声明的顺序依次传递给函数。

这种方式较为简单,但当参数较多时,容易出错。

2.使用数组:将多个参数封装在一个数组中,然后将数组作为参数传递给函数。

这种方式可以减少参数传递的错误,但需要注意数组的大小和类型。

3.使用结构体:将多个参数封装在一个结构体中,然后将结构体作为参数传递给函数。

这种方式可以方便地管理多个参数,同时具有较好的封装性。

【传递参数的注意事项】在函数参数传递过程中,需要注意以下几点:1.参数类型匹配:确保实参的类型与形参的类型匹配,否则会导致编译错误。

2.参数顺序正确:按照函数声明的顺序传递参数,否则会导致函数调用失败。

3.注意参数传递的方式:根据参数的类型选择合适的传递方式,避免因为传递方式不当导致的程序错误。

【结论】C 语言函数多个参数的传递是程序设计中常见的场景。

通过掌握不同的参数传递方式和注意事项,可以有效提高程序的编写效率和稳定性。

C语言中如何进行函数的调用和参数传递

C语言中如何进行函数的调用和参数传递

C语言中如何进行函数的调用和参数传递C语言是一种广泛应用于系统编程和嵌入式开发的高级编程语言。

在C语言中,函数的调用和参数传递是非常重要的概念。

本文将介绍C语言中如何进行函数的调用和参数传递的基本原理和方法。

在C语言中,函数是程序的基本组成单元之一。

通过函数的调用,可以将程序的执行流程切换到函数中,并执行函数中的代码。

函数的调用可以帮助我们实现代码的模块化和重用,提高程序的可读性和可维护性。

在C语言中,函数的调用需要遵循一定的规则。

首先,我们需要在函数调用前声明函数的原型或定义函数的实现。

函数的原型告诉编译器函数的名称、返回值类型和参数列表等信息,以便编译器能够正确地处理函数的调用和参数传递。

函数的调用可以使用函数名称后跟一对圆括号的方式进行。

在圆括号中,可以传递函数所需的参数。

参数可以是常量、变量或表达式等。

在函数调用时,传递的参数将被复制到函数的形参中,函数在执行时可以使用这些参数进行计算或处理。

在C语言中,参数的传递可以通过值传递或引用传递进行。

值传递是指将参数的值复制到函数的形参中,函数在执行时使用的是形参的副本,对形参的修改不会影响到实参。

而引用传递是指将参数的地址传递给函数,函数在执行时使用的是实参的地址,对形参的修改会影响到实参。

在C语言中,函数的参数传递是通过栈来实现的。

栈是一种后进先出的数据结构,用于存储函数的局部变量、参数和返回值等信息。

在函数调用时,参数被依次压入栈中,然后函数开始执行。

在函数执行完毕后,栈会弹出参数,将控制权返回给调用函数。

除了值传递和引用传递外,C语言还支持指针传递。

指针传递是指将参数的指针传递给函数,函数在执行时可以通过指针来访问和修改实参。

通过指针传递参数,可以避免复制大量的数据,提高程序的效率。

在C语言中,函数的调用可以有返回值和无返回值两种形式。

有返回值的函数可以通过return语句返回一个值给调用者。

无返回值的函数可以使用void关键字来声明,表示函数不返回任何值。

c语言函数参数传递方式

c语言函数参数传递方式

c语言函数参数传递方式C语言是一种广泛使用的编程语言,函数参数传递方式是C语言中非常重要的概念之一。

函数参数传递方式可以分为按值传递、按址传递和按引用传递三种方式。

本文将针对这三种方式进行详细讲解。

一、按值传递按值传递是指在函数调用时,将实际参数的值复制给形式参数,函数内部对形参的修改不会影响到实际参数的值。

这种方式适用于参数较少、参数值不需要在函数内部被修改的情况。

在按值传递的方式下,函数在栈内存中为形参分配空间,并将实参的值复制到形参中。

函数执行结束后,栈内存中的形参被销毁,不会影响到实参的值。

二、按址传递按址传递是指在函数调用时,将实际参数的地址传递给形式参数,函数内部通过指针对实参进行操作,可以修改实参的值。

这种方式适用于需要在函数内部修改实参值的情况。

在按址传递的方式下,函数在栈内存中为形参分配空间,并将实参的地址传递给形参。

函数内部通过指针对实参进行操作,修改实参的值。

由于传递的是地址,所以函数内部对形参的修改会影响到实参。

三、按引用传递按引用传递是C++中的特性,其本质是通过指针来实现的。

在C语言中,可以通过传递指针的方式来模拟按引用传递。

按引用传递的特点是可以修改实参的值,并且不需要像按址传递那样使用指针操作。

在按引用传递的方式下,函数在栈内存中为形参分配空间,并将实参的地址传递给形参。

函数内部通过引用的方式操作形参,可以直接修改实参的值。

由于传递的是地址,所以函数内部对形参的修改会影响到实参。

需要注意的是,按引用传递需要使用指针来实现。

在函数调用时,需要将实参的地址传递给形参,即传递一个指向实参的指针。

函数内部通过解引用指针来操作实参,可以达到修改实参的目的。

总结:C语言中的函数参数传递方式包括按值传递、按址传递和按引用传递三种方式。

按值传递适用于参数较少、参数值不需要在函数内部被修改的情况;按址传递适用于需要在函数内部修改实参值的情况;按引用传递需要使用指针来实现,通过传递实参的地址来实现对实参的修改。

c语言函数调用时参数传递方式的有哪几种,分别简述他们的传递方式

c语言函数调用时参数传递方式的有哪几种,分别简述他们的传递方式

c语言函数调用时参数传递方式的有哪几种,分别简述他们的传
递方式
C语言函数调用时参数的传递方式主要有以下几种:
1. 值传递:函数调用时,将实际参数的值复制给形式参数,函数内部对形式参数进行修改不会影响实际参数的值。

这是最常见的参数传递方式。

2. 引用传递:通过传递变量的指针作为参数,函数内部可以直接通过指针访问和修改实际参数的值。

这种方式可以实现在函数内部改变实参的值。

3. 地址传递:传递变量的地址作为参数,在函数内部通过指针来访问和修改实际参数的值。

和引用传递类似,通过地址传递也可以改变实参的值。

4. 数组传递:将数组的首地址作为参数传递给函数,函数内部可以通过指针来访问和修改数组的元素。

5. 结构体传递:将整个结构体作为参数传递给函数,在函数内部可以直接访问和修改结构体中的成员。

需要注意的是,C语言中的参数传递都是按值传递的,包括引
用传递和地址传递。

所谓按值传递,是指在函数调用时将实参的值复制给形参,函数内部对形参的操作不会影响到实参的值。

但是通过引用传递和地址传递,可以通过指针来访问和修改实参的值,使得函数可以改变实参的值。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C语言调用函数过程详解Sunny.man1.使用环境:gcc 版本4.1.2 20071124 (Red Hat 4.1.2-42)2.示例源代码int foo(int a,int b){int a1=0x123;return a1+a+b;}int main(){foo(2,3);return 0;}3.运行程序命令:gdb a.outStartDisassemble4.汇编函数清单4.1main函数的汇编0x0804836c <main+0>: lea 0x4(%esp),%ecx0x08048370 <main+4>: and $0xfffffff0,%esp0x08048373 <main+7>: pushl 0xfffffffc(%ecx)0x08048376 <main+10>: push %ebp0x08048377 <main+11>: mov %esp,%ebp0x08048379 <main+13>: push %ecx0x0804837a <main+14>: sub $0x8,%esp0x0804837d <main+17>: movl $0x3,0x4(%esp)0x08048385 <main+25>: movl $0x2,(%esp)0x0804838c <main+32>: call 0x8048354 <foo>0x08048391 <main+37>: mov $0x0,%eax0x08048396 <main+42>: add $0x8,%esp0x08048399 <main+45>: pop %ecx0x0804839a <main+46>: pop %ebp0x0804839b <main+47>: lea 0xfffffffc(%ecx),%esp0x0804839e <main+50>: ret4.2Foo函数的汇编0x08048354 <foo+0>: push %ebp0x08048355 <foo+1>: mov %esp,%ebp0x08048357 <foo+3>: sub $0x10,%esp0x0804835a <foo+6>: movl $0x123,0xfffffffc(%ebp)0x08048361 <foo+13>: mov 0x8(%ebp),%eax0x08048364 <foo+16>: add 0xfffffffc(%ebp),%eax0x08048367 <foo+19>: add 0xc(%ebp),%eax0x0804836a <foo+22>: leave0x0804836b <foo+23>: ret5.程序执行时分析(gdb) info registerseax 0xbf820894 -1081997164ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207ec 0xbf8207ecebp 0xbf8207f8 0xbf8207f8esi 0x42cca0 4377760edi 0x0 0eip 0x804837d 0x804837d <main+17>eflags 0x200292 [ AF SF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 51注:此时已经执行到main的第14行下一条指令是movl $0x3,0x4(%esp)此时的esp是0xbf8207ec。

5.1分析esp=0xbf8207ec的来历(gdb) x/20 $esp0xbf8207ec: 0x0056eff4 0x004205d0 0xbf820810 0xbf8208680xbf8207fc: 0x00445dec 0x0042cca0 0x080483b0 0xbf8208680xbf82080c: 0x00445dec 0x00000001 0xbf820894 0xbf82089c0xbf82081c: 0x0042d810 0x00000000 0x00000001 0x000000010xbf82082c: 0x00000000 0x0056eff4 0x0042cca0 0x000000005.1.1Main+140x0804837a <main+14>: sub $0x8,%esp现在的esp=0xbf8207ec ebp=0xbf8207f8 eip=0x804837d 则原来esp的值就是0xbf8207ec+0x8=0xbf8207f45.1.2 Main+130x08048379 <main+13>: push %ecxEsp=0xbf8207f4+0x04=0xbf8207f85.1.3 Main+110x08048377 <main+11>: mov %esp,%ebpEbp=0xbf8207f8 和现在的EBP值是一样的。

5.1.4 Main+100x08048376 <main+10>: push %ebpEsp=0xbf8207f8+4=0xBF8207FC5.1.5 Main+70x08048373 <main+7>: pushl 0xfffffffc(%ecx)ESP的值= 0xBF8207FC+4=0xBF8208005.1.6 Main+40x08048370 <main+4>: and $0xfffffff0,%esp从这句可以看出esp的值是0xBF82080X,无法进一步得出了。

不过没有关系,我们可以通过上一句来看出.5.1.7 Main+00x0804836c <main+0>: lea 0x4(%esp),%ecx这个说明现在的ecx寄存器中,存着原来Esp的值+4,那我们知道ecx里存的是0xbf820810。

这个值是最初的esp+4那最初的esp就是0xbf82080c。

5.2从main+0开始进行推导1.最早的esp=0xbf82080c ebp=0xbf8207f82.现在的各地址的值是:0xbf8207ec: 0x0056eff4 0x004205d0 0xbf820810 0xbf8208680xbf8207fc: 0x00445dec 0x0042cca0 0x080483b0 0xbf8208680xbf82080c: 0x00445dec 0x00000001 0xbf820894 0xbf82089c0xbf82081c: 0x0042d810 0x00000000 0x00000001 0x000000010xbf82082c: 0x00000000 0x0056eff4 0x0042cca0 0x000000003.0x0804836c <main+0>: lea 0x4(%esp),%ecx4.0x08048370 <main+4>: and $0xfffffff0,%espesp=0xbf82080c & 0xFFFF FFF0=0xbf8208005.0x08048373 <main+7>: pushl 0xfffffffc(%ecx)esp=0xbf820800-4=0xbf8207fc ecx所指向的地值-4也就是原来esp(0xbf82080c )所指向的值0x00445dec6.0x08048376 <main+10>: push %ebpesp=0xbf8207fc -4=0xbf8207f8 原来的ebp内容=0xbf8208687.0x08048377 <main+11>: mov %esp,%ebpEbp=esp=0xbf8207f88.0x08048379 <main+13>: push %ecxEsp=0xbf8207f8=4=0xbf8207f4 里面的内容: 0xbf820810 来缘是原来的esp(0xbf82080c)+49.0x0804837a <main+14>: sub $0x8,%espEsp=0xbf8207f4-8=0xbf8207ec10.0x0804837d <main+17>: movl $0x3,0x4(%esp)11.0x08048385 <main+25>: movl $0x2,(%esp)12.0x0804838c <main+32>: call 0x8048354 <foo>Call把下一个指令的地址压栈,并esp-4同时改写eipeax 0xbf820894 -1081997164ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207e8 0xbf8207e8ebp 0xbf8207f8 0xbf8207f8esi 0x42cca0 4377760edi 0x0 0eip 0x8048354 0x8048354 <foo>eflags 0x200292 [ AF SF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 51esp=0xbf8207ec-4=0xbf8207e8 内容: 0x08048391这个值正式一下条指令Main+37的地址值。

0x08048391 <main+37>: mov $0x0,%eax(gdb)x/20 $esp0xbf8207e8: 0x08048391 0x00000002 0x00000003 0xbf8208100xbf8207f8: 0xbf820868 0x00445dec 0x0042cca0 0x080483b00xbf820808: 0xbf820868 0x00445dec 0x00000001 0xbf8208940xbf820818: 0xbf82089c 0x0042d810 0x00000000 0x000000010xbf820828: 0x00000001 0x00000000 0x0056eff4 0x0042cca013.0x08048354 <foo+0>: push %ebpEsp=esp-4=0xbf8207e4(gdb) info registerseax 0xbf820894 -1081997164ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207e4 0xbf8207e4ebp 0xbf8207f8 0xbf8207f8esi 0x42cca0 4377760edi 0x0 0eip 0x8048355 0x8048355 <foo+1>eflags 0x200292 [ AF SF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 5114.0x08048355 <foo+1>: mov %esp,%ebpEbp=esp(gdb) info registerseax 0xbf820894 -1081997164ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207e4 0xbf8207e4ebp 0xbf8207e4 0xbf8207e4esi 0x42cca0 4377760edi 0x0 0eip 0x8048357 0x8048357 <foo+3>eflags 0x200292 [ AF SF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 51(gdb) x/20 $esp0xbf8207e4: 0xbf8207f8 0x08048391 0x00000002 0x00000003 0xbf8207f4: 0xbf820810 0xbf820868 0x00445dec 0x0042cca0 0xbf820804: 0x080483b0 0xbf820868 0x00445dec 0x00000001 0xbf820814: 0xbf820894 0xbf82089c 0x0042d810 0x00000000 0xbf820824: 0x00000001 0x00000001 0x00000000 0x0056eff415.0x08048357 <foo+3>: sub $0x10,%espEsp=esp-0x10=0xbf8207e4-0x10=0xbf8207d416.0x0804835a <foo+6>: movl $0x123,0xfffffffc(%ebp) 0xfffffffc(%ebp)=0xbf8207e4-4=0xbf8207e0(gdb) info registerseax 0xbf820894 -1081997164ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207d4 0xbf8207d4ebp 0xbf8207e4 0xbf8207e4esi 0x42cca0 4377760edi 0x0 0eip 0x804835a 0x804835a <foo+6>eflags 0x200286 [ PF SF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 51(gdb) x/20 $esp0xbf8207d4: 0x0056d210 0xbf820808 0x080483c9 0x00000123 0xbf8207e4: 0xbf8207f8 0x08048391 0x00000002 0x00000003 0xbf8207f4: 0xbf820810 0xbf820868 0x00445dec0x0042cca0 0xbf820804: 0x080483b0 0xbf820868 0x00445dec 0x00000001 0xbf820814: 0xbf820894 0xbf82089c 0x0042d810 0x00000000 Esp=0xbf8207d4 Ebp-4=0x123 Ebp=0xbf8207e417.0x08048361 <foo+13>: mov 0x8(%ebp),%eax18.0x08048364 <foo+16>: add 0xfffffffc(%ebp),%eax19.0x08048367 <foo+19>: add 0xc(%ebp),%eaxEbp+8是传来的参数ebp-4是第一个临时变量20.0x0804836a <foo+22>: leaveLeave等同于下列两句Move $ebp,$esppop %ebp把esp=ebp= 0xbf8207e4ebp=0xbf8207f8esp=esp+4=0xbf8207e8(gdb)info registerseax 0x128 296ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207e8 0xbf8207e8ebp 0xbf8207f8 0xbf8207f8esi 0x42cca0 4377760edi 0x0 0eip 0x804836b 0x804836b <foo+23>eflags 0x200206 [ PF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 5121.0x0804836b <foo+23>: retpop %eipesp=esp+4=0xbf8207ec(gdb)info regeax 0x128 296ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207ec 0xbf8207ecebp 0xbf8207f8 0xbf8207f8esi 0x42cca0 4377760edi 0x0 0eip 0x8048391 0x8048391 <main+37>eflags 0x200206 [ PF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 5122.0x08048396 <main+42>: add $0x8,%esp esp=esp+8=0xbf8207ec+8=0xbf8207f4(gdb) info registerseax 0x0 0ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207f4 0xbf8207f4ebp 0xbf8207f8 0xbf8207f8esi 0x42cca0 4377760edi 0x0 0eip 0x8048399 0x8048399 <main+45>eflags 0x200292 [ AF SF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 51(gdb) x/20 $esp0xbf8207f4: 0xbf820810 0xbf820868 0x00445dec 0x0042cca0 0xbf820804: 0x080483b0 0xbf820868 0x00445dec 0x00000001 0xbf820814: 0xbf820894 0xbf82089c 0x0042d810 0x00000000 0xbf820824: 0x00000001 0x00000001 0x00000000 0x0056eff4 0xbf820834: 0x0042cca0 0x00000000 0xbf820868 0x7f1f8fc023.0x08048399 <main+45>: pop %ecxesp=esp+4=0xbf8207f8(gdb) info registerseax 0x0 0ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207f8 0xbf8207f8ebp 0xbf8207f8 0xbf8207f8esi 0x42cca0 4377760edi 0x0 0eip 0x804839a 0x804839a <main+46>eflags 0x200292 [ AF SF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 5124.0x0804839a <main+46>: pop %ebpesp=esp+4=0xbf8207fcebp=0xbf820868(gdb) info registerseax 0x0 0ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf8207fc 0xbf8207fcebp 0xbf820868 0xbf820868esi 0x42cca0 4377760edi 0x0 0eip 0x804839b 0x804839b <main+47>eflags 0x200292 [ AF SF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 5125.0x0804839b <main+47>: lea 0xfffffffc(%ecx),%espEsp=0xbf820810 -4=0xbf82080c 恢复到原来的esp 26.0x0804839e <main+50>: ret等同于pop %eipEsp=esp+4=0xbf820810(gdb) info registerseax 0x0 0ecx 0xbf820810 -1081997296edx 0x1 1ebx 0x56eff4 5697524esp 0xbf820810 0xbf820810ebp 0xbf820868 0xbf820868esi 0x42cca0 4377760edi 0x0 0eip 0x445dec 0x445dec <__libc_start_main+220>eflags 0x200292 [ AF SF IF ID ]cs 0x73 115ss 0x7b 123ds 0x7b 123es 0x7b 123fs 0x0 0gs 0x33 5127.mov %eax,(%esp)把0做为返回值传给libc_start_main0x00445de9 <__libc_start_main+217>: call *0x8(%ebp) 0x00445dec <__libc_start_main+220>: mov %eax,(%esp)。

相关文档
最新文档