mips体系架构abi中,在参数传递这块还真是坑(不同于aaarch64)。具体分3种情况:
如果callee(子函数)的参数列表都是整数,那么caller(调用函数)可以使用通用寄存器a0-a7($4 - $11)传递前8个参数。如果参数列表大于8个,则多余的参数通过栈传递。
比如 void callee(int a,int b) ; //callers使用a0,a1来传递2个参数。
如果callee(子函数)的参数列表都是浮点数,那么caller(调用函数)可以使用浮点寄存器f12-f19传递前8个参数。如果参数列表大于8个,则多余的参数通过栈传递。
比如 void callee(float a,float b) ; //callers使用f12,f13来传递2个参数。
这种情况下,mips架构处理就很特性。具体的寄存器使用规则如下表:
Argument | List Register and Stack Assignments |
---|---|
n1,n2,n3,n4 | $4,$5,$6,$7 |
d1,d2,d3,d4,d5 | $f12, $f13, $f14, $f15, $f16 |
n1,n2,d1 | $4, 5 , 5, 5,f14 |
d1,n1,n2 | $f12, $5,$6 |
d1,d2,d3,d4,d5,s1,s2,s3,s4 | $f12, $f13, $f14, $f15, $f16, f 17 , f17, f17,f18,$f19,stack |
d1,d2,d3,s1,s2,s3,n1,n2,n3 | $f12, $f13, $f14, $f15, $f16, $f17, $10,$11,stack |
从上表看出规律了吗?表中第1行和第2行列举的是参数中只有整数或者浮点的情况。第3行(n1,n2,d1)表示参数列表中有2个整数和1个浮点数的情况,那么寄存器使用规则是$4(a0) ,$5(a1), $f14。这里并没有使用$12来传递浮点数。而第4行(d1,n1,n2)使用寄存器是 $f12, $5(a1), 6 ( a 2 ) , 而 非 6(a2),而非 6(a2),而非f12, $4(a0),$5(a1)。这就是差别所在。mips abi规定参数传递时,a0-a7和f12-f19这16个寄存器统一计算,当a0被使用后,参数列表遇到浮点时f12不在使用而要用f13;如果a0,a1被占用,浮点f12,f13都不再使用而是用f14传递下一个浮点,以此类推。超过8个即上栈,例如表格中最后两行。
#include
#include
void test1(int a,int b,float f){
printf("result a=%d b=%d f=%f \n",a,b,f);
}
void test2(float f, int a, int b){
printf("result a=%d b=%d f=%f \n",a,b,f);
}
void test3(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8,int arg9, int arg10){
printf("result %d %d %d %d %d %d %d %d %d %d\n",arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10);
}
int main(){
test1(1, 2, 3.5);
test2(3.5, 1, 2);
test3(1,2,3,4,5,6,7,8,9,10);
return 0;
}
从上面的两张图片可以发现AARCH64中参数传递规则是整数从X0-X7(32位使用W0-W7),浮点使用S0-S7,如果参数队列里既有整数又有浮点。整数寄存器和浮点寄存器分别从X0或S0开始使用,不会有跳跃的情况。
同时可以发现,同样的C语言函数main()。AARCH64的汇编指令行数要远少于MIPS64,不知道运行效率上如何?有行家可以指点一二。