2010年12月18日 星期六

Inline Assembly


最近在看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
為了讓GCC的asm能跨平台,所以可以用%0、%1...%n代表後面依序出現的register。


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]
  • 沒用的欄位可以空下來。
Addressing a particular C variable:
  • 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;
}


參考資料
  1. http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html
  2. http://www.study-area.org/cyril/opentools/opentools/x969.html



沒有留言:

張貼留言

熱門文章