本文章为《Linux内核分析》实验报告
梁永锐
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”
-----
以下为要分析的c代码
int g(intx)
{return x + 36;
}int f(intx)
{return g(x) * 4;
}int main(void)
{return f(81) + 12;
}
gcc –S –o main.s main.c -m32
编译成32位汇编后(去了点开头的行
g:pushl %ebp
movl %esp, %ebp
movl8(%ebp), %eax
addl $36, %eax
popl %ebpret
f:pushl %ebp
movl %esp, %ebp
pushl8(%ebp)callg
addl $4, %esp
sall $2, %eaxleave
ret
main:pushl %ebp
movl %esp, %ebp
pushl $81
callf
addl $4, %esp
addl $12, %eaxleave
ret
一.实验截图:
二. 汇编代码的工作过程中堆栈的变化
从main开始
pushl %ebp
movl %esp, %ebp
也就是enter指令(不知道为什么这里并没有把他写成enter而是分开写了)
这两条指令执行后我们假设,ebp,esp均为100(以下内容用ebp=100, esp=100这种方法表示)
pushl $81
ebp=100, esp = 96,[96]=81([96]=81, 表示位置96的地方存了81这个数, 以下均用这种方法表示)
call f
ebp = 100, esp = 92, [92]= 22(这里用行号做eip)
跳到了f
pushl %ebp
ebp = 100, esp = 88, [88]=100
movl %esp, %ebp
ebp = 88, esp = 88
pushl 8(%ebp)
ebp = 88, esp = 84, [84] = 81
call g
ebp = 88, esp = 80, [80] = 13
然后调到了g函数
pushl %ebp
ebp = 88, esp = 76, [76] = 88
movl %esp, %ebp
ebp = 76, esp = 76
movl 8(%ebp), %eax
把传入的参数放在eax中, eax = 81
addl $36, %eax
eax = 81 + 36 = 117
popl %ebp
ebp = 88, esp = 80
ret
ebp = 88, esp = 84, eip = 13
此时就跳到13行了
addl $4, %esp
弹出传入的参数,不赋值
ebp = 88, esp = 88
sall $2, %eax
编译器很智能,乘4,自动变成了左移两位, eax = 117 << 2 = 468
leave
leave就是
movl %ebp, %esp : ebp = 88, esp = 88
popl %ebp : ebp = 100, esp = 92
ret
ebp = 100, esp = 94, eip = 22
跳到第22行
addl $4, %esp
弹出参数
esp = 96
addl $12, %eax
eax = 468 + 12 = 480
leave
ret
回到main函数之前的堆栈和eip
三.计算机是如何工作的
简单的说,计算机就是按照ip一条条的执行指令,执行的时候需要一些寄存器做辅助,ip有时候也会跳。