1、首先,EBP默认也使用SS作为段寄存器。
2、寻址方式(Intel汇编语法):
mov ax,idata;立即数寻址
mov [idata],ax;直接寻址
mov ax,[bx];间接寻址
mov ax,[bx+idata];相对寻址
mov ax,[bx+si];基址变址寻址
mov ax,[bx+si+idata];相对基址编址寻址
3、C语言函数的局部变量是存储在堆栈中的,并采用EBP作为访问它们的指针。在进入子函数开始,先将EBP压栈以保存其初值,然后将ESP赋给EBP,这样EBP就指向了当前堆栈的最开始了,就可以通过EBP进行相对寻址来存取局部变量了。为什么不用ESP呢(如使用mov ax,[sp+idata]这样的指令访问函数的局部变量和输入参数)?因为ESP在程序中可能经常用到,比如通过PUSH和POP成对操作来访问一些临时数据:
...
push ax;程序执行过程中,需要使用ax保存一些中间值,这时需要先将ax入栈保存
mov ax,1234
...
pop ax
...
上述操作将使esp的值发生改变,从而丢失了之前保存在堆栈中的变量和参数的地址信息。
局部变量保存在堆栈中,需要为局部变量在堆栈中安排存储空间,此时需要修改ESP的值,比如:
sub esp,8;为局部变量预留8个字节的存储空间
之后就可以执行诸如mov [bp+偏移量],123类似的指令来存取局部变量了。
在Intel汇编中,ESP始终指向栈顶,EBP始终指向栈底(EBP的值未发生改变),使用EBP作为基址进行相对寻址,以存取局部变量。
函数的形式一般为(AT&T汇编):
funcname:
pushl %ebp;保存原来ebp中的值
movl %esp,%ebp;使ebp指向栈顶,在AT&T汇编语言中,压栈使ESP增加;而在Intel汇编中,压栈使ESP减少
;如果有局部变量,可以改变esp以为局部变量预留空间
...
...
movl %ebp,%esp;清理堆栈
popl %ebp;恢复原来ebp的内容
ret
注意,函数的形参是由函数的调用者压入堆栈的,函数中可以通过ebp进行相对寻址访问输入参数,函数调用结束后,调用者可以通过出栈操作或直接修改esp以使堆栈平衡。
关于栈帧如下图描述: