GNU內聯彙編 內聯彙編 即在C中直接使用彙編語句進行編程,使程式可以在C程式中實現C語言不能完成的一些工作,例如,在下麵幾種情況中必須使用內聯彙編或嵌入型彙編 1. 程式中使用飽和算術運算(Saturating Arithmetic) 2. 程式需要對協處理器進行操作 3. 在C程式中完成對程式狀 ...
GNU內聯彙編
內聯彙編即在C中直接使用彙編語句進行編程,使程式可以在C程式中實現C語言不能完成的一些工作,例如,在下麵幾種情況中必須使用內聯彙編或嵌入型彙編
- 程式中使用飽和算術運算(Saturating Arithmetic)
- 程式需要對協處理器進行操作
- 在C程式中完成對程式狀態寄存器的操作
__asm__ __volatile__("asm code":output:input:changed registers);
Note:
- 使用
__asm__
和__volatile__
表示編譯器將不檢查後面的內容,而是直接交給彙編器。 - 如果希望變壓器你優化,
__volatile__
可以不加 - 沒有asm code也不能省略
""
- 沒有前面的和中間的部分,不可以相應的省略
:
- 沒有changed 部分,必須相應的省略
:
- 最後的
;
不能省略,對於C語言來說這是一條語句 - 彙編代碼必須放在一個字元串內,且字元串中間不能直接按回車換行,可以寫成多個字元串,註意中間不能有任何符號,這樣就會將兩個字元串合併為一個
- 指令之間必須要換行,還可以使用
\t
使指令在彙編中保持整齊
asm code
"mov r0, r0\n\t"
"mov r1,r1\n\t"
"mov r2,r2"
output(asm->C)
:"constraint" (variable)
"constraint"
用於定義variable的存放位置:
r
表示使用任何可用的寄存器
m
表示使用變數的記憶體地址
+
可讀可寫
=
只寫
&
表示該輸出操作數不能使用輸入部分使用過的寄存器,只能用"+&"
或"=&"
的方式使用
input(C->asm)
:"constraint" (variable/immediate)
"constraint"
用於定義variable的存放位置:
r
表示使用任何可用的寄存器(立即數和變數都可以)
m
表示使用變數的記憶體地址
i
表示使用立即數
例子
int a=100,b=200;
int result;
__asm__ __volatile__(
"mov %0,%3\n\t" //%0是一個占位符,表示result,之後的類推
"ldr r0,%1\n\t"
"ldr r1,%2\n\t"
"str r0,%2\n\t"
"str %1,%1\n\t"
:"=r"(result),"+m"(a),"+m"(b)
:"i"(123)
);
ATPCS
- 子程式間通過寄存器R4~R11來傳遞參數,如果參數多於四個,則多出的部分用堆棧傳遞,被調用的子程式在返回前無須恢復寄存器R0~R3的內容
- 在子程式中,使用寄存器R4~R11來保存局部變數,如果在子程式中使用到了R4~R11中的某些寄存器,子程式進入時必須保存這些寄存器的值,在返回前必須恢復這些寄存器的值;對於子程式中沒有用到的寄存器則不必進行這些操作,在Thumb程式中,通常只能使用寄存器R4~R7來保存局部變數
- R12用作子程式間scrtach寄存器(用於保存SP,在函數返回時使用該寄存器出棧),記作ip
- R13用作數據棧指針,記作sp
- R14用作連接寄存器,記作lr
- R15記作程式寄存器,記作pc
相互調用
C和彙編相互調用要特別註意遵守相應的ATPCS規則
C調用彙編
//.c
#include <stdio.h>
extern void strcopy(char* des, const char* src);
int main(){
const char* srcstr = "src string";
char desstr[]="des string";
strcopy(desstr, srcstr);
return 0;
}
;.asm
.global strcopy
strcopy: ;R0指向目的字元串
;R1指向源字元串
LDRB R2, [R1], #1 ;載入位元組並更新源字元串指針地址
STRB R2, [R0], #1 ;存儲季節並更新目的字元串指針地址
CMP R2, #0 ;判斷是否為字元串結尾
BNE strcopy ;如果不是,程式跳轉到strcopy繼續迴圈
MOV pc, ir ;程式返回
彙編調用C
//.c
int fcn(int a, int b , int c, int d, int e){
return a+b+c+d+e;
}
;.asm
;假設程式進入f時,R0中的值為i
;int f(int i){return fcn(i, 2*i, 3*i, 4*i, 5*i);}
.text
.global _start
_start:
STR lr, [sp, #-4]! ;保存返回地址lr
ADD R1, R0, R0 ;計算2*i(第2個參數)
ADD R2, R1, R0 ;計算3*i(第3個參數)
ADD R3, R1, R2 ;計算5*i
STR R3, [SP, #-4]! ;第5個參數通過堆棧傳遞
ADD R3, R1, R1 ;計算4*i(第4個參數)
BL fcn ;調用C程式
ADD sp, sp, #4 ;從堆棧中刪除第五個參數
.end