一、实验二
1、前置知识
32位-x86 cpu的寄存器
2、反汇编c程序
// main.c
int g(int x)
{
return x + 2023;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(66) + 123;
}
对其进行汇编后如图所示
对其内部代码进行分析有:
首先执行main
函数
pushl %ebp //将ESP寄存器指向堆栈中标号1的位置,然后讲EBP中的值放入标号1中(其实就是ebp入栈),与此同时EIP寄存器已经指向了下一行代码
movl %esp, %ebp //使EBP也指向标号1的位置,同时EIP寄存器指向下一行代码
sub $4, %esp //将ESP寄存器的值减4,其实就是把ESP向下移动一个标号,指向标号2,同时EIP指向下一行代码
movl $66, (%esp) //把立即数66放入ESP指向的标号2的位置,同时EIP指向下一行代码
call f //EIP自动+1指向下一行,eip入栈,调用f函数。eip的入栈是为了执行完f函数的时候能回到main函数
addl $123,%eax //立即数123放到eax里头
leave //栈回到初始状态
ret //pop EIP,所有东西都结束
f
函数的分析
pushl %ebp //把ESP的值向下移一位到标号4,然后把EBP的值标号1放到标号4的位置,
movl %esp,%ebp //让EBP指向ESP的位置,即标号4
sub 4,%esp //ESP寄存器的值-4,即指向标号5
movl 8(%ebp),%eax //通过EBP变址寻址,EBP的值+8,指向标号2的位置,然后标号2存储的是立即数66.将66放入到EAX中
movl %eax,(%esp) //把EAX中的值放到ESP所指向的位置,即标号5
call g //eip入栈,调用g函数,eip的入栈是为了执行完g函数之后,能够回到f函数
leave //这东西就相当于move %ebp,%esp;pop %ebp
ret //pop eip,返回到main函数
g
函数
pushl %ebp //ebp入栈
movl %esp,%ebp //让EBP和ESP指向当前栈顶
movl 8(%ebp),%eax //EBP指向的位置向上移两个
addl $2023,%eax //把立即数2023加到EAX里头
popl %ebp //把第12步中入栈的ebp ,pop掉
ret //返回到f函数
所有函数的头两条指令都用于初始化自己的调用堆栈空间
总结和问题
1、刚开始的时候理解不了esp指针的变动规则,后来发现这东西是栈顶指针,栈顶变它就变。
2、栈是向下增长的,
3、每次执行call func指令的时候,都会把eip+1的值压到栈里,为了之后用
4、栈是向下长的
询问AI情况