指针寄存器:
(1)BP为基指针(BasePointer)寄存器,用它可直接存取堆栈中的数据;
(2)SP为堆栈指针(StackPointer)寄存器,用它只可访问栈顶。
RBP、RSP:64位,EBP、ESP32位,BP、SP16位
- %rax 作为函数返回值使用。
- %rsp 栈指针寄存器,指向栈顶
- %rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数。。。。当参数超过6个时,参数会向地址压栈。(下面有例子可以看)
- %rbx,%rbp,%r12,%r13,%14,%15 用作数据存储,遵循被调用者使用规则,简单说就是随便用,调用子函数之前要备份它,以防他被修改
- %r10,%r11 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存原值
代码用例
void fun(int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8)
{
int a = a7,b = a8;
}
void funl(long int a1,long int a2,long int a3,long int a4,long int a5,long int a6,int a7,int a8)
{
long int a = 100;
}
int main()
{
int a = 10;
fun(1,2,3,4,5,6,7,8);
funl(1,2,3,4,5,6,7,8);
return 2;
}
经过:gcc -g -o test test.c后,objdump -d test反编译:
00000000000005fa <fun>:
5fa: 55 push %rbp
5fb: 48 89 e5 mov %rsp,%rbp
5fe: 89 7d ec mov %edi,-0x14(%rbp)
601: 89 75 e8 mov %esi,-0x18(%rbp)
604: 89 55 e4 mov %edx,-0x1c(%rbp)
607: 89 4d e0 mov %ecx,-0x20(%rbp)
60a: 44 89 45 dc mov %r8d,-0x24(%rbp)
60e: 44 89 4d d8 mov %r9d,-0x28(%rbp)
612: 8b 45 10 mov 0x10(%rbp),%eax
615: 89 45 f8 mov %eax,-0x8(%rbp)
618: 8b 45 18 mov 0x18(%rbp),%eax
61b: 89 45 fc mov %eax,-0x4(%rbp)
61e: 90 nop
61f: 5d pop %rbp
620: c3 retq
0000000000000621 <funl>:
621: 55 push %rbp
622: 48 89 e5 mov %rsp,%rbp
625: 48 89 7d e8 mov %rdi,-0x18(%rbp)
629: 48 89 75 e0 mov %rsi,-0x20(%rbp)
62d: 48 89 55 d8 mov %rdx,-0x28(%rbp)
631: 48 89 4d d0 mov %rcx,-0x30(%rbp)
635: 4c 89 45 c8 mov %r8,-0x38(%rbp)
639: 4c 89 4d c0 mov %r9,-0x40(%rbp)
63d: 48 c7 45 f8 64 00 00 movq $0x64,-0x8(%rbp)
644: 00
645: 90 nop
646: 5d pop %rbp
647: c3 retq
0000000000000648 <main>:
648: 55 push %rbp
649: 48 89 e5 mov %rsp,%rbp
64c: 48 83 ec 10 sub $0x10,%rsp
650: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
657: 6a 08 pushq $0x8
659: 6a 07 pushq $0x7
65b: 41 b9 06 00 00 00 mov $0x6,%r9d
661: 41 b8 05 00 00 00 mov $0x5,%r8d
667: b9 04 00 00 00 mov $0x4,%ecx
66c: ba 03 00 00 00 mov $0x3,%edx
671: be 02 00 00 00 mov $0x2,%esi
676: bf 01 00 00 00 mov $0x1,%edi
67b: e8 7a ff ff ff callq 5fa <fun>
680: 48 83 c4 10 add $0x10,%rsp
684: 6a 08 pushq $0x8
686: 6a 07 pushq $0x7
688: 41 b9 06 00 00 00 mov $0x6,%r9d
68e: 41 b8 05 00 00 00 mov $0x5,%r8d
694: b9 04 00 00 00 mov $0x4,%ecx
699: ba 03 00 00 00 mov $0x3,%edx
69e: be 02 00 00 00 mov $0x2,%esi
6a3: bf 01 00 00 00 mov $0x1,%edi
6a8: e8 74 ff ff ff callq 621 <funl>
6ad: 48 83 c4 10 add $0x10,%rsp
6b1: b8 02 00 00 00 mov $0x2,%eax
6b6: c9 leaveq
6b7: c3 retq
6b8: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
6bf: 00
参考文章:
keil 函数最多可以传几个参数_x86-64 规定只有6个寄存器来存参数,那 C 函数为什么还能超过6个参数呢?..._德川家康薛定谔的博客-CSDN博客
X86-64寄存器和栈帧_u013737447的博客-CSDN博客_rdi寄存器