被调用者如何知道,要在 x64 中弹出多少个参数以及以什么顺序? [英] How callee knows, how many args to pop and in which order in x64?
问题描述
据此:UNIX & 的调用约定是什么?Linux 系统调用 i386 和 x86-64,在 x64-amd System V ABI 中,参数在这些寄存器上依次传递:%rdi, %rsi, %rdx, %rcx, %r8 和 %r9
,按这个顺序.第 7 个和更高的 arg 在堆栈上传递.所以问题是,被调用者如何知道剩余的(第 7 个及更多)参数有多少以及以何种顺序 pop
?被调用者是否从 argc
知道它?我有和例子:
According to this: What are the calling conventions for UNIX & Linux system calls on i386 and x86-64, in x64-amd System V ABI, the args are passed successively on these registers:
%rdi, %rsi, %rdx, %rcx, %r8 and %r9
, in that order. The 7th and higher arg is passed on the stack. So the question is, how does the callee know, how many and in which order to pop
the remained (7th and more) args? Does the callee know it from argc
? I have and example:
#include <stdio.h>
#include <stdlib.h>
int main(){
int i=0;
printf("\n%i;%i;%i;%i;%i;%i;%i\n",i,i+1,i+2,i+3,i+4,i+5,i+6 );
}
未优化编译:
.text
.section .rodata
.LC0:
.string "\n%i;%i;%i;%i;%i;%i;%i\n"
.text
.globl main
.type main, @function
main:
pushq %rbp #
movq %rsp, %rbp #,
subq $16, %rsp #,
# a.c:5: int i=0;
movl $0, -4(%rbp) #, i
# a.c:6: printf("\n%i;%i;%i;%i;%i;%i;%i\n",i,i+1,i+2,i+3,i+4,i+5,i+6 );
movl -4(%rbp), %eax # i, tmp95
leal 6(%rax), %edi #, _1
movl -4(%rbp), %eax # i, tmp96
leal 5(%rax), %esi #, _2
movl -4(%rbp), %eax # i, tmp97
leal 4(%rax), %r9d #, _3
movl -4(%rbp), %eax # i, tmp98
leal 3(%rax), %r8d #, _4
movl -4(%rbp), %eax # i, tmp99
leal 2(%rax), %ecx #, _5
movl -4(%rbp), %eax # i, tmp100
leal 1(%rax), %edx #, _6
movl -4(%rbp), %eax # i, tmp101
pushq %rdi # _1
pushq %rsi # _2
movl %eax, %esi # tmp101,
leaq .LC0(%rip), %rdi #,
movl $0, %eax #,
call printf@PLT #
addq $16, %rsp #,
movl $0, %eax #, _10
# a.c:7: }
leave
ret
.size main, .-main
.ident "GCC: (Debian 8.3.0-6) 8.3.0"
.section .note.GNU-stack,"",@progbits
这里以某种方式对这些寄存器进行了错误排序,它(从最后开始):(我在这里不考虑寄存器的大小,只是说明)di->si->r9->r8->cx->dx
,然后 si
,di
被压入并重新分配到字符串地址和第一个参数 (i
).所以现在看起来顺序正确.那么被调用函数是如何知道有多少以及以什么顺序弹出的呢?(si
应该在 di
之前,因为 si
包含 5
和 di
>6
)
Here is somehow misorder those register, it goes (from last):(i am not regarding the size of register here, just ilustration)
di->si->r9->r8->cx->dx
, then si
,di
are pushed and reasign to string address and first argument (i
). So now it seems in correct order. So how does the callee function knows, how many, and in what order to pop ? (si
should be before di
, since si
contains 5
and di
6
)
推荐答案
printf
不知道有多少个参数.它必须相信格式字符串与您实际传递的内容相匹配,如果它是错误的,它最终会跳过一些或从堆栈中读取其他随机内容.不采用格式字符串的可变参数函数使用不同的方法来表示结束(例如,像 execlp
使用的 NULL
哨兵,或程序员传递的计数变量手动).同样,如果您没有正确标记结尾,它将读取错误数量的参数.
printf
doesn't know how many arguments there are. It has to trust that the format string matches what you actually passed, and if it's wrong, it'll end up skipping some or reading other random stuff off the stack. Varargs functions that don't take a format string use a different approach to signal the end (e.g., a NULL
sentinel like execlp
uses, or a count variable that the programmer passes manually). Again, if you don't mark the end correctly, it'll read the wrong number of arguments.
这篇关于被调用者如何知道,要在 x64 中弹出多少个参数以及以什么顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!