1. 程式人生 > 其它 >內聯彙編

內聯彙編

一、基本內聯彙編

1.asm [volatile] ("彙編指令")

——所有彙編指令,必須用雙引號包起來,超過一條指令必須用用 \n 進行分割,為了排版,需要加上 \t。比如說,下面是一張加 \t 和不加 \t 的對比圖,可以看出加上 \t 後指令會對齊

  和 C 語言一樣,加上 volatile 會告訴編譯器不要優化內聯彙編。

2.操作全域性變數

  暫存器和記憶體之間可以互相交換資料,對於暫存器,必須要加 % 引用

二、擴充套件內聯彙編

  全域性變數有著自己的標籤,可以被內聯彙編識別出來,但是區域性變數就不行了。為了解決這個問題,出現了擴充套件內聯彙編格式

  asm [volatile] ("彙編指令" : "輸出運算元列表" : "輸入運算元列表" : "改動的暫存器"),其規則如下:

——輸出運算元列表,將處理結果傳遞到 C 程式碼。

——輸入運算元列表,將 C 程式碼的運算元傳遞給內聯彙編。

——告訴編譯器用了哪些暫存器。

——改動的暫存器可以忽略,但前兩個冒號必須要有,即使其中一個什麼也沒有。

1.輸入輸出運算元列表

  告訴內聯彙編程式碼,向哪些記憶體地址或暫存器讀取/輸出資料,這個過程需要滿足一定的格式:

  "[輸出修飾符]約束"(暫存器或記憶體地址)

1.約束

——a:使用 eax/ax/al 暫存器;

——b:使用 ebx/bx/bl 暫存器;

——c:使用 ecx/cx/cl 暫存器;

——d:使用 edx/dx/dl 暫存器;

——r:使用通用暫存器;

——m:使用記憶體地址。

2.輸出修飾符

——+:表示被修飾的運算元可讀可寫;

——=:表示被修飾的運算元只能寫入;

——%:表示被修飾的運算元可以和下一個運算元互換;

——&:行內函數完成前,可以重新使用或刪除被修飾的運算元。

2.使用暫存器操作區域性變數

  用 eax 修飾變數 a,用 ebx 修飾變數 b,用 ecx 修飾變數 sum,輸入變數可以不加輸出修飾符,但輸出變數需要加 "="去修飾,同時擴充套件內聯彙編需要加兩個 %% 去修飾暫存器

3.宣告改動的暫存器

  上一小節中,可以看到 gcc 使用了 edx 暫存器,現在來讓 gcc 不使用這個暫存器:

 

三、使用佔位符

  如果變數很多的話,暫存器不太夠用,所以出現了佔位符。

1.用佔位符代替暫存器

  按照輸入輸出列表中的順序,分別是 0,1,2......:

2.給暫存器起別名

  編號看起來還需要對比運算元列表,閱讀體驗感不佳,所以可以給他取個別名,這樣一眼就可以看出是要進行 a + b 的操作,將結果賦給 sum:

3.直接操作記憶體

  其實和使用暫存器沒啥區別,就是將修飾符改成 "m" 而已,但是由於指令不能直接操作兩個記憶體,需要暫存器做中間變數: