国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 操作系統 > 正文

C程序匯編運行模式簡析

2024-06-28 13:21:41
字體:
來源:轉載
供稿:網友
C程序匯編運行模式簡析

SJTUBEAR 原創作品轉載請注明出處 /《linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000

1. 匯編

在修習LINUX內核這門課的初始階段,首先需要掌握的就是匯編以及匯編程序對于堆棧的操作。

下面我們就來分析一下一個簡單地C程序是如何被匯編程序所表達的!

2. 得到匯編代碼

首先,我們寫一個簡單地C程序,命名為exp1.c:

 1 #include <stdio.h> 2  3 int g(int x) 4 { 5     return x+3; 6 } 7  8 int f(x) 9 {10     return g(x);11 }12 13 int main()14 {15     return f(8)+1;    16 }

程序非常的簡單,我們此時再通過編譯指令將其編譯為匯編程序:

1 gcc –S –o main.s main.c -m32

這樣我們就得到了這個簡單C程序的匯編代碼:

 1     .file    "exp1.c" 2     .text 3     .globl    g 4     .type    g, @function 5 g: 6 .LFB0: 7     .cfi_startPRoc 8     pushl    %ebp 9     .cfi_def_cfa_offset 810     .cfi_offset 5, -811     movl    %esp, %ebp12     .cfi_def_cfa_register 513     movl    8(%ebp), %eax14     addl    $3, %eax15     popl    %ebp16     .cfi_def_cfa 4, 417     .cfi_restore 518     ret19     .cfi_endproc20 .LFE0:21     .size    g, .-g22     .globl    f23     .type    f, @function24 f:25 .LFB1:26     .cfi_startproc27     pushl    %ebp28     .cfi_def_cfa_offset 829     .cfi_offset 5, -830     movl    %esp, %ebp31     .cfi_def_cfa_register 532     subl    $4, %esp33     movl    8(%ebp), %eax34     movl    %eax, (%esp)35     call    g36     leave37     .cfi_restore 538     .cfi_def_cfa 4, 439     ret40     .cfi_endproc41 .LFE1:42     .size    f, .-f43     .globl    main44     .type    main, @function45 main:46 .LFB2:47     .cfi_startproc48     pushl    %ebp49     .cfi_def_cfa_offset 850     .cfi_offset 5, -851     movl    %esp, %ebp52     .cfi_def_cfa_register 553     subl    $4, %esp54     movl    $8, (%esp)55     call    f56     addl    $1, %eax57     leave58     .cfi_restore 559     .cfi_def_cfa 4, 460     ret61     .cfi_endproc62 .LFE2:63     .size    main, .-main64     .ident    "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"65     .section    .note.GNU-stack,"",@progbits
3.匯編代碼分析

匯編出的代碼,多了很多輔助信息,為了能夠更好地看清主干,我們刪減一下:

 1 g: 2     pushl    %ebp            //保存現場,將父函數的棧底寄存器存入當前程序棧中 3     movl    %esp, %ebp      //構建當前函數堆棧 4     movl    8(%ebp), %eax   //從父函數堆棧中取得參數,存入ax寄存器 5     addl    $3, %eax        //完成+3操作 6     popl    %ebp            //恢復原父函數堆棧 7     ret                     //pop出原Eip地址,恢復執行 8 f: 9     pushl    %ebp            //保存現場,將父函數的棧底寄存器存入當前程序棧中10     movl    %esp, %ebp      //構建當前函數堆棧11     subl    $4, %esp        //棧頂加一,用以儲存變量傳遞給g函數12     movl    8(%ebp), %eax   //取得參數13     movl    %eax, (%esp)    //將參數傳入變量位置14     call    g               //調用g15     leave                   //清楚局部變量空間16     ret                     //返回17 main:18     pushl    %ebp19     movl    %esp, %ebp20     subl    $4, %esp        //空出局部變量空間21     movl    $8, (%esp)      //為變量賦值22     call    f               //調用f23     addl    $1, %eax        //完成+1操作24     leave                   //清理局部變量25     ret                     //返回

我們對f函數進行詳細的分析:

1. 首先進行enter指令:

此時,ebp當前所指向的位置存入棧頂,并且將ebp重定向指向esp:

2.棧頂加一并存入變量值:

3.調用g

4.從g返回后,返回值儲存在AX寄存器中,不用操作,調用leave,清理變量

5.最后ret,同時EIP被讀出恢復到原位置繼續執行,返回值在AX中傳遞給調用函數

3.個人的一點感悟:

程序的調用就是這樣嵌套的執行下去,每個函數都有自己的堆棧用以儲存當前變量以及環境值,并通過將父函數的EBP放入棧底用以恢復環境。

同時EIP存入父棧棧頂,便于恢復到原節點處繼續執行。

這樣,就可以有規律的一直嵌套下去。

如果使用遞歸函數,就是一個碼堆棧的過程,知道最頂部的堆棧返回,函數就像多米諾骨牌一樣收回所有的堆棧。

這也是遞歸函數占用空間比較多的原因之一。如果沒有很好地退出機制,有可能內存溢出。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 安化县| 翼城县| 庆云县| 江安县| 泽库县| 读书| 大安市| 永善县| 霞浦县| 房产| 宁河县| 新巴尔虎左旗| 霍州市| 兴义市| 洛川县| 得荣县| 名山县| 南川市| 和平县| 灵璧县| 搜索| 即墨市| 博野县| 茌平县| 康马县| 泰来县| 甘肃省| 德清县| 屯昌县| 香港 | 铜山县| 维西| 慈溪市| 万安县| 台江县| 商城县| 临海市| 铜梁县| 青海省| 长岛县| 衡山县|