开发Arm程序的时候,大多数时候使用C/C++语言就可以了,但汇编语言在某些情况下能够实现一些C语言无法实现的功能,这时候就要调用一些汇编语言的程序.我们需要大概了解一下在C语言中如何嵌入汇编语言.* b& ]& ]( V9 Y+ N: H 1 g8 }; H: o, z+ W1 n V内嵌汇编语法如下: ) w3 S/ H0 r" b0 h9 e $ [9 n" K3 j7 h& B __asm__ __volatile__ (汇编语句模板: 输出部分: 输入部分: 破坏描述部分) t) g1 S! r9 y* L# H 共四个部分:汇编语句模板,输出部分,输入部分,破坏描述部分,各部分使用“:”格开,汇编语句模板必不可少,其他三部分可选,如果使用了后面的部分,而前面部分为空,也需要用“:”格开,相应部分内容为空。例如: ! ]' s4 \2 a0 ]' Q q __asm__ __volatile__("cli": : :"memory") 1 d; K5 h8 G, y) _* L9 w5 Y5 X, g/ B' i+ G 1、汇编语句模板 ( `/ c" q% U8 X1 r: N, i9 S 汇编语句模板由汇编语句序列组成,语句之间使用“;”、“\n”或“\n\t”分开。指令中的操作数可以使用占位符引用C语言变量,操作数占位符最多10个,名称如下:%0,%1,…,%9。指令中使用占位符表示的操作数,总被视为long型(4个字节),但对其施加的操作根据指令可以是字或者字节,当把操作数当作字或者字节使用时,默认为低字或者低字节。对字节操作可以显式的指明是低字节还是次字节。方法是在%和序号之间插入一个字母,“b”代表低字节,“h”代表高字节,例如:%h1。 + E& v& N" ?0 a# j8 C* c4 X4 o 3 e7 N! ]0 z1 P. }# T3 U. p: n 2、输出部分 : S t9 v, B* M) P 输出部分描述输出操作数,不同的操作数描述符之间用逗号格开,每个操作数描述符由限定字符串和C 语言变量组成。每个输出操作数的限定字符串必须包含“=”表示他是一个输出操作数。 6 l5 f8 ?: J6 ~# T! D% l1 _ 例: + N* K& _; j2 \+ A6 u% N __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x) ) ) `0 i( Z7 [+ L/ U描述符字符串表示对该变量的限制条件,这样GCC 就可以根据这些条件决定如何分配寄存器,如何产生必要的代码处理指令操作数与C表达式或C变量之间的联系。 : ~5 e) ^4 _% P' [$ U- S* z * {/ q I! h, g, E4 ?; h* b2 R3、输入部分 1 O4 d# ~0 m! d2 Z, Z输入部分描述输入操作数,不同的操作数描述符之间使用逗号格开,每个操作数描述符由限定字符串和C语言表达式或者C语言变量组成。 % G+ b" k/ l# v* R% {例1 : 3 G5 y( j, V/ i5 g! u __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); - L0 @" |+ @1 s+ ?$ X' h7 n' y& h% C- d 先小试牛刀从最简单的的delay函数开始分析:( I' }7 M) \5 A2 _: U0 I static inline void delay (unsigned long loops) + d4 `* {+ R! a# ]5 S7 y' t( z+ L{ " j/ u4 E) o0 u/ q( G7 k" Y* y __asm__ volatile ("1:\n"; W/ a! d6 k2 Q1 `! W "subs %0, %1, #1\n"* K1 ^8 s; ~2 }! h" Z3 W8 g "bne 1b":"=r" (loops):"0" (loops)); / R1 ~; I/ j. O- [}( X( i* s* I& p9 f' {2 P4 ` 先看下上述代码反汇编出来的结果是啥样的:. s C9 m0 `/ {/ h static inline void delay (unsigned long loops) . S) X- h' e) s. M) a# Q0 G{6 P' `- g3 Q& z1 ], k __asm__ volatile ("1:\n"+ s n f1 D8 w% e& K" U "subs %0, %1, #1\n" T1 ^2 s1 x+ ~! q "bne 1b":"=r" (loops):"r" (loops));& l% U! F5 R1 d7 s6 G } 1 c! j9 _1 X, ]- q 4 L, n0 ?$ D7 u9 Avoid main(void) + `* h/ v0 v. v: z. D) I6 T8 c+ f& s{: G2 ?' D7 I( C! J: q8 i: @5 a delay(2000);& y" C1 ]! ~, M1 e! x } " ~2 B' J. p* P4 @' U% r _' e" A " j S. a( r$ m" ]& {0 C2 J6 w$ d: v9 e1 F8 M8 c 000103e8 <delay>: 8 H( t1 O, _* U+ Q. R& G `5 c 103e8: e52db004 push {fp} ; (str fp, [sp, #-4]!) ( \# }9 k, O5 a2 P3 h7 B, d* Y 103ec: e28db000 add fp, sp, #0 /* fp指向当前栈的栈顶 */ . @. F' ?! k$ O9 m! w 103f0: e24dd00c sub sp, sp, #123 l7 n: [. C% `9 E5 H6 x! j1 m 103f4: e50b0008 str r0, [fp, #-8] /* loops 入栈 */ 3 s- b" ^6 z/ ~$ H6 ], r 103f8: e51b3008 ldr r3, [fp, #-8] /* loops值保存至r3寄存器 */ 7 h( K% q) k& [' W q3 k9 C3 e! ` 103fc: e2533001 subs r3, r3, #1 1 W9 l5 K' _( l: I- o0 K7 @4 | | 10400: 1afffffd bne 103fc <delay+0x14>) p' X; G |( j" ]/ U4 I% z 10404: e50b3008 str r3, [fp, #-8] /* 将loops 值写回r0,此函数无返回值这么做个人认为意义不大*/; w4 u4 E/ N q+ z3 J! ]1 q 10408: e1a00000 nop ; (mov r0, r0)* B% D8 T, s6 G! \' o 1040c: e24bd000 sub sp, fp, #0 /* 恢复sp寄存器的值 */ g; y" o$ w, ~0 e: V0 H) D 10410: e49db004 pop {fp} ; (ldr fp, [sp], #4)% S# ]6 _' J. D 10414: e12fff1e bx lr, V. ?; F5 A; W; ]3 P- P0 ^, X 2 m1 | f- z1 h/ |00010418 <main>:# ^7 X# m) s) C( w 10418: e92d4800 push {fp, lr} & S" v7 Z# c9 z, y; M% n 1041c: e28db004 add fp, sp, #4 1 }# m$ P4 f. y 10420: e3a00e7d mov r0, #2000 ; 0x7d07 t0 @4 O3 T2 s% r; ?4 R7 f. T 10424: ebffffef bl 103e8 <delay>" @1 e9 j0 T9 J0 ] 10428: e1a00000 nop ; (mov r0, r0) * M/ S4 O( s/ D5 q' s( A 1042c: e8bd8800 pop {fp, pc}! ?: g4 V& R0 z 不知道大家对上述的输入部和输出部的概念是否清晰,不过个人刚接触的时候确实是迷糊的,在网上找到如下解释,感觉还是很清晰的。 ( f7 {' z; f- |0 z; Cfsinx:汇编指令名%1, %0:汇编指令操作数“=f”(result):操作数%0是一个浮点寄存器,与变量result关联(对输出操作数,“关联”的意思就是说gcc执行完这条汇编指令后会把寄存器%0的内容送到变量result中)“f”(angle):操作数%1是一个浮点寄存器,与变量angle关联(对输入操作数,“关联”的意思是就是说gcc执行这条汇编指令前会先将变量angle的值读取到寄存器%1中)% T/ C' M5 }8 P stack frame 5 u3 ?8 [* b Y# I$ Q* b* H% Fstack我们都知道,每一个进程都有自己的栈。考虑进程执行时发生函数调用的场景,母函数和子函数使用的是同一个栈,在通常的情况下,我们并不需要区分母函数和子函数分别使用了栈的哪个部分。但是,当我们需要在执行过程中对函数调用进行backtrace的时候,这一信息就很重要了。 - p/ ]8 b+ z, }- u简单的说,stack frame就是一个函数所使用的stack的一部分,所有函数的stack frame串起来就组成了一个完整的栈。stack frame的两个边界分别由FP和SP来限定。 8 w y3 w s' ]& j) E! d (, 下载次数: 18) 上传 点击文件名下载附件 & o2 V2 \9 U! Z上述的简单的示例,输入部和输出部都对应传入的loops变量,根据反汇编的结果期待的结果也一直,暂时先写个最简单的内嵌汇编,后续慢慢研究更复杂的使用场景。- W( P4 o! e" b6 N# b4 ~" {7 q0 R & s$ L' k; {" x 以下代码是armv7-m 屏蔽中断的的内嵌汇编的代码' ^/ F- ^% G4 m9 | : u0 Q' }9 ?1 Y0 e* q. z #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY) h/ z% O0 r6 X4 \) J! S #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) 5 C) d$ D( P" N) u/ T0 _ #endif 0 h; x: b+ w3 E& c: }* K8 _ #define SEGGER_RTT_LOCK() { \5 I! I6 |7 ]1 r$ @4 n$ V unsigned int LockState; \; V3 d! X$ @* N0 N- j6 ] __asm volatile ("mrs %0, basepri \n\t" \# a; P7 y3 U$ b1 Z8 | "mov r1, %1 \n\t" \" }2 P% L9 i" ?+ Z8 J8 v$ S! [8 D; ` "msr basepri, r1 \n\t" \ 2 G! Q) b/ |9 O' I6 _ : "=r" (LockState) \ ; k/ V2 \; A- J- q# ]+ {5 r$ O : "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \ % e4 V: U& N7 b6 Z# } : "r1" \ : i9 U) S' z5 T6 \ ); . Y7 i& N) _1 ^, e2 J$ U8 k . q5 u" I2 M; e5 l #define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \* i# v+ P# A {) a4 o : \ % X* X9 T0 |0 M5 ]% f : "r" (LockState) \ ' ?! n' |8 i" B# X$ y : \ 1 @5 v* L" @4 ^, e0 I' {. \: s, i ); \ Z" t! ]' a1 O( Q$ p6 D: D" P; v }复制代码根据之前的理解,我们分析下SEGGER_RTT_LOCK 函数。输出部:LockState 代表0%,修饰符号为"=r"说明这个c语言变量LockState需要分配个寄存器并且该变量的值会被更新。" @) r- O& R# X( Z1 ~& \% `9 s; ^ 输入部:"i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) 声明1%代表的是个立即数。+ q9 W# J" _4 @4 i 损坏部:"r1" 说明该段内嵌汇编使用到r1寄存器 & p5 E6 D4 y5 l5 Z5 ^3 A . L! f$ _" Q* W我们反汇编输出下上述代码转化为真正的汇编代码如下:- Y( D) [/ J; g 发现:LockState c变量分配了R3寄存器进行保存,最终通过str r3, [r7, #4] 更新了变量LockState 的值,达到了读取basepri寄存器并保存至LockState 变量的目的,mov.w r1, #32 代码保存立即数至r1寄存器,反汇编的代码也使用了r1寄存器,跟之前的分析也是一致的。5 s/ Q9 s# t$ S4 x. u2 l- k SEGGER_RTT_LOCK(); . ?- N+ X( Q) J G" A 93e2: f3ef 8311 mrs r3, BASEPRI : r7 T. B% G# t. H: a9 E% T1 C- j 93e6: f04f 0120 mov.w r1, #32 ! ?9 u7 [) p1 ] 93ea: f381 8811 msr BASEPRI, r1 0 ~$ t* o* z& ^+ a; m 93ee: 607b str r3, [r7, #4]复制代码SEGGER_RTT_UNLOCK() 的代码只有一个输入部,将 c变量LockState 的值分配寄存去存储,根据如下的代码读取该变量的值至r3寄存器,之后通过r3恢复BASEPRI寄存器的内容。 # R/ L" o; T" |! N: V, h5 b3 [; h3 k4 ~& y! ?, L SEGGER_RTT_UNLOCK() 7 n* |' d. K( P: j- L 93f6: 687b ldr r3, [r7, #4] * l Z( H. ?) T8 o 93f8: f383 8811 msr BASEPRI, r3复制代码 $ m# A4 N+ A: X+ k+ `) Z' W! w7 X8 f/ R' P , `& E) y4 s/ i: z) o, W2 W- p