System V AMD64 ABI 浮点可变参数顺序

System V AMD64 ABI floating point varargs order

我使用不同类型的参数编译了对 printf 的调用。
这是代码 + 生成的 asm:

int main(int argc, char const *argv[]){
    //   0: 55                      push   rbp
    //   1: 48 89 e5                mov    rbp,rsp
    //   4: 48 83 ec 20             sub    rsp,0x20
    //   8: 89 7d fc                mov    DWORD PTR [rbp-0x4],edi
    //   b: 48 89 75 f0             mov    QWORD PTR [rbp-0x10],rsi
    printf("%s %f %d %f\n", "aye u gonna get some", 133.7f, 420, 69.f);
    //   f: f2 0f 10 05 00 00 00 00 movsd  xmm0,QWORD PTR [rip+0x0]        # 17 <main+0x17> 13: R_X86_64_PC32   .rodata+0x2c    69
    //  17: 48 8b 05 00 00 00 00    mov    rax,QWORD PTR [rip+0x0]        # 1e <main+0x1e>  1a: R_X86_64_PC32   .rodata+0x34    133.7
    //  1e: 66 0f 28 c8             movapd xmm1,xmm0
    //  22: ba a4 01 00 00          mov    edx,0x1a4 (420)
    //  27: 48 89 45 e8             mov    QWORD PTR [rbp-0x18],rax
    //  2b: f2 0f 10 45 e8          movsd  xmm0,QWORD PTR [rbp-0x18]
    //  30: 48 8d 35 00 00 00 00    lea    rsi,[rip+0x0]        # 37 <main+0x37>    33: R_X86_64_PC32   .rodata-0x4  "aye u wanna get some"
    //  37: 48 8d 3d 00 00 00 00    lea    rdi,[rip+0x0]        # 3e <main+0x3e>    3a: R_X86_64_PC32   .rodata+0x18 "%s %f %d %f\n"
    //  3e: b8 02 00 00 00          mov    eax,0x2
    //  43: e8 00 00 00 00          call   48 <main+0x48>   44: R_X86_64_PLT32  printf-0x4
    return 0;
    //  48: b8 00 00 00 00          mov    eax,0x0
    //  4d: c9                      leave  
    //  4e: c3                      ret    
}

这里的大部分内容对我来说都很有意义。 事实上,这里的一切对我来说都有一定的意义。
"%s %f %d %f\n" -> rdi
"aye u gonna get some" -> rsi
133.7 -> xmm0
420 -> rdx
69 -> xmm1
2 -> rax(表示有 2 个浮点参数)

现在我不明白的是 printf(或任何其他可变参数函数)如何确定这些浮点参数在其他参数中的位置。

它也不是编译器的魔法,因为它是动态链接的。
所以我唯一能想到的可能只是 va_arg 内部结构,以及当您提供类型时,如果它是浮点数,它必须从 xmms(或堆栈)而不是其他方式获取。

对吗?如果不是,对方怎么知道从哪里得到它们?提前致谢。

对于 printf,格式字符串指示剩余参数的类型。

va_arg 的实现知道类型,因为它是 va_arg 的参数,并且可以从类型中推断出正确的寄存器。