什么寄存器必须由x86函数保留?

时间:2012-03-07 14:09:29

标签: assembly x86 calling-convention

我正在x86程序集中编写一个函数,该函数应该可以从c代码中调用,我想知道在返回调用者之前我必须恢复哪些寄存器。

目前我只恢复espebp,而返回值位于eax

是否还有其他我应该关注的注册表,或者我可以留下任何令我满意的内容吗?

3 个答案:

答案 0 :(得分:12)

使用Microsoft's 32 bit ABIcdeclstdcall或其他调用约定),EAXEDXECX是临时注册(调用已被破坏) )。其他通用整数寄存器是调用保留的。

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 ,您只需要恢复RBXRBPRDIRSIR12R13R14R15。 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),其中调用保留的整数寄存器为RBPRBXRSPR12R13R14R15。所有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中。