TrisT
TrisT

Reputation: 667

System V AMD64 ABI floating point varargs order

I compiled a call to printf with different kinds of args.
Here's the code + generated 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    
}

Most stuff here makes sense to me. In fact everything here makes some level of sense to me.
"%s %f %d %f\n" -> rdi
"aye u gonna get some" -> rsi
133.7 -> xmm0
420 -> rdx
69 -> xmm1
2 -> rax (to indicate there are 2 floating point arguments)

Now what I don't understand is how printf (or any other varargs function) would figure out the position of these floating point arguments among the others.

It can't be compiler magic either since it's dynamically linked.
So the only thing I can think of is maybe it's just va_arg internals, and how when you provide a type, if it's floating point, it must get from the xmms (or stack) instead of otherwise.

Is that correct? If not, how does the other side know where to get 'em? Thanks in advance.

Upvotes: 0

Views: 396

Answers (1)

Timothy Baldwin
Timothy Baldwin

Reputation: 3675

For printf the format string indicates the type of the remaining argments.

The implementation of va_arg knows the type as it is an argument of va_arg, and the correct register can be deduced from the types.

Upvotes: 3

Related Questions