陈呵+《Linux内核分析》 MOOC课程http://mooc.study.163.com/course/USTC-1000029000
实验截图如下
将.开头的汇编语句删去。。我是手动删的,删了好久,在网上找到一条命令,还未验证
$/g/\s*\./d
分析:
g: pushl %ebp ;ebp=x-16, esp=x-28, %esp=x-16 movl %esp, %ebp ;ebp=x-28, esp=x-28, %esp=ebp[x-16] ;初始化新栈 movl 8(%ebp), %eax ;eax=25 ;获取参数 addl $4, %eax ;eax=29 ;函数内x+4的运算 popl %ebp ;将栈底设置为上一个栈的栈底,恢复旧栈,此时ebp=x-16, esp=x-24, %esp=eip[f:7] ret ;ret指令如下 ;popl %eip ;将eip设置为上次中断的位置,恢复执行流,此时ebp=x-16, esp=x-20, %esp=25, eip=[f:7] ;整个过程实现了恢复中断的执行流的功能,栈状态恢复为call之前[f:5]的状态,eip指向了[f:7] ;完成了{函数返回} f: pushl %ebp ;ebp=x-4, esp=x-16 movl %esp, %ebp ;ebp=x-16, esp=x-16 ;初始化新栈 subl $4, %esp ;增加栈位,此时ebp=x-16, esp=x-20,用来保存参数 movl 8(%ebp), %eax ;将eax设置为(x-16+8)所在栈的值,即25 movl %eax, (%esp) ;将eax放到栈顶位置,此时ebp=x-16, esp=x-20, %esp=25,完成参数的传递 ;整个过程实现了从栈中取值并将值压栈的操作 ;配合执行流跳转前将25压栈的操作实现了{函数调用及参数的传递} ;指令1,3又将此值压栈是为了调用g做准备 call g ;ebp=x-16, esp=x-24, %esp=eip[f:7], eip={g} ;跳转到g ;从g返回 ;ebp=x-16, esp=x-20, %esp=25, eip=[f:7] leave ;movl %ebp, %esp ;将栈顶设置为栈底,销毁当前栈,此时ebp=x-16, esp=x-16, %esp=ebp[x-4] ;popl %ebp ;恢复旧栈,此时ebp=x-4, esp=x-12, %esp=eip[main:6] ret ;整个过程实现了函数返回的作用 ;与[g:5-6]不同在于此函数中执行过压栈的操作,所以要先销毁当前栈才能恢复旧栈, ;[g:5-6]因为没有压栈操作所以可以直接使用popl,是不是不用向其它函数传递参数就不用压栈存参数?
main: pushl %ebp ;将ebp压栈,此时设ebp=x, 则esp=x-4, esp指向的栈空间存储的是ebp movl %esp, %ebp ;将ebp的值设置为esp,此时ebp=x-4, esp=x-4, ;整个过程实现了将旧栈保存并初始化新栈 subl $4, %esp ;将esp=x-8,栈顶下移,增加栈位,此时ebp=x-4, esp=x-8 movl $25, (%esp) ;将立即数25放到栈顶位置,此时ebp=x-4, esp=x-8, %esp=25 ;整个过程实现将立即数25压栈 call f ;call指令如下 ;push %eip ;将下一条将要执行的指令的地址压栈,此时ebp=x-4, esp=x-12, %esp=eip[main:6] ;movl f, %eip ;将eip设置为f标号所指向的指令地址,此时eip = {f} ;整个过程实现了执行流跳转的功能,下一条指令将会执行标号f:所在的指令, ;从f返回 addl $1, %eax ;eax=30 ;函数内f(x)+1 leave ;恢复栈 ret ;函数返回,这里返回到调用此程序的函数中去了