找回密码
 注册
关于网站域名变更的通知
查看: 299|回复: 1
打印 上一主题 下一主题

ARM下的参数传递

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-11-9 13:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
" y9 p7 Z: c2 w5 f' J2 {3 N
之前在学习如何在C语言中嵌入汇编时有了解到C语言之前的参数调用是使用寄存器R0传递第一个参数,R1传递到
6 M/ B' G* V4 k/ f8 M" Y6 Z& J
4 S/ |: d% p9 E2 a/ R3 X第二个..一直到R3传递第四个参数.但是实际上有时可能传递的参数非常多,超过8个,或是参数中有浮点数之类,# O* o; A; Z# [7 g! e* m! L

( \0 N5 M2 q! q; F参数也会超过4个寄存器,对于超出的部份并不使用R4,而是使用堆栈的方式
3 i  M+ F4 t7 R0 d( Y/ i  ]/ f/ X2 i2 K( Y
—————————————————华丽的分割线————————————————
0 f" J& Q7 O. U# G: N' p9 ^* }! x5 E/ L" ]: e
对于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure
; F7 c4 P6 L7 W' X
2 z8 e: P0 p; M( VCall Standard),ATPCS主要是定义了函数呼叫时参数的传递规则以及如何从函数返回,关于ATPCS的详细内容
$ O( W" d9 C2 u. r' f9 H5 u6 m4 Q1 V/ m2 e1 o) w
可以查看ADS1.2 Online Books ——Developer Guide的2.1节。这篇文档要讲的是 汇编代码中对C函数调用时如
: D5 m9 R& S. }$ g* X
+ m, ]: a2 [$ [( {; C- w何进行参数的传递以及如何从C函数正确返回
0 D* _/ H+ i9 j2 f5 b4 @不同于x86的参数传递规则,ATPCS建议函数的形参不超过4个,如果形参个数少于或等于4,则形参由) Z3 @7 V0 {2 @( H; j* t+ j3 h
( A, k; n8 u5 P; k
R0,R1,R2,R3四个寄存器进行传递;若形参个数大于4,大于4的部分必须通过堆栈进行传递。% U! s. \  Z6 ]
我们先讨论一下形参个数为4的情况.: C1 S1 m9 j( y1 |. p
实例1:
' i( w5 @* ]0 F/ a) N1 z2 Q; A: Stest_asm_args.asm0 c* x( c0 {7 x& E  \
//——————————————————————————–( h8 P% Y$ `# q, C$ O( g
IMPORT test_c_args ;声明test_c_args函数$ a- Q& `$ G, r$ j. i
AREA TEST_ASM, CODE, READONLY
) y* m6 y( d5 h* R( g; K# }EXPORT test_asm_args
- G7 m9 ]6 R8 \! S' Z" xtest_asm_args8 M* {3 Q) T- G* v$ F! p7 w
STR lr, [sp, #-4]! ;保存当前lr
" j3 X/ O; |& X* v) M3 K0 Cldr r0,=0×10 ;参数 1% T0 _- i6 ?, f3 y2 k: k* H
ldr r1,=0×20 ;参数 2
/ B) u$ g, J% x4 S2 G5 Uldr r2,=0×30 ;参数 3
  j# [5 M0 w1 K* Lldr r3,=0×40 ;参数 4( d# G' R+ Y: W* V) g
bl test_c_args ;调用C函数
( Z7 Z! t/ S! YLDR pc, [sp], #4 ;将lr装进pc(返回main函数)
* ]: l- w! c7 x' p$ FEND1 y! o5 s- e+ u2 B+ g' }  C; a
test_c_args.c+ b9 c/ B/ Y0 S, y- l0 Y3 X7 Q; H
//——————————————————————————–5 I' z; w6 q2 i
void test_c_args(int a,int b,int c,int d)  o9 }1 T% y8 T4 `4 v* ]7 f4 u/ I
{
  @; U- E! Q2 {2 i& n& y$ L+ a4 `printk(“test_c_args:\n”);
  a  U. W/ V: H' Cprintk(“%0x %0x %0x %0x\n”,a,b,c,d);& _0 V/ r# J$ o6 U% C( B
}1 I- c, c0 y0 ^
main.c
- [* S# v; P3 G/ s$ G, E& k( X//——————————————————————————–
0 C6 `0 R* d! L  x( Dint main()$ u- K8 w( M3 m4 e5 {/ y. J$ Z
{
7 r7 L% y: T" h6 ztest_asm_args();2 m) w1 q; S/ w. A5 r$ {
for(;;);
. g; _# V( s5 |2 k}) k+ o6 ^: S, W* G# j5 B7 g1 ^, U
程序从main函数开始执行,main调用了test_asm_args,test_asm_args调用了test_c_args,最后从test_asm_args* {3 _1 U/ t3 [+ P

/ m# [0 J: K1 t: g4 m6 i返回main.
# @' P6 ^% x. K2 T$ B0 r9 L代码分别使用了汇编和C定义了两个函数,test_asm_args 和 test_c_args,test_asm_args调用了test_c_args,& h4 v2 M. m, S: ?9 a/ u
, K: q; T, \0 p! R& D
其参数的传递方式就是向R0~R3分别写入参数值,之后使用bl语句对test_c_args进行调用。其中值得注意的地
: b6 {5 _: Z4 T  Q8 q3 w6 Z
! N7 Z; ~3 S5 @$ j& F: {方是用红色标记的语句,test_asm_args在调用test_c_args之前必须把当前的lr入栈,调用完test_c_args之后( Q* k8 t0 W% r
4 l; T& S- b# m1 x' R9 r  X0 h
再把刚才保存在栈中的lr写回pc,这样才能返回到main函数中。# r2 B6 _; ~" L" C$ O
如果test_c_args的参数是8个呢?这种情况test_asm_args应该怎样传递参数呢?
( s/ S. P9 q6 t" P  P实例2:
6 O% d3 k+ e) jtest_asm_args.asm
, J9 _. j9 l, `: E/ Q! `" l//——————————————————————————–
  X9 {3 U- [6 T+ T: U' dIMPORT test_c_args ;声明test_c_args函数, T0 ^) ?/ X. J4 T9 @+ c& {
AREA TEST_ASM, CODE, READONLY
+ B& o# e+ ?8 E+ \' L! p0 y1 J" N$ _EXPORT test_asm_args
/ e: w4 g6 B+ l' J# L- itest_asm_args1 a9 t8 V* T" C
STR lr, [sp, #-4]! ;保存当前lr/ D3 b6 _( S) D9 b# C( f: @
ldr r0,=0×1 ;参数 10 E; S* q$ s" I
ldr r1,=0×2 ;参数 2+ }7 ?5 \$ T! T2 d  H# b, m
ldr r2,=0×3 ;参数 3  {' m. P$ Y, \0 e
ldr r3,=0×4 ;参数 4
" {+ U8 A2 _; }6 V' B# [ldr r4,=0×8
. {# N3 _6 |& J* m/ G( m8 ustr r4,[sp,#-4]! ;参数 8 入栈
. t& ~" Z6 I8 Bldr r4,=0×7
  T) y7 w9 m6 L( i7 Kstr r4,[sp,#-4]! ;参数 7 入栈
% R5 ?# {0 w% j$ |  H. c5 Bldr r4,=0×6% M* B9 [* y0 ^$ ~! a2 `  n# t
str r4,[sp,#-4]! ;参数 6 入栈
: ^- n% I/ N; H% u9 u6 Vldr r4,=0×5
5 E, H+ ~, l. i2 T* [; Z# [5 b7 Pstr r4,[sp,#-4]! ;参数 5 入栈
. O3 V; I: I. v- A) {9 Bbl test_c_args_lots. Z+ B. h0 `1 P
ADD sp, sp, #4 ;清除栈中参数 5,本语句执行完后sp指向 参数6
. q3 |9 V/ M% N9 n1 R" vADD sp, sp, #4 ;清除栈中参数 6,本语句执行完后sp指向 参数7
2 O8 t* h8 v; u5 |) z& L& G* o* I9 eADD sp, sp, #4 ;清除栈中参数 7,本语句执行完后sp指向 参数8
: M1 ]( t9 w; I* k7 M  jADD sp, sp, #4 ;清除栈中参数 8,本语句执行完后sp指向 lr
* K4 L: _' `# F$ G8 s" u- r7 Y) wLDR pc, [sp],#4 ;将lr装进pc(返回main函数)
5 m5 h1 k3 M. V' @# h( L; xEND
6 \' T  `4 f/ n) Z. Ftest_c_args.c
! e: M; ]- L, ?  S. N1 R! p//——————————————————————————–
/ I& g  A4 b( X; v% Y& V5 C; V4 d( Svoid test_c_args(int a,int b,int c,int d,int e,int f,int g,int h)
2 P! |) n+ N+ b& [2 Z{
- g" \- N# @/ W$ Y; T0 pprintk(“test_c_args_lots:\n”);
! T0 n+ A+ w, _' {$ N  a$ `printk(“%0x %0x %0x %0x %0x %0x %0x %0x\n”,
& @- X9 U9 I, A/ A; _3 J) K' g# q( {' p8 K% {7 ?$ A
a,b,c,d,e,f,g,h);
, O& ?* H1 T8 u- ^}
: b$ [; o$ h) H4 m4 C) W, b7 {main.c
# t( D' ^: M, g4 O. |5 J//——————————————————————————–4 }9 N8 ~. }4 F$ C% I9 I
int main()
$ C1 t) N- l5 M# S' o{1 k, g! e1 \& O$ m* \
test_asm_args();
1 W1 L1 E4 F1 e" G, v( _for(;;);
0 Z8 |( }9 t0 P) \9 e7 U( H}
6 A% y5 |* K4 l) I" b这部分的代码和实例1的代码大部分是相同的,不同的地方是test_c_args的参数个数和test_asm_args的参数传1 n$ z" i$ f! U+ L" g' [* M+ ~
- o/ U4 u. Y; F+ }1 @/ ?
递方式。6 [* h" Q, ]+ Z7 Q# J9 U& A2 c
在test_asm_args中,参数1~参数4还是通过R0~R3进行传递,而参数5~参数8则是通过把其压入堆栈的方式进; C& V' w4 l( H) a+ ]
) E) U* O( ~  [/ ~' H# |
行传递,不过要注意这四个入栈参数的入栈顺序,是以参数8->参数7->参数6->参数5的顺序入栈的。' j" t) [7 r5 |3 P/ x$ J/ X, T3 V
直到调用test_c_args之前,堆栈内容如下:
* E- [) s, h1 s# g: l' Tsp->+———-+
( Q6 z9 f; L7 S5 \! g& R8 S3 @( ?| 参数5 |# W" _) ]: N2 S/ \+ ~! b. p1 Y* d) z
+———-+
2 C9 b+ R1 I7 `% G| 参数6 |
, ^9 X: M) Q. s5 ^: G8 m+———-+
: b4 G) r$ l2 E- \0 y| 参数7 |/ O: v. X% w2 \
+———-+
. o  `6 n( Q6 H8 `' O| 参数8 |
' t1 g! [7 j& a+———-+
, i* X' H( \4 A1 g5 P, Q4 U| lr |, J' m: ~  S, H" z
+———-+
( E6 ?* I/ a0 u3 B9 F" J" ^test_c_args执行返回后,则设置sp,对之前入栈的参数进行清除,最后将lr装入pc返回main函数,在执行 LDR
# f  W9 D$ t3 H2 M* u6 S) n
( }( [) m" l0 I; ?+ w& K. tpc, [sp],#4 指令之前堆栈内容如下:
: `9 q% h* B- G+———-+
& ?/ }' ^3 i# d6 {| 参数5 |1 w" V: R' w) H) l$ c
+———-+$ r% c* S3 |6 G7 |! I. f8 ?
| 参数6 |* Q) e# _" F9 E  t0 e
+———-+" I3 @/ d* ^1 w% Q1 L
| 参数7 |- p0 c" |2 K. w/ T
+———-+
  ]  ]/ x. s4 S| 参数8 |
* r. x& R. w' q, ^sp->+———-+, S/ ]$ Y- b8 o+ c/ F# O
| lr |) A4 j* @& I/ h7 B9 h
+———-+
  • TA的每日心情

    2019-11-29 15:37
  • 签到天数: 1 天

    [LV.1]初来乍到

    2#
    发表于 2020-11-9 14:57 | 只看该作者
    ARM下的参数传递
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-11-24 21:23 , Processed in 0.156250 second(s), 23 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表