• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 60, 文章 - 0, 評(píng)論 - 197, 引用 - 0
            數(shù)據(jù)加載中……

            GCC 內(nèi)聯(lián)匯編

             
            有時(shí)為了高效,有時(shí)為了直接控制硬件,有些模塊我們不得不直接用匯編語言來編寫,并且對(duì)外提供調(diào)用的接口,隱藏細(xì)節(jié),這其實(shí)就是內(nèi)聯(lián)匯編。如何使用內(nèi)聯(lián)匯編?我們就以 GCC 為例,一窺其中奧秘!


            一、關(guān)鍵字 
               
            如何讓 GCC 知道代碼中內(nèi)嵌的匯編呢? 借助關(guān)鍵字!來看下面的例子:

                 __asm__ __volatile__("hlt");

              __asm__
            表示后面的代碼為內(nèi)嵌匯編,asm __asm__ 的別名。__volatile__ 表示編譯器不要優(yōu)化代碼,后面的指令保留原樣,volatile 是它的別名。括號(hào)里面是匯編指令。

            二、示例分析 
              
            使用內(nèi)嵌匯編,要先編寫匯編指令模板,然后將 C 語言表達(dá)式與指令的操作數(shù)相關(guān)聯(lián),并告訴 GCC 對(duì)這些操作有哪些限制條件。示例如下:
             
               __asm__ __violate__ ("movl %1,%0" : "=r" (result) : "m" (input));   

                movl %1,%0  
            是指令模板;%0   %1 代表指令的操作數(shù),稱為占位符,內(nèi)嵌匯編靠它們將C 語言表達(dá)式與指令操作數(shù)相對(duì)應(yīng)。

               
            指令模板后面用小括號(hào)括起來的是 C 語言表達(dá)式,本例中只有兩個(gè):result input ,他們按照出現(xiàn)的順序分別與指令操作數(shù) %0 %1 對(duì)應(yīng);注意對(duì)應(yīng)順序:第一個(gè) C 表達(dá)式對(duì)應(yīng) %0 ;第二個(gè)表達(dá)式對(duì)應(yīng) %1 ,依次類推,操作數(shù)至多有10 個(gè),分別用 %0, %1 …. %9 表示。

               
            在每個(gè)操作數(shù)前面有一個(gè)用引號(hào)括起來的字符串,字符串的內(nèi)容是對(duì)該操作數(shù)的限制或者說要求。result 前面的限制字符串是 =r ,其中 = 表示 result 是輸出操作數(shù), r  表示需要將 result 與某個(gè)通用寄存器相關(guān)聯(lián),先將操作數(shù)的值讀入寄存器,然后在指令中使用相應(yīng)寄存器,而不是 result 本身,當(dāng)然指令執(zhí)行完后需要將寄存器中的值存入變量 result ,從表面上看好像是指令直接對(duì) result 進(jìn)行操作,實(shí)際上 GCC 做了隱式處理,這樣我們可以少寫一些指令。 input 前面的 r 表示該表達(dá)式需要先放入某個(gè)寄存器,然后在指令中使用該寄存器參加運(yùn)算。 

              C
            表達(dá)式或者變量與寄存器的關(guān)系由 GCC 自動(dòng)處理,我們只需使用限制字符串指導(dǎo) GCC 如何處理即可。限制字符必須與指令對(duì)操作數(shù)的要求相匹配,否則產(chǎn)生的匯編代碼將會(huì)有錯(cuò),讀者可以將上例中的兩個(gè) r,都改為 m (m表示操作數(shù)放在內(nèi)存,而不是寄存器中),編譯后得到的結(jié)果是: 

                       movl input, result

            很明顯這是一條非法指令,因此限制字符串必須與指令對(duì)操作數(shù)的要求匹配。例如指令 movl 允許寄存器到寄存器,立即數(shù)到寄存器等,但是不允許內(nèi)存到內(nèi)存的操作,因此兩個(gè)操作數(shù)不能同時(shí)使用 m 作為限定字符。
            內(nèi)嵌匯編語法如下: 

                       __asm__(
            匯編語句模板: 輸出部分: 輸入部分: 破壞描述部分)

            共四個(gè)部分:匯編語句模板,輸出部分,輸入部分,破壞描述部分,各部分使用“:”格開,匯編語句模板必不可少,其他三部分可選,如果使用了后面的部分,而前面部分為空,也需要用“:”格開,相應(yīng)部分內(nèi)容為空。例如: 

                       __asm__ __volatile__("cli": : :"memory")

            具體這幾部分都有什么限制呢?這得從細(xì)處著手!


            三、語法細(xì)節(jié)
            1
            、匯編語句模板
               
            匯編語句模板由匯編語句序列組成,語句之間使用“;”“\n” “\n\t” 分開。指令中的操作數(shù)可以使用占位符引用 C 語言變量,操作數(shù)占位符最多10 個(gè),名稱如下:%0%1%9。指令中使用占位符表示的操作數(shù),總被視為 long 型(4個(gè)字節(jié)),但對(duì)其施加的操作根據(jù)指令可以是字或者字節(jié),當(dāng)把操作數(shù)當(dāng)作字或者字節(jié)使用時(shí),默認(rèn)為低字或者低字節(jié)。對(duì)字節(jié)操作可以顯式的指明是低字節(jié)還是次字節(jié)。方法是在 % 和序號(hào)之間插入一個(gè)字母,b 代表低字節(jié),h 代表高字節(jié),例如:%h1

            2
            、輸出部分
               
            輸出部分描述輸出操作數(shù),不同的操作數(shù)描述符之間用逗號(hào)格開,每個(gè)操作數(shù)描述符由限定字符串和 C 語言變量組成。每個(gè)輸出操作數(shù)的限定字符串必須包含“=”表示他是一個(gè)輸出操作數(shù)。 例如:
             
                     __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x) )

            描述符字符串表示對(duì)該變量的限制條件,這樣 GCC 就可以根據(jù)這些條件決定如何分配寄存器,如何產(chǎn)生必要的代碼處理指令操作數(shù)與 C 表達(dá)式或 C 變量之間的聯(lián)系。

            3
            、輸入部分
               
            輸入部分描述輸入操作數(shù),不同的操作數(shù)描述符之間使用逗號(hào)格開,每個(gè)操作數(shù)描述符由限定字符串和 C 語言表達(dá)式或者 C 語言變量組成。 示例如下:

            1
             __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));

            2
            Static __inline__ void __set_bit(int nr, volatile void * addr)

                   __asm__(
                                   "btsl %1,%0"
                                   :"=m" (ADDR)
                                   :"Ir" (nr));
            }

            后例功能是將 (*addr) 的第 nr 位設(shè)為 1。第一個(gè)占位符 %0 語言變量 ADDR 對(duì)應(yīng),第二個(gè)占位符 %1 C 語言變量 nr 對(duì)應(yīng)。因此上面的匯編語句代碼與下面的偽代碼等價(jià):btsl nr, ADDR,該指令的兩個(gè)操作數(shù)不能全是內(nèi)存變量,因此將 nr 的限定字符串指定為“Ir”,將 nr 與立即數(shù)或者寄存器相關(guān)聯(lián),這樣兩個(gè)操作數(shù)中只有 ADDR 為內(nèi)存變量。

            4
            、限制字符
               
            限制字符有很多種,有些是與特定體系結(jié)構(gòu)相關(guān),此處僅列出常用的限定字符和i386中可能用到的一些常用的限定符。它們的作用是指示編譯器如何處理其后的 C 語言變量與指令操作數(shù)之間的關(guān)系。

             

            分類

            限定符

            描述

            通用寄存器

            “a”

            將輸入變量放入eax

            “b”

            將輸入變量放入ebx

            “c”

            將輸入變量放入ecx

            “d”

            將輸入變量放入edx

            “s”

            將輸入變量放入esi

            “d”

            將輸入變量放入edi

            “q”

            將輸入變量放入eaxebxecxedx中的一個(gè)

            “r”

            將輸入變量放入通用寄存器,eax,ebx,ecx,edx,esi,edi之一

            “A”

            eaxedx合成一個(gè)64 位的寄存器(use long longs)

            內(nèi)存

            “m”

            內(nèi)存變量

            “o”

            操作數(shù)為內(nèi)存變量,但其尋址方式是偏移量類型, 也即基址尋址

            “V”

            操作數(shù)為內(nèi)存變量,但尋址方式不是偏移量類型

            “ ”

            操作數(shù)為內(nèi)存變量,但尋址方式為自動(dòng)增量

            “p”

            操作數(shù)是一個(gè)合法的內(nèi)存地址(指針)

            寄存器或內(nèi)存

            “g”

            將輸入變量放入eaxebxecxedx之一,或作為內(nèi)存變量

            “X”

            操作數(shù)可以是任何類型

            立即數(shù)

            “I”

            0-31之間的立即數(shù)(用于32位移位指令)

            “J”

            0-63之間的立即數(shù)(用于64位移位指令)

            “N”

            0-255之間的立即數(shù)(用于out指令)

            “i”

            立即數(shù)

            “n”

            立即數(shù),有些系統(tǒng)不支持除字以外的立即數(shù),則應(yīng)使用“n”而非 “i”

            匹配

            “ 0 ”

            表示用它限制的操作數(shù)與某個(gè)指定的操作數(shù)匹配

            “1” ...

            也即該操作數(shù)就是指定的那個(gè)操作數(shù),例如“0”

            “9”

            去描述1”操作數(shù),那么“%1”引用的其實(shí)就是“%0”操作數(shù),注意作為限定符字母的09 與指令中的0”9”的區(qū)別,前者描述操作數(shù), 后者代表操作數(shù)。

            &

            該輸出操作數(shù)不能使用過和輸入操作數(shù)相同的寄存器

            操作數(shù)類型

            “=”

            操作數(shù)在指令中是只寫的(輸出操作數(shù))   

            “+”

            操作數(shù)在指令中是讀寫類型的(輸入輸出操作數(shù))

            浮點(diǎn)數(shù)

            “f”

            浮點(diǎn)寄存器

            “t”

            第一個(gè)浮點(diǎn)寄存器

            “u”

            第二個(gè)浮點(diǎn)寄存器

            “G”

            標(biāo)準(zhǔn)的80387浮點(diǎn)常數(shù)

            %

            該操作數(shù)可以和下一個(gè)操作數(shù)交換位置,例如addl的兩個(gè)操作數(shù)可以交換順序(當(dāng)然兩個(gè)操作數(shù)都不能是立即數(shù))

            #

            部分注釋,從該字符到其后的逗號(hào)之間所有字母被忽略

            *

            表示如果選用寄存器,則其后的字母被忽略



             5
            、破壞描述部分
               
            破壞描述符用于通知編譯器我們使用了哪些寄存器或內(nèi)存,由逗號(hào)格開的字符串組成,每個(gè)字符串描述一種情況,一般是寄存器名;除寄存器外還有 “memory”。例如:“%eax”“%ebx”“memory” 等。

             

             

            posted on 2008-02-26 15:20 Normandy 閱讀(8731) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Programming

            狠狠人妻久久久久久综合| 久久午夜伦鲁片免费无码| 蜜臀久久99精品久久久久久小说| 伊人热热久久原色播放www| 日本精品久久久久影院日本| 久久天天躁狠狠躁夜夜2020老熟妇| 久久精品免费网站网| 精品久久久久成人码免费动漫| 久久综合给合综合久久| 少妇熟女久久综合网色欲| 麻豆成人久久精品二区三区免费| 久久久久人妻精品一区二区三区| 好属妞这里只有精品久久| 精品久久久久久久久久久久久久久| 久久精品国产一区二区三区不卡| 久久久久久曰本AV免费免费| 久久久久久久亚洲Av无码| 久久久久久狠狠丁香| 超级碰碰碰碰97久久久久| 国产人久久人人人人爽| 日本欧美国产精品第一页久久| 色88久久久久高潮综合影院 | 久久国产欧美日韩精品| 精品久久久久久国产三级| 亚洲国产精品无码久久SM| 精品综合久久久久久88小说| 无码国内精品久久人妻蜜桃| 久久久精品日本一区二区三区| 人妻久久久一区二区三区| 久久久久久久久久免免费精品| 精品久久久久久中文字幕人妻最新| 看全色黄大色大片免费久久久| 99国产精品久久| 久久久噜噜噜久久中文福利| 狠狠色噜噜色狠狠狠综合久久| 精品久久人人爽天天玩人人妻| 国产亚洲色婷婷久久99精品| 久久www免费人成看片| 麻豆久久| 热RE99久久精品国产66热| 久久精品国内一区二区三区|