久久婷婷香蕉热狠狠综合,精品无码国产自产拍在线观看蜜,寡妇房东在做爰3,中文字幕日本人妻久久久免费,国产成人精品三上悠亚久久

歡迎來到(dao)高端IT就業培訓專家——華清遠見教育(yu)科(ke)技集(ji)團

400-611-6270

當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 >
__asm__ __volatile__內嵌匯編用法簡述
時間:2018-08-16作者:華清遠見

__asm__ __volatile__內嵌(qian)匯(hui)(hui)編用法簡述 在(zai)閱讀C/C++原碼(ma)時經常會遇(yu)到內聯匯(hui)(hui)編的情況(kuang),下(xia)面(mian)(mian)簡要介紹下(xia)__asm__ __volatile__內嵌(qian)匯(hui)(hui)編用法。因為(wei)我(wo)們華(hua)清遠見教學平臺是ARM體系結構的,所以下(xia)面(mian)(mian)的示例都是用ARM匯(hui)(hui)編。

帶(dai)有(you)C/C++表達式的內聯匯編格式為(wei):

__asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify);

其中每項的概念及功(gong)能(neng)用法(fa)描述如下:

1、 __asm__

__asm__是GCC 關鍵字asm 的(de)宏定義:

#define __asm__ asm

__asm__或asm 用來聲明一個(ge)(ge)內聯匯編表達式,所以任何(he)一個(ge)(ge)內聯匯編表達式都是(shi)以它開頭(tou)的(de),是(shi)必(bi)不可少的(de)。

2、Instruction List

Instruction List 是(shi)(shi)匯編指令序列(lie)。它可以(yi)是(shi)(shi)空(kong)的,比如(ru):__asm__ __volatile__(""); 或(huo) __asm__ ("");都是(shi)(shi)完(wan)全合(he)法的內(nei)聯(lian)匯編表(biao)達式,只不過這(zhe)兩(liang)條語句沒有什么意義。但并非所有Instruction List 為空(kong)的內(nei)聯(lian)匯編表(biao)達式都是(shi)(shi)沒有意義的,比如(ru):__asm__ ("":::"memory");

就非常有(you)意義,它向GCC 聲(sheng)明:“內存作了改動(dong)”,GCC 在(zai)(zai)(zai)編譯的(de)時候(hou)(hou),會(hui)將此因素考(kao)慮(lv)進(jin)去。 當在(zai)(zai)(zai)"Instruction List"中有(you)多條(tiao)(tiao)(tiao)(tiao)指令(ling)(ling)的(de)時候(hou)(hou),可(ke)(ke)以(yi)在(zai)(zai)(zai)一對引號(hao)(hao)中列出全部指令(ling)(ling),也可(ke)(ke)以(yi)將一條(tiao)(tiao)(tiao)(tiao) 或(huo)幾條(tiao)(tiao)(tiao)(tiao)指令(ling)(ling)放(fang)(fang)在(zai)(zai)(zai)一對引號(hao)(hao)中,所有(you)指令(ling)(ling)放(fang)(fang)在(zai)(zai)(zai)多對引號(hao)(hao)中。如果(guo)是(shi)前者,可(ke)(ke)以(yi)將每(mei)一條(tiao)(tiao)(tiao)(tiao)指令(ling)(ling)放(fang)(fang)在(zai)(zai)(zai)一行(xing),如果(guo)要將多條(tiao)(tiao)(tiao)(tiao)指令(ling)(ling)放(fang)(fang)在(zai)(zai)(zai)一行(xing),則必(bi)須(xu)(xu)用分號(hao)(hao)(;)或(huo)換行(xing)符(fu)(\n)將它們分開(kai). 綜上(shang)述:(1)每(mei)條(tiao)(tiao)(tiao)(tiao)指令(ling)(ling)都必(bi)須(xu)(xu)被雙引號(hao)(hao)括起(qi)來(lai) (2)兩條(tiao)(tiao)(tiao)(tiao)指令(ling)(ling)必(bi)須(xu)(xu)用換行(xing)或(huo)分號(hao)(hao)分開(kai)。

例如(ru): 在ARM系統結(jie)構(gou)上(shang)關(guan)閉中斷的(de)操作

int disable_interrupts (void) 
        { 
                unsigned long old,temp; 
                __asm__ __volatile__("mrs %0, cpsr\n" 
                                "orr %1, %0, #0x80\n" 
                                "msr cpsr_c, %1" 
                                : "=r" (old), "=r" (temp) 
                                : 
                                : "memory"); 
                return (old & 0x80) == 0; 
        }

3. __volatile__

__volatile__是GCC 關(guan)鍵字volatile 的宏定義

#define __volatile__ volatile

__volatile__或volatile 是可選(xuan)的。如果用了它(ta),則是向GCC 聲明不允許對(dui)該內(nei)聯匯編優(you)化,否則當 使用了優(you)化選(xuan)項(-O)進行編譯(yi)時,GCC 將(jiang)(jiang)會(hui)根據自(zi)己的判斷決定是否將(jiang)(jiang)這(zhe)個內(nei)聯匯編表(biao)達式中的指(zhi)令優(you)化掉(diao)。

4、 Output

Output 用來指定當前內聯匯編語句的輸出

例如:從arm協(xie)處理器(qi)p15中讀出C1值

static unsigned long read_p15_c1 (void) 
        { 
                unsigned long value; 
                __asm__ __volatile__( 
                                "mrc p15, 0, %0, c1, c0, 0 @ read control reg\n" 
                                : "=r" (value) @編譯器選擇一個R*寄存器 
                                : 
                                : "memory"); 
        #ifdef MMU_DEBUG 
                printf ("p15/c1 is = %08lx\n", value); 
        #endif 
                return value; 
        }

5、 Input

Input 域(yu)的內容用來(lai)指定(ding)當前內聯(lian)匯編語句的輸入(ru)Output和Input中,格式為形如“constraint”(variable)的列表(逗(dou)號(hao)分隔(ge))

例(li)如:向arm協處理器p15中寫(xie)入C1值(zhi)

static void write_p15_c1 (unsigned long value) 
        { 
        #ifdef MMU_DEBUG 
                printf ("write %08lx to p15/c1\n", value); 
        #endif 
                __asm__ __volatile__( 
                                "mcr p15, 0, %0, c1, c0, 0 @ write it back\n" 
                                : 
                                : "r" (value) @編譯器選擇一個R*寄存器 
                                : "memory"); 
                read_p15_c1 (); 
        } 

6.、Clobber/Modify

有(you)時候,你(ni)想(xiang)通知GCC當前(qian)內(nei)聯匯(hui)編(bian)語(yu)句可能會對某些(xie)寄(ji)(ji)(ji)存(cun)器或內(nei)存(cun)進(jin)行修改(gai)(gai),希望GCC在(zai)編(bian)譯時能夠(gou)將(jiang)這一(yi)(yi)點考(kao)慮進(jin)去(qu)。那么你(ni)就可以(yi)在(zai)Clobber/Modify域(yu)聲(sheng)明這些(xie)寄(ji)(ji)(ji)存(cun)器或內(nei)存(cun)。這種情況(kuang)一(yi)(yi)般發生在(zai)一(yi)(yi)個(ge)寄(ji)(ji)(ji)存(cun)器出現在(zai)"Instruction List",但卻(que)不是(shi)由(you)Input/Output操作表達式所指(zhi)定的(de)(de),也不是(shi)在(zai)一(yi)(yi)些(xie)Input/Output操作表達式使用"r"約束時由(you)GCC 為(wei)其選擇(ze)的(de)(de),同時此(ci)寄(ji)(ji)(ji)存(cun)器被"Instruction List"中的(de)(de)指(zhi)令修改(gai)(gai),而這個(ge)寄(ji)(ji)(ji)存(cun)器只是(shi)供當前(qian)內(nei)聯匯(hui)編(bian)臨時使用的(de)(de)情況(kuang)。

例如:

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

寄存器(qi)R0出現在"Instruction List中(zhong)",并且被(bei)mov指(zhi)令修改,但卻(que)未被(bei)任(ren)何Input/Output操作表(biao)達式指(zhi)定(ding),所以你需要在Clobber/Modify域指(zhi)定(ding)"R0",以讓GCC知(zhi)道這一(yi)點。

因為你在Input/Output操作(zuo)表達(da)式(shi)所(suo)指(zhi)定的(de)寄存(cun)(cun)器(qi)(qi),或(huo)當你為一(yi)些(xie)Input/Output操作(zuo)表達(da)式(shi)使(shi)用"r"約(yue)束(shu),讓(rang)(rang)GCC為你選擇一(yi)個寄存(cun)(cun)器(qi)(qi)時(shi),GCC對這(zhe)些(xie)寄存(cun)(cun)器(qi)(qi)是非常清楚的(de)——它(ta)(ta)知道這(zhe)些(xie)寄存(cun)(cun)器(qi)(qi)是被修(xiu)改的(de),你根本(ben)不需要(yao)在Clobber/Modify域再聲(sheng)明它(ta)(ta)們。但除此(ci)之(zhi)外, GCC對剩下的(de)寄存(cun)(cun)器(qi)(qi)中哪些(xie)會被當前的(de)內聯(lian)匯(hui)編修(xiu)改一(yi)無所(suo)知。所(suo)以如果你真的(de)在當前內聯(lian)匯(hui)編指(zhi)令中修(xiu)改了它(ta)(ta)們,那么就(jiu)好在Clobber/Modify 中聲(sheng)明它(ta)(ta)們,讓(rang)(rang)GCC針對這(zhe)些(xie)寄存(cun)(cun)器(qi)(qi)做相應(ying)的(de)處理。否則有可能(neng)會造成(cheng)寄存(cun)(cun)器(qi)(qi)的(de)不一(yi)致,從而造成(cheng)程序執行錯(cuo)誤(wu)。

如果(guo)一(yi)個內(nei)聯匯編(bian)語句的(de)(de)Clobber/Modify域存(cun)(cun)(cun)在(zai)(zai)(zai)"memory",那(nei)么GCC會保證在(zai)(zai)(zai)此內(nei)聯匯編(bian)之前(qian),如果(guo)某個內(nei)存(cun)(cun)(cun)的(de)(de)內(nei)容被裝入了寄(ji)存(cun)(cun)(cun)器(qi),那(nei)么在(zai)(zai)(zai)這個內(nei)聯匯編(bian)之后(hou),如果(guo)需(xu)要使(shi)用這個內(nei)存(cun)(cun)(cun)處(chu)的(de)(de)內(nei)容,就會直(zhi)接到這個內(nei)存(cun)(cun)(cun)處(chu)重新讀取,而不是使(shi)用被存(cun)(cun)(cun)放在(zai)(zai)(zai)寄(ji)存(cun)(cun)(cun)器(qi)中的(de)(de)拷貝。因(yin)為(wei)這個 時候寄(ji)存(cun)(cun)(cun)器(qi)中的(de)(de)拷貝已經(jing)很可(ke)能和內(nei)存(cun)(cun)(cun)處(chu)的(de)(de)內(nei)容不一(yi)致了。

這只是使(shi)用"memory"時,GCC會保證做到的一點(dian),但這并不(bu)是全部。因(yin)為(wei)使(shi)用"memory"是向GCC聲明內(nei)存(cun)發生了(le)變化,而內(nei)存(cun)發生變化帶來的影(ying)響并不(bu)止這一點(dian)。

例如:

int main(int __argc, char* __argv[]) 
        { 
        int* __p = (int*)__argc; 
        (*__p) = 9999; 
        __asm__("":::"memory"); 
        if((*__p) == 9999) 
        return 5; 
        return (*__p); 
         }

本例中(zhong),如(ru)果沒(mei)有(you)那條內聯匯(hui)編(bian)語句(ju),那個(ge)if語句(ju)的(de)判斷條件就完(wan)全(quan)是一句(ju)廢話。GCC在優化時會(hui)意識到這(zhe)一點,而直接只生(sheng)成return 5的(de)匯(hui)編(bian)代(dai)碼(ma)(ma),而不會(hui)再生(sheng)成if語句(ju)的(de)相(xiang)(xiang)(xiang)關代(dai)碼(ma)(ma),而不會(hui)生(sheng)成return (*__p)的(de)相(xiang)(xiang)(xiang)關代(dai)碼(ma)(ma)。但你加(jia)上了(le)這(zhe)條內聯匯(hui)編(bian)語句(ju),它除了(le)聲明內存變化之外,什么都(dou)沒(mei)有(you)做(zuo)。但GCC此時就不能簡單的(de)認為它不需(xu)要判斷都(dou)知道 (*__p)一定與9999相(xiang)(xiang)(xiang)等,它只有(you)老(lao)老(lao)實實生(sheng)成這(zhe)條if語句(ju)的(de)匯(hui)編(bian)代(dai)碼(ma)(ma),一起相(xiang)(xiang)(xiang)關的(de)兩個(ge)return語句(ju)相(xiang)(xiang)(xiang)關代(dai)碼(ma)(ma)。

另(ling)外在linux內(nei)核中內(nei)存屏障也是基于(yu)它(ta)實現的include/asm/system.h中

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

主要是保(bao)證程序的(de)執行遵循順序一致性(xing)。呵(he)呵(he),有(you)的(de)時候你寫代碼的(de)順序,不(bu)一定(ding)是終執行的(de)順序,這個是處(chu)理器有(you)關的(de)。


發表評論

全國咨詢電話:400-611-6270,雙休(xiu)日及節假日請致電值班(ban)手機:15010390966

在線咨詢(xun): 曹老(lao)師QQ(3337544669), 徐老(lao)師QQ(1462495461), 劉老(lao)師 QQ(3108687497)

企業(ye)培(pei)訓洽(qia)談專線(xian):010-82600901,院(yuan)校合作洽(qia)談專線(xian):010-82600350,在線(xian)咨詢(xun):QQ(248856300)

Copyright 2004-2018 華清遠見教育科技集團 版權所(suo)有 ,京(jing)ICP備16055225號(hao),京(jing)公海網(wang)安備11010802025203號(hao)