I've noticed that a lot of calling conventions insist that [e]bx be preserved for the callee.Now, I can understand why they'd preserve something like [e]sp or [e]bp, since that can mess up the callee's stack. I can also understand why you might want to preserve [e]si or [e]di since that can break the callee's string instructions if they aren't particularly careful.But [e]bx? What on earth is so important about [e]bx? What makes [e]bx so special that multiple calling conventions insist that it be preserved throughout function calls?Is there some sort of subtle bug/gotcha that can arise from messing with [e]bx?Does modifying [e]bx somehow have a greater impact on the callee than modifying [e]dx or [e]cx for instance?I just don't understand why so many calling conventions single out [e]bx for preservation. 解决方案 Not all registers make good candidates for preserving:no (e)ax -- Implicitly used in some instructions; Return valueno (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)Looking at the table, two registers have good reason to be preserved and two have a reason not to be preserved. accumulator = (e)ax e.g. is the most often used register due to short encoding. SI,DI make a logical register pair -- on REP MOVS and other string operations, both are trashed.In a half and half callee/caller saving paradigm the discussion would basically go only if bx/cx is preferred over si/di. In other calling conventions, it's just EDX,EAX and ECX that can be trashed.EBX does have a few obscure implicit uses that are still relevant in modern code (e.g. CMPXGH8B / CMPXGH16B), but it's the least special register in 32/64-bit code.EBX makes a good choice for a call-preserved register because it's rare that a function will need to save/restore EBX because they need EBX specifically, and not just any non-volatile register. As Brett Hale's answer points out, it makes EBX a great choice for the global offset table (GOT) pointer in ABIs that need one.In 16-bit mode, addressing modes were limited to (any subset of) [BP|BX + DI|SI + disp8/disp16]), so BX is definitely special there. 这篇关于x86 程序集 - 为什么 [e]bx 保留在调用约定中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
06-05 08:44