2011年9月15日 星期四

Inline Assembly: 在C語言裡面嵌入assembly

Reference:
1. http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html
2. http://stenlyho.blogspot.com/2008/08/cinline-casmasm-code-asmmovl-1eaxnt.html
3. Linux device driver programming, Chapter 7-8

The Syntax
兩種不同的表示方法src和dst是相反的
AT&T: movl %eax, %ebx
Intel: mov ebx, eax

The Basic Inline Assembly
1. asm("nop")
2. push the register onto the stack.
asm (
  "pushl %eax\n\t"
  "movl $0, %eax\n\t"
  "popl %eax");
 eax的value放到stack, 在pop出來

3. inline assembly的通式
asm ( "statements" : output_registers : input_registers : clobbered_registers);
asm("組合語言指令碼"
      : 輸出暫存器
      : 輸入暫存器
      : 會更變的暫存器);

輸出暫存器語法, "="代表寫入專用, "+"代表讀寫兩用:
"=暫存器字源(輸出變數)"
"+暫存器字源(輸出變數)"

example from ref3:
u16 cx, ax, dx;
ams("int $0x11"
    : "+a" (ax), "=c" (cx), "=d", (dx)
    :
    : "ebx", "esi", "edi");

example from ref2 (自動分配暫存器):

int main (void) {
      int operand1, operand2, sum, accumulator;
   
      operand1 = rand (); operand2 = rand ();
     
      asm("movl %1, %0\n\t"
              "addl %2, %0"
        : "=r" (sum)   /* output operands */
        : "r" (operand1), "r" (operand2) /* input operands */
        : "0");    /* clobbered operands */
     
      accumulator = sum;
     
      asm("addl %1, %0\n\t"
        "addl %2, %0"
        : "=r" (accumulator)
        : "0" (accumulator), "g" (operand1), "r" (operand2)
        : "0");
      return accumulator;
}

- Note the use of = to specify an output register. You just have to do it that way.
- %0, %1, %2分別代表 "=r", "r" (operand1), 和 "r" (operand2), 順序是從output -> input
- clobber list = "0" 告訴gcc說%0的質已經被改變了 必須重新考慮合法性, "you can no longer count on the values you loaded into ecx or edi to be valid." This doesn't mean they will be reloaded for certain. This is the clobberlist.
- When you do the clobber list, you specify the registers as above with the %. If you write to a variable, you must include "memory" as one of The Clobbered.
- 如果statement裡真要指定register要多加個%變成%%eax

example:
asm ("leal (%0,%0,4), %0"
     : "=r" (x)
     : "0" (x) );
This also works, by the way:
asm ("leal (%%ebx,%%ebx,4), %%ebx"
     : "=b" (x)
     : "b" (x) );

--- list of register loading code ---
a        eax
b        ebx
c        ecx
d        edx
S        esi
D        edi
I        constant value (0 to 31)
q,r      dynamically allocated register (see below) 自動分配
g        eax, ebx, ecx, edx or variable in memory
A        eax and edx combined into a 64-bit integer (use long longs)
 
Example:
asm volatile("int %1\n"
 : "=a" (ret)
 : "i" (T_SYSCALL),
  "a" (num),
  "d" (a1),
  "c" (a2),
  "b" (a3),
  "D" (a4),
  "S" (a5)
 : "cc", "memory"); 
Here %1 means the 2nd parameter in the extended inline assembly code 
(and not the immediate value 1) which is T_SYSCALL (similarly %0
corresponds to the 1st parameter that is ret). 

沒有留言:

張貼留言