ARM中C和彙編混合編程及示例ARM中C和彙編混合編程及示

2021-01-18 電子產品世界
嵌入式系統開發中,目前使用的主要程式語言是C彙編,C++已經有相應的編譯器,但是現在使用還是比較少的。在稍大規模的嵌入式軟體中,例如含有OS,大部分的代碼都是用C編寫的,主要是因為C語言的結構比較好,便於人的理解,而且有大量的支持庫。

儘管如此,很多地方還是要用到彙編語言,例如開機時硬體系統的初始化,包括CPU狀態的設定,中斷的使能,主頻的設定,以及RAM的控制參數及初始化,一些中斷處理方面也可能涉及彙編。另外一個使用彙編的地方就是一些對性能非常敏感的代碼塊,這是不能依靠C編譯器的生成代碼,而要手工編寫彙編,達到優化的目的。而且,彙編語言是和CPU的指令集緊密相連的,作為涉及底層的嵌入式系統開發,熟練對應彙編語言的使用也是必須的。

本文引用地址:http://www.eepw.com.cn/article/201611/317675.htm

單純的C或者彙編編程請參考相關的書籍或者手冊,這裡主要討論C和彙編的混合編程,包括相互之間的函數調用。下面分四種情況來進行討論,暫不涉及C++。

1. 在C語言中內嵌彙編

在C中內嵌的彙編指令包含大部分的ARM和Thumb指令,不過其使用與彙編文件中的指令有些不同,存在一些限制,主要有下面幾個方面:

a. 不能直接向PC寄存器賦值,程序跳轉要使用B或者BL指令

b. 在使用物理寄存器時,不要使用過於複雜的C表達式,避免物理寄存器衝突

c. R12和R13可能被編譯器用來存放中間編譯結果,計算表達式值時可能將R0到R3、R12及R14用於子程序調用,因此要避免直接使用這些物理寄存器

d. 一般不要直接指定物理寄存器,而讓編譯器進行分配

內嵌彙編使用的標記是 __asm或者asm關鍵字,用法如下:

__asm

{

instruction [; instruction]

[instruction]

}

asm(「instruction [; instruction]」);

下面通過一個例子來說明如何在C中內嵌彙編語言,

#include

void my_strcpy(const char *src, char *dest)

{

char ch;

__asm

{

loop:

ldrb ch, [src], #1

strb ch, [dest], #1

cmp ch, #0

bne loop

}

}

int main()

{

char *a = "forget it and move on!";

char b[64];

my_strcpy(a, b);

printf("original: %s", a);

printf("copyed: %s", b);

return 0;

}

  在這裡C和彙編之間的值傳遞是用C的指針來實現的,因為指針對應的是地址,所以彙編中也可以訪問。

2. 在彙編中使用C定義的全局變量

內嵌彙編不用單獨編輯彙編語言文件,比較簡潔,但是有諸多限制,當彙編的代碼較多時一般放在單獨的彙編文件中。這時就需要在彙編和C之間進行一些數據的傳遞,最簡便的辦法就是使用全局變量。

#include

int gVar_1 = 12;

extern asmDouble(void);

int main()

{

printf("original value of gVar_1 is: %d", gVar_1);

asmDouble();

printf(" modified value of gVar_1 is: %d", gVar_1);

return 0;

}

對應的彙編語言文件

;called by main(in C),to double an integer, a global var defined in C is used.

AREA asmfile, CODE, READONLY

EXPORT asmDouble

IMPORT gVar_1

asmDouble

ldr r0, =gVar_1

ldr r1, [r0]

mov r2, #2

mul r3, r1, r2

str r3, [r0]

mov pc, lr

END

3. 在C中調用彙編的函數

在C中調用彙編文件中的函數,要做的主要工作有兩個,一是在C中聲明函數原型,並加extern關鍵字;二是在彙編中用EXPORT導出函數名,並用該函數名作為彙編代碼段的標識,最後用mov pc, lr返回。然後,就可以在C中使用該函數了。從C的角度,並不知道該函數的實現是用C還是彙編。更深的原因是因為C的函數名起到表明函數代碼起始地址的左右,這個和彙編的label是一致的。

#include

extern void asm_strcpy(const char *src, char *dest);

int main()

{

const char *s = "seasons in the sun";

char d[32];

asm_strcpy(s, d);

printf("source: %s", s);

printf(" destination: %s",d);

return 0;

}

;asm function implementation

AREA asmfile, CODE, READONLY

EXPORT asm_strcpy

asm_strcpy

loop

ldrb r4, [r0], #1 ;address increment after read

cmp r4, #0

beq over

strb r4, [r1], #1

b loop

over

mov pc, lr

END

  在這裡,C和彙編之間的參數傳遞是通過ATPCS(ARM Thumb Procedure Call Standard)的規定來進行的。簡單的說就是如果函數有不多於四個參數,對應的用R0-R3來進行傳遞,多於4個時藉助棧,函數的返回值通過R0來返回。

4. 在彙編中調用C的函數

在彙編中調用C的函數,需要在彙編中IMPORT 對應的C函數名,然後將C的代碼放在一個獨立的C文件中進行編譯,剩下的工作由連接器來處理。

;the details of parameters transfer comes from ATPCS

;if there are more than 4 args, stack will be used

EXPORT asmfile

AREA asmfile, CODE, READONLY

IMPORT cFun

ENTRY

mov r0, #11

mov r1, #22

mov r2, #33

BL cFun

END

int cFun(int a, int b, int c)

{

return a + b + c;

}

  在彙編中調用C的函數,參數的傳遞也是通過ATPCS來實現的。需要指出的是當函數的參數個數大於4時,要藉助stack,具體見ATPCS規範。

小結

  以上通過幾個簡單的例子演示了嵌入式開發中常用的C和彙編混合編程的一些方法和基本的思路,其實最核心的問題就是如何在C和彙編之間傳值,剩下的問題就是各自用自己的方式來進行處理。以上只是拋磚引玉,更詳細和複雜的使用方法要結合實際應用並參考相關的資料。

說明

  以上代碼在ADS 1.2的工程中編譯,並在對應的AXD中軟體仿真通過。

在C和彙編混合編程的時候,存在C語言和彙編語言的變量以及函數的接口問題。
在C程序中定義的變量,編譯為.asm文件後,都被放進了.bss區,而且變量名的前面都帶了一個下劃線。在C程序中定義的函數,編譯後在函數名前也帶了一個下劃線。例如:

extern int num就會變成 .bss _num, 1
extern float nums[5]就會變成.bss _nums, 5
extern void func ( )就會變成 _func,

彙編和C的相互調用可以分以下幾種情況:

(1) 彙編程序中訪問c程序中的變量和函數。
在彙編程序中,用_XX就可以訪問C中的變量XX了。訪問數組時,可以用_XX+偏移量來訪問,如_XX+3訪問了數組中的XX[3]。

在彙編程序調用C函數時,如果沒有參數傳遞,直接用_funcname 就可以了。如果有參數傳遞,則函數中最左邊的一個參數由寄存器A給出,其他的參數按順序由堆棧給出。返回值是返回到A寄存器或者由A寄存器給出的地址。同時注意,為了能夠讓彙編語言能訪問到C語言中定義的變量和函數,他們必須聲明為外部變量,即加extern 前綴。

(2) c程序中訪問彙編程序中的變量

如果需要在c程序中訪問彙編程序中的變量,則彙編程序中的變量名必須以下劃線為首字符,並用global使之成為全局變量。

如果需要在c程序中調用彙編程序中的過程,則過程名必須以下劃線為首字符,並且,要根據c程序編譯時使用的模式是stack-based model還是register argument model來正確地編寫該過程,使之能正確地取得調用參數。

(3) 在線彙編

在 C程序中直接插入 asm(「***」),內嵌彙編語句,需要注意的是這種用法要慎用,在線彙編提供了能直接讀寫硬體的能力,如讀寫中斷控制允許寄存器等,但編譯器並不檢查和分析在線彙編語言,插入在線彙編語言改變彙編環境或可能改變C變量的值可能導致嚴重的錯誤。

二 彙編和C接口中尋址方式的改變:

需要注意的是,在C語言中,對於局部變量的建立和訪問,是通過堆棧實現的,它的尋址是通過堆棧寄存器SP實現的。而在彙編語言中,為了使程序代碼變得更為精簡,TI在直接尋址方式中,地址的低7位直接包含在指令中,這低7位所能尋址的具體位置可由DP寄存器或SP寄存器決定。具體實現可通過設置ST1寄存器的CPL位實現,CPL=0,DP尋址,CPL=1,SP尋址。在DP尋址的時候,由DP提供高9位地址,與低7位組成16位地址;在SP尋址的時候,16位地址是由SP(16位)與低7位直接相加得來。

由於在C語言的環境下,局部變量的尋址必須通過SP寄存器實現,在混合編程的時候,為了使彙編語言不影響堆棧寄存器SP,通常的方式是在彙編環境中使用DP方式尋址,這樣可以使二者互不幹擾。編程中只要注意對CPL位正確設置即可。

相關焦點

  • ARM中ADS環境下C語言和彙編語言混合編程及示例
    另外在一些對性能非常敏感的代碼塊,基於彙編與機器碼一一對應的關係,這時不能依靠C編譯器的生成代碼,而要手工編寫彙編,從而達到優化的目的。彙編語言是和CPU的指令集緊密相連的,作為涉及底層的嵌入式系統開發,熟練對應彙編語言的使用也是必須的。這裡主要討論C和彙編的混合編程,包括相互之間的函數調用。下面分四種情況來進行討論,不涉及C++語言。
  • 單片機程序C語言與彙編語言混合編程
    C語言與彙編語言混合編程本文引用地址:http://www.eepw.com.cn/article/201611/322505.htm1.C語言函數和彙編語言函數相互調用在這個示例中C語言函數main()調用彙編語言函數get_rand()以得到一個隨機數;彙編語言函數get_rand()首先調用C語言的標準庫函數rand()得到一個整型隨機值,然後用調用C語言函數mult()的方法把這個隨機值乘以main()函數傳遞給自己的實參,並把乘積值返回給
  • 基於Android的ARM彙編語言系列之二:C/C++程序生成ARM彙編程序
    章節列表之一:ARM彙編語言開篇之二:C/C++程序生成ARM彙編程序的過程分析之三:ARM彙編語言程序結構之四:ARM處理器的尋址方式之五:ARM指令集與Thumb指令集之六:NEON指令集與VFP指令集本文引用地址:http://www.eepw.com.cn
  • C語言與彙編語言混合編程應遵守的規則
    在使用C語言時,要用到和彙編語言的混合編程。若彙編代碼較為簡潔,則可使用直接內嵌彙編的方法;否則要將彙編程序以文件的形式加入到項目中,按照ATPCS(ARM/Thumb過程調用標準,ARM/Thumb Procedure Call Standard)的規定與C程序相互調用與訪問。
  • 有關arm彙編中的align
    經常會看到arm-linux彙編中有如下的指令:.align n它的含義就是使得下面的代碼按一定規則對齊,.align n 指令的對齊值有兩種方案,n 或 2^n ,各種平臺最初的彙編器一般都不是gas,採取方案1或2的都很多,gas的目標是取代原來的彙編器,必然要保持和原來彙編器的兼容,因此在gas中如何解釋 .align指令會顯得有些混亂,原因在於保持兼容。
  • arm彙編中的跳轉指令
    那問題就來了,4位元組是不可能同時存的下指令控制碼和32位立即數的,那麼我要把一個32位立即數(比如一個32位地址值)傳送給寄存器該怎麼 辦? RISC CPU提供一個通用的方法就是把地址值作為數據而不是代碼,從存儲器中相應的位置讀入到寄存器中。像在代碼一中,將所有讀取的32位數據放到label標 注的內存地址中,使用ldr偽指令,從該內存處讀出該數據。
  • ARM裸機開發bootloader彙編語言
    編寫bootloader和內核時使用,主要是對cpu和內存進行初始化時使用,因為這個時候還沒有c語言的環境(堆棧還沒有建立),所以不能用c語言。2、高效率的特殊需求。因為彙編語言的執行效率要高於c語言,所以對某些對效率要求高的程序要用到彙編,可以是彙編與c語言的混合編程。
  • iOS ARM彙編
    一、簡介1、模擬器和真機的彙編是不一樣的3、如何學好arm64彙編除了有arm64,還有arm32彙編,不過以後手機都是arm64構架,所以沒必要學arm32彙編。學好arm64彙編要學好3個東西:學好這三個東西,這門彙編語言也就掌握的差不多了
  • 基於Android的ARM彙編語言系列之三:ARM彙編語言程序結構
    \n");return 0;}對應的彙編代碼:.arch armv5te.fpu softvfp.eabi_attribute 20, 1.eabi_attribute 21, 1.eabi_attribute 23, 3.eabi_attribute 24, 1.eabi_attribute 25, 1.eabi_attribute
  • PIC單片機asm與C混合編程
    這一選項在C 和彙編混合編程時特別有用。通過解讀C 程序對應的彙編指令,可以掌握C 程序中存取變量的具體方法,然後用在自己編寫的彙編指令中。我們將在稍後專門做介紹。11.8.5 連接器選項設定(PICC Linker)連接器PICC Linker 的選項基本不用作太多的改變,在圖11-6 的對話框中顯示了可設定的各類項目。其中有兩項有用的信息輸出可以考慮加以利用:..
  • ARM 彙編的mov操作立即數的疑問
    因為對arm彙編有些指令還不能理解,特別是一些相似功能指令間的區別。偶然在網上搜到「faq ARM assembly」,其中描述的幾個問題還是值得好好研究一下。2. 慢慢的發現自己也不再害怕英文的文檔了,耐心看至少也能懂個大概。
  • 混合使用C、C++和彙編語之:內聯彙編和嵌入型彙編的使用
    例如,在下面幾種情況中必須使用內聯彙編或嵌入型彙編。·程序中使用飽和算術運算(Saturatingarithmetic),如SSAT16和USAT16指令。·程序中需要對協處理器進行操作。·在C或C++程序中完成對程序狀態寄存器的操作。使用內聯彙編編寫的程序代碼效率也比較高。
  • 「正點原子FPGA連載」附錄A2 ARM彙編基礎
    為此我們需要參考兩份跟Cortex-A內核有關的文檔:《ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》和《ARM Cortex-A(armV7)編程手冊V4.0.pdf》,第一份文檔主要講解ARMv7-A和ARMv7-R指令集的開發,Cortex-A9使用的是ARMv7-A指令集,第二份文檔主要講解Cortex-A(
  • 自學編程第1節:程式語言有哪些,什麼關係?彙編C/C++,JAVA簡介
    首先,謝謝大家點擊閱讀獵奇哥的編程系列教程,後期慢慢補充,詳細介紹C語言,C++語言編程的方方面面,儘量幫助大家能夠儘量簡單的學會C++編程核心入門知識。總章節數待定,視內容的更新情況。說起編程,最早的是彙編語言,這種語言大家通常叫做低級語言,做一個程序,需要非常多的指令和代碼,完成的卻是一個非常簡單的功能,程式設計師的工作量非常大,當然,那個時期,電腦的功能也沒有現在的這麼強大,彙編對於當時來說,也是夠用。
  • 單片機編程用C語言還是彙編?
    單片機是一種可編程器件,單片機的出現使硬體設計變得更為簡單,產品的功能也更強大,而程序就是單片機的靈魂。目前功能稍微複雜一點的電子產品,都是以單片機為核心,再加以不通的外設電路實現不通的功能需求。單片機的編程可以通過彙編語言和C語言來實現。
  • ARM彙編語言(4) 指令、偽操作、偽指令學習
    WHILE,WEND:根據條件重複彙編相同的或者幾乎相同的一段原始碼;WHILE logical expressioninstructions or directivesWENDMACRO,MEND:定義宏定義體;MEXIT:從宏中跳轉出去;棧中數據幀描述偽操作;
  • C語言和彙編語言是什麼?他們之間可以有怎樣的合作?為你解析
    在彙編語言中,用助記符(Mnemonics)代替機器指令的操作碼,用地址符號(Symbol)或標號(Label)代替指令或操作數的地址。在不同的設備中,彙編語言對應著不同的機器語言指令集,通過彙編過程轉換成機器指令。普遍地說,特定的彙編語言和特定的機器語言指令集是一一對應的,不同平臺之間不可直接移植。
  • LiteOS Studio零成本學習ARM彙編 五 移花接木
    本文僅代表個人的立場和觀點,並不代表任何公司或組織。基於LiteOS Studio & Qemu零成本學習ARM 彙編——0x05 移花接木下面的全部操作僅適用Window 10 64bits 環境。 前幾篇中的示例程序都存儲在Flash memory內,屬於EEPROM(Electrically Erasable Programmable read only memory,是指帶電可擦可編程只讀存儲器,是一種掉電後數據不丟失的存儲晶片),類似硬碟。變量不方便存儲在Flash內,需要存儲在RAM內,以便進行變量的修改。
  • DSP編程技巧之24---C/C++與彙編語言的交互之-(2)從C/C++代碼調用...
    在C/C++與彙編語言混合編程的情況下,一般我們都會選擇C/C++來實現所期待的大部分功能,對於少數和硬體關聯度高(例如操作某些CPU寄存器)以及對運算的實時性要求高(例如高速、多點的FFT)的功能才使用彙編來實現,這就使得大多數情況下,C/C++與彙編的交互都是從C/C++代碼調用彙編代碼中的函數與變量,所以在此我們就來看一下這種調用的規則。
  • 嵌入式arm開發學習第三天
    arm開發學習第三天交叉編譯裸板程序:1.arm-cortex_a9-linux-gnueabi-gcc -nostdlib -c -o xxx.o xxx.c-c: 只編譯不連結-nostdlib: 不允許使用標準c庫內容2.arm-cortex_a9-linux-gnueabi-ld -nostartfiles