为什么80%的码农都做不了架构师?>>>   

[技術] C的function call與stack frame心得

Written on 12:00 上午 by Yu Lai

從大二的Program Language中學到stack對於C的function call的實做與功用的概念,
以及各個register的功用,但從未實際地深入了解其中register的變化.
剛好最近T40灌了Ubuntu Linux (x86),就直接寫了些C code,
配合objdump與gdb來trace其中register的變化,於是有了這篇的心得.

首先是複習一下register:
%eip:instruction pointer,用來指到下一個instruction的位置.
%esp:stack pointer,用來指到目前stack的top.
%ebp:Frame pointer,用來指到目前stack frame的開頭.

這次所使用的source code:

#include <stdio.h>
void hi(int a, int b) {int i = 3;return;
}
int main(int argc, char *argv[]) {hi(1, 2);return 0;
}

我們先透過$ gcc -o test test.c編出test,
然後再透過objdump -d test來觀察disassemble出來的部份:

08048344 <hi>:8048344: 55                    push   %ebp8048345: 89 e5                 mov    %esp,%ebp8048347: 83 ec 10              sub    $0x10,%esp804834a: c7 45 fc 03 00 00 00  movl   $0x3,-0x4(%ebp)8048351: c9                    leave  8048352: c3                    ret    08048353 <main>:8048353: 8d 4c 24 04           lea    0x4(%esp),%ecx8048357: 83 e4 f0              and    $0xfffffff0,%esp804835a: ff 71 fc              pushl  -0x4(%ecx)804835d: 55                    push   %ebp804835e: 89 e5                 mov    %esp,%ebp8048360: 51                    push   %ecx8048361: 83 ec 08              sub    $0x8,%esp8048364: c7 44 24 04 02 00 00  movl   $0x2,0x4(%esp)804836b: 00 804836c: c7 04 24 01 00 00 00  movl   $0x1,(%esp)8048373: e8 cc ff ff ff        call   8048344 <hi>8048378: b8 00 00 00 00        mov    $0x0,%eax804837d: 83 c4 08              add    $0x8,%esp8048380: 59                    pop    %ecx8048381: 5d                    pop    %ebp8048382: 8d 61 fc              lea    -0x4(%ecx),%esp8048385: c3                    ret    8048386: 90                    nop

從0x0804835d開始,我們可以看到main()在呼叫hi()時的步驟,
首先先把ebp的值塞進stack中,然後把esp的值塞到ebp裡.
接著把esp減8(因為stack是由高位往低位),再分別把0x2和0x1塞入stack中,
這2個其實就是把hi()所需的變數放入stack中,最後就是call 8048344 <hi>.
接著透過gdb設好breakpoint把stack中的值給印出來.

$ gdb -q test
(gdb) b hi
Breakpoint 1 at 0x804834a
(gdb) r
Starting program: /home/lazyf/test Breakpoint 1, 0x0804834a in hi ()
Current language:  auto; currently asm
(gdb) x/32xw $esp
0xbfb9a074: 0x0804953c 0xbfb9a088 0x08048280 0xb7f95ff4
0xbfb9a084: 0xbfb9a098 0x08048378 0x00000001 0x00000002
0xbfb9a094: 0xbfb9a0b0 0xbfb9a108 0xb7e61450 0xb7fc8ce0
0xbfb9a0a4: 0x080483a0 0xbfb9a108 0xb7e61450 0x00000001
0xbfb9a0b4: 0xbfb9a134 0xbfb9a13c 0xb7facb38 0x00000000
0xbfb9a0c4: 0x00000001 0x00000000 0x080481f5 0xb7f95ff4
0xbfb9a0d4: 0xb7fc8ce0 0x00000000 0xbfb9a108 0x67416081
0xbfb9a0e4: 0xd8282a91 0x00000000 0x00000000 0x00000000
(gdb)

從stack內的值我們可以觀察到,其實call指令所做的動作就是把下一筆instruction的
address(eip)給push進stack裡(0x08048378被放入0xbfb9a088中),接著再把call的address
塞到eip再執行它.

接著到了hi()中,和main()一樣的先把ebp塞入stack中,然後把把esp的值塞到ebp裡.
從這裡我們可以知道,一個function開始時,會先把上一個function的ebp放入stack中,
接著馬上設定自己的ebp.從這裡可以用來確保目前所在function的ebp的值的正確性,
以及保存之後要return時上一個function的ebp的值.

在hi()中把ebp設定好後,它先在stack中allocate了16個byte來使用,接著我們看到了
在ebp-4的位置上被填入了0x3的值,也就是我們在程式中宣告的變數int i = 3;的實做.

最後是leave指令和ret指令所實做出來的return;.在這裡leave指令的操作相當於
把ebp的值放到esp中,然後從stack中pop出值來放到ebp裡,而ret指令的操作則相當於從
stack中pop出值來放到eip裡.也就是說除了eip外,esp和ebp都回到呼叫hi()之前的狀況.
完成hi()的呼叫.

另外,如果hi()有值需要被return時,通常會透過eax register來傳遞.
也就是說在$lt;hi>中的leave指令前會加入mov xxx,%eax指令,
在<main>中call <hi>指令的下一個指令會是mov %eax,yyy指令讀出eax放入yyy中
和mov $0x0,%eax指令把eax清空.

以上就是我從gdb與objdump中所觀察到的一個C的function被呼叫的過程.
如內容有所錯誤,煩請有看到的人不吝賜教.Thanks.

转载于:https://my.oschina.net/tsh/blog/1613642

C的function call與stack frame心得相关推荐

  1. Stack frame omission (FPO) optimization part1

    Stack frame omission (FPO) optimization and consequences when debugging, part 1 During the course of ...

  2. LWN:Fedora关于stack frame的争论!

    关注了就能看到更多这么棒的文章哦- Fedora's tempest in a stack frame By Jonathan Corbet January 16, 2023 DeepL assist ...

  3. 浅谈函数栈帧(Stack Frame)

  4. 《memory leak: stackwalk》

    <memory leak: stackwalk> /// // // StackWalk.cpp // // Author: Oleg Starodumov // // NOTE: THI ...

  5. 操作系统课程设计pintos project1实验摘记

    前言: 本篇意在记录本学期结束的操作系统课程设计pintos project1实验报告和实现过程.整个实验参考了多篇文章也查阅了一些代码,其中部分内容或与其他文章相同,还请见谅.同时,也为了测试CSD ...

  6. A Web Crawler With asyncio Coroutines

    注:本文网上有翻译,参见 ? 一个使用 asyncio 协程的网络爬虫(一) ? 一个使用 asyncio 协程的网络爬虫(二) ? 一个使用 asyncio 协程的网络爬虫(三)? Overview ...

  7. (android 源码下开发应用程序) 如何在 Android 各 level ( 包含 user space 與 kernel space ) 使用dump call stack的方法...

    http://janbarry0914.blogspot.com/2014/07/androiddump-call-stack.html dump call stack [文章重點] 了解 Andro ...

  8. React 源碼解析 - Fiber/Reconcile 系列:Fiber 與 Diff

    React 源碼解析 - Fiber/Reconcile 系列:Fiber 與 Diff 前言 正文 從 DOM 到 Fiber 對象 DOM VDOM React 元素(React Element) ...

  9. Lua 中的 function、closure、upvalue

    Lua 中的 function.closure.upvalue function,local,upvalue,closure 参考: Lua基础 语句 lua学习笔记之Lua的function.clo ...

最新文章

  1. python 多进程_说说Python多线程与多进程的区别?
  2. 最新的SqlHelper 类
  3. 机器学习中的目标函数、损失函数、代价函数有什么区别?
  4. CentOS6 kvm添加网卡桥接口脚本
  5. Java提升篇-事务隔离级别和传播机制
  6. linux 编辑文件乱码,Linux 下 vim 编辑文件,解决中文乱码,设置Tab键空格数
  7. Linux下redis的安装及部署
  8. 白话空间统计之二十五:空间权重矩阵(四)R语言中的空间权重矩阵(1)
  9. spring boot内置容器性能比较(Jetty、Tomcat、Undertow)
  10. 网络安全建设网络可用性管理方法
  11. 什么表示计算机的存储容量,计算机的存储容量是指它具有的什么
  12. 安卓辅助功能获取控件id
  13. 推荐几款好用的UI框架 和 后台管理系统(开源免费)
  14. mysql数据库表中插入中文字段时报错 ‘\xCD\xF5\xBB\xAA‘
  15. Intelligent Designer
  16. linux+查看磁带信息,15 条实用 Linux/Unix 磁带管理命令
  17. [机缘参悟-53]:《素书》-2-俊、豪、杰[正道章第二]
  18. 生成Excel的” 源代码
  19. 纳米器件,量子点理论文献拾遗
  20. SciChart_V6.最新的图表控件发布了!

热门文章

  1. Android SDK上手指南:应用程序数据
  2. 模拟银行自助终端系统
  3. MapReduce V1:Job提交流程之JobTracker端分析
  4. python常见模块命令(os/sys/platform)
  5. ffmpeg个人翻译文档1-8转
  6. [ACM] hdu 1232 畅通工程(并查集)
  7. 使用谷歌浏览器模拟微信(android或ios)浏览器
  8. 学习_HTML5_day2
  9. IDEA远程调试服务器代码
  10. bzoj1207: [HNOI2004]打鼹鼠