EDA365电子论坛网
标题:
ARM下的参数传递
[打印本页]
作者:
thinkfunny
时间:
2020-11-9 13:49
标题:
ARM下的参数传递
' w6 }/ y0 C; @* }8 x7 W
之前在学习如何在C语言中嵌入汇编时有了解到C语言之前的参数调用是使用寄存器R0传递第一个参数,R1传递到
( G* O" P7 e) @. {& u2 _1 `$ s
$ W- D- p. y: `2 O
第二个..一直到R3传递第四个参数.但是实际上有时可能传递的参数非常多,超过8个,或是参数中有浮点数之类,
6 y# e% G2 ]. a/ s$ L F1 |' U% m; u( L
3 ^3 [2 g" T, X# T1 ~5 }! {
参数也会超过4个寄存器,对于超出的部份并不使用R4,而是使用堆栈的方式
- c; @# k+ G8 m7 m$ ]
$ z! _- b; }: a7 b S5 I! j
—————————————————华丽的分割线————————————————
j4 A ^9 l0 A* W! Y5 k2 T. x0 }
3 o, O4 J* J5 D# H/ H: Y
对于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure
5 x5 Z# @+ P) q% g
( m5 E. _) r- i
Call Standard),ATPCS主要是定义了函数呼叫时参数的传递规则以及如何从函数返回,关于ATPCS的详细内容
5 s; q8 Z; I' v/ I" y
1 x7 ^: r; u) N, G# {2 ^2 w$ b
可以查看ADS1.2 Online Books ——Developer Guide的2.1节。这篇文档要讲的是 汇编代码中对C函数调用时如
2 p1 w0 m6 x1 T5 T
, S6 l) z% |! \- ]- h" F% U o
何进行参数的传递以及如何从C函数正确返回
7 \' N! T. u8 w% Z5 \
不同于x86的参数传递规则,ATPCS建议函数的形参不超过4个,如果形参个数少于或等于4,则形参由
, ~' `" K+ @1 U' {# l
5 a8 {/ k9 ~. o5 h/ U
R0,R1,R2,R3四个寄存器进行传递;若形参个数大于4,大于4的部分必须通过堆栈进行传递。
9 T& ^; i0 t0 w) v$ i+ k
我们先讨论一下形参个数为4的情况.
% w) ]8 S" q6 @" y/ x2 q
实例1:
8 r2 o6 }) L7 ?& Z& M4 s# S
test_asm_args.asm
3 L% d$ }( y! n: N
//——————————————————————————–
7 u' m4 U! [( L _6 T3 s# E# r
IMPORT test_c_args ;声明test_c_args函数
, {! M* Y1 r1 j& r
AREA TEST_ASM, CODE, READONLY
7 W( U. H" }# A& K1 Y" [7 z U4 @
EXPORT test_asm_args
g% ?. r9 y3 V) y/ A9 g, {
test_asm_args
( S9 }; w+ v; [
STR lr, [sp, #-4]! ;保存当前lr
& J6 K' \6 a# B& {4 E
ldr r0,=0×10 ;参数 1
. [9 r1 r+ x& I* N% d1 ^6 O
ldr r1,=0×20 ;参数 2
1 C$ X1 \) C9 s2 P1 f
ldr r2,=0×30 ;参数 3
) v U7 \2 O+ B+ [2 m7 i
ldr r3,=0×40 ;参数 4
6 N' x& j% x' e+ P9 m. e7 C6 U
bl test_c_args ;调用C函数
5 B9 e( ` a- \ Z/ @0 O1 m
LDR pc, [sp], #4 ;将lr装进pc(返回main函数)
) i: w5 ?0 K: b
END
+ f: k1 H& v" D" Y) e; [
test_c_args.c
7 f# x/ ?0 @8 @* X* l" U9 y4 r% r
//——————————————————————————–
/ ?% i! U/ u: Y
void test_c_args(int a,int b,int c,int d)
" A( u2 ?0 W4 v1 L4 B: y" u
{
! A. k4 l% z# H
printk(“test_c_args:\n”);
, t% I3 T8 O) r3 H( F% f/ @
printk(“%0x %0x %0x %0x\n”,a,b,c,d);
7 \1 l4 m) Q7 v2 z. e
}
' w; s J) m7 D) v
main.c
+ l6 p4 U: }% S% F$ s7 M- l
//——————————————————————————–
2 s. u4 n; |1 |( ]" r
int main()
/ j/ \( C0 @4 k* a
{
8 @! h/ b% u. a; z' O" u# Y* Y \+ i8 N
test_asm_args();
: l! k, @9 p7 q8 R6 e8 Z4 b
for(;;);
- [: g# b/ b2 {" C
}
$ v& g. W; F! m0 n
程序从main函数开始执行,main调用了test_asm_args,test_asm_args调用了test_c_args,最后从test_asm_args
* N2 k" K4 t% s% d, Y
+ a$ j8 z) Z5 y7 d2 O; x
返回main.
0 T6 L/ y$ q5 I& r+ H: V" z
代码分别使用了汇编和C定义了两个函数,test_asm_args 和 test_c_args,test_asm_args调用了test_c_args,
5 w8 I7 h7 o( a8 u1 i
) C. h# U n9 U& _, l- G9 q0 C
其参数的传递方式就是向R0~R3分别写入参数值,之后使用bl语句对test_c_args进行调用。其中值得注意的地
' F* C. e j1 u p) Q' t
* z8 u: K+ I3 Q5 k
方是用红色标记的语句,test_asm_args在调用test_c_args之前必须把当前的lr入栈,调用完test_c_args之后
7 U) C" _- r3 }5 N, A
! S8 A% I4 S- l- j4 ?. G) x
再把刚才保存在栈中的lr写回pc,这样才能返回到main函数中。
' p+ `# n& P* O8 `9 e: o4 u0 k
如果test_c_args的参数是8个呢?这种情况test_asm_args应该怎样传递参数呢?
5 Z3 z; Z9 x! l/ e" [7 j7 B
实例2:
+ f( y3 A) k/ b4 Y3 o
test_asm_args.asm
' F0 X' k" r% T& U* ]
//——————————————————————————–
+ G! ?; Z+ W( N( Z$ T3 W! ]
IMPORT test_c_args ;声明test_c_args函数
5 W' g8 t6 ?4 i; z, k4 B+ h9 f
AREA TEST_ASM, CODE, READONLY
( f$ `# k) n# _/ @
EXPORT test_asm_args
& G' c3 N A5 f; l) f, V* ?
test_asm_args
0 T ?8 \* |9 h7 b
STR lr, [sp, #-4]! ;保存当前lr
# y# T, ?" }4 h% O
ldr r0,=0×1 ;参数 1
& v5 X J$ s# G: \/ \
ldr r1,=0×2 ;参数 2
4 P o) b/ Q$ z, l" g2 [: @
ldr r2,=0×3 ;参数 3
' }+ q9 v$ \3 d" q1 b: U
ldr r3,=0×4 ;参数 4
9 v4 x9 B$ w" X
ldr r4,=0×8
8 o& N# n$ l0 S- B6 X, l7 M& h
str r4,[sp,#-4]! ;参数 8 入栈
4 m7 @$ i0 k8 V; Z" c9 ?* r
ldr r4,=0×7
0 P$ x2 l! O( T$ `$ k
str r4,[sp,#-4]! ;参数 7 入栈
- [/ F4 s/ U, A5 r( Z Q+ [
ldr r4,=0×6
8 `0 c4 r/ A' Y6 G
str r4,[sp,#-4]! ;参数 6 入栈
& }/ P' u8 [0 x% E; G8 `/ n
ldr r4,=0×5
6 P, }( d) S: \0 H3 j
str r4,[sp,#-4]! ;参数 5 入栈
7 Y7 ]9 a. K4 y. c# ~$ O
bl test_c_args_lots
0 k5 w) S( X6 G% }+ V3 t
ADD sp, sp, #4 ;清除栈中参数 5,本语句执行完后sp指向 参数6
/ k, ]% i0 b9 Q
ADD sp, sp, #4 ;清除栈中参数 6,本语句执行完后sp指向 参数7
+ l- }, L. R8 c/ @/ [& q. d
ADD sp, sp, #4 ;清除栈中参数 7,本语句执行完后sp指向 参数8
* H4 n: q g+ T; d8 T; g/ c, n
ADD sp, sp, #4 ;清除栈中参数 8,本语句执行完后sp指向 lr
5 ^8 c- l" Y1 X
LDR pc, [sp],#4 ;将lr装进pc(返回main函数)
& `5 a* ~) N2 m- B. M: G) L
END
& r; P( `' X- n
test_c_args.c
; h3 g( @; L" J$ o5 n
//——————————————————————————–
- V1 s% k) D/ ~, B- ~
void test_c_args(int a,int b,int c,int d,int e,int f,int g,int h)
# R8 a8 T3 R3 X9 r. N- G
{
9 i: j3 n' \- w9 w, d& ^
printk(“test_c_args_lots:\n”);
) a" B" R- }1 E% K! q/ p1 g& X7 P
printk(“%0x %0x %0x %0x %0x %0x %0x %0x\n”,
& A5 m9 k/ I% j* f/ B1 b0 {
4 S0 Y1 Z' _! |8 `0 {9 X
a,b,c,d,e,f,g,h);
" V |. o4 X9 Z5 N+ o* |% U' ^
}
6 l% O2 i+ _7 C7 w) t! X, f
main.c
) S8 W% w8 F. t6 F* K/ a# b
//——————————————————————————–
. d. K' g; }' X" Y
int main()
% N# o# h" j' r3 D8 K. Q+ l
{
; X A" ^+ J' s/ j# S& b2 f
test_asm_args();
" N4 F/ A) O; w5 P# e8 o! d" q
for(;;);
/ J7 ~2 a. P: o: |
}
4 G6 K/ J& ]) c- {$ a: E
这部分的代码和实例1的代码大部分是相同的,不同的地方是test_c_args的参数个数和test_asm_args的参数传
/ B1 i0 w6 m. R2 V4 c, y/ k
' x+ Q3 Q0 l% J
递方式。
' B( S6 R! W3 R0 |. ?* c# m, v2 X& Q
在test_asm_args中,参数1~参数4还是通过R0~R3进行传递,而参数5~参数8则是通过把其压入堆栈的方式进
4 o& P0 L. G% U1 l1 m9 a) {# ]
; O. t" E# D0 } |0 ^3 Z! o
行传递,不过要注意这四个入栈参数的入栈顺序,是以参数8->参数7->参数6->参数5的顺序入栈的。
/ h- |0 @+ ~' D& Z
直到调用test_c_args之前,堆栈内容如下:
- J5 \/ ^- }& V4 p) {
sp->+———-+
) ]. @# j! f! i( s5 B3 k
| 参数5 |
- J8 `8 Q9 v& q( [/ W
+———-+
; q4 A2 b/ L' S1 o# X4 n& |
| 参数6 |
5 q/ G3 j* J4 y
+———-+
6 R: l* [: y9 B5 |: O9 m
| 参数7 |
# u B2 J0 @9 j5 l" A: ]
+———-+
, K7 M, E5 w/ S+ y6 G
| 参数8 |
, R( z+ `- R. t; |$ T2 b
+———-+
& v0 H6 i L5 r2 v
| lr |
) {8 S8 ~0 I9 X7 e, G
+———-+
, ?/ i W y; s5 I; j/ ?$ r
test_c_args执行返回后,则设置sp,对之前入栈的参数进行清除,最后将lr装入pc返回main函数,在执行 LDR
+ g. K4 k% o1 o5 P* L. ^ O
7 X) Z/ U* U+ V& R* e! t3 Q
pc, [sp],#4 指令之前堆栈内容如下:
, f3 Z: i/ S1 o
+———-+
/ O* U- [$ c0 u- d
| 参数5 |
( ~8 C+ M v. F9 ~1 v' M: y& U2 i
+———-+
4 f! C6 U4 I) r( R* m& i# G8 T
| 参数6 |
$ a! v' \( p' |# l: P4 j
+———-+
2 Z! g7 g! y/ G3 [3 H* A* A( E
| 参数7 |
% G1 h9 h. k3 S
+———-+
& E. r" y& ?0 p
| 参数8 |
. C7 g1 u2 \, Z2 Q" \+ k* H
sp->+———-+
9 O- n( m- U6 R
| lr |
- y2 Q F5 L! ~: L5 O. X
+———-+
作者:
yin123
时间:
2020-11-9 14:57
ARM下的参数传递
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2