從匯編代碼理解函數調用過程

如何理解函數調用過程?本文把一個簡單的C語言程序匯編成目標代碼,然后用objdump目標文件反編譯成的匯編代碼,從而一窺函數調用過程,希望對你有所啟發。
C語言源碼:

#include <stdio.h>

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

int main()
{
        int x = 5;
        int y = 10;
        int u = add(x, y);

        return 1;
}
~

經過編譯:gcc -g -c add.c,生成目標代碼add.o
查看目標文件(生成匯編代碼): objdump -d -S add.o

add.o:  file format Mach-O 64-bit x86-64

Disassembly of section __TEXT,__text:
_main:
; {                         //這是注釋(ps)
       0:   55  pushq   %rbp
       1:   48 89 e5    movq    %rsp, %rbp
       4:   48 83 ec 10     subq    $16, %rsp
       8:   c7 45 fc 00 00 00 00    movl    $0, -4(%rbp)
; int x = 5;
       f:   c7 45 f8 05 00 00 00    movl    $5, -8(%rbp)
; int y = 10;
      16:   c7 45 f4 0a 00 00 00    movl    $10, -12(%rbp)
; int u = add(x, y);
      1d:   8b 7d f8    movl    -8(%rbp), %edi
      20:   8b 75 f4    movl    -12(%rbp), %esi
      23:   e8 00 00 00 00  callq   0 <_main+0x28>
      28:   be 01 00 00 00  movl    $1, %esi
      2d:   89 45 f0    movl    %eax, -16(%rbp)
; return 1;
      30:   89 f0   movl    %esi, %eax
      32:   48 83 c4 10     addq    $16, %rsp
      36:   5d  popq    %rbp
      37:   c3  retq
      38:   0f 1f 84 00 00 00 00 00     nopl    (%rax,%rax)

_add:
; {
      40:   55  pushq   %rbp
      41:   48 89 e5    movq    %rsp, %rbp         ;當前函數的棧指針
      44:   89 7d fc    movl    %edi, -4(%rbp)      ;把寄存器的參數移動到棧上
      47:   89 75 f8    movl    %esi, -8(%rbp)      ;把寄存器的參數移動到棧上
; return a+b;
      4a:   8b 75 fc    movl    -4(%rbp), %esi
      4d:   03 75 f8    addl    -8(%rbp), %esi
      50:   89 f0   movl    %esi, %eax
      52:   5d  popq    %rbp
      53:   c3  retq

從上面可以看出:
1、目標文件(.o)的地址是從0開始的 (還沒有在虛擬地址空間中分配地址,ld的時候才分配)
2、函數開始地址是4字節對齊的。
3、X86架構指令長度是變長的(ARM指令是定長的4字節)。
4、名字修飾,符號名稱是通過下劃線+函數名得到。

程序調用過程

調用方:
  1. 先把參數保存在寄存器edi和esi中(通過寄存器傳參數)
  2. 調用callq
  3. 處理返回值eax

其中,callq做了兩件事情:
1) 保存下一條指令的地址,用于函數返回繼續執行
2) 跳轉到子函數的地址

被調用方:
  1. 上一個函數的幀指針rbp入棧
  2. 棧指針rsp保存到幀指針
  3. 從寄存器(edi和esi)取出參數到棧中
  4. 運算
  5. 把計算結果保存在eax
  6. 彈出幀指針(還原前一個函數的rbp)
  7. 函數返回,取下一跳指令繼續執行

特別說明
上面函數傳參和返回參數傳遞是通過寄存器傳遞的,還可以通過棧和內存區域傳遞,具體可以參考C語言調用慣例。

一個函數的幀結構中包含哪些數據?

1、上一個棧幀寄存器保存在棧中的值
2、本函數用的臨時變量
3、調用子函數傳的參數
4、調用子函數后返回時繼續執行的(返回地址)

棧幀結構

棧幀示意

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容

  • 原文地址:C語言函數調用棧(一)C語言函數調用棧(二) 0 引言 程序的執行過程可看作連續的函數調用。當一個函數執...
    小豬啊嗚閱讀 4,649評論 1 19
  • 由于不是科班出生,又是自學開發,對很多方面的知識都是只知其然而不知其所以然。加上最近公司事情不多,剛好乘此機會把長...
    寒咯閱讀 13,052評論 3 8
  • 首先寄存器使用慣例:eip :指令地址寄存器,保存程序計數器的值,當前執行的指令的下一條指令的地址值,16位中為i...
    扎Zn了老Fe閱讀 1,994評論 0 0
  • 一、溫故而知新 1. 內存不夠怎么辦 內存簡單分配策略的問題地址空間不隔離內存使用效率低程序運行的地址不確定 關于...
    SeanCST閱讀 7,844評論 0 27
  • 從本篇開始,我們討論一些高級語言中的基礎設施:堆棧,函數調用,變量生命周期等等話題。因為這里本身會涉及到比較多的匯...
    SlayerNux閱讀 13,067評論 1 27