2019-2020-1 20209311《Linux内核原理与分析》第二周作业
2019-2020-1 20209311《Linux内核原理与分析》第二周作业
反汇编C程序
1.生成汇编代码
反汇编的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 test.s test.c -m32
命令生成汇编代码,打开test.s文件查看生成的汇编代码:
可以看到生成的汇编码较为杂乱,我们可以使用vim打开test.s文件,使用g/\.s*/d
命令可以删除以"."开头的字符串,效果如下:
2.代码分析
汇编指令
- pushl %eax指令可以将EAX寄存器的值压到堆栈栈顶。实际上分为两个动作,第一个动作为:subl $4 %esp,把堆栈的栈顶ESP寄存器的值减4。因为堆栈是向下增长的,所以用subl减指令。第二个为:movl %eax, (%esp),把EAX寄存器的值放到ESP寄存器所指向的地方,这时ESP寄存器已经指向预留出的存储单元。
popl %eax指令可以从堆栈的栈顶取一个存储单元,从堆线枝顶的位置放到EAX寄存器里,称为出栈。出栈同样对应两个操作:movl (%esp) ,%eax,addl $4 , %esp,第一步是把栈顶的数值放到EAX寄存器里,然后用指令addl把栈顶加4,相当于栈向上回退了一个存储单元的位置。 - call指令是函数调用,调用一个地址。与call指令对应的是ret指令,ret指令是函数返回。
- enter指令的作用是堆起一个空栈,leave指令可以撤销这个堆栈。
汇编过程
- 程序从main函数开始执行,也就是main:之下的pushl %esp(endbr32不是汇编指令而是end break的缩写),作用是把esp寄存器的值压栈;此时eip寄存器自动增加(每执行一次指令,eip寄存器的值都会自动增加,指向要执行的下一条指令),指向pushl %esp之后的指令movl %esp,%ebp,这条指令的执行将使ebp的指向和esp的指向相同;执行指令subl $4,%esp使esp寄存器减4,指向下一个位置;movl $8,(%esp)指令将立即数8放入了esp寄存器所指的位置;call f指令调用f函数,具体操作是使esp寄存器地址减4,然后将eip寄存器存的行号数23压入栈,接着把f函数的第一条指令行号9放入EIP寄存器中。
- 开始执行f函数,即第9行指令,第9行指令pushl %ebp的作用是把esp寄存器的值压栈;第10行指令movl %esp,%ebp使得ebp寄存器和esp寄存器一样指向相同位置;第11行指令subl $4,%esp使esp寄存器减4,指向下一个位置;第12行指令改变了ebp寄存器的指向,将立即数8放入了eax寄存器中;第13行指令的作用是把eax寄存器中的立即数8放到第11行指令预留出的栈位置,这样做的目的是将函数f的参数取出来,为调用函数g做好参数入栈的准备;第14行指令是调用g函数。
- 随后执行g函数,从第2行指令开始;2、3、4行指令的作用与之前所说的相同,作用使把立即数8存放到eax寄存器中;第5行指令把立即数3加到eax寄存器中,此时eax寄存器内的值为11;第6、7行拆除g函数调用堆栈,并返回到调用函数g的位置;第23行指令把1加到eax寄存器中,此时此时eax寄存器内的值为12,eax寄存器是默认存储函数返回值的寄存器;第15、16、24、25条指令将堆栈空间、ebp和esp寄存器还原到main函数开始执行之初的状态。
3.遇到的问题
在使用自己的Ubuntu进行实验时,得到的反编译代码与在实验楼中得到的结果并不相同。
有可能是不同版本的Ubuntu使用了不同的指令集导致的。