關於C代碼在linux中的彙編分析

做者 雲青
原創做品轉載請註明出處html

基本的彙編知識:ubuntu

movl,subl,pushl,topl,ret,addl,leave,enter

參考資料下載地址。http://pan.baidu.com/s/1cdISDC
課程地址:《Linux內核分析》MOOC課程http://mooc.study.163.com/cou...框架

1、準備

建立文件,並進行編譯ide

int g(int x)
{
  return x + 3;
}
 
int f(int x)
{
  return g(x);
}
 
int main(void)
{
  return f(8) + 1;
}

編譯命令:函數

gcc -S -o demo1.s demo1.c -m32

運行完畢後生成以下文件:spa

.file    "demo1.c"
    .text
    .globl    g
    .type    g, @function
g:
.LFB0:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    movl    8(%ebp), %eax
    addl    $3, %eax
    popl    %ebp
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size    g, .-g
    .globl    f
    .type    f, @function
f:
.LFB1:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $4, %esp
    movl    8(%ebp), %eax
    movl    %eax, (%esp)
    call    g
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE1:
    .size    f, .-f
    .globl    main
    .type    main, @function
main:
.LFB2:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $4, %esp
    movl    $8, (%esp)
    call    f
    addl    $1, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE2:
    .size    main, .-main
    .ident    "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
    .section    .note.GNU-stack,"",@progbits

咱們將命令簡化獲得以下彙編指令:.net

g:
    pushl    %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    addl    $3, %eax
    popl    %ebp
    ret

f:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    movl    8(%ebp), %eax
    movl    %eax, (%esp)
    call    g
    leave
    ret

main:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    movl    $8, (%esp)
    call    f
    addl    $1, %eax
    leave
    ret

備註:
%開頭表示寄存器
$開頭表示當即數
()表示間接尋址,樣例(GAS = C語言):(%eax)= *eax [[2]](http://www.cnblogs.com/lxgeek...
Imm(Ea) ,變址尋址,樣例(GAS = C語言):4(%eax) = *(4+eax)3d

2、彙編指令執行流程分析

咱們以簡化版爲例:rest

編譯事後的彙編指令

C語言的都是從mian函數開始運行的,同理,彙編也是從main函數開始運行的,下面咱們來從main函數入手。
首先執行的是18行pushl指令,
先畫出內存的棧此時的狀況:esp和ebp此時都指向棧底。code

初始寄存器的指向狀況

pushl %ebx ,即將數據壓棧,指令至關於

subl $4, %esp
movl %ebx,(%esp)

  1. 執行pushl %ebp以後,eip指向下一條指令,變爲:

image.png

二、執行movl %esp,%ebp,以後eip指向下一條指令,變爲

image.png

三、執行 subl $4, %esp

subl    $4, %esp

四、執行movl $8, (%esp)

movl    $8, (%esp)

5 、call f

call f等價於

pushl %eip
movl f %eip

call f

6 、pushl %ebp

pushl %ebp

七、movl %esp, %ebp

movl    %esp, %ebp

八、 subl $4, %esp

subl    $4, %esp

九、movl 8(%ebp), %eax

image.png

十、movl %eax, (%esp)

十一、call g

十二、

pushl %ebp

movl %esp,%ebp
每進入一個函數都會執行這兩個彙編指令
這兩步操做是個規範化步驟, 叫作前序(prologue) [1]。

前序

執行函數時,彙編會生成一個堆棧調用框架:

具體以下:

//創建被調用者函數的堆棧框架
pushl %ebp
movl %esp,%ebp
//被調用者函數體
//do something

//拆除被調用者的函數的堆棧框架
movl %ebp,%esp
popl %ebp
ret

1三、 movl 8(%ebp), %eax

1四、addl $3,%eax

image.png

1五、popl %ebp

popl %ebp 至關於

movl (%esp),%ebp
addl $4,%esb

1六、ret
等價於 popl %eip

ret

1七、leave 等價於

movl %ebp,%esp

popl %ebp

leave

1八、ret

ret

1九、addl $1,%eax

addl

20 leave
image.png

2一、ret
main函數運行結束,將%eax的值返回,即12

參考文章:
[1]  X86彙編調用框架淺析與CFI簡介
[2] http://www.cnblogs.com/lxgeek...

相關文章
相關標籤/搜索