|
在 x86 上,regparm 属性会传递一个数值给编译器,这个数值会告诉编译器要用多少个寄存器来传递函数参数(EAX, EDX 或 ECX,最多 3 个寄存器),通常情况下函数是用堆栈来传递参数的。如果参数比较多,那么其余的参数仍然通过堆栈来传递。
比如我们指定 __attribute__((regparm(0))) ,则表示不用寄存器来传递参数,所有参数都通过堆栈来传递;如果我们指定 __attribute__((regparm(3))),那么就是说会用 3 个寄存器来传递参数(EAX, EDX, ECX),其余的参数通过堆栈来传递。
下面先看不用寄存器来传递参数的情况:
[C++] 纯文本查看 复制代码 #include <stdio.h>
__attribute__((regparm(0))) int parm_to_register (int reg1, int reg2, int reg3, int stack)
{
return (reg1 + reg2 + reg3 + stack);
}
int main()
{
int reg1 = 1;
int reg2 = 2;
int reg3 = 3;
int stack = 4;
parm_to_register(reg1, reg2, reg3, stack);
return (0);
}
反汇编代码:.file "regparm.c"
.text
.globl parm_to_register
.type parm_to_register, @function
parm_to_register:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax #leal 指令将 edx 和 eax 中的值相加然后将其和看做是一个地址值送往 eax 中(这样比 movl 更快)
addl 16(%ebp), %eax
addl 20(%ebp), %eax
popl %ebp
ret
.size parm_to_register, .-parm_to_register
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $32, %esp
#main 中 4 个参数入栈保存
movl $1, -16(%ebp)
movl $2, -12(%ebp)
movl $3, -8(%ebp)
movl $4, -4(%ebp)
#照函数参数从右到左依次入栈保存
movl -4(%ebp), %eax
movl %eax, 12(%esp)
movl -8(%ebp), %eax
movl %eax, 8(%esp)
movl -12(%ebp), %eax
movl %eax, 4(%esp)
movl -16(%ebp), %eax
movl %eax, (%esp)
call parm_to_register
movl $0, %eax
leave
movl $0, %eax
addl $20, %esp
popl %ebx
popl %ebp
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.4 20100726 (Red Hat 4.4.4-13)"
.section .note.GNU-stack,"",@progbits 下面用 regparm 指定函数参数使用 3 个寄存器,即 EAX, EDX, ECX 来保存。将上面 C 程序中的 __attribute__((regparm(0))) 改为 __attribute__((regparm(3))),然后再看一下反汇编:.file "regparm.c"
.text
.globl parm_to_register
.type parm_to_register, @function
parm_to_register:
pushl %ebp
movl %esp, %ebp
subl $12, %esp
#分别从 eax, edx, ecx 取出相应的参数值入栈
movl %eax, -4(%ebp)
movl %edx, -8(%ebp)
movl %ecx, -12(%ebp)
#从栈中取出参数进行相加
movl -8(%ebp), %eax
movl -4(%ebp), %edx
leal (%edx,%eax), %eax
addl -12(%ebp), %eax
addl 8(%ebp), %eax
leave
ret
.size parm_to_register, .-parm_to_register
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
# main() 中的 4 个参数入栈保存
movl $1, -20(%ebp)
movl $2, -16(%ebp)
movl $3, -12(%ebp)
movl $4, -8(%ebp)
#使用 eax, ecx, edx 来传递参数。注意参数存入寄存器的顺序:(reg3-reg1)依次进入 ecx, edx, eax
movl -12(%ebp), %ecx
movl -16(%ebp), %edx
movl -20(%ebp), %eax
#第 4 个参数仍然用栈来传递
movl -8(%ebp), %ebx
movl %ebx, (%esp)
call parm_to_register
movl $0, %eax
addl $20, %esp
popl %ebx
popl %ebp
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.4 20100726 (Red Hat 4.4.4-13)"
.section .note.GNU-stack,"",@progbits |
|