最近在看kernel的code,裡面有些組語的語法,所以就花點時間把它看了一下,基本上,這邊幾乎都是參考Brennan's Guide to Inline Assembly[1]。
GCC使用的asm是AT&T/UNIX的語法而不是Intel的語法,所以有些不同必須先弄清楚。
GCC 的 inline assembly 基本格式是:
asm ( assembler template : output operands (optional) : input operands (optional) : list of clobbered registers (optional) );沒用的欄位可以空下來。最後一個欄位是用來告訴GCC在asm code中,我們已經用了哪些register。
Register name:
Register的名稱前面必須加上”%”
- AT&T:%eax
- Intel:eax
Source/Destination ordering:
AT&T的source永遠在左邊而destination永遠在右邊
- AT&T:movl %eax, %ebx
- Intel:mov ebx, eax 您可以在Instruction後面會被加上b、w和l,用以區分operand的size,分別代表byte、word和long,在不加的情況下,gcc會自動判斷,但有可能誤判。
Constant value/immediate value format:
Constant value/immediate value前面必須加上”$”
- AT&T:movl $boo, %eax
- Intel:mov eax, boo 將boo的address載到eax中,boo必須是static變數。
#include <stdio.h> int main(int argc, char *argv[]) { static int x __asm__ ("x") = 10; int y; x = atoi(argv[1]); __asm__("movl $x, %0" // 這邊的%0代表後面出現的第一個register,即y。 : "=r" (y)); // output operand前一定要有個"="表示這個constraint是write-only, // "="叫constraint modifier。 // input output operands後一定要跟著相對應的C 變數的參數, // 這是給asm的參數。 printf("x=%p, y=0x%x\n", &x, y); return 0; }
- AT&T:movl $0xabcd, %eax
- Intel:mov eax, abcd 將eax設為0xabcd。
#include <stdio.h> int main(int argc, char *argv[]) { int y; __asm__("movl $0xabcd, %0" : "=r" (y)); printf("y=0x%x\n", y); return 0; }
Referencing memory:
- AT&T:immed32(basepointer,indexpointer,indexscale)
- Intel:[basepointer + indexpointer*indexscale + immed32] 沒用的欄位可以空下來。
- AT&T:_booga
- Intel:[_booga]
#include <stdio.h> int main(int argc, char *argv[]) { static int i __asm__ ("i"); int io; i = atoi(argv[1]); __asm__("movl i, %0;\n" : "=r"(io)); printf("i=%d, io=%d\n", i, io); return 0; }
Addressing a variable offset by a value in a register:
- AT&T:_variable(%eax)
- Intel:[eax + _variable]
#include <stdio.h> int main(int argc, char *argv[]) { struct ic { int i; char c; }; int i = 0; char c = 0; static struct ic ic __asm__ ("ic"); ic.i = 11; ic.c = 'b'; __asm__("movl $ic, %%eax;\n" "mov (%%eax), %0;\n" "mov 4(%%eax), %1;\n" : "=r"(i), "=r"(c) : "m"(ic) : "%eax"); printf("i=%d, c=%c\n", i, c); return 0; }
Addressing a value in an array of integers (scaling up by 4):
- AT&T:_array(,%eax,4)
- Intel:[eax*4 + array]
#include <stdio.h> int main(int argc, char *argv[]) { int i; static int ary[2][3] __asm__("ary") = { {0, 1, 2}, {10, 11, 12} }; // i = ary[1][1] __asm__("movl $12, %%eax;\n" // cal how many size of one raw "movl $4, %%ebx;\n" // which column "movl ary(%%ebx, %%eax, 1), %0;\n" : "=r" (i) : : "%eax", "%ebx"); printf("i=%d\n", i); return 0; }
參考資料
- http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html
- http://www.study-area.org/cyril/opentools/opentools/x969.html