lll*_*lll 7 x86 assembly x86-64
我的问题很简单,为什么x86架构使用两个堆栈寄存器(esp ; ebp)?
堆栈帧的长度已在编译期间确定,然后我认为我们可以只使用一个寄存器(例如esp)来访问堆栈,并维护以前在ebp堆栈中(或在其他内存中的寄存器中)的基址地区,但这将导致更多的性能损失)
可能吗?
pax*_*blo 10
这一切都取决于调用约定当然,但它通常是这样的.
该堆栈指针是能够根据任何你需要推到,或从栈中弹出掉在任何给定的时间点任意移动.这可以在函数内的任何时间发生,因为您需要临时在堆栈上保存一些数据.
所述碱指针通常被设置为对于任何给定堆栈深度相同的值,并且用于访问(在另一侧)传递的参数(在一侧上)和局部变量.它还用于在退出函数时快速移动堆栈指针.
它以这种方式完成的原因是简化代码,这样您就不必根据可能改变的堆栈指针引用堆栈内容.使用基指针可以大大减轻代码生成的任务(您无需知道任何给定时间的堆栈指针是什么,只需使用基本指针,在指定函数期间保持不变).
没有它,想要推送局部变量的两个副本以调用下一个函数的代码将如下所示:
mov eax, [esp+16] ; get var1
push eax ; push it
mov eax, [esp+20] ; get var1 again
push eax
call _somethingElse
Run Code Online (Sandbox Code Playgroud)
抛开你不会eax在这种情况下重新加载的事实,我想要做的是,移动堆栈指针中的项目的相对位置可能不必要地使问题复杂化.
例如,这是一个在程序集中编码的函数,它遵循一个通用的调用约定:
_doSomething:
push ebp ; stack current base pointer
mov ebp, esp ; save previous stack pointer
sub esp, 48 ; incl 48 bytes local storage
; do whatever you want here, including changing
; esp, as long as it ends where it started.
mov esp, ebp ; restore previous stack pointer
pop ebp ; and previous base pointer
ret ; then return
_callIt:
mov eax, 7
push eax ; push parameter for function
call _doSomething
add esp, 4 ; get rid of pushed value
:
Run Code Online (Sandbox Code Playgroud)
如果按照代码,可以看到,ebp内部函数体是具有固定基准点[ebp](的内容ebp作为返回地址)[ebp+4]被的推值7,并且[ebp-N]是用于本地存储_doSomething,其中N从变化1到48.
无论在函数体内推送或弹出多少项,都是如此.
| 归档时间: |
|
| 查看次数: |
2306 次 |
| 最近记录: |