0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于gcc將C語(yǔ)言變量與指令操作數(shù)相關(guān)聯(lián)

Linux閱碼場(chǎng) ? 2018-01-16 14:55 ? 次閱讀

有時(shí)候我們希望在C/C++代碼中使用嵌入式匯編,因?yàn)镃中沒(méi)有對(duì)應(yīng)的函數(shù)或語(yǔ)法可用。比如我最近在ARM上寫FIR程序時(shí),需要對(duì)最后的結(jié)果進(jìn)行飽和處理,但gcc沒(méi)有提供ssat這樣的函數(shù),于是不得不在C代碼中嵌入?yún)R編指令。

1. 入門

在C中嵌入?yún)R編的最大問(wèn)題是如何將C語(yǔ)言變量與指令操作數(shù)相關(guān)聯(lián)。當(dāng)然,gcc都幫我們想好了。下面是是一個(gè)簡(jiǎn)單例子。

asm(“fsinx %1, %0”:”=f”(result):”f”(angle));

這里我們不需要關(guān)注fsinx指令是干啥的;只需要知道這條指令需要兩個(gè)浮點(diǎn)寄存器作為操作數(shù)。作為專職處理C語(yǔ)言的gcc編譯器,它是沒(méi)辦法知道fsinx這條匯編指令需要什么樣的操作數(shù)的,這就要求程序猿告知gcc相關(guān)信息,方法就是指令后面的”=f”和”f”,表示這是兩個(gè)浮點(diǎn)寄存器操作數(shù)。這被稱為操作數(shù)規(guī)則(constraint)。規(guī)則前面加上”=”表示這是一個(gè)輸出操作數(shù),否則是輸入操作數(shù)。constraint后面括號(hào)內(nèi)的是與該寄存器關(guān)聯(lián)的變量。這樣gcc就知道如何將這條嵌入式匯編語(yǔ)句轉(zhuǎn)成實(shí)際的匯編指令了:

fsinx:匯編指令名

%1, %0:匯編指令操作數(shù)

“=f”(result):操作數(shù)%0是一個(gè)浮點(diǎn)寄存器,與變量result關(guān)聯(lián)(對(duì)輸出操作數(shù),“關(guān)聯(lián)”的意思就是說(shuō)gcc執(zhí)行完這條匯編指令后會(huì)把寄存器%0的內(nèi)容送到變量result中)

“f”(angle):操作數(shù)%1是一個(gè)浮點(diǎn)寄存器,與變量angle關(guān)聯(lián)(對(duì)輸入操作數(shù),“關(guān)聯(lián)”的意思是就是說(shuō)gcc執(zhí)行這條匯編指令前會(huì)先將變量angle的值讀取到寄存器%1中)

因此這條嵌入式匯編會(huì)轉(zhuǎn)換為至少三條匯編指令(非優(yōu)化):

將angle變量的值加載到寄存器%1

fsinx匯編指令,源寄存器%1,目標(biāo)寄存器%0

將寄存器%0的值存儲(chǔ)到變量result

當(dāng)然,在高優(yōu)化級(jí)別下上面的敘述可能不適用;比如源操作數(shù)可能本來(lái)就已經(jīng)在某個(gè)浮點(diǎn)寄存器中了。

這里我們也看到constraint前加”=”符號(hào)的意義:gcc需要知道這個(gè)操作數(shù)是在執(zhí)行嵌入?yún)R編前從變量加載到寄存器,還是在執(zhí)行后從寄存器存儲(chǔ)到變量中。

常用的constraints有以下幾個(gè)(更多細(xì)節(jié)參見(jiàn)gcc手冊(cè)):

m 內(nèi)存操作數(shù)

r 寄存器操作數(shù)

i 立即數(shù)操作數(shù)(整數(shù))

f 浮點(diǎn)寄存器操作數(shù)

F 立即數(shù)操作數(shù)(浮點(diǎn))

從這個(gè)栗子也可以看出嵌入式匯編的基本格式:

asm(“匯編指令”:”=輸出操作數(shù)規(guī)則”(關(guān)聯(lián)變量):”輸入操作數(shù)規(guī)則”(關(guān)聯(lián)變量));

輸出操作數(shù)必須為左值;這個(gè)顯然。

2. 多個(gè)操作數(shù),或沒(méi)有輸出操作數(shù)

如果某個(gè)指令有多個(gè)輸入或輸出操作數(shù)怎么辦?例如arm有很多指令是三操作數(shù)指令。這個(gè)時(shí)候用逗號(hào)分隔多個(gè)規(guī)則:

asm(“add %0, %1, %2”:”=r”(sum):”r”(a), “r”(b));

每條操作數(shù)規(guī)則按順序?qū)?yīng)操作數(shù)%0, %1, %2。

對(duì)于沒(méi)有輸出操作數(shù)的情況,在匯編指令后就沒(méi)有輸出規(guī)則,于是就出現(xiàn)兩個(gè)連續(xù)冒號(hào),后跟輸入規(guī)則。

3. 輸入-輸出(或讀-寫)操作數(shù)

有時(shí)候一個(gè)操作數(shù)既是輸入又是輸出,比如x86下的這條指令:

add %eax, %ebx

注意指令使用AT&T格式而不是Intel格式。寄存器ebx同時(shí)作為輸入操作數(shù)和輸出操作數(shù)。對(duì)這樣的操作數(shù),在規(guī)則前使用”+”字符:

asm("add %1, %0" : "+r"(a) : "r"(b));

對(duì)應(yīng)C語(yǔ)言語(yǔ)句a=a+b。

注意這樣的操作數(shù)不能使用”=”符號(hào),因?yàn)間cc看到”=”符號(hào)會(huì)認(rèn)為這是一個(gè)單輸出操作數(shù),于是在將嵌入?yún)R編轉(zhuǎn)換為真正匯編的時(shí)候就不會(huì)預(yù)先將變量a的值加載到寄存器%0中。

另一個(gè)辦法是將讀-寫操作數(shù)在邏輯上拆分為兩個(gè)操作數(shù):

asm(“add %2, %0” : “=r”(a) : “0”(a), “r”(b));

對(duì)“邏輯”輸入操作數(shù)1指定數(shù)字規(guī)則”0”,表示這個(gè)邏輯操作數(shù)占用和操作數(shù)0一樣的“位置”(占用同一個(gè)寄存器)。這種方法的特點(diǎn)是可以將兩個(gè)“邏輯”操作數(shù)關(guān)聯(lián)到兩個(gè)不同的C語(yǔ)言變量上:

asm("add %2, %0" : "=r"(c) : "0"(a), "r"(b));

對(duì)應(yīng)于C程序語(yǔ)句c=a+b。

數(shù)字規(guī)則僅能用于輸入操作數(shù),且必須引用到輸出操作數(shù)。拿上例來(lái)說(shuō),數(shù)字規(guī)則”0”位于輸入規(guī)則段,且引用到輸出操作數(shù)0,該數(shù)字規(guī)則自身占用操作數(shù)計(jì)數(shù)1。

這里要注意,通過(guò)同名C語(yǔ)言變量是無(wú)法保證兩個(gè)操作數(shù)占用同一“位置”的。比如下面這樣的寫法是不行的:

(錯(cuò)誤寫法)asm(“add %2, %0”:”=r”(a):”r”(a), “r”(b));

4. 指定寄存器

有時(shí)候我們需要在指令中使用指定的寄存器;典型的栗子是系統(tǒng)調(diào)用,必須將系統(tǒng)調(diào)用碼和參數(shù)放在指定寄存器中。為了達(dá)到這個(gè)目的,我們要在聲明變量時(shí)使用擴(kuò)展語(yǔ)法:

register int a asm(“%eax”) = 1; // statement 1

register int b asm(“%ebx”) = 2; // statement 2

asm("add %1, %0" : "+r"(a) : "r"(b)); // statement 3

注意只有在執(zhí)行匯編指令時(shí)能確定a在eax中,b在ebx中,其他時(shí)候a和b的存放位置是不可知的。

另外,在這么用的時(shí)候要注意,防止statement 2在執(zhí)行時(shí)覆蓋了eax。例如statement 2改成下面這句:

register int b asm(“%ebx”) = func();

函數(shù)調(diào)用約定會(huì)將func()的返回值放在eax里,于是破壞了statement 1對(duì)a的賦值。這個(gè)時(shí)候可以先用一條語(yǔ)句將func返回值放在臨時(shí)變量里:

int t = func();

register int a asm(“%eax”) = 1; // statement 1

register int b asm(“%ebx”) = t; // statement 2

asm("add %1, %0" : "+r"(a) : "r"(b)); // statement 3

5. 隱式改變寄存器

有的匯編指令會(huì)隱含修改一些不在指令操作數(shù)中的寄存器,為了讓gcc知道這個(gè)情況,將隱式改變寄存器規(guī)則列在輸入規(guī)則之后。下面是VAX機(jī)上的栗子:

asm volatile(“movc3 %0,%1,%2”

: /* no outputs */

:”g”(from),”g”(to),”g”(count)

:”r0”,”r1”,”r2”,”r3”,”r4”,”r5”);

(movc3是一條字符塊移動(dòng)(Move characters)指令)

這里要注意的是輸入/輸出規(guī)則中列出的寄存器不能和隱含改變規(guī)則中的寄存器有交叉。比如在上面的栗子里,規(guī)則“g”中就不能包含r0-r5。以指定寄存器語(yǔ)法聲明的變量,所占用的寄存器也不能和隱含改變規(guī)則有交叉。這個(gè)應(yīng)該好理解:隱含改變規(guī)則是告訴gcc有額外的寄存器需要照顧,自然不能和輸入/輸出寄存器有交集。

另外,如果你在指令里顯式指定某個(gè)寄存器,那么這個(gè)寄存器也必須列在隱式改變規(guī)則之中(有點(diǎn)繞了哈)。上面我們說(shuō)過(guò)gcc自身是不了解匯編指令的,所以你在指令中顯式指定的寄存器,對(duì)gcc來(lái)說(shuō)是隱式的,因此必須包含在隱式規(guī)則之中。另外,指令中的顯式寄存器前需要一個(gè)額外的%,比如%%eax。

6. volatile

asm volatile通知gcc你的匯編指令有side effect,千萬(wàn)不要給優(yōu)化沒(méi)了,比如上面的栗子。

如果你的指令只是做些計(jì)算,那么不需要volatile,讓gcc可以優(yōu)化它;除此以外,無(wú)腦給每個(gè)asm加上volatile或者是個(gè)好辦法。

基于gcc將C語(yǔ)言變量與指令操作數(shù)相關(guān)聯(lián)

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5294

    瀏覽量

    119814
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    2966

    瀏覽量

    73812
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7594

    瀏覽量

    135856
  • GCC
    GCC
    +關(guān)注

    關(guān)注

    0

    文章

    105

    瀏覽量

    24802

原文標(biāo)題:byeyear: gcc內(nèi)嵌匯編詳解

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    python的操作數(shù)據(jù)庫(kù)

    python操作數(shù)據(jù)庫(kù)
    發(fā)表于 05-20 12:11

    ARM指令集的格式與操作數(shù)符號(hào)簡(jiǎn)析

    1)指令格式①一般格式{條件域}{執(zhí)行時(shí)是否更新CPSR},,{第二個(gè)源操作數(shù)}其中內(nèi)為不可省略,{}內(nèi)為可省略。②指令中的條件域每條ARM指令包含4位的條件碼,位于
    發(fā)表于 01-07 07:29

    IBM-PC匯編語(yǔ)言指令

    IBM-PC匯編語(yǔ)言指令集 數(shù)據(jù)傳送指令集 MOV 功能: 把源操作數(shù)送給目的操作數(shù) 語(yǔ)法: MOV 目的
    發(fā)表于 12-25 10:08 ?1187次閱讀

    C#教程之Linq操作數(shù)組集合

    C#教程之Linq操作數(shù)組集合,很好的C#資料,快來(lái)學(xué)習(xí)吧。
    發(fā)表于 04-20 15:27 ?5次下載

    2按鍵加減操作數(shù)碼管顯示

    2按鍵加減操作數(shù)碼管顯示--C51單片機(jī)源碼,KEIL源文件,C語(yǔ)言編寫
    發(fā)表于 06-20 16:15 ?22次下載

    駕駛操作數(shù)據(jù)采集系統(tǒng)設(shè)計(jì)研究

    駕駛操作數(shù)據(jù)采集系統(tǒng)設(shè)計(jì)研究
    發(fā)表于 01-22 21:11 ?12次下載

    PLC的相關(guān)指令詳細(xì)介紹

    CMP指令有三個(gè)操作數(shù):兩個(gè)源操作數(shù)[S1.]和[S2.],一個(gè)目標(biāo)操作數(shù)[D.],該指令[S
    發(fā)表于 07-04 11:50 ?3544次閱讀
    PLC的<b class='flag-5'>相關(guān)</b><b class='flag-5'>指令</b>詳細(xì)介紹

    單片機(jī)尋找操作數(shù)存放單元地址的方法解析

    尋找操作數(shù)存放單元的地址的方式,共6種方式。 1.立即數(shù)尋址 所要找的操作數(shù)是一二進(jìn)制數(shù)或十進(jìn)制數(shù),出現(xiàn)在指令中,用“#”作前綴 MOVA,#20H 2.寄存器尋址
    發(fā)表于 10-18 17:04 ?3969次閱讀
    單片機(jī)尋找<b class='flag-5'>操作數(shù)</b>存放單元地址的方法解析

    使用單片機(jī)實(shí)現(xiàn)兩按鍵加減操作數(shù)碼管顯示的C語(yǔ)言程序免費(fèi)

    本文檔的主要內(nèi)容詳細(xì)介紹的是使用單片機(jī)實(shí)現(xiàn)兩按鍵加減操作數(shù)碼管顯示的C語(yǔ)言程序免費(fèi)。
    發(fā)表于 11-19 18:10 ?28次下載
    使用單片機(jī)實(shí)現(xiàn)兩按鍵加減<b class='flag-5'>操作數(shù)</b>碼管顯示的<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>程序免費(fèi)

    PLC編程中的操作數(shù)是什么

    操作數(shù)是指等待CPU處理的數(shù)據(jù),也是指等待處理的數(shù)據(jù)所在的內(nèi)存地址。操作數(shù)包括標(biāo)識(shí)符和標(biāo)識(shí)參數(shù),標(biāo)識(shí)符分為主標(biāo)識(shí)符和輔助標(biāo)識(shí)符。 (1)標(biāo)識(shí)符(存儲(chǔ)操作數(shù)的內(nèi)存區(qū)域):I、q、PI、PQ、m、t、
    發(fā)表于 12-20 10:13 ?7356次閱讀

    S7-1200比較操作-變量指令說(shuō)明

    SCL指令:TypeOf(操作數(shù)),操作數(shù)是FC/FB的Input/Output/InOut/Temp中定義為Variant類型的參數(shù),該語(yǔ)句輸出是數(shù)據(jù)類型,在程序中只能用在IF與CASE進(jìn)行比較。
    的頭像 發(fā)表于 03-28 11:12 ?4580次閱讀

    簡(jiǎn)單的gcc內(nèi)嵌匯編例分析

    在內(nèi)嵌匯編中,可以C語(yǔ)言表達(dá)式指定為匯編指令操作數(shù),而且不用去管如何
    發(fā)表于 03-09 12:15 ?541次閱讀

    掃描操作數(shù)的信號(hào)上升沿

    使用“掃描操作數(shù)的信號(hào)上升沿”指令,可以確定所指定操作數(shù))的信號(hào)狀態(tài)是否從“0”變?yōu)椤?”。
    的頭像 發(fā)表于 06-27 09:39 ?2576次閱讀
    掃描<b class='flag-5'>操作數(shù)</b>的信號(hào)上升沿

    西門子博途:掃描操作數(shù)的信號(hào)下降沿

    使用“掃描操作數(shù)的信號(hào)下降沿”指令,可以確定所指定操作數(shù))的信號(hào)狀態(tài)是否從“1”變?yōu)椤?”。
    的頭像 發(fā)表于 07-17 10:51 ?2706次閱讀
    西門子博途:掃描<b class='flag-5'>操作數(shù)</b>的信號(hào)下降沿

    匯編指令是什么 計(jì)算機(jī)語(yǔ)言匯編指令簡(jiǎn)介

    匯編指令簡(jiǎn)介 匯編語(yǔ)言是計(jì)算機(jī)語(yǔ)言的一種,是一種低級(jí)語(yǔ)言。相比高級(jí)語(yǔ)言,匯編語(yǔ)言更接近底層硬件,
    的頭像 發(fā)表于 12-13 11:18 ?1103次閱讀
    匯編<b class='flag-5'>指令</b>是什么 計(jì)算機(jī)<b class='flag-5'>語(yǔ)言</b>匯編<b class='flag-5'>指令</b>簡(jiǎn)介