Linux内核分析——分析C程序的反汇编内容

作者:耿介之

原创作品转载请注明出处http://blog.csdn.net/jiezhi2013/article/details/44132493

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000


1.C程序代码

首先我们写一段小程序:

main.c

int g(int x)
{
    return x + 5;
}

int f(int x)
{
    return g(x) + 1;
}

int main(void)
{
    return f(2) + 3;
}


2.反汇编

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

得到如下文件

main.s

	.file	"main.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	$5, %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
	addl	$1, %eax
	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	$2, (%esp)
	call	f
	addl	$3, %eax
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE2:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
	.section	.note.GNU-stack,"",@progbits


其中以.开头的为注释,精简后如下:
g:
	pushl	%ebp
	movl	%esp, %ebp
	movl	8(%ebp), %eax
	addl	$5, %eax
	popl	%ebp
	ret
f:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$4, %esp
	movl	8(%ebp), %eax
	movl	%eax, (%esp)
	call	g
	addl	$1, %eax
	leave
	ret
main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$4, %esp
	movl	$2, (%esp)
	call	f
	addl	$3, %eax
	leave
	ret


3.汇编分析

分析当然从main函数开始:

0

  1. pushl %ebp:将当前ebp(堆栈基指针)压栈,同时esp(堆栈顶指针)向下移动1个单位(32位下即4个字节);
  2. movl %esp, %ebp:将esp的值赋给ebp;
  3. subl $4, %esp:将esp下移1个单位(堆栈是从上而下的,所以减去4实则为栈顶加1个单位);
  4. movl $2, (%esp):将值2压栈;
  5. call f:call可以分解为两个动作,pushl %eip(*)和movl $24, %eip(*),这里的$24其实就是把下一行的地址复制给eip(指令寄存器,存放当前指令的下一条指令的地址),ebp下移一个单位,下面从f函数执行:1
  6. 其中 pushl %ebp,movl%esp, %ebp,subl $4, %esp三条指令和前面的1,2,3是一样的,略过;
  7. movl 8(%ebp), %eax:ebp+8即为ebp往上两个单位的位置,我们知道其实指向第4步压入的值2并将其复制为eax(累加器);
  8. movl %eax, (%esp):将eax赋值给esp;
  9. call g:同5;2
  10. g函数中的pushl %ebp,movl%esp, %ebp, movl8(%ebp), %eax同上;
  11. addl $5, %eax:把5加给eax,通过上面我们知道eax现在的值是2,所以现在eax值为2+5 = 7;
  12. popl %ebp:上一个压入ebp是在g函数的开始,所以这里相当于把ebp指向进入g函数之前的位置了,esp也相应的移到上个单位;
  13. ret:即return,相当于popl %eip,而上一个eip是在进入g函数的时候压入的(即call g),至此g函数执行完,继续回到f函数执行,(所计算的值7还保存在eax里)。
  14. addl $1, %eax:再把eax加1,此时eax的值为8;
  15. leave:相当于movl $esp, %eip和popl %ebp两条指令。此时esp指向main函数的call f的下一条指令,ebp指向main函数的ebp了。
  16. ret:同上
  17. addl $3, %eax:eap的值为11了。
  18. leave:同上;
  19. ret:同上。
至此,我们把这一小段反汇编代码看完了。


4.总结

其实我们可以看到,这段C程序在计算机内的执行,其实都是建立在对堆栈操作的基础上的。而堆栈的操作基本也是对栈底、栈顶的操作,所以理解了上面诸如,push、pop、move等操作后,我们就可以对一些简单的程序进行汇编分析了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值