歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

ARM匯編與C混合編程

GNU內聯匯編

內聯匯編即在C中直接使用匯編語句進行編程,使程序可以在C程序中實現C語言不能完成的一些工作,例如,在下面幾種情況中必須使用內聯匯編或嵌入型匯編

  1. 程序中使用飽和算術運算(Saturating Arithmetic)
  2. 程序需要對協處理器進行操作
  3. 在C程序中完成對程序狀態寄存器的操作
__asm__ __volatile__("asm code":output:input:changed registers);

Note:

  1. 使用__asm____volatile__表示編譯器將不檢查後面的內容,而是直接交給匯編器。
  2. 如果希望變壓器你優化,__volatile__可以不加
  3. 沒有asm code也不能省略""
  4. 沒有前面的和中間的部分,不可以相應的省略:
  5. 沒有changed 部分,必須相應的省略:
  6. 最後的;不能省略,對於C語言來說這是一條語句
  7. 匯編代碼必須放在一個字符串內,且字符串中間不能直接按回車換行,可以寫成多個字符串,注意中間不能有任何符號,這樣就會將兩個字符串合並為一個
  8. 指令之間必須要換行,還可以使用\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

  1. 子程序間通過寄存器R4~R11來傳遞參數,如果參數多於四個,則多出的部分用堆棧傳遞,被調用的子程序在返回前無須恢復寄存器R0~R3的內容
  2. 在子程序中,使用寄存器R4~R11來保存局部變量,如果在子程序中使用到了R4~R11中的某些寄存器,子程序進入時必須保存這些寄存器的值,在返回前必須恢復這些寄存器的值;對於子程序中沒有用到的寄存器則不必進行這些操作,在Thumb程序中,通常只能使用寄存器R4~R7來保存局部變量
  3. R12用作子程序間scrtach寄存器(用於保存SP,在函數返回時使用該寄存器出棧),記作ip
  4. R13用作數據棧指針,記作sp
  5. R14用作連接寄存器,記作lr
  6. 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

Copyright © Linux教程網 All Rights Reserved