內聯彙編
一、基本內聯彙編
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" 而已,但是由於指令不能直接操作兩個記憶體,需要暫存器做中間變數: