一、AT&T vs Intel 語法核心差異
| 項目 | Intel | AT&T |
| 大小寫 | 指令大寫 | 指令小寫 |
| 運算元順序 | 目的, 來源 (右←左) | 來源, 目的 (左→右) |
| 暫存器前綴 | 無 | % (如 %eax) |
| 立即數前綴 | 無 | $ (如 $1) |
| 間接尋址 | [base+index*scale+disp] | disp(base,index,scale) |
| 運算大小後綴 | BYTE PTR 等 | b/w/l/q (如 movl) |
範例對照
Intel: MOV EAX, EBX
AT&T: movl %ebx, %eax
Intel: MOV EAX, [EBX+ECX*4+10h]
AT&T: movl 0x10(%ebx,%ecx,4), %eax
二、GCC 內嵌匯編語法
基本格式
__asm__ __volatile__ (
"assembly template"
: output_operands /* 輸出 */
: input_operands /* 輸入 */
: clobbered_regs /* 破壞描述 */
);
關鍵元件說明
- 範本:匯編指令字串,
%0, %1... 為佔位符對應輸出/輸入
- 輸出部:
"=r" (var) — = 唯寫,r 暫存器約束,var C 變數
- 輸入部:
"r" (expr) — r 暫存器約束,expr C 運算式
- 約束字母:
r 通用暫存器, m 記憶體, i 立即數, g 任意
- 破壞描述:列出被隱性修改的暫存器/記憶體 (如
"cc" 條件碼, "memory")
完整範例:原子加法
int atomic_add(int *ptr, int val) {
int old;
__asm__ __volatile__ (
"lock; xaddl %1, %0"
: "+m" (*ptr), "=r" (old)
: "1" (val)
: "memory", "cc"
);
return old;
}
+m 讀寫記憶體操作數
"1" (val) 指定 %1 使用與輸出 %1 同一暫存器
lock 前綴確保總線鎖定 (多核心原子性)
三、GCC 編譯內嵌匯編流程
- 解析約束,分配暫存器/記憶體位置
- 產生暫存器保存/恢復代碼 (如需要)
- 展開範本,替換佔位符為實際暫存器/位址
- 插入輸出寫回、輸入載入指令
- 輸出最終匯編檔
四、實務建議
- 優先使用編譯器內建函數 (
__sync_*, __atomic_*) 替代手寫原子操作
- 複雜邏輯寫獨立
.s 檔,以 .globl 導出,C 端 extern 呼叫
- 善用
__asm__ goto (GCC 4.5+) 實現控制流跳轉
- 永遠標註
__volatile__ 防止編譯器優化移除/重排
- 破壞描述務必完整,避免編譯器假設暫存器未變而產生錯誤代碼