寄存器
32位
通用寄存器:
EAX EBX ECX EDX
EBP ESP ESI EDI
段寄存器:ES CS SS DS FS GS
指令指针寄存器:EIP
标志寄存器:EFlags
EIP:指令寄存器,用来存储CPU要读取指令的地址。每次执行指令后EIP就会增加。
EAX:扩展累加器,乘除指令默认使用
ECX:cpu默认使用ECX为循环计数器
EBP:扩展基址指针寄存器(extended base pointer) 其内存放着一个指向系统栈最上面一个栈帧底部的指针。用于引用函数参数和局部变量。
ESP:栈指针寄存器(extended stack pointer),其内存放着一个指向系统栈最上面一个栈帧栈顶的指针。32位模式下,ESP寄存器存放的是某个位置的32位偏移量。ESP基本上不会被程序员控制,它是由CALL、RET、PUSH、POP等指令间接修改。
堆栈
注:栈在内存中,栈顶在低位,栈低在高位。当函数调用时,参数按逆序压栈。
入栈操作:PUSH指令
在32位中,入栈操作是将ESP(栈顶指针)减4(栈在内存中是向下生长,4*8=32),再将数值复制到ESP指向的位置。
出栈操作:POP指令
出栈操作从堆栈中删除数据,ESP指针增加。
函数调用栈
函数调用栈是指程序运行时内存一段连续的区域
用来保存函数运行时的状态信息,包括函数参数与局部变量等
称之为“栈”是因为发生函数调用时,调用函数(caller)的状态被保存在栈内,被调用函数(callee)的状态被压入调用栈的栈顶
在函数调用结束时,栈顶的函数(callee)状态被弹出,栈顶恢复到调用函数(caller)的状态
函数调用栈在内存中从高地址向低地址生长,所以栈顶对应的内存地址在压栈时变小,退栈时变大
函数状态主要涉及三个寄存器:esp,ebp,eip。 esp 用来存储函数调用栈的栈顶地址,在压栈和退栈时发生变化。 ebp
用来存储当前函数状态的基地址,在函数运行时不变,可以用来索引确定函数参数或局部变量的位置。 eip 用来存储即将执行的程序指令的地址,cpu
依照 eip 的存储内容读取指令并执行,eip 随之指向相邻的下一条指令,如此反复,程序就得以连续执行指令。
调用开始
函数调用,变换的核心就是将caller(调用函数)状态保存,将callee(被调函数)创建
函数调用时,栈和寄存器的变换过程:
①将callee的参数逆序压栈
②将caller进行调用后的下一条指令地址作为返回地址压栈(保存caller’ eip到栈中)
③将当前ebp的值压栈(此时ebp是caller的基址指针,此操作保存caller’ ebp到栈中),并将ebp更新为栈顶的地址(创建callee’ ebp)
④将callee的局部变量压栈
调用结束
结束函数调用的核心就是将callee的状态丢弃,并将栈顶还原为caller的状态
①局部变量弹出 esp指向callee’ ebp
②将存储在栈中的caller’ ebp弹出,并存到ebp内(恢复caller’ ebp)
③将存储在栈中的caller’ eip弹出,并存到eip内(恢复caller’ eip)
④caller的函数状态已恢复