被调用者如何知道参数是通过寄存器而不是堆栈传递的
How does callee know arguments are passed through registers instead of stack
假设我们有一个简单的程序
#include <cstdio>
int main(int argc, char* argv[]) {
int n = argc;
if (n > 1) {
n = 1;
}else {
n = -1;
}
printf("%d\n", n);
return 0;
}
和在 ubuntu x64(Windows 子系统)
下使用 g++ main.cpp -S -O1
生成的汇编代码片段
subq , %rsp
cmpl , %edi
setg %dl
movzbl %dl, %edx
leal -1(%rdx,%rdx), %edx
movl $.LC0, %esi
movl , %edi
movl [=11=], %eax
call __printf_chk
movl [=11=], %eax
addq , %rsp
ret
既没有push
也没有访问和写入内存的指令。所以参数 n
必须通过 %edx
传递。现在我想知道 c 库函数 __printf_chk
是如何知道 %edx
包含预期参数的?更一般地说,它如何知道使用了哪个寄存器?
这是由平台的ABI(应用程序二进制接口)指定的。编译器已编译 __printf_chk
以遵循您的平台 ABI(在本例中为 amd64 SysV ABI),导致它期望参数位于特定位置。如需进一步阅读,请查看此 ABI 文档。
假设我们有一个简单的程序
#include <cstdio>
int main(int argc, char* argv[]) {
int n = argc;
if (n > 1) {
n = 1;
}else {
n = -1;
}
printf("%d\n", n);
return 0;
}
和在 ubuntu x64(Windows 子系统)
下使用g++ main.cpp -S -O1
生成的汇编代码片段
subq , %rsp
cmpl , %edi
setg %dl
movzbl %dl, %edx
leal -1(%rdx,%rdx), %edx
movl $.LC0, %esi
movl , %edi
movl [=11=], %eax
call __printf_chk
movl [=11=], %eax
addq , %rsp
ret
既没有push
也没有访问和写入内存的指令。所以参数 n
必须通过 %edx
传递。现在我想知道 c 库函数 __printf_chk
是如何知道 %edx
包含预期参数的?更一般地说,它如何知道使用了哪个寄存器?
这是由平台的ABI(应用程序二进制接口)指定的。编译器已编译 __printf_chk
以遵循您的平台 ABI(在本例中为 amd64 SysV ABI),导致它期望参数位于特定位置。如需进一步阅读,请查看此 ABI 文档。