Linux内核分析,c程序汇编代码分析--第一周

c程序汇编代码分析


做作业,顺便记录笔记

AT&T相关指令入门知识笔记,见外联  http://ouonline.net/att-asm-1

1.  汇编语言的五种寻址模式

movl %eax,%edx             edx=eax                        寄存器寻址 registermode(相当于c地址指针赋值)

movl  $0x123, %edx        edx=0x123                    立即寻址 immediate(相当于直接赋值地址值给c指针)

movl  0x123,%edx            edx=*(int*)0x123           直接寻址 direct(相当于获取地址指针的内容,* 操作)

movl (%ebx),%edx            edx=*(int*)ebx               间接寻址 indirect(相当于地址指针赋值后取值)

movl 4(%ebx),%edx            edx=*(int*)(ebx +4)      变址寻址 displaced(相当于地址指针增加后,赋值后取值)


2. 几个重要的汇编指令

Pushl %eax

Subl $4, %esp   //栈顶指针减4

Movl %eax, (%esp) //将eax中的值放入栈顶指针指向的内存位置

Popl %eax

Movl (%esp), %eax //从栈顶指针指向的内存中的值放入eax中

Addl $4, %esp //栈顶指针加4,栈在向上收缩

Call 0x12345
(eip 无法直接操作)

Pushl %eip //ip压栈

Movl $0x12345, %eip //将0x12345放入eip中

RetPopl %eip //ip出栈
EnterPushl %ebp   ebp入栈
Movl %esp, %ebp  使得ebp等于当前esp
leaveMovl %ebp, %esp  使得esp等于当前ebp(相当于栈清空了)
Popl %ebp  ebp地址出栈


================================================================================================================

现做汇编分析实验

实现环境:

系统 win7 64位

编译器 mingwin

现有c程序 main.c :

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

对其进行  gcc –S –o main.s main.c -m32

去掉相关带.的行,分析main.s

_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
	andl	$-16, %esp
	subl	$16, %esp
	call	___main
	movl	$8, (%esp)
	call	_f
	addl	$1, %eax
	leave
	ret

逐条分析

1.程序由_mian进入,首先 pushl %ebp

堆栈变化如下图,堆顶压入了ebp的值


2. movl %esp,%ebp

改变ebp的值使得其指向esp



3.andl $-16,%esp

esp 与 0xfffffff0 与运算,使得它对齐寻址空间,加快cpu处理速度


4.subl $16,%esp

esp 向下移动4位


4.call ___main

调用___main,由于在.def 里面被我删了,开始无法理解,然后google才知道,是编译器加入的,理解为加入调试信息,初始化变量等。真正的函数开始是这里开始的

.def___main;.scl2;.type32;.endef

至于.scl 2 和 .type 32 的意思,上网查一下就有的了。stackoverflow

5.因为call返回后,堆空间不变的,直接进入下一条

movl $8,(%esp)

6.call _f  调用_f 函数,由于eip不可以直接修改,只能调用 call

call 是两条指令组成的,它先压入下一条指令的地址到栈顶,这里就是addl $1,%eax的地址,然后把f的地址赋予eip寄存器。函数调用开始。


7.运行_f 函数的指令

pushl %ebp

movl  %esp,%ebp

后,变成下图,注意这里压入之前ebp地址A


8


9.运行movl 8(%ebp),%eax,从图可知就是把8的值移动加入到eax寄存器里面


10.然后把eax的值传给exp所指的空间


11.call _g


12.之后和之前的一样,压入ebp地址,改变ebp,然后把8赋予eax


13.往eax加3


14.popl %ebp  把exp的值给ebp,相当于ebp值回地址B


15.ret后,eip指向leave指令的地址,esp加四


16.运行f函数的leave指令,有两个过程

先movl %ebp,%esp


然后popl %ebp,相当于堆栈返回了


17.ret指令,eip指向addl指令


18.往eax加1


19.leave,ebp恢复到进入程序之前的ebp地址


20.ret 终于结束了,把esp上指的内容给会eip,函数返回。




总结,计算机程序运行是依照冯诺依曼体系结构,从硬件上看其工作的方式,就是cpu依次读取寄存器中的指令来进行工作,不同的指令集合构成不同的计算机系统和程序。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值