2020-04-25
- 用参数寄存器存放函数的参数(寄存器不够:栈)
- 参数从R0开始
- 查看方法
- 看函数跳转的寄存器(B,BL,BLX),如果涉及到参数寄存器(Rn),如果n<=4,则参数为R0-Rn
- 比如 BLX R3 ,那么参数就是R0,R1,R2
- 如果BLX 后面的不是参数寄存器,则说明参数至少4个,
- 本人新手,至于如何判断函数的参数个数,,下面通过具体的汇编代码查看,,
- 示例
- java层代码
public native int testOneParam(int a); public native int testTwoParam(int a, int b); public native int testThreeParam(int a, int b, int c); public native int testFourParam(int a, int b, int c,int d); public native int testFiveParam(int a, int b, int c,int d,int e); public native int testSixParam(int a, int b, int c,int d,int e,int f); public native int testSevenParam(int a, int b, int c,int d,int e,int f,int g);
- 汇编代码public native int testOneParam(int a);
libparamtest.so:B4D8A100 Java_com_ldj_leanndk001_TestParamActivity_testOneParam libparamtest.so:B4D8A100 MOV R0, R2 //1 libparamtest.so:B4D8A104 BX LR //2 libparamtest.so:B4D8A104 ; End of function Java_com_ldj_leanndk001_TestParamActivity_testOneParam //注释1处。 首先这个是jni函数,而且是静态注册,所以有两个固定参数R0(JNIEnv*),R1(jobject), 此处将R2赋值给R0,并且参与BX运算,可知函数有三个参数,,传递进来的java层有一个参数
- public native int testTwoParam(int a, int b);
libparamtest.so:B4D8A108 Java_com_ldj_leanndk001_TestParamActivity_testTwoParam libparamtest.so:B4D8A108 ADD R0, R3, R2 //注释1 libparamtest.so:B4D8A10C BX LR //注释2 libparamtest.so:B4D8A10C ; End of function Java_com_ldj_leanndk001_TestParamActivity_testTwoParam //注释1 将R2+R3的结果赋值给R0,不涉及别的寄存器,可知参数为2+2=4,java层有两个参数
- public native int testThreeParam(int a, int b, int c);
libparamtest.so:B4D8A110 Java_com_ldj_leanndk001_TestParamActivity_testThreeParam libparamtest.so:B4D8A110 libparamtest.so:B4D8A110 arg_0= 0 libparamtest.so:B4D8A110 libparamtest.so:B4D8A110 LDR R0, [SP,#arg_0] //将栈顶数据赋值给R0 libparamtest.so:B4D8A114 ADD R1, R3, R2 //R1=R2+R3 libparamtest.so:B4D8A118 ADD R0, R1, R0 //R0=R1+R0 libparamtest.so:B4D8A11C BX LR libparamtest.so:B4D8A11C ; End of function Java_com_ldj_leanndk001_TestParamActivity_testThreeParam //分析: jni函数有两个固定参数,然后LDR指令获取了一个参数,加上原本的参数寄存器R0-R3,所以jni层一共有5个参数,java层有3个
调试截图:
- public native int testFourParam(int a, int b, int c,int d);
libparamtest.so:B4D8A120 Java_com_ldj_leanndk001_TestParamActivity_testFourParam libparamtest.so:B4D8A120 libparamtest.so:B4D8A120 arg_0= 0 libparamtest.so:B4D8A120 arg_4= 4 libparamtest.so:B4D8A120 libparamtest.so:B4D8A120 LDR R1, [SP,#arg_0] //从栈顶获取数据赋值给R1,也就是第5个参数 libparamtest.so:B4D8A124 ADD R2, R3, R2 //R2=R2+R3 libparamtest.so:B4D8A128 LDR R0, [SP,#arg_4] //从栈[SP+4]处获取第6个参数,赋值给R0 libparamtest.so:B4D8A12C ADD R1, R2, R1 //R1=R2+R1 libparamtest.so:B4D8A130 ADD R0, R1, R0 //R0=R1+R0 libparamtest.so:B4D8A134 BX LR libparamtest.so:B4D8A134 ; End of function Java_com_ldj_leanndk001_TestParamActivity_testFourParam //分析: jni函数有两个固定参数R0,R1, 原本的参数寄存器R0-R3,LDR指令获取了两个参数,所以总共是6个参数,java层4个
调试截图:
- public native int testFiveParam(int a, int b, int c,int d,int e);
libparamtest.so:B4D8A138 testFiveParam libparamtest.so:B4D8A138 libparamtest.so:B4D8A138 arg_8= 8 libparamtest.so:B4D8A138 libparamtest.so:B4D8A138 LDMFD SP, {R0,R12} //1.将栈前两个数据分别赋值给R0,R12 libparamtest.so:B4D8A13C ADD R2, R3, R2 //2. libparamtest.so:B4D8A140 ADD R0, R2, R0 libparamtest.so:B4D8A144 LDR R1, [SP,#arg_8] //3.从[SP+8]数据赋值给R1 libparamtest.so:B4D8A148 ADD R0, R0, R12 libparamtest.so:B4D8A14C ADD R0, R0, R1 libparamtest.so:B4D8A150 BX LR libparamtest.so:B4D8A150 ; End of function testFiveParam //分析: jni函数有两个固定参数R0,R1, 第一个LDMFD指令,将SP+0,SP+4两个数据赋值给R0和R12,可以看出是两个参数 然后LDR指令将SP+8数据赋值给R1。又是一个参数 加上4个参数寄存器可知,一共是7个参数,,java层5个参数
调试截图:
- public native int testSixParam(int a, int b, int c,int d,int e,int f);
libparamtest.so:B4D8A154 testSixParam libparamtest.so:B4D8A154 libparamtest.so:B4D8A154 arg_0= 0 libparamtest.so:B4D8A154 arg_4= 4 libparamtest.so:B4D8A154 arg_8= 8 libparamtest.so:B4D8A154 arg_C= 0xC libparamtest.so:B4D8A154 libparamtest.so:B4D8A154 STMFD SP!, {R11,LR} //压栈,SP=SP-0x8 libparamtest.so:B4D8A158 LDR R0, [SP,#8+arg_0] //SP+0x8,第五个参数 libparamtest.so:B4D8A15C ADD R2, R3, R2 //参数寄存器 libparamtest.so:B4D8A160 LDR LR, [SP,#8+arg_4] //SP+0xc,第6个参数 libparamtest.so:B4D8A164 ADD R0, R2, R0 libparamtest.so:B4D8A168 LDR R1, [SP,#8+arg_8] //SP+0x10,第7个参数 libparamtest.so:B4D8A16C ADD R0, R0, LR libparamtest.so:B4D8A170 LDR R12, [SP,#8+arg_C] //SP+0x14,第8个参数 libparamtest.so:B4D8A174 ADD R0, R0, R1 libparamtest.so:B4D8A178 ADD R0, R0, R12 libparamtest.so:B4D8A17C LDMFD SP!, {R11,PC} //平栈,,SP=Sp+0x8 libparamtest.so:B4D8A17C ; End of function testSixParam //分析: jni函数有两个固定参数R0,R1, 从上面注释可以看出,一共使用LDR指令从栈中获取了4个参数 加上4个参数寄存器可知,一共是8个参数,,java层6个参数
调试截图
-
- public native int testSevenParam(int a, int b, int c,int d,int e,int f,int g);
libparamtest.so:B4D8A180 testSevenParam libparamtest.so:B4D8A180 libparamtest.so:B4D8A180 arg_0= 0 libparamtest.so:B4D8A180 arg_4= 4 libparamtest.so:B4D8A180 libparamtest.so:B4D8A180 STMFD SP!, {R4,LR} ; 压栈,SP=SP-0x08 libparamtest.so:B4D8A184 ADD LR, SP, #8+arg_4 ; 将PC+0x8+4 栈地址保存到LR 寄存器,此时LR寄存器中保存的是第6个参数地址 libparamtest.so:B4D8A188 LDR R4, [SP,#8+arg_0] ; 将SP+0x8中保存的数给R4,就是第五个参数 libparamtest.so:B4D8A18C ADD R2, R3, R2 ; 加法运算 libparamtest.so:B4D8A190 LDMIA LR, {R0,R1,R12,LR} ; 批量加载栈中保存的数据,并且赋值 给R0,R1,R12,LR, libparamtest.so:B4D8A190 ; 此时这四个寄存器中保存的都是传递进来的参数 libparamtest.so:B4D8A194 ADD R2, R2, R4 libparamtest.so:B4D8A198 ADD R0, R2, R0 libparamtest.so:B4D8A19C ADD R0, R0, R1 libparamtest.so:B4D8A1A0 ADD R0, R0, R12 libparamtest.so:B4D8A1A4 ADD R0, R0, LR libparamtest.so:B4D8A1A8 LDMFD SP!, {R4,PC} ; 平栈,,恢复栈顶指针 libparamtest.so:B4D8A1A8 ; End of function testSevenParam //分析: jni函数有两个固定参数R0,R1, 从上面注释可以看出,一共使用LDR指令从栈中获取了1个参数 LDMIA指令获取了4个, 加上4个参数寄存器可知,一共是9个参数,,java层7个参数
调试截图: