the*_*box 5 x86 assembly calling-convention
我注意到很多调用约定都坚持为被调用者保留[e] bx.
现在,我可以理解为什么他们会保留像[e] sp或[e] bp这样的东西,因为这会弄乱被调用者的堆栈.我也可以理解为什么你可能想要保留[e] si或[e] di,因为如果他们不是特别小心的话可以打破被调用者的字符串指令.
但是[e] bx?究竟是什么对[e] bx如此重要?是什么让[e] bx如此特殊以至于多个调用约定都坚持在整个函数调用中保留它?
是否有某种微妙的错误/陷阱可能会因为[e] bx的混乱而产生?
修改[e] bx对被调用者的影响是否比修改[e] dx或[e] cx更大?
我只是不明白为什么这么多的召唤惯例单独列出[e] bx进行保存.
并非所有寄存器都是保留的良好候选者:
no (e)ax -- Implicitly used in some instructions; Return value
no (e)dx -- edx:eax is implicity used in cdq, div, mul and in return values
(e)bx -- generic register, usable in 16-bit addressing modes (base)
(e)cx -- shift-counts, used in loop, rep
(e)si -- movs operations, usable in 16-bit addressing modes (index)
(e)di -- movs operations, usable in 16-bit addressing modes (index)
Must (e)bp -- frame pointer, usable in 16-bit addressing modes (base)
Must (e)sp -- stack pointer, not addressable in 8086 (other than push/pop)
Run Code Online (Sandbox Code Playgroud)
看一下这个表,两个寄存器有充分的理由被保留,两个寄存器有理由不被保留.accumulator =(e)ax eg是由于短编码而最常用的寄存器.SI,DI构成逻辑寄存器对 - 在REP MOVS和其他字符串操作上,都被删除.
在半被调用者/来电者保存范例中,只有当bx/cx优于si/di时,讨论基本上才会进行.在其他调用约定中,只有EDX,EAX和ECX可以被删除.
EBX确实有一些模糊的隐式用法仍然与现代代码相关(例如CMPXGH8B/CMPXGH16B),但它是32/64位代码中最不特殊的寄存器.
EBX是一个保留调用寄存器的不错选择,因为一个函数很少需要保存/恢复EBX,因为它们需要专门的EBX,而不仅仅是任何非易失性寄存器.正如Brett Hale的回答所指出的那样,它使EBX成为需要ABI的全局偏移表(GOT)指针的绝佳选择.
在16位模式下,寻址模式仅限于(任何子集)[BP|BX + DI|SI + disp8/disp16]
),因此BX绝对是特殊的.
这是在不保存任何寄存器并将其全部保存之间的折衷方案.可以提出既不保存也不保存全部,但要么极端都会导致将内容复制到内存(堆栈)导致效率低下.选择允许保留一些寄存器而不保留一些寄存器,可以降低函数调用的平均成本.
对于i386 ELF ABI 来说,主要原因之一是它ebx
保存了位置无关代码 (PIC) 的全局偏移表 (GOT) 寄存器的地址。详见规范3-35。在极端情况下,如果共享库代码必须在每次函数调用返回后恢复 GOT,那将是破坏性的。
归档时间: |
|
查看次数: |
924 次 |
最近记录: |