被调用者如何知道,要在 x64 中弹出多少个参数以及以什么顺序? [英] How callee knows, how many args to pop and in which order in x64?

查看:13
本文介绍了被调用者如何知道,要在 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 包含 5di >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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆