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

AT&T匯編語(yǔ)法

GCC只支持AT&T匯編語(yǔ)法內(nèi)嵌在C語(yǔ)言中。

Intel和AT&T匯編風(fēng)格對(duì)比:

compare.png

AT&T尋址

寄存器間接尋址:

  • mov (%eax), %ebx ;表示將地址eax所指的內(nèi)存復(fù)制4字節(jié)到ebx

寄存器相對(duì)尋址:

  • movb -4(%eax), %al; 表示將地址(eax - 4)所指的內(nèi)存復(fù)制一字節(jié)到al

變址尋址:

segreg(段基址):base_address(offset_address,index,size)
對(duì)應(yīng)表達(dá)式為:
segreg(段基址):base_address + offset_address + index * size

格式中不存在的部分要用‘,’占位,共有4種組合:

  • 無base_address,無offset_address

    movl %eax, (,%esi,2) -- 表示將eax的值寫入esi*2所指的內(nèi)存

  • 無base_address,有offset_address

    movl %eax,(%ebx,%esi,2) -- 表示將eax的值寫入ebx + esi*2所指的內(nèi)存

  • 有base_address,無offset_address

    movl %eax, base_value(,%esi,2) -- 表示將eax的值寫入base_value + esi*2`所指的內(nèi)存

  • 有base_address,有offset_address

    movl %eax, base_value(%ebx,%esi,2) -- 表示將eax的值寫入base_value + %ebx + esi*2`所指的內(nèi)存

基本內(nèi)聯(lián)匯編

內(nèi)聯(lián)匯編基本格式:

  asm [volatile] ("assembly code")  
  volatile關(guān)鍵字可選,使得gcc在-O指定優(yōu)化時(shí),不改變匯編代碼

assembly code規(guī)則:

  1. 指令必須在雙引號(hào)內(nèi)。
  2. 指令之間用分號(hào)、換行符\n或者換行符加制表符\n\t分隔

示例:

char* str = "hello,world\n";
int count = 0;
void main(){
    asm volatile ("\
        pusha; \
        movl $4, %eax; \
        movl $1, %ebx; \
        movl str, %ecx; \
        movl $12, %edx; \
        int $0x80; \
        movl %eax, count; \
        popa \
    ");
}

擴(kuò)展內(nèi)聯(lián)匯編

當(dāng)匯編代碼嵌入到C代碼中,如何找到可用的寄存器是個(gè)問題,程序員不知道哪些寄存器已經(jīng)被分配。GCC提供了擴(kuò)展內(nèi)聯(lián)匯編格式。

擴(kuò)展內(nèi)聯(lián)匯編格式:

asm [volatile] ("assembly code" : output : input : clobber/modify)

  1. output : <output> 用來指定匯編代碼的數(shù)據(jù)如何傳遞給C代碼使用,output中每個(gè)操作數(shù)的格式為:

"操作數(shù)修飾符 + 約束名"(C變量名)

引號(hào)和圓括號(hào)不可少,操作數(shù)修飾符通常為‘=’。多個(gè)操作數(shù)之間用‘,’分隔

  1. input : <input> 用來指定C中數(shù)據(jù)如何傳遞給匯編使用,input中每個(gè)操作數(shù)的格式為:

”[操作數(shù)修飾符] + 約束名“(C變量名)

引號(hào)和圓括號(hào)不可少,操作數(shù)修飾符為可選項(xiàng)。多個(gè)操作數(shù)之間用‘,’分隔

  1. clobber/modify : 匯編代碼執(zhí)行后會(huì)破壞一些內(nèi)存或寄存器資源,通過此項(xiàng)通知編譯器,哪些寄存器或內(nèi)存需要提前保護(hù)起來。

  2. 約束名

    寄存器約束

    寄存器約束就是要求gcc使用哪個(gè)寄存器

    a: eax/ax/al
    b: ebx/bx/bl
    c: ecx/cx/cl
    d: edx/dx/dl
    D: edi/di
    S: esi/si
    q: eax/ebx/ecx/edx中任意一個(gè)
    r: eax/ebx/ecx/edx/esi/edi中任意一個(gè)
    g: 表示存放到任意地點(diǎn)(寄存器和內(nèi)存)
    A:把eax和edx組合成64位整數(shù)
    f: 表示浮點(diǎn)寄存器
    t: 表示第1個(gè)浮點(diǎn)寄存器
    u: 表示第2個(gè)浮點(diǎn)寄存器
    

    示例:

 #include <stdio.h>
 void main(){
     int in_a = 1, in_b = 2, out_sum;
     asm ("addl %%ebx, %%eax":"=a"(out_sum):"a"(in_a),"b"(in_b));
     printf("sum = %d\n",out_sum);
  }

ps: 擴(kuò)展內(nèi)聯(lián)匯編中寄存器前綴是兩個(gè)%

內(nèi)存約束

m: 表示操作數(shù)可以使用任意一種內(nèi)存形式
o: 操作數(shù)位內(nèi)存變量

示例 :

#include <stdio.h>

void main(){
    int in_a = 1, in_b = 2;
    asm ("movb %b0, %1"::"a"(in_a),"m"(in_b));
    printf("in_b = %d\n",in_b);
}

%1序號(hào)占位符,代表in_b的內(nèi)存地址(指針)

%b0表示對(duì)寄存器eax的引用,b表示一個(gè)字節(jié),所以%b0表示al寄存器

立即數(shù)約束

只放在input中

i: 整數(shù)立即數(shù)
F: 浮點(diǎn)數(shù)立即數(shù)
I: 0-31之間的立即數(shù)
J: 0-63之間的立即數(shù)
N: 0-255之間的立即數(shù)
O: 0-32之間的立即數(shù)
X: 任何類型的立即數(shù)

通用約束

0-9: 只用在input部分,表示與output和input中第n個(gè)操作數(shù)用相同的寄存器或內(nèi)存
  1. 占位符

    為方便對(duì)操作數(shù)的引用,擴(kuò)展內(nèi)聯(lián)匯編提供了占位符來表示指定操作數(shù)。

    序號(hào)占位符

    序號(hào)占位符是對(duì)在output和input中的操作數(shù),按照他們從左到右出現(xiàn)的次序從0開始編號(hào),一直到9,最多支持10個(gè)序號(hào)占位符。引用它的格式是%0-9

    若%0表示eax,則%h0 -- 表示ah,%b0表示al

    名稱占位符

    可以對(duì)操作數(shù)進(jìn)行顯示命名,格式如下:

    [名稱]”約束名“(c變量)
    采用%[名稱]的形式引用操作數(shù)

    示例:

    #include <stdio.h>
    
    void main(){
        int in_a = 18, in_b = 3, out = 0;
        asm ("divb %[divisor]; movb %b1, %[result]":[result]"=m"(out):"a"(in_a),[divisor]"m"(in_b));
        printf("out = %d\n",out);
    }
    
  2. 操作數(shù)修飾符

    在output中:

    =: 表示操作數(shù)只寫
    +: 表示操作數(shù)可讀寫
    &: 表示此output中的操作數(shù)要獨(dú)占約束(分配的)寄存器,只供output使用,任何input中分配的寄存器不能與此相同
    

    input中:

    %: 該操作數(shù)可以和下一個(gè)輸入操作數(shù)交換
    

    一般情況下input中的C變量是只讀的,output中的C變量是只寫的。

    示例:

    #include <stdio.h>
    
    void main(){
        int in_a = 1, in_b = 2;
        asm ("addl %%ebx, %%eax":"+a"(in_a):"b"(in_b));
        printf("sum = %d\n",in_a);
    }
    

    參考

《操作系統(tǒng)真相還原》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文作者 Sandeep.S英文原文 [https://www.ibiblio.org/gferg/ldp/GCC...
    JeffreyLi閱讀 40,599評(píng)論 8 41
  • lodsb: ds:[esi] -> al stosb: al -> es:[edi] SCASB: 比較 [ed...
    lindyang閱讀 812評(píng)論 0 0
  • 對(duì)于輸出部和輸入部編號(hào) 輸入代表在匯編開始的時(shí)候進(jìn)行的賦值,或者與匯編中的占位相對(duì)應(yīng),在本例中,匯編中只用到%4,...
    Wi1ls努力努力再努力閱讀 778評(píng)論 0 1
  • 文章來自這里:gcc內(nèi)聯(lián)匯編...... 在閱讀Linux內(nèi)核源碼或?qū)Υa做性能優(yōu)化時(shí),經(jīng)常會(huì)有在C語(yǔ)言中嵌入一段...
    Yihulee閱讀 869評(píng)論 0 0
  • 推薦指數(shù): 6.0 書籍主旨關(guān)鍵詞:特權(quán)、焦點(diǎn)、注意力、語(yǔ)言聯(lián)想、情景聯(lián)想 觀點(diǎn): 1.統(tǒng)計(jì)學(xué)現(xiàn)在叫數(shù)據(jù)分析,社會(huì)...
    Jenaral閱讀 5,984評(píng)論 0 5

友情鏈接更多精彩內(nèi)容