嵌入式編程:C與彙編的混用

來源:互聯網
上載者:User

標籤:

主要參考:《深度探索嵌入式作業系統》 5.4節

??

為什麼要嵌入組合語言?

開關CPU中斷、

讀取CPU的一些特殊寄存器、

設定CPU模式等功能無法用C語言實現(因為C語言屬於進階語言,而進階語言是屏蔽底層硬體的)。

提高速度?好像是有這麼一種目的,還不太清楚。

??

【代碼模板】

__asm__ __volatile__ (

"代碼部分" 冒號是分隔字元,如果是有彙編代碼部分,則冒號可以省略

:輸出部分列表 如果沒有輸入列表,冒號也是必須加的

:輸入部分列表

:損壞部分列表);

asm volatile();

??

C語言中嵌入彙編代碼的執行個體:

__asm__ __volatile__( : : : "memory");

// 告訴GCC記憶體中的資料可能發生了改變了,要回寫寄存器了,這是為了達到防止GCC過度最佳化帶來問題的目的

??

C語言中嵌入彙編代碼的加法函數:

1 intadd(int a1,int a2)

2 {

3 ????????int sum;

4 ????????__asm__ __volatile__(

5 ????????????????"add %[sv1], %[av1], %[av2]\n\t"

6 ????????????????: [sv1]"=r"[sum]

7 ????????????????: [av1]"r" (a1), [av2]"r" (a2)

8 ????????????????:"r4","cc","memory"

9 ????????);

10 ????????return sum;

11 }

輸入列表用逗號分隔:相當於管理C語言變數和組合語言變數

[條目名稱] "儲存類型"(C語言運算式) 因為C語言裡的變數此時要用組合語言來操作,所以要指定分配的類似,儲存類型

"r" 通用寄存器

"m" 表示後面的C運算式是記憶體位址

"I" 表示後面的C運算式是常數

更多見GCC手冊

??

輸出資料行表:

[條目名稱] "=限定符"(C語言運算式)

"=r"(sum) 表示讓GCC給sum分配一個寄存器,只不過是用於輸出計算的

??

損壞列表部分:告訴GCC這些寄存器需要產生代碼來儲存和恢複,還有記憶體中的資料可能發生改變

"寄存器"

"cc" CPU標誌寄存器

"memory"

??

指令部分:

指令部分由引號包含的,"\n\t"即分行符號和定位字元,完全是為了讓GCC格式化輸出彙編代碼的。

add %[sv1], %[av1], %[av2],為什麼不直接使用寄存器呢?當然是可以的,但這裡使用條目名主要是為了讓GCC能動態分配寄存器、最佳化代碼,也就是好比在組合語言裡面我們可以定義變數了,而原來我們寫組合語言的時候,是直接使用寄存器的,此處相當於通過GCC使彙編編程更加進階。

比如,代碼 add %[sv1], %[av1], %[av2], 一般情況下會被GCC處理成代碼 add r0, r0, r1,這是不是比直接寫原始的純彙編代碼進階得多了。

??

【例子解讀】

讀取CPU標誌寄存器:也就是在C語言編程過程中,我們可以像調用C函數來使用只有組合語言才能完成的功能了:

1 cpuflg_t hal_read_cpuflg()

2 {

3 ????cpuflg_t cpuflg;

4 ????__asm__ __volatile__(

5 ????????"mrs %[retcpr], cpsr\n\t"

6 ????????: [retcpr]"=r"(cpuflg) 有一個輸出條目[retcpr],關聯一個分配一個通用寄存器給他的變數,這個條目本質上其實C語言變數在彙編世界裡的代言人,最後C語言直接問cpuflg取值,而[retcpr]就負責在彙編世界管理它

7 ????????:

8 ????????:"cc","memory"

9 ????);

10 ????return cpuflg

11 }

理想情況下這行代碼"mrs %[retcpr], cpsr \n\t"會被GCC處理成"mrs r0, cpsr \n\t",而r0寄存器正是GCC用來存放函數傳回值的,

最後嵌入式彙編代碼模板的損壞部分高速gcc,CPU的標誌寄存器可能損壞,記憶體中的值可能發生改變(但是這部分的處理方式就不需要C程式員關心了,暫時也不必關係)

??

開關ARM920T CPU中斷的函數:讀(到某個寄存器中) > 改 > 寫(把寄存器回寫)

??

CPU中開關中斷是通過設定CPU上的CPSR寄存器中的相關位來實現的,代碼中的CIRQFIQ是個宏,會被GCC預先處理時,替換成常數0xc0.

從上面的代碼的輸入條目中它前面的限定符"I"可以告訴GCC,CIRQFIQ是一個常數。GCC會根據這個常數的大小決定把它分配在寄存器(寄存器本質上其實和記憶體差不多,區別在於訪問速度極快以及可能有約定的儲存作用)中或者直接放在指令編碼資料(要滿足存放立即數的條件)中。並且會在__asm__ __volatile__()中的指令執行之前,產生相關代碼處理好這個問題。

損壞部分:這裡C語言其實沒有輸出變數的,也沒有中間變數,所以彙編代碼部分之間使用寄存器了r0,因為代碼中用到了r0、CPSR寄存器,所以要在代碼模板的損壞部分寫上r0(讓GCC在__asm__ __volatile__()中的指令執行之前,產生儲存r0寄存器中的值的相關代碼,一遍在其後恢複到r0寄存器中,可見GCC是先整體分析嵌入部分,然後在處理彙編代碼部分)。

??

??

嵌入式編程:C與彙編的混用

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.