2019-2020-1 20199309《Linux内核原理与分析》第二周作业

计算机是如何工作的

反汇编一个简单的C程序

首先,我们新建一个C程序main.c

在vim编辑器中键入

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

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

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

实验部分(64位Linux虚拟机环境下适用,32位Linux环境可能会稍有不同) 使用:

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

打开main.s,并手动删除.打头的字符串后得到:

下面,我试着用自己的语言解释一下这23行汇编语言:

/*
** 个人理解,有错望不吝指出
*/
g:
        pushl   %ebp  /*同样,先把f函数的栈底地址存到栈顶*/
        movl    %esp, %ebp  /*再把基指针指向栈顶,也就是g函数的栈底*/
        movl    8(%ebp), %eax  /*相对寻址,ebp的内容指向的地址倒退2个单元格,指向的是
                               esp中的数据8,将其存入累加器eax中*/
        addl    $3, %eax  /*教累加器运算8+3,存在累加器eax中*/
        ret   /*返回到f*/
f:
        pushl   %ebp  /*执行f这个函数之前,同样需要把基指针(main这一段的
                       栈底)存入栈顶*/
        movl    %esp, %ebp  /*然后将新的基指针指向f这个函数指令的栈底*/
        pushl   8(%ebp)  /*这里汇编与书中不同,相当于:
                         subl $4, %esp  堆栈减4,相当于加一个单元格
                         movl 8(%ebp), %eax  相对寻址,ebp指向的esp的位置在esp上退
                         两个单元格(2*4)指向的数据(刚刚main那里push进去的8)
                         存到累加器eax中
                         movl %eax, (%esp)  把刚刚存到累加器的数据(8)打入栈顶*/
        call    g   /*又是一个中断,去g*/ 
        addl    $4, %esp  /*中断返回,esp指针退回一个单元格*/
        leave  /*把上一条指令的栈底地址存到堆栈esp中,并弹出当前ebp的“栈顶”*/
        ret    /*返回到main*/
main:
        pushl   %ebp  /*ebp,基指针寄存器,指向的是当前指令的栈底(可以
                       理解为每条指令占据堆栈的一段),在运行的一开始,
                       我们需要把这段指令的开头位置存到堆栈寄存器esp中
                       以便后面被别的指令中断之后还能找回来*/
        movl    %esp, %ebp  /*esp,堆栈寄存器,地址指向栈顶,这里把栈顶
                            的位置存到ebp,是因为当执行main函数时,相当
                            于一次中断,之前的指令被打断,等会儿还需要
                            回来执行它,所以把当前的栈顶地址存到ebp中*/
        pushl   $8    /*现在我们执行这条新的指令,它把8这个数据打入栈顶,
                        一会儿就盘它*/
        call    f     /*这又是一次中断,main的执行被打断,去f*/
        addl    $4, %esp  /*esp再退一格*/
        addl    $1, %eax  /*eax中的数据是8+3,此时再+1,结果12.eax寄存器是
                          默认存储函数返回值的寄存器*/
        leave   /*撤销main函数*/
        ret   /*回到初始状态*/

(PS:太难画了,求老师推荐一个好用的画图软件)

问题: leave这条指令不是很理解。书中说相当于:

movl %ebp, %esp
popl %ebp

但每次中断去执行新指令的时候,ebp的值是存到堆栈中了的,为什么此时还要movl ebp的值到堆栈中。我认为ebp只是把每次中断调用的初始位置存到堆栈的暂存器,不知道这样理解对不对?

猜你喜欢

转载自www.cnblogs.com/fungi/p/11564807.html