【发布时间】:2016-02-09 18:05:23
【问题描述】:
Windows调用转换后,只有RAX、RCX、RDX、r8和r9可以不用保存(称为volatile),其余的称为nonvolatile(必须保存)。
使用非易失性寄存器而不保留它们有什么问题吗? (我经常这样做,到目前为止我还没有遇到任何问题)
调用约定说只有 RCX、RDX、r8 和 r9 用于传递整数参数,额外的应该在堆栈上传递。
使用 r10 作为第五个参数而不是堆栈有什么缺点吗? (知道内存至少比寄存器慢100倍,我尽量用好寄存器)
当有十几个额外的寄存器时,为什么调用约定会在 4 个寄存器处停止以传递参数?
【问题讨论】:
-
大多数函数平均可能有 4 个或更少的参数(只是猜测)。如果您使用所有可用的寄存器作为参数(并且您的函数有很多参数),那么您必须先保存寄存器的内容(例如在堆栈上),然后才能在函数中使用它们。 64 位 ABI 开发人员可能正在寻求平衡。一些寄存器用于加快对函数参数的访问,但保留寄存器可用,而无需保存它们。
-
如果您使用非易失性寄存器而不保留它们,那么您的程序似乎可以正常工作是幸运的。这是非常糟糕的做法,可能会导致以后出现奇怪而奇妙的行为。如果寄存器被标记为非易失性,请为未经证实的全能实体或下一个可能必须维护您的代码的开发人员的爱 - 保留非易失性寄存器!
-
@Henri:他们的状态只有在你回来时才重要。推送/弹出您在函数开始/结束时使用的那些。另请参阅stackoverflow.com/tags/x86/info:“学习资源”链接之一是关于为什么有些寄存器是调用保留而有些不是的问题。 “volatile”在 C 中具有不同的技术含义,因此我不建议在这种情况下以这种方式使用它。 Linux 64 位调用约定有更多的临时(调用破坏)寄存器,我认为这可能会导致整体代码更好。我不确定在这方面是否有很多共识。
-
无论您做什么,请确保生成正确的展开代码,以便操作系统在发生异常时执行正确的操作。
-
如果您在函数中使用易失性寄存器,并且需要在必须进行的函数调用中保留它,那么您可能必须在函数调用周围保存/恢复它。如果您的函数不调用其他函数,这不是问题。如果您确实调用了其他函数,则调用者(您的函数)有责任保留可能需要在 CALL 中保存的任何寄存器
标签: windows assembly x86-64 cpu-registers win64