首页 > 解决方案 > System V AMD64 ABI 浮点可变参数命令

问题描述

我用不同类型的参数编译了对 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 (或任何其他 varargs 函数)如何找出这些浮点参数的位置。

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

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

标签: clinuxassemblycalling-conventionabi

解决方案


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

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


推荐阅读