为什么 x86-64 System V 调用约定在寄存器中传递参数而不仅仅是堆栈?
Why does the x86-64 System V calling convention pass args in registers instead of just the stack?
为什么 32 位 C 将所有函数参数直接压入堆栈,而 64 位 C 将前 6 个参数放入寄存器,其余的放入堆栈?
所以 32 位堆栈看起来像:
...
arg2
arg1
return address
old %rbp
虽然 64 位堆栈看起来像:
...
arg8
arg7
return address
old %rbp
arg6
arg5
arg4
arg3
arg2
arg1
那么为什么 64 位 C 会这样做呢?将所有内容压入堆栈而不是将前 6 个参数放入寄存器只是为了在函数序言中将它们移动到堆栈上不是更容易吗?
instead of put the first 6 arguments in registers just to move them onto the stack in the function prologue?
I was looking at some code that gcc generated and that's what it always did.
那你忘了启用优化。 gcc -O0
将所有内容溢出到内存中,因此您可以在单步执行时使用调试器修改它们。这对性能来说显然是可怕的,所以编译器不会这样做,除非你通过编译 -O0
.
来强制他们这样做
x86-64 System V 允许 int add(int x, int y) { return x+y; }
编译为
lea eax, [rdi + rsi]
/ ret
,正如您在 the Godbolt compiler explorer.
上看到的那样,这是编译器实际执行的操作
Stack-args 调用约定缓慢且过时。 RISC 机器自 x86-64 出现之前就一直在使用 register-args 调用约定,在仍然关心 32 位 x86(即 Windows)的操作系统上,有更好的调用约定,如 __vectorcall
寄存器中的前 2 个整数参数。
i386 System V 尚未被取代,因为人们大多不太关心其他操作系统上的 32 位性能;我们只使用具有精心设计的 x86-64 System V 调用约定的 64 位代码。
有关调用约定设计中寄存器 args 和调用保留与调用破坏寄存器之间权衡的更多信息,请参阅 , and also Why does Windows64 use a different calling convention from all other OSes on x86-64?。
为什么 32 位 C 将所有函数参数直接压入堆栈,而 64 位 C 将前 6 个参数放入寄存器,其余的放入堆栈?
所以 32 位堆栈看起来像:
...
arg2
arg1
return address
old %rbp
虽然 64 位堆栈看起来像:
...
arg8
arg7
return address
old %rbp
arg6
arg5
arg4
arg3
arg2
arg1
那么为什么 64 位 C 会这样做呢?将所有内容压入堆栈而不是将前 6 个参数放入寄存器只是为了在函数序言中将它们移动到堆栈上不是更容易吗?
instead of put the first 6 arguments in registers just to move them onto the stack in the function prologue?
I was looking at some code that gcc generated and that's what it always did.
那你忘了启用优化。 gcc -O0
将所有内容溢出到内存中,因此您可以在单步执行时使用调试器修改它们。这对性能来说显然是可怕的,所以编译器不会这样做,除非你通过编译 -O0
.
x86-64 System V 允许 int add(int x, int y) { return x+y; }
编译为
lea eax, [rdi + rsi]
/ ret
,正如您在 the Godbolt compiler explorer.
Stack-args 调用约定缓慢且过时。 RISC 机器自 x86-64 出现之前就一直在使用 register-args 调用约定,在仍然关心 32 位 x86(即 Windows)的操作系统上,有更好的调用约定,如 __vectorcall
寄存器中的前 2 个整数参数。
i386 System V 尚未被取代,因为人们大多不太关心其他操作系统上的 32 位性能;我们只使用具有精心设计的 x86-64 System V 调用约定的 64 位代码。
有关调用约定设计中寄存器 args 和调用保留与调用破坏寄存器之间权衡的更多信息,请参阅