摘自自博客网址 http://www.cnblogs.com/bangerlee/archive/2012/05/22/2508772.html

  • ax(accumulator): 可用于存放函数返回值
  • bp(base pointer): 用于存放执行中的函数对应的栈帧的栈底地址
  • sp(stack poinger): 用于存放执行中的函数对应的栈帧的栈顶地址
  • ip(instruction pointer): 指向当前执行指令的下一条指令

example code:

//func_call.c

int bar(int c, int d)

{

int e = c + d;

return e;

}

int foo(int a, int b)

{

return bar(a, b);

}

int main(void)

{

foo(2, 5);

return 0;

}

main函数汇编代码:

(gdb) disassemble /rm

Dump of assembler code for function main:

{

0x0000000000400521 :     55                push %rbp

0x0000000000400522 :     48 89 e5          mov %rsp,%rbp

foo(2, 5);

0x0000000000400525 :     be 05 00 00 00    mov $0x5,%esi

0x000000000040052a :     bf 02 00 00 00    mov $0x2,�i

0x000000000040052f :    e8 d2 ff ff ff    callq 0x400506

return 0;

0x0000000000400534 :    b8 00 00 00 00    mov $0x0,eax

}

0x0000000000400539 :     c9               leaveq

0x000000000040053a :     c3               retq

End of assembler dump.

函数调用关系

main->foo->bar

# gcc -g func_call.c -o func_call

反汇编分析

(gdb) start
start命令用于拉起被调试程序,并执行至main函数的开始位置
现进程跑在main函数中,我们disassemble命令显示当前函数的汇编信息:
(gdb) disassemble /rm
/m指示显示汇编指令的同时,显示相应的程序源码;/r指示显示十六进制的计算机指令(raw instruction)
一个函数被调用,首先默认要完成以下动作:
将调用函数的栈帧栈底地址入栈,即将bp寄存器的值压入调用栈中
建立新的栈帧,将被调函数的栈帧栈底地址放入bp寄存器中
以下两条指令即完成上面动作:
push %rbp
mov %rsp, %rbp
main并不是程序拉起后第一个被执行的函数,它被_start函数调用
传递参数
mov $0x5, %esi
mov $0x2, �i
或者:\\x86 is diffrent from x86_64
sub $0x8, %esp
mov $0x5, -0x4(%ebp) //栈底对应低地址
mov $0x2, -0x8(�p)
call指令完成控制全转移
0x000000000040052f 14>:     e8 d2 ff ff ff    callq  0x400506
执行完start命令后,现在程序停在0x400522的位置,下面我们通过gdb的si指令,让程序执行完call指令
(gdb) si 3
foo (a=0, b=4195328) at func_call.c:8
8 {
(gdb)
查看rsp、rbp寄存器的值,它们保存了程序实际用到的物理内存地址
(gdb) info registers rbp rsp
rbp 0x7fffffffe8e0 0x7fffffffe8e0
rsp 0x7fffffffe8d8 0x7fffffffe8d8
(gdb)
将main函数栈帧的栈底地址入栈,建立foo函数的栈帧:
0x0000000000400506 0>:     55             push   %rbp
0x0000000000400507 1>: 48 89 e5 mov %rsp,%rbp //rsp的值从哪里得到的?
将参数传入esi、edi寄存器,然后执行call指令
0x000000000040051a 20>:     e8 cd ff ff ff    callq  0x4004ec
10 }
0x000000000040051f 25>: c9 leaveq
0x0000000000400520 26>: c3 retq
最后一个被调用的函数结果保存在eax寄存器中,以作为结果返回
函数调用过程对应着调用栈的建立,而函数返回则是进行调用栈的销毁,
0x0000000000400504 24>:     c9    leaveq//相当于mov %rbp, %rsp/pop %rbp
0x0000000000400505 25>:     c3    retq
修改sp、bp寄存器记录栈帧的高、低地址,以此完成函数调转;
push/mov操作保存caller变量、指令信息,保证callee返回之后caller继续正常执行;
下一个函数的bp由sp传入,从kernel传入的?

调用栈变化过程:
call foo之前 ox400534是call后main的下一条指令地址

call bar后,汇编bar前,0x40051f是foo执行bar后的下一条指令

汇编bar后

执行完bar后


Function call process的更多相关文章

  1. nodejs笔记一--模块,全局process对象;

    一.os模块可提供操作系统的一些基本信息,它的一些常用方法如下: var os = require("os"); var result = os.platform(); //查看操 ...

  2. setTimeout和setImmediate以及process.nextTick的区别

    在javascript中我们了解到了setTimeout和setInterVal函数事件队列(任务队列)的相关知识,除了setTimeout和setInterval这两个方法外,Node.js还提供了 ...

  3. Nodejs随笔(三):全局对象之process

    process是全局对象,在任何地方都可以访问,而且它是EventEmitter的一个实例(关于EventEmitter后面会提到). process对象对一些标准的输入输出流进行了封装,如stdin ...

  4. Process Node.js 进程

    Process 进程 process.argv 是命令行参数数组,第一个元素是node,第二个元素是脚本文件名,从第三个元素开始每个元素是一个运行参数. process.stdout 标准输出流 co ...

  5. js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)

    javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...

  6. node.js中process进程的概念和child_process子进程模块的使用

    进程,你可以把它理解成一个正在运行的程序.node.js中每个应用程序都是进程类的实例对象. node.js中有一个 process 全局对象,通过它我们可以获取,运行该程序的用户,环境变量等信息. ...

  7. Node.js进程管理之Process模块

    在前面Node.js事件运行机制也有提到,Node.js应用在单个线程运行,但是现在大部分服务器都是多处理器,为了方便使用多个进程,Node.js提供了3个模块.Process模块提供了访问正在运行的 ...

  8. 【APUE】Chapter8 Process Control

    这章的内容比较多.按照小节序号来组织笔记的结构:再结合函数的示例带代码标注出来需要注意的地方. 下面的内容只是个人看书时思考内容的总结,并不能代替看书(毕竟APUE是一本大多数人公认的UNIX圣经). ...

  9. node.js(API解读) - process (http://snoopyxdy.blog.163.com/blog/static/60117440201192841649337/)

    node.js(API解读) - process 2011-10-28 17:05:34|  分类: node |  标签:nodejs  nodejsprocess  node.jsprocess  ...

随机推荐

  1. Note: RewriteCond规则

    如果文件存在,就直接访问文件,不进行下面的RewriteRule:RewriteCond %{REQUEST_FILENAME} !-f 如果目录存在,就直接访问目录,不进行下面的RewriteRul ...

  2. 使用PHP发送邮件的两种方法

    使用PHP发送邮件的两种方法 May242013 作者:Jerry Bendy   发布:2013-05-24 22:25   分类:PHP   阅读:2,107 views   抢沙发     今天 ...

  3. [SHELL进阶] (转)最牛B的 Linux Shell 命令 (三)

    1. 更友好的显示当前挂载的文件系统 mount | column -t 这条命令适用于任何文件系统,column 用于把输出结果进行列表格式化操作,这里最主要的目的是让大家熟悉一下 columnt ...

  4. Flink DataSet API Programming Guide

     https://ci.apache.org/projects/flink/flink-docs-release-0.10/apis/programming_guide.html   Example ...

  5. 关于Java的File.separator

    在Windows下的路径分隔符和Linux下的路径分隔符是不一样的,当直接使用绝对路径时,跨平台会暴出“No such file or diretory”的异常. 比如说要在temp目录下建立一个te ...

  6. java event

    What is an Event? Change in the state of an object is known as event i.e. event describes the change ...

  7. cwe

  8. Java实验报告五:Java网络编程及安全

    Java实验报告五:Java网络编程及安全                                                                               ...

  9. Region的预分区

    1.预分区的方式 共有四种方式 2.帮助信息 help 'create' 3.第一种方式 4.在页面上查看效果(端口号:60010) 5.第二种方式 )创建文件,并在文件中书写分区的值 )创建表 6. ...

  10. php-- memcache 与 memcached支架的区别与共同点 个人整理

    首先声明:memcache 与 memcached 之间没有关系 1.概念相似 MemCache是一个自由.源码开放.高性能.分布式的分布式内存对象缓存系统,用于动态Web应用以减轻数据库的负载. m ...