Andrew Huang <bluedrum@163.com> 轉(zhuǎn)載請注明作者及出處
一.嵌入式匯編關(guān)健字 asm 在所有C程序中,嵌入式匯編的寫法有asm{} asm(), __asm__ __volatile__ ("");其中asm 和 __asm 含義是一樣的. 而ARM的C編譯器中,主流是兩大類,一類ARM公司出品的ARMCC,另一類用得更廣的是gnu 的匯編,兩者嵌入式匯編語法主和格式,有著很多細(xì)節(jié)微差別,這里主要討論 Gnu格式的.
ARM的嵌入式匯編是沒有引號,用花括號包括進(jìn)來,如下格式,多行之間直接采用回車分隔,語法采用ARM匯編格式.后文將不討論 asm { nop mvn r0,#0 } __voliatie 主要主要讓編譯不要對讀寫進(jìn)行優(yōu)化.
GNU 嵌入式匯編格式,用gcc編譯的匯編必須滿足如下格式 - 一般以 __asm __volatile打頭,用()包括起來,
- 每句語句用""包括起來
- 多語句之間用 \n或\nt分隔
- 專用寄存器用%%的打頭表示,
以下就是一個簡單的嵌入式匯編格式 - __asm__ __volatile__ (
-
"mov %0, #55\n"
-
"mov %1, #66\n"
- "xor %%eax, %%eax\n"
-
)
- asm(
-
"mov r0, r0\n\t"
-
"mov r0, r0\n\t"
-
"mov r0, r0\n\t"
-
"mov r0, r0"
-
);
關(guān)于嵌入式匯編,可以參見如下文章 <<ARM GCC Inline Assembler Cookbook>> <<Using Inline Assembly With gcc>> 二.嵌入式匯編與C的數(shù)據(jù)交互
一般嵌入式匯編是一段特定代碼,因此有可以從C語言變量中讀取數(shù)據(jù),或者把處理后的數(shù)據(jù)交給C程序.
2.1 從C變量取值. 一般是從局域變量中取值,按定義的先后,用%0到%9表示,最多10個變量. 比如下代碼 asm("add %1,%2"); 2.2 向C程序返回結(jié)果. 這里要用更復(fù)雜的分段式表達(dá)式.完整的嵌入式匯編分為四大部分: 匯編代碼部分(code),輸出部分(output operand list ),輸入部分(input operand list ),破壞段(clobber list)部分,每一部分用":"分開. 其中匯編語句段就一般的匯編指令,可以是多句.
其中輸出部分即是向C變量賦值的部分. 我們看如下示例 asm("mov %0, %1, ror #1" : "=r" (result) : "r" (value)); 這里的語句部分是 "mov %0,%1,ror 1",這里把%1的值賦給%0,并且與1作位與.
:后是輸出部 "=r(result)", 而且"r" (value)是輸入部, 這里破壞部省略.
2.3 輸出部格式 在上例中 =r(result), =表示只用輸出,r表示通用寄存器的值賦給變量,result表示輸出C變量名字. 這個"=r(result)"的完整意思是把結(jié)果賦給result. 其中除 =外,還有其它保留字 - = 只寫/輸出變量
- + 可讀可寫變量
- & 該輸出操作數(shù)不能使用輸入操作數(shù)相同的寄存器
而輸出部的關(guān)健字除r外,還有其它很多.它們用來表示輸出變量與前一部分語句中操作寄存器的關(guān)系, r 把r0~r15的值賦給變量 f 使用浮點(diǎn)的寄存器f0~f15 m 任意內(nèi)存地址 a, b.c d 表示要求使用寄存器eax/ax/al, ebx/bx/bl, ecx/cx/cl或edx/dx/dl
這里有一個完整的表格 Constraint | Usage in ARM state | Usage in Thumb state | f | Floating point registers f0 .. f7 | Not available | h | Not available | Registers r8..r15 | G | Immediate floating point constant | Not available | H | Same a G, but negated | Not available | I | Immediate value in data processing instructions e.g. ORR R0, R0, #operand | Constant in the range 0 .. 255 e.g. SWI operand | J | Indexing constants -4095 .. 4095 e.g. LDR R1, [PC, #operand] | Constant in the range -255 .. -1 e.g. SUB R0, R0, #operand | K | Same as I, but inverted | Same as I, but shifted | L | Same as I, but negated | Constant in the range -7 .. 7 e.g. SUB R0, R1, #operand | l | Same as r | Registers r0..r7 e.g. PUSH operand | M | Constant in the range of 0 .. 32 or a power of 2 e.g. MOV R2, R1, ROR #operand | Constant that is a multiple of 4 in the range of 0 .. 1020 e.g. ADD R0, SP, #operand | m | Any valid memory address | N | Not available | Constant in the range of 0 .. 31 e.g. LSL R0, R1, #operand | O | Not available | Constant that is a multiple of 4 in the range of -508 .. 508 e.g. ADD SP, #operand | r | General register r0 .. r15 e.g. SUB operand1, operand2, operand3 | Not available | w | Vector floating point registers s0 .. s31 | Not available | X | Any operand
|
常見實(shí)例 :"=&r" (__val), "=m" (*mem) 2.4 輸入部分格式 可以看是輸入變量的聲明,格式:關(guān)系關(guān)健字(變量名) ,關(guān)系關(guān)健字與輸入段類型,,所以這一個段經(jīng)常可以省略. 如 r(result) 可以還可以加上%的限定,表示可以變量對應(yīng)的%0,%1之類變量可以交換位置,比如add加數(shù),放前放后均可. :"r"(result) 表示%0是C變量result的值 : "%r"(x),"r"(y) 還有常量0表示與第一個輸出數(shù)相同 如下示例 asm("mov %0, %0, ror #1" : "=r" (value) : "0" (value))
2.5 破壞段(clobber list)格式 表示匯編代碼產(chǎn)生什么樣后果,一般是"memory",表示內(nèi)存發(fā)現(xiàn)變化 :"memory"
除此之多,還有cc,表示改變條件代碼寄存器(condition code register),如果一個寄存器名字,如r12,表示代碼修改了r12.
參見下面的代碼,其中省略了輸出段和輸入段 - asm volatile("mrs r12, cpsr\n\t"
-
"orr r12, r12, #0xC0\n\t"
-
"msr cpsr_c, r12\n\t" ::: "r12", "cc");
- asm volatile("mrs r12, cpsr\n"
-
"bic r12, r12, #0xC0\n"
-
"msr cpsr_c, r12" :: "X" (c) : "r12", "cc"
- __asm__ __volatile__ (
-
"loop:\n"
-
"ldrb r1, [%0], #1\n"
-
"strb r1, [%1], #1\n"
-
"cmp r1, #0\n"
-
"bne loop\n"
-
:
-
: "r" (a), "r" (b)
-
: "r0", "r1", "memory"
-
);
2.6 使用把匯編代碼段定義成宏 這時建議使用 __asm__來代替 __asm ,__volatile__代替 __valatile,這樣在ANSI C沒有編譯警告 - #define BYTESWAP(val) \
-
__asm__ __volatile__ ( \
-
"eor r3, %1, %1, ror #16\n\t" \
-
"bic r3, r3, #0x00FF0000\n\t" \
-
"mov %0, %1, ror #8\n\t" \
-
"eor %0, %0, r3, lsr #8" \
-
: "=r" (val) \
-
: "0"(val) \
-
: "r3", "cc" \
-
);
2.7 代碼段內(nèi)部標(biāo)簽, 這個可以在一個代碼段使用標(biāo)簽,但是不能從一個段跳到另一個段的標(biāo)簽里.標(biāo)簽用1: 2:這樣的定義方法.用b 語句跳轉(zhuǎn) ,如 bne 1b 參見如下實(shí)例 - #define __arch_compare_and_exchange_val_64_rel(mem, newval, oldval) \
-
({ \
-
__typeof (*(mem)) __tmp; \
-
-
__typeof (mem) __memp = (mem); \
-
-
__asm __volatile (__ARCH_REL_INSTR "\n" \
-
"1: ldarx %0,0,%1" MUTEX_HINT_REL "\n" \
-
" cmpd %0,%2\n" \
-
" bne 2f\n" \
-
" stdcx. %3,0,%1\n" \
-
" bne- 1b\n" \
-
"2: " \
-
: "=&r" (__tmp) \
-
: "b" (__memp), "r" (oldval), "r" (newval) \
-
: "cr0", "memory"); \
-
__tmp; \
-
})
|