AT&T vs Intel 語法核心差異
| 特性 | AT&T (GCC默認) | Intel (MSVC/NASM) |
| 操作數順序 | 源 → 目的 movl %ecx, %eax | 目的 ← 源 mov eax, ecx |
| 寄存器前綴 | % %eax | 無 eax |
| 立即數前綴 | $ $42 | 無 42 |
| 內存操作數後綴 | b/w/l/q (1/2/4/8字節) movl (%ecx), %eax | byte/word/dword/qword ptr mov eax, dword ptr [ecx] |
| 間接寻址 | disp(base,index,scale) 8(%rbp,%rax,4) | [base + index*scale + disp] [rbp + rax*4 + 8] |
GCC 內聯匯編完整模板
asm (
"汇编指令模板" // 指令字符串,%0 %1 對應操作數
: "=约束" (输出变量) // 輸出操作數,= 表示只寫
: "约束" (输入变量) // 輸入操作數
: "clobber列表" // 被隱式修改的寄存器/內存/cc
);
實戰案例:循環左移優化
C語言版本 (編譯器可能優化為rol)
unsigned int rotl_c(unsigned int x, unsigned char n) {
return (x << n) | (x >> (32 - n));
}
內聯匯編版本 (顯式控制)
unsigned int rotl_asm(unsigned int x, unsigned char n) {
unsigned int res;
__asm__ (
"rolb %1, %0" // 8位旋轉,cl隱含計數
: "=a" (res) // 輸出:eax → res
: "0" (x), "c" (n) // 輸入:eax←x, ecx←n ("0"綁定第0輸出)
: "cc" // 修改標誌寄存器
);
return res;
}
關鍵約束解析
"=a":輸出到%eax,=表示覆蓋寫入
"0":輸入綁定第0個輸出操作數(這裡也是%eax)
"c":輸入放入%ecx (x86旋轉指令隱含計數器)
"cc":告知編譯器標誌位被修改,避免錯誤優化
常用約束字母速查表
| 字母 | 含義 | 適用寄存器 |
a | 累加器 | eax/ax/al |
b | 基址 | ebx/bx/bl |
c | 計數器 | ecx/cx/cl |
d | 數據 | edx/dx/dl |
S | 源索引 | esi/si |
D | 目的索引 | edi/di |
r | 任意通用寄存器 | eax/ebx/ecx/edx/esi/edi |
q | 任意低8位可寻址 | eax/ebx/ecx/edx |
m | 內存操作數 | 任意地址 |
g | 通用 (寄存器/內存/立即數) | 最靈活 |
I/J/K... | 特定範圍立即數 | 架構相關 |
進階技巧
1. 條件碼輸出
int cmp_asm(int a, int b) {
int result;
__asm__ (
"cmpl %1, %2; setg %0"
: "=q" (result) // q: 可用al/bl/cl/dl (setg只寫低8位)
: "r" (a), "r" (b)
: "cc"
);
return result;
}
2. 內存屏障與volatile
// 防止編譯器重排/刪除
__asm__ __volatile__ ("" ::: "memory"); // 編譯器屏障
__asm__ __volatile__ ("mfence" ::: "memory"); // 硬件屏障
3. 輸出C源碼為匯編
# AT&T 語法
gcc -S -O2 -masm=att foo.c -o foo_att.s
# Intel 語法 (需源碼無AT&T內聯匯編)
gcc -S -O2 -masm=intel foo.c -o foo_intel.s
避坑指南
- 雙重百分號:模板中寄存器寫
%%eax,輸出單個%
- clobber列表:漏寫導致編譯器假設寄存器不變,產生極難調試的錯誤
- 輸入輸出別名:用
"0"綁定避免多餘mov指令
- 早期clobber:
"=&r" 防止輸入輸出分配同一寄存器
- 64位調用約定:System V AMD64 ABI 前6參數用 RDI,RSI,RDX,RCX,R8,R9
總結
GCC內聯匯編是「高性能C」的終極武器。掌握AT&T語法、約束系統、clobber語義、調用約定,配合-O2 -march=native,能在關鍵熱點路徑榨乾CPU性能。但切記:優先相信編譯器優化,僅在SIMD、特權指令、精確時序、鎖自由算法等編譯器無能為力處手寫匯編,並用內建函數(__builtin_*)作為中間選擇。
- 上一篇文章: C語言limits.h詳解:整型邊界常量的權威指南與避坑實戰
- 下一篇文章: C語言標準預定義宏:調試定位的「GPS定位系統」
Copyright ©
程式碼之家 All Rights Reserved