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 的参数,并且可以从类型中推断出正确的寄存器。
我使用不同类型的参数编译了对 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 的参数,并且可以从类型中推断出正确的寄存器。