关于C代码在linux中的汇编分析

作者 云青
原创作品转载请注明出处

基本的汇编知识:

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

参考资料下载地址。http://pan.baidu.com/s/1cdISDC
课程地址:《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

一、准备

创建文件,并进行编译

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

运行完毕后生成如下文件:

    .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

我们将命令简化得到如下汇编指令:

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]
Imm(Ea) ,变址寻址,样例(GAS = C语言):4(%eax) = *(4+eax)

二、汇编指令执行流程分析

我们以简化版为例:

关于C代码在linux中的汇编分析_第1张图片
编译过后的汇编指令

C语言的都是从mian函数开始运行的,同理,汇编也是从main函数开始运行的,下面我们来从main函数入手。
首先执行的是18行pushl指令,
先画出内存的栈此时的情况:esp和ebp此时都指向栈底。

关于C代码在linux中的汇编分析_第2张图片
初始寄存器的指向情况

pushl %ebx ,即将数据压栈,指令相当于
subl $4, %esp
movl %ebx,(%esp)

  1. 执行pushl %ebp之后,eip指向下一条指令,变为:
关于C代码在linux中的汇编分析_第3张图片
image.png

2、执行movl %esp,%ebp,之后eip指向下一条指令,变为

关于C代码在linux中的汇编分析_第4张图片
image.png

3、执行 subl $4, %esp

关于C代码在linux中的汇编分析_第5张图片
subl $4, %esp

4、执行movl $8, (%esp)

关于C代码在linux中的汇编分析_第6张图片
movl $8, (%esp)

5 、call f

call f等价于
pushl %eip
movl f %eip

关于C代码在linux中的汇编分析_第7张图片
call f

6 、pushl %ebp

关于C代码在linux中的汇编分析_第8张图片
pushl %ebp

7、movl %esp, %ebp

关于C代码在linux中的汇编分析_第9张图片
movl %esp, %ebp

8、 subl $4, %esp

关于C代码在linux中的汇编分析_第10张图片
subl $4, %esp

9、movl 8(%ebp), %eax

关于C代码在linux中的汇编分析_第11张图片
image.png

10、movl %eax, (%esp)

关于C代码在linux中的汇编分析_第12张图片

11、call g

关于C代码在linux中的汇编分析_第13张图片

12、

pushl %ebp
movl %esp,%ebp
每进入一个函数都会执行这两个汇编指令
这两步操作是个规范化步骤, 叫做前序(prologue) [1]。

关于C代码在linux中的汇编分析_第14张图片
前序

13、 movl 8(%ebp), %eax

关于C代码在linux中的汇编分析_第15张图片

14、addl $3,%eax

关于C代码在linux中的汇编分析_第16张图片
image.png

15、popl %ebp

popl %ebp 相当于
movl (%esp),%ebp
addl $4,%esb

关于C代码在linux中的汇编分析_第17张图片

16、ret
等价于 popl %eip

关于C代码在linux中的汇编分析_第18张图片
ret

17、leave 等价于

movl %ebp,%esp
popl %ebp

关于C代码在linux中的汇编分析_第19张图片
leave

18、ret

关于C代码在linux中的汇编分析_第20张图片
ret

19、addl $1,%eax

关于C代码在linux中的汇编分析_第21张图片
addl

20 leave


关于C代码在linux中的汇编分析_第22张图片
image.png

21、ret
main函数运行结束,将%eax的值返回,即12

参考文章:
[1] X86汇编调用框架浅析与CFI简介
[2] http://www.cnblogs.com/lxgeek/archive/2011/01/01/1923738.html

你可能感兴趣的:(关于C代码在linux中的汇编分析)