linux 运行c 代码分析,关于C代码在linux中的汇编分析

作者 云青

原创作品转载请注明出处

基本的汇编知识:

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

一、准备

创建文件,并进行编译

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]](http://www.cnblogs.com/lxgeek...

Imm(Ea) ,变址寻址,样例(GAS = C语言):4(%eax) = *(4+eax)

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

我们以简化版为例:

1460000011448413?w=803&h=678

C语言的都是从mian函数开始运行的,同理,汇编也是从main函数开始运行的,下面我们来从main函数入手。

首先执行的是18行pushl指令,

先画出内存的栈此时的情况:esp和ebp此时都指向栈底。

1460000011448414?w=962&h=706

pushl %ebx ,即将数据压栈,指令相当于

subl $4, %esp

movl %ebx,(%esp)

执行pushl %ebp之后,eip指向下一条指令,变为:

1460000011448415?w=977&h=676

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

1460000011448416?w=979&h=682

3、执行 subl $4, %esp

1460000011448417?w=980&h=690

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

1460000011448418?w=989&h=661

5 、call f

call f等价于

pushl %eip

movl f %eip

1460000011448419?w=990&h=675

6 、pushl %ebp

1460000011448420?w=982&h=659

7、movl %esp, %ebp

1460000011448421?w=985&h=692

8、 subl $4, %esp

1460000011448422?w=992&h=688

9、movl 8(%ebp), %eax

1460000011448423?w=966&h=635

10、movl %eax, (%esp)

1460000011448424?w=998&h=681

11、call g

1460000011448425?w=982&h=700

12、

pushl %ebp

movl %esp,%ebp

每进入一个函数都会执行这两个汇编指令

这两步操作是个规范化步骤, 叫做前序(prologue) [1]。

1460000011448426?w=985&h=653

执行函数时,汇编会生成一个堆栈调用框架:

具体如下:

//建立被调用者函数的堆栈框架

pushl %ebp

movl %esp,%ebp

//被调用者函数体

//do something

//拆除被调用者的函数的堆栈框架

movl %ebp,%esp

popl %ebp

ret

13、 movl 8(%ebp), %eax

1460000011448427?w=1012&h=660

14、addl $3,%eax

1460000011448428?w=968&h=659

15、popl %ebp

popl %ebp 相当于

movl (%esp),%ebp

addl $4,%esb

1460000011448429?w=1002&h=648

16、ret

等价于 popl %eip

1460000011448430?w=996&h=653

17、leave 等价于

movl %ebp,%esp

popl %ebp

1460000011448431?w=990&h=659

18、ret

1460000011448432?w=982&h=648

19、addl $1,%eax

1460000011448433?w=989&h=674

20 leave

1460000011448434?w=998&h=660

21、ret

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值