`
lin_llx
  • 浏览: 127593 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

C语言函数调用分析

阅读更多

今天突发奇想想要研究一下C语言的函数调用.

因为以前有个课程设计涉及到C语言函数返回地址的问题,今天看Thinking in C++的时候,看到类似的东西...就想要验证一下.

 

编译器:gcc4.0.1 on darwin

操作系统:Mac OS X 10.5.8

编辑器:MacVim  :)

 

首先上C语言源程序

 

#include <stdio.h>
void a(int b);

int main()
{
    int x = 0x11223344;
    printf("&x == %p\n", &x);
    a(x);
    x = 1;
    printf("x == %d\n", x);
    return 0;
}
void a(int b){
    int c = 0x11223344;
    void *p = &c;
    int i = 0;
    printf("&b = %p\n", &b);
    printf("&c = %p\n", &c);
    printf("%d\n", &b - &c);
    for(i = 0; i < 32; ++i){
        printf("@%p = %x\n", p + i, *(char * )(p + i));
    }
}

 

用gcc -g 编译以后..用gdb进行调试

 

首先看生成的汇编代码..

输入disas main查看main函数汇编

 

0x00001ec2 <main+0>:    push   %ebp
0x00001ec3 <main+1>:    mov    %esp,%ebp
0x00001ec5 <main+3>:    push   %ebx
0x00001ec6 <main+4>:    sub    $0x24,%esp
0x00001ec9 <main+7>:    call   0x1ece <main+12>
0x00001ece <main+12>:   pop    %ebx
0x00001ecf <main+13>:   movl   $0x11223344,-0xc(%ebp) //注意点1
0x00001ed6 <main+20>:   lea    -0xc(%ebp),%eax
0x00001ed9 <main+23>:   mov    %eax,0x4(%esp)
0x00001edd <main+27>:   lea    0xfd(%ebx),%eax
0x00001ee3 <main+33>:   mov    %eax,(%esp)
0x00001ee6 <main+36>:   call   0x3005 <dyld_stub_printf>
0x00001eeb <main+41>:   mov    -0xc(%ebp),%eax //注意点2
0x00001eee <main+44>:   mov    %eax,(%esp)
0x00001ef1 <main+47>:   call   0x1f1d <a>
0x00001ef6 <main+52>:   movl   $0x1,-0xc(%ebp)//注意点3
0x00001efd <main+59>:   mov    -0xc(%ebp),%eax
0x00001f00 <main+62>:   mov    %eax,0x4(%esp)
0x00001f04 <main+66>:   lea    0x107(%ebx),%eax
0x00001f0a <main+72>:   mov    %eax,(%esp)
0x00001f0d <main+75>:   call   0x3005 <dyld_stub_printf>
0x00001f12 <main+80>:   mov    $0x0,%eax
0x00001f17 <main+85>:   add    $0x24,%esp
0x00001f1a <main+88>:   pop    %ebx
0x00001f1b <main+89>:   leave  
0x00001f1c <main+90>:   ret    

 然后输入disas a查看a函数的汇编代码

 

0x00001f1d <a+0>:       push   %ebp //注意点4
0x00001f1e <a+1>:       mov    %esp,%ebp
0x00001f20 <a+3>:       push   %ebx
0x00001f21 <a+4>:       sub    $0x24,%esp
0x00001f24 <a+7>:       call   0x1f29 <a+12>
0x00001f29 <a+12>:      pop    %ebx
0x00001f2a <a+13>:      movl   $0x55667788,-0x14(%ebp)
0x00001f31 <a+20>:      lea    -0x14(%ebp),%eax
0x00001f34 <a+23>:      mov    %eax,-0x10(%ebp)
0x00001f37 <a+26>:      movl   $0x0,-0xc(%ebp)
0x00001f3e <a+33>:      lea    0x8(%ebp),%eax
0x00001f41 <a+36>:      mov    %eax,0x4(%esp)
0x00001f45 <a+40>:      lea    0xb5(%ebx),%eax
0x00001f4b <a+46>:      mov    %eax,(%esp)
0x00001f4e <a+49>:      call   0x3005 <dyld_stub_printf>
0x00001f53 <a+54>:      lea    -0x14(%ebp),%eax
0x00001f56 <a+57>:      mov    %eax,0x4(%esp)
0x00001f5a <a+61>:      lea    0xbe(%ebx),%eax
0x00001f60 <a+67>:      mov    %eax,(%esp)
0x00001f63 <a+70>:      call   0x3005 <dyld_stub_printf>
0x00001f68 <a+75>:      lea    0x8(%ebp),%edx
0x00001f6b <a+78>:      lea    -0x14(%ebp),%eax
0x00001f6e <a+81>:      mov    %edx,%ecx
0x00001f70 <a+83>:      sub    %eax,%ecx
0x00001f72 <a+85>:      mov    %ecx,%eax
0x00001f74 <a+87>:      sar    $0x2,%eax
0x00001f77 <a+90>:      mov    %eax,0x4(%esp)
0x00001f7b <a+94>:      lea    0xc7(%ebx),%eax
0x00001f81 <a+100>:     mov    %eax,(%esp)
0x00001f84 <a+103>:     call   0x3005 <dyld_stub_printf>
0x00001f89 <a+108>:     movl   $0x0,-0xc(%ebp)
0x00001f90 <a+115>:     jmp    0x1fbf <a+162>
0x00001f92 <a+117>:     mov    -0xc(%ebp),%eax
0x00001f95 <a+120>:     add    -0x10(%ebp),%eax
0x00001f98 <a+123>:     movzbl (%eax),%eax
0x00001f9b <a+126>:     movsbl %al,%edx
0x00001f9e <a+129>:     mov    -0xc(%ebp),%eax
0x00001fa1 <a+132>:     add    -0x10(%ebp),%eax
0x00001fa4 <a+135>:     mov    %edx,0x8(%esp)
0x00001fa8 <a+139>:     mov    %eax,0x4(%esp)
0x00001fac <a+143>:     lea    0xcb(%ebx),%eax
0x00001fb2 <a+149>:     mov    %eax,(%esp)
0x00001fb5 <a+152>:     call   0x3005 <dyld_stub_printf>
0x00001fba <a+157>:     lea    -0xc(%ebp),%eax
0x00001fbd <a+160>:     incl   (%eax)
0x00001fbf <a+162>:     cmpl   $0x1f,-0xc(%ebp)
0x00001fc3 <a+166>:     jle    0x1f92 <a+117>
0x00001fc5 <a+168>:     add    $0x24,%esp
0x00001fc8 <a+171>:     pop    %ebx
0x00001fc9 <a+172>:     leave  
0x00001fca <a+173>:     ret  

 

果然和书上写的一样..从右往左压参数,再压返回值,再压局部变量。

下面解释一下汇编代码里面的注意点...

注意点1:因为x是main函数的局部变量..所以需要将局部变量压栈.注意压栈的地址是%ebp - c..因为unix下面的栈是从高地址往低地址的方向延伸的.所以用减

注意点2:把a函数的参数压到栈里面...可以想象,在传值过程中,值会被复制一份到栈里面..那么对象也会重新生成一个在栈里面..难怪要搞拷贝构造函数了....这里一个疑问是为什么不用push?

注意点3:这个时候下一条命令的地址是0x00001ef6

 

注意点4:把栈基址推到栈里面...这里是一个关键哦...

 

ok...接着按l显示源代码..然后输入 b 8在第8行做了一个断点...

按r执行函数...

到断点的时候..输入i reg看一下寄存器..

 

esp            0xbffff630       0xbffff630
ebp            0xbffff658       0xbffff658

 ok...按s进入函数

再按一下n 执行那条int c的声明语句.

 

这时候看一下寄存器

 

esp            0xbffff600       0xbffff600
ebp            0xbffff628       0xbffff628

 有变化了..

输入x/20x $esp查看一下esp后面的地址内容

 

0xbffff600:     0xa054e638      0xa054ade0      0x00001fcb      0xbffff634
0xbffff610:     0x00000004      0x55667788      0xbffff678      0xbffff634
0xbffff620:     0x00001ece      0x00001ece      0xbffff658      0x00001ef6
0xbffff630:     0x11223344      0xbffff64c      0x8fe0154b      0x00001000
0xbffff640:     0x00000000      0x00000000      0xbffff66c      0x11223344

 ok..看见我们可爱的 11223344 和55667788了..

而11223344下面的一个地址内容..果然是注意3里面提到的地址..

而注意4里面的..也再他恰当的位置出现了.....

 

唯一还存在疑问的地方就是....

我们的55667788并没有按照书上所说的..紧紧跟着原来老的$ebp的值后面出现....

中间多了16个字节奇怪的数字...

究竟这些数字是做什么用的....

 

如果有人知道..可以回帖....

我也会查资料去了解的....

 

恩...C语言还是很奇妙的东东

分享到:
评论

相关推荐

    C语言函数调用汇编语言函数[归纳].pdf

    C语言函数调用汇编语言函数知识点总结 C语言函数调用汇编语言函数是软件开发中的一种常见技术。本文将对C语言函数调用汇编语言函数进行总结,详细介绍相关知识点。 一、C语言函数调用汇编语言函数的定义 C语言...

    c语言函数调用关系图自动生成方法之使用egypt和gcc的-fdump-rtl-expand生成Graphviz

    在C语言编程中,理解函数调用关系是调试和优化代码的关键...总的来说,利用egypt和GCC的-fdump-rtl-expand选项生成Graphviz图是一种有效的可视化C语言函数调用关系的方法,可以帮助开发者更深入地理解代码的运行逻辑。

    C语言函数调用栈(一) - clover_toeic - 博客园1

    "C语言函数调用栈" C语言函数调用栈是一种常见的编程概念,它是指在程序执行过程中,函数调用时创建的一种栈结构。这种栈结构用于存储函数的局部变量、参数和返回地址等信息。 在C语言中,每个函数调用都会在内存...

    采用汇编语言对C语言函数调用方法求平均数

    使用汇编语言对C语言函数调用方法求平均数 在计算机编程中,汇编语言和C语言都是常用的编程语言。汇编语言是一种低级语言,它可以直接控制计算机硬件,具有高效、灵活和可靠的特点。但是,汇编语言的编程难度较高,...

    Windows下生成函数关系调用图

    总之,通过使用这款工具,开发者可以在Windows环境下高效地分析多语言项目,生成清晰的函数调用关系图,从而提升代码质量和维护性,促进团队协作,加速问题解决。对于任何涉及复杂代码结构的项目,这都是一种不可或...

    C语言函数的定义、声明以及函数的调用方法_c语言函数学习实例_

    函数的定义、声明和调用是C语言编程中不可或缺的部分。本篇将深入探讨这三个概念,以及如何处理参数传递,特别是数组作为函数参数的情况。 1. **函数的定义**: 函数定义是创建一个函数的过程,它包括函数名、返回...

    C语言函数调用.docx

    c语言函数调用

    C语言函数调用及定义ppt课件.ppt

    C语言函数调用及定义 本节课程主要讲解了C语言函数的定义和调用,包括函数的定义、函数的类型、函数的调用、函数的声明、函数的执行等内容。 一、函数的定义 函数是指完成一个特定工作的独立程序模块,可以是...

    C语言函数递归调用学习教案.pptx

    C语言函数递归调用学习教案 C语言函数递归调用是指在调用一个函数的过程中,出现直接或间接地调用该函数本身的现象。递归调用可以用来解决一些复杂的问题,但也需要注意递归调用的深度和性能问题。 函数的递归...

    C语言函数调用栈实例分析.md

    C语言函数调用栈实例分析.md

    c语言程序设计函数调用PPT课件.pptx

    以下是关于C语言函数调用的详细解释: 1. **函数的分类:** - **标准函数**,也称库函数,是由系统提供的,如`printf`、`scanf`等,可以直接在程序中调用,无需用户编写。 - **用户自定义函数**,由程序员根据...

    C语言函数的调用

    "C语言函数的调用" C语言函数的调用是指在程序中使用已经定义好的函数,以实现代码的重用和提高程序的结构清晰度。在一个程序中,如果把所有的语句都写到main函数中,程序会变得很乱另一方面,当同一个功能需要在...

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

    总结来说,C语言函数调用的底层机制主要包括以下几个步骤: 1. 参数通过堆栈传递,遵循从右向左的顺序。 2. `call` 指令调用函数,并将返回地址压栈。 3. 函数内部创建栈帧,分配局部变量空间。 4. 函数执行,计算...

    C语言函数选择练习题

    C语言函数是编程中至关重要的组成部分,它们是代码组织和重用的核心机制。在C语言中,函数可以接受参数并返回值,它们有自己的作用域,允许局部变量的声明。下面我们将详细讨论题目中涉及的几个关键知识点: 1. **...

    C语言函数调用参数压栈的相关问题

    "C语言函数调用参数压栈的相关问题" 本文主要讲解了C语言函数调用参数压栈的相关问题。函数调用时,参数入栈的顺序是一个经常被问到的问题。很多人认为参数入栈的顺序是从右向左,但是这只是部分正确的。事实上,...

    C语言函数调用

    介绍函数的调用!How to invoke method!

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

    C语言函数调用的底层机制涉及到了计算机程序执行的基础,主要包括函数调用的过程、参数传递方式、函数调用约定以及栈帧的管理等概念。在C语言中,函数调用是一个复杂的操作,涉及到一系列的汇编指令来实现。 首先,...

Global site tag (gtag.js) - Google Analytics