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

ARM下的参数传递

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

; t8 R* u0 K$ j  s# H0 ?- h之前在学习如何在C语言中嵌入汇编时有了解到C语言之前的参数调用是使用寄存器R0传递第一个参数,R1传递到
" F9 Q  J; G9 E8 H  T! N# w( Y/ Z6 h/ I- x5 P: a6 C2 Z' P
第二个..一直到R3传递第四个参数.但是实际上有时可能传递的参数非常多,超过8个,或是参数中有浮点数之类,2 O. H% j9 A$ ~7 b5 q- Q" M

6 x! R) B9 @, r8 \; b) l参数也会超过4个寄存器,对于超出的部份并不使用R4,而是使用堆栈的方式
) S. P% p, [3 _" J
3 |, X2 h3 _; y* t) ~2 t—————————————————华丽的分割线————————————————
' Z6 m; g/ M- Y4 k3 Q) u5 n1 X3 r9 l* j' m
对于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure* S; O8 m$ N4 I) d

0 a2 F. C4 [/ ?- o5 V. W9 J3 Q" CCall Standard),ATPCS主要是定义了函数呼叫时参数的传递规则以及如何从函数返回,关于ATPCS的详细内容
, }. S  k. ~9 N& N
1 w# g6 ~+ s9 C. i& ?( z5 H8 B可以查看ADS1.2 Online Books ——Developer Guide的2.1节。这篇文档要讲的是 汇编代码中对C函数调用时如5 g! r; S# j/ f
6 u2 o' D  x/ h9 y
何进行参数的传递以及如何从C函数正确返回
3 J- g) i5 g$ X不同于x86的参数传递规则,ATPCS建议函数的形参不超过4个,如果形参个数少于或等于4,则形参由
" E2 m9 b& m0 D# h$ \4 R5 S) j. B- I1 X. \  p* Z4 j% M3 [
R0,R1,R2,R3四个寄存器进行传递;若形参个数大于4,大于4的部分必须通过堆栈进行传递。+ o+ g7 E9 c4 M
我们先讨论一下形参个数为4的情况.+ M. }2 O1 @  T( ^  E1 m6 h
实例1:
& U2 \$ I7 A2 otest_asm_args.asm' Y" c- J- [! a4 P3 M9 y0 C' \1 a
//——————————————————————————–
2 ~! e+ v5 x' e6 ?6 z& iIMPORT test_c_args ;声明test_c_args函数
3 t0 u5 v  y& u) s5 }. QAREA TEST_ASM, CODE, READONLY
; f" r2 I6 @# q$ Q% \" f: WEXPORT test_asm_args
0 F6 e0 X' w. o. H+ t' A( Ktest_asm_args+ M: ~+ q4 R9 h
STR lr, [sp, #-4]! ;保存当前lr
/ D6 @% d# A2 [ldr r0,=0×10 ;参数 1$ C$ S, |" @! x
ldr r1,=0×20 ;参数 2
$ m4 E7 P3 @; kldr r2,=0×30 ;参数 38 d, f' U3 U( \" Q2 N# h
ldr r3,=0×40 ;参数 4
5 w% _# g% ]. u) u3 vbl test_c_args ;调用C函数
" Y5 d9 [# p8 SLDR pc, [sp], #4 ;将lr装进pc(返回main函数)
$ ]  k$ {1 K' P' j% W9 h/ s/ W% vEND6 K2 x; v& N0 a* @: y
test_c_args.c; d* C: l# e! e. O
//——————————————————————————–
8 ^. K- C1 C/ c) t- U. ovoid test_c_args(int a,int b,int c,int d)
' C! Q& `, r3 w{
# S7 a6 `2 _! q/ Y9 o7 p) Mprintk(“test_c_args:\n”);
- ?& X  ^6 D+ L1 C4 ^, {printk(“%0x %0x %0x %0x\n”,a,b,c,d);
0 d# P. P  n. S+ I2 _- O}
* i" e# F" J: n$ rmain.c
7 v- j6 _2 X4 b# @5 G//——————————————————————————–
# a% R; T  x! D' T3 z/ B& T( O, j3 eint main()
! j' f2 X3 a* d& a9 b" O{
! [- g; U! A9 n  _test_asm_args();( o! E0 \6 B3 n2 K$ q/ u
for(;;);4 E" t, r6 W2 U4 S1 h! E$ Y
}' S. d- u2 k) ]. k* X& m* Z
程序从main函数开始执行,main调用了test_asm_args,test_asm_args调用了test_c_args,最后从test_asm_args7 K$ b/ ]" G1 J. g

, N9 ]) r8 l! x  {0 `+ f0 k返回main.
' Q& o+ h: V6 L4 \代码分别使用了汇编和C定义了两个函数,test_asm_args 和 test_c_args,test_asm_args调用了test_c_args,
; _! R5 g  L# a5 _& W
& V& D$ R; Q2 y( U; Q) ~其参数的传递方式就是向R0~R3分别写入参数值,之后使用bl语句对test_c_args进行调用。其中值得注意的地" ?+ H6 Z+ t5 d, V3 `% M
* y4 n! N1 u! Y; N% `$ C
方是用红色标记的语句,test_asm_args在调用test_c_args之前必须把当前的lr入栈,调用完test_c_args之后/ l1 E+ W; K3 g: C/ v- a7 v

6 y& X& I) @- x$ o0 P, Y3 Q再把刚才保存在栈中的lr写回pc,这样才能返回到main函数中。
# n" a/ W7 D2 i. S/ z. `如果test_c_args的参数是8个呢?这种情况test_asm_args应该怎样传递参数呢?5 Y7 V+ ~% ^- t" Y; E- k5 A
实例2:
+ I2 k4 J8 ]% |3 f7 Ktest_asm_args.asm
2 ^3 x9 r! ]( Z! \//——————————————————————————–
" R8 K" X: E4 N9 b, B# h$ XIMPORT test_c_args ;声明test_c_args函数
3 ~2 A: I; Y$ y5 ]AREA TEST_ASM, CODE, READONLY6 h' D7 h1 P4 P/ _2 N* o7 Y' W
EXPORT test_asm_args5 J" O( ?2 d4 M' k. a" D4 }% L) L
test_asm_args8 y  g" v- u" J+ F! c
STR lr, [sp, #-4]! ;保存当前lr7 s  u; ^2 F: a. X1 s8 y  v4 g( H' ?
ldr r0,=0×1 ;参数 1
, [9 B' q0 Q# U& X! g+ kldr r1,=0×2 ;参数 2
; P: L, p9 e- Hldr r2,=0×3 ;参数 3$ S+ B' }) }4 m
ldr r3,=0×4 ;参数 4% d; Q7 r5 V! _0 H* G$ q* s
ldr r4,=0×8" Y5 o  a- ^: C$ E& k: Y4 A
str r4,[sp,#-4]! ;参数 8 入栈
# |* @" y1 a& G4 lldr r4,=0×7  I8 k% t7 l$ k+ V( j: I3 v+ f
str r4,[sp,#-4]! ;参数 7 入栈
! ^! y. E& [7 {( Nldr r4,=0×6, i6 x* T* w8 |& N8 ~3 ]
str r4,[sp,#-4]! ;参数 6 入栈) ?3 S, `- |/ |2 W. \
ldr r4,=0×5
/ L# w; S3 G9 k0 [/ d# Qstr r4,[sp,#-4]! ;参数 5 入栈1 a' l& v/ R$ ~
bl test_c_args_lots8 x& k6 w' j8 N" M4 F# H( \& M
ADD sp, sp, #4 ;清除栈中参数 5,本语句执行完后sp指向 参数6$ `; a0 F5 m0 b4 l% O  C- g
ADD sp, sp, #4 ;清除栈中参数 6,本语句执行完后sp指向 参数7
  I6 o9 c# K9 o( R! C+ @# n4 r, V' [ADD sp, sp, #4 ;清除栈中参数 7,本语句执行完后sp指向 参数87 e, u' x4 c! y6 j: C
ADD sp, sp, #4 ;清除栈中参数 8,本语句执行完后sp指向 lr
" U0 S0 j4 W  U9 p( FLDR pc, [sp],#4 ;将lr装进pc(返回main函数)$ _+ F! z6 G$ O9 F
END1 j1 B. P7 N3 W7 \
test_c_args.c
: X7 D$ A$ n% e1 d1 @1 m//——————————————————————————–
+ F1 a0 M5 t" {, u. Svoid test_c_args(int a,int b,int c,int d,int e,int f,int g,int h)
5 j. C9 \+ M# W% j( c{
$ v- q  ~) F, Z: z5 I9 sprintk(“test_c_args_lots:\n”);
8 [  |+ _. E5 G) \printk(“%0x %0x %0x %0x %0x %0x %0x %0x\n”,
  w9 y% h4 B6 G2 {% A$ D
! l) O4 Q, k0 \a,b,c,d,e,f,g,h);
& W6 }1 z, M8 Q}4 X& s. d: W$ y! o/ h$ j' g
main.c, H. [% q2 W! w5 u6 A: K1 _
//——————————————————————————–/ @: h' @( ^+ T9 n+ i3 z
int main()
2 G$ V) D/ [$ k5 r# I, e: M& w{
; y- A/ l* n! r2 S, t1 ttest_asm_args();" b/ {" D- E6 M/ |
for(;;);6 F  m5 _3 ^: J7 M
}
3 r7 d4 o, Z* _+ c- _这部分的代码和实例1的代码大部分是相同的,不同的地方是test_c_args的参数个数和test_asm_args的参数传
! k: ~: m7 E5 k2 c% r. ^7 v3 c( m( t8 L2 i; @' @( m: p$ P
递方式。+ Z! n2 g& ]/ U3 d
在test_asm_args中,参数1~参数4还是通过R0~R3进行传递,而参数5~参数8则是通过把其压入堆栈的方式进
8 `* P% q$ g* v! y" c  i3 q
7 }( }6 S( l; z1 n. R4 X; u行传递,不过要注意这四个入栈参数的入栈顺序,是以参数8->参数7->参数6->参数5的顺序入栈的。
' T6 F* M! B$ Q0 P. F  i5 {直到调用test_c_args之前,堆栈内容如下:& _; M- ?3 b4 c% P
sp->+———-+& J3 Y$ _7 Z" X/ l  _9 j8 i
| 参数5 |
9 |/ z" l& M9 q* E7 N7 L+———-+
- Y" u4 m) I- a% W3 c| 参数6 |
' s+ a0 m2 }$ j3 T) h+———-+& m8 c6 N" o, d' C" Q
| 参数7 |
3 P& @7 w, `# d, E) S+———-+
. n: f/ G/ r- C1 T4 [5 t| 参数8 |
  S8 h5 i! W6 q. B) A+ q+———-+, w7 ?% N+ L! d' Q3 a8 l' M
| lr |% g3 D$ Q) _% R- W. X8 ^$ g0 D" j
+———-+1 x, q) i1 v; \
test_c_args执行返回后,则设置sp,对之前入栈的参数进行清除,最后将lr装入pc返回main函数,在执行 LDR
; [! T; Y2 v* @6 C& ?% R
' i. r$ M: I3 Mpc, [sp],#4 指令之前堆栈内容如下:
  O( O) R/ G2 i! H. b7 M* j+———-+
5 k. Q8 I+ R' k6 R; T) K8 y, k5 B) H# G| 参数5 |0 q! f, _  O, F* }+ d% E; l* k
+———-+, U4 C6 W( }* e, D3 [+ q" t
| 参数6 |
1 Z& G# L5 N- `& U* A5 P' S+———-+1 X& T+ d5 O/ w7 B  g& ?
| 参数7 |
8 n2 P: r. j% k+ q+———-+' J# T, P- B1 x$ C
| 参数8 |
/ h9 s- b4 \0 m' D/ K3 _) nsp->+———-++ x4 G3 x: J2 [5 Q1 V9 J
| lr |1 D9 q5 ], R: M, f
+———-+
  • 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-25 00:09 , Processed in 0.171875 second(s), 25 queries , Gzip On.

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

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

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