1.为什么pushl会使得esp-4?
回答:
pushl是使得栈顶指针进行压栈,由于是l,所以压栈的大小为四个字节32位,pushl指令的具体运行过程是,将pushl指令所带的参数放至ESP的位置上,再将esp-4来完成压栈的操作。
2.为什么会ret跳转到call的下一条指令?
回答:
call指令将EIP的值存入ESP,当ret的时候重新获得原来EIP的值,然后再进行下一条指令时,发生EIP+4,所以就指向了call指令的下一条指令。
3.在使用makefile的过程中,修改了头文件的名字以及代码中与相关的名字,makefile搜索不到头文件
回答:
同时要完成对c文件中对头文件的修改,不然.c文件搜索不到头文件。
4.附带完成本周实验的实验报告
回答:
1.本次实验所选用的C语言代码
// main.c
int g(int x)
{
return x + 3;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(8) + 1;
}
2.所编译出的汇编代码以及解释
g:
pushl %ebp "压栈,ESP->7,在7号位置中存入EBP的值(4号位置的地址)"
movl %esp, %ebp "EBP指向7号地址,栈不变"
movl 8(%ebp), %eax "[EBP]+8:EBP指向7号位置,加8后指向5号位置,即把5号位置中存的立即数4取出存入EAX"
addl $5, %eax "[EAX]=[EAX]+5,新[EAX]=9"
popl %ebp "EBP重新指向4的位置,ESP->6"
ret "RET的含义为POP %EIP,所以EIP的值为6号位置的值,即指向call指令的下一条指令,ESP->5,跳转到call的下一条指令"
f:
pushl %ebp "ESP指向4的位置,在4号位置中存入ebp的值(1号位置的地址)"
movl %esp, %ebp "EBP指向4号位置,栈不变"
subl $4, %esp "ESP指向5"
movl 8(%ebp), %eax "[EBP]+8:EBP指向4号位置,加8后指向2号位置,即把2号位置中存的立即数4取出存入EAX"
movl %eax, (%esp) "把4存入ESP所指向的5号单元"
call g "先压栈,esp->6,原EIP的值赋给6号地址,新EIP为g的地址,跳转到g继续执行"
leave "leave的意思为:movl %ebp,%esp;pop %ebp;即ESP->4,然后把4号位置的值(1号位置的地址)赋给EBP,再ESP->3"
ret "把ESP指向的3号位置的值(f的地址)存入EIP,ESP->2,然后跳转到call的下一条指令"
main:
pushl %ebp "EBP指向0号位置,而esp指向1号位置,把EBP存入1号位置"
movl %esp, %ebp "EBP指向1号位置。栈不变。"
subl $4, %esp "ESP指向2号位置"
movl $4, (%esp) "在ESP所指向的2号位置存一个立即数4"
call f "call指令的意思为push %eip+mov f %eip,所以指令运行过程为,先压栈,ESP->3,3号地址中存入原EIP的值,给EIP赋f的地址,跳转到f继续执行"
addl $2, %eax "[EAX]=[EAX]+2"
leave "ESP->1,EBP->0,ESP->0"
ret "return到main函数之前的堆栈,跟当前的没关系"