我正在x86程序集中编写一个函数,该函数应该可以从c代码中调用,我想知道在返回调用者之前我必须恢复哪些寄存器。
目前我只恢复esp
和ebp
,而返回值位于eax
。
是否还有其他我应该关注的注册表,或者我可以留下任何令我满意的内容吗?
答案 0 :(得分:12)
使用Microsoft's 32 bit ABI(cdecl
或stdcall
或其他调用约定),EAX
,EDX
和ECX
是临时注册(调用已被破坏) )。其他通用整数寄存器是调用保留的。
EFLAGS中的条件代码被调用破坏。呼叫/返回时需要DF = 0,因此您可以先使用rep movsb
而不使用cld
。 x87堆栈在调用时必须为空,或者在不返回FP值的函数返回时为空。 (FP返回值进入st0
,除此之外x87堆栈为空。)XMM6和7是调用保留的,其余是调用被破坏的临时寄存器。
在Windows之外,大多数32位调用约定(包括Linux上的i386 System V)都同意这种选择的EAX,EDX和ECX作为call-clobbered,但所有 xmm寄存器都是调用的-clobbered。
对于Windows下的x64 ,您只需要恢复RBX
,RBP
,RDI
,RSI
,R12
, R13
,R14
和R15
。 XMM6..15是呼叫保留的。 (并且您必须为被调用者保留32个字节的阴影空间,无论是否存在任何不适合寄存器的args。)xmm6..15是调用保留的。
有关详细信息,请参阅https://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention。
其他操作系统使用x86-64 System V ABI (see figure 3.4),其中调用保留的整数寄存器为RBP
,RBX
,RSP
,R12
,R13
,R14
和R15
。所有XMM / YMM / ZMM寄存器都是call-clobbered。
EFLAGS和x87堆栈与32位约定相同:DF = 0,条件标志被破坏,x87堆栈为空。 (x86-64约定在XMM0中返回FP值,因此x87堆栈寄存器总是在调用/返回时需要为空。)
有关官方通话约定文档的链接,请参阅https://stackoverflow.com/tags/x86/info
答案 1 :(得分:8)
32-bit: EBX, ESI, EDI, EBP
64-bit Windows: RBX, RSI, RDI, RBP, R12-R15, XMM6-XMM15
64-bit Linux,BSD,Mac: RBX, RBP, R12-R15
有关详情,请参阅Agner Fog的“Software optimization resources”。调用约定在this pdf中描述。
答案 2 :(得分:1)
如果您不确定寄存器的情况,下面的这些说明可以轻松地节省一天。
PUSHA/PUSHAD -- Push all General Registers
POPA/POPAD -- Pop all General Registers
这些指令按一定顺序推送和弹出通用和SI / ESI,DI / EDI寄存器。
PUSHA / PUSHAD指令的顺序如下。
Opcode Instruction Clocks Description
60 PUSHA 18 Push AX, CX, DX, BX, original SP, BP, SI, and DI
60 PUSHAD 18 Push EAX, ECX, EDX, EBX, original ESP, EBP ESI, and EDI
POPA / POPAD指令的顺序如下。 (按相反顺序)
Opcode Instruction Clocks Description
61 POPA 24 Pop DI, SI, BP, SP, BX, DX, CX, and AX
61 POPAD 24 Pop EDI, ESI, EBP, ESP(***),EBX, EDX, ECX, and EAX
*** ESP值被丢弃而不是加载到ESP中。