ARM彙編和內嵌彙編

2021-07-01 23:30:43 字數 3785 閱讀 3765

彙編指令

跳轉指令

b bl

blxbx

資料處理指令

mov 

mvnadd

adcsub

rsbrsc

andor

eorbic

cmncmp

tstteq

狀態暫存器指令

mrs 

msrldr

strldm

stmmcr  arm和協處理器之間資料交換

mrccond 可選的條件**

rd 存放返回狀態的暫存器

rt 要載入或儲存的暫存器

rt2 進行雙位元組載入或儲存時要用到的第二個暫存器

rn 記憶體位址所基於的暫存器

offset rn的可選偏移量,只使用在thumb-2指令中

arm是risc結構,資料從記憶體到cpu之間的移動只能通過l/s指令來完成,也就是ldr/str指令。

store register

load  register

ldm --》load multiple

stm --》store multiple

cp15協處理器部分

mcr 將 arm 處理器的暫存器中的資料寫

到 cp15 中的暫存器中

mcr{} p15, , ,, , {}

mrc 將 cp15 中的暫存器中的資料讀到

arm 處理器的暫存器中

mcr{} p15, , ,, , {}

mrc p15, 0, r0, c1, c0 ;將 cp15 的暫存器 c1 的值讀到 r0 中

mcr p15, 0, r0, c1, c0 ;將 r0 的值寫到 cp15 的暫存器 c1 中

arm內嵌彙編

__asm__ __volatile__內嵌彙編用法簡述 在閱讀c/c++原碼時經常會遇到內聯彙編的情況,下面簡要介紹下__asm__ __volatile__內嵌彙編用法。因為我們華清遠見教學平台是arm體系結構的,所以下面的示例都是用arm彙編。 

帶有c/c++表示式的內聯彙編格式為: 

__asm__ __volatile__("instruction list" : output : input : clobber/modify); 

其中每項的概念及功能用法描述如下: 

1、 __asm__ 

__asm__是gcc 關鍵字asm 的巨集定義: 

#define __asm__ asm 

__asm__或asm 用來宣告乙個內聯彙編表示式,所以任何乙個內聯彙編表示式都是以它開頭的,是必不可少的。 

2、instruction list 

instruction list 是彙編指令序列。它可以是空的,比如:__asm__ __volatile__(""); 或 __asm__ ("");都是完全合法的內聯彙編表示式,只不過這兩條語句沒有什麼意義。但並非所有instruction list 為空的內聯彙編表示式都是沒有意義的,比如:__asm__ ("":::"memory"); 

就非常有意義,它向gcc 宣告:「記憶體作了改動」,gcc 在編譯的時候,會將此因素考慮進去。 當在"instruction list"中有多條指令的時候,可以在一對引號中列出全部指令,也可以將一條 或幾條指令放在一對引號中,所有指令放在多對引號中。如果是前者,可以將每一條指令放在一行,如果要將多條指令放在一行,則必須用分號(;)或換行符(\n)將它們分開. 綜上述:(1)每條指令都必須被雙引號括起來 (2)兩條指令必須用換行或分號分開。 

例如: 在arm系統結構上關閉中斷的操作 

int disable_interrupts (void) 

3. __volatile__ 

__volatile__是gcc 關鍵字volatile 的巨集定義 

#define __volatile__ volatile 

__volatile__或volatile 是可選的。如果用了它,則是向gcc 宣告不允許對該內聯彙編優化,否則當 使用了優化選項(-o)進行編譯時,gcc 將會根據自己的判斷決定是否將這個內聯彙編表示式中的指令優化掉。 

4、 output 

output 用來指定當前內聯彙編語句的輸出 

例如:從arm協處理器p15中讀出c1值 

static unsigned long read_p15_c1 (void) 

5、 input 

input 域的內容用來指定當前內聯彙編語句的輸入output和input中,格式為形如「constraint」(variable)的列表(逗號分隔) 

例如:向arm協處理器p15中寫入c1值 

static void write_p15_c1 (unsigned long value) 

6.、clobber/modify 

有時候,你想通知gcc當前內聯彙編語句可能會對某些暫存器或記憶體進行修改,希望gcc在編譯時能夠將這一點考慮進去。那麼你就可以在clobber/modify域宣告這些暫存器或記憶體。這種情況一般發生在乙個暫存器出現在"instruction list",但卻不是由input/output操作表示式所指定的,也不是在一些input/output操作表示式使用"r"約束時由gcc 為其選擇的,同時此暫存器被"instruction list"中的指令修改,而這個暫存器只是供當前內聯彙編臨時使用的情況。 

例如: 

__asm__ ("mov r0, #0x34" : : : "r0"); 

暫存器r0出現在"instruction list中",並且被mov指令修改,但卻未被任何input/output操作表示式指定,所以你需要在clobber/modify域指定"r0",以讓gcc知道這一點。 

因為你在input/output操作表示式所指定的暫存器,或當你為一些input/output操作表示式使用"r"約束,讓gcc為你選擇乙個暫存器時,gcc對這些暫存器是非常清楚的——它知道這些暫存器是被修改的,你根本不需要在clobber/modify域再宣告它們。但除此之外, gcc對剩下的暫存器中哪些會被當前的內聯彙編修改一無所知。所以如果你真的在當前內聯彙編指令中修改了它們,那麼就最好在clobber/modify 中宣告它們,讓gcc針對這些暫存器做相應的處理。否則有可能會造成暫存器的不一致,從而造成程式執行錯誤。 

如果乙個內聯彙編語句的clobber/modify域存在"memory",那麼gcc會保證在此內聯彙編之前,如果某個記憶體的內容被裝入了暫存器,那麼在這個內聯彙編之後,如果需要使用這個記憶體處的內容,就會直接到這個記憶體處重新讀取,而不是使用被存放在暫存器中的拷貝。因為這個 時候暫存器中的拷貝已經很可能和記憶體處的內容不一致了。 

這只是使用"memory"時,gcc會保證做到的一點,但這並不是全部。因為使用"memory"是向gcc宣告記憶體發生了變化,而記憶體發生變化帶來的影響並不止這一點。 

例如: 

int main(int __argc, char* __argv) 

本例中,如果沒有那條內聯彙編語句,那個if語句的判斷條件就完全是一句廢話。gcc在優化時會意識到這一點,而直接只生成return 5的彙編**,而不會再生成if語句的相關**,而不會生成return (*__p)的相關**。但你加上了這條內聯彙編語句,它除了宣告記憶體變化之外,什麼都沒有做。但gcc此時就不能簡單的認為它不需要判斷都知道 (*__p)一定與9999相等,它只有老老實實生成這條if語句的彙編**,一起相關的兩個return語句相關**。 

另外在linux核心中記憶體屏障也是基於它實現的include/asm/system.h中 

# define barrier() _asm__volatile_("": : :"memory") 

主要是保證程式的執行遵循順序一致性。呵呵,有的時候你寫**的順序,不一定是最終執行的順序,這個是處理器有關的。

ARM彙編 從內嵌彙編開始

對於基於arm的risc處理器,gnu c編譯器提供了在c 中內嵌彙編的功能。這種特性提供了c 沒有的功能,比如手動優化軟體關鍵部分的 使用相關的處理器指令。asm volatile hlt asm 表示後面的 為內嵌彙編,asm 是 asm 的別名。volatile 表示編譯器不要優化 後面的指令...

內嵌彙編和內聯彙編的使用

有時為了高效,有時為了直接控制硬體,有些模組我們不得不直接用組合語言來編寫,並且對外提供呼叫的介面,隱藏細節,這其實就是內聯彙編。如何使用內聯彙編?我們就以 gcc 為例,一窺其中奧秘!一 關鍵字 如何讓 gcc 知道 中內嵌的彙編呢?借助關鍵字!來看下面的例子 asm volatile hlt a...

Linux下彙編語法和內嵌彙編

做了乙個小例子 例子程式 使用了內嵌彙編 int main 彙編 使用gcc s 獲得 file test.c text globl main type main,function main leal 4 esp ecx andl 16,esp pushl 4 ecx pushl ebp movl ...