본문 바로가기

Programming/Linux_Kernel

x86 inline assembly

http://www.hep.wisc.edu/~pinghc/x86AssmTutorial.htm


http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html






        
        int a=10, b;
        asm ("movl %1, %%eax; 
              movl %%eax, %0;"
             :"=r"(b)        /* output */
             :"r"(a)         /* input */
             :"%eax"         /* clobbered register */
             );       

Here what we did is we made the value of ’b’ equal to that of ’a’ using assembly instructions. Some points of interest are:

  • "b" is the output operand, referred to by %0 and "a" is the input operand, referred to by %1.
  • "r" is a constraint on the operands. We’ll see constraints in detail later. For the time being, "r" says to GCC to use any register for storing the operands. output operand constraint should have a constraint modifier "=". And this modifier says that it is the output operand and is write-only.
  • There are two %’s prefixed to the register name. This helps GCC to distinguish between the operands and registers. operands have a single % as prefix.
  • The clobbered register %eax after the third colon tells GCC that the value of %eax is to be modified inside "asm", so GCC won’t use this register to store any other value.

When the execution of "asm" is complete, "b" will reflect the updated value, as it is specified as an output operand. In other words, the change made to "b" inside "asm" is supposed to be reflected outside the "asm".



요약하자면...

"r" 이나 "m" 같은 것들은 modifier 이다.

리턴값으로 사용할 것은 "=" 를 앞에 붙여준다.


modifier 를 정리해 보면...


6.1 Commonly used constraints.

There are a number of constraints of which only a few are used frequently. We’ll have a look at those constraints.

  1. Register operand constraint(r)

    When operands are specified using this constraint, they get stored in General Purpose Registers(GPR). Take the following example:

    asm ("movl %%eax, %0\n" :"=r"(myval));

    Here the variable myval is kept in a register, the value in register eax is copied onto that register, and the value of myval is updated into the memory from this register. When the "r" constraint is specified, gcc may keep the variable in any of the available GPRs. To specify the register, you must directly specify the register names by using specific register constraints. They are:

    +---+--------------------+
    | r |    Register(s)     |
    +---+--------------------+
    | a |   %eax, %ax, %al   |
    | b |   %ebx, %bx, %bl   |
    | c |   %ecx, %cx, %cl   |
    | d |   %edx, %dx, %dl   |
    | S |   %esi, %si        |
    | D |   %edi, %di        |
    +---+--------------------+
    

  2. Memory operand constraint(m)

    When the operands are in the memory, any operations performed on them will occur directly in the memory location, as opposed to register constraints, which first store the value in a register to be modified and then write it back to the memory location. But register constraints are usually used only when they are absolutely necessary for an instruction or they significantly speed up the process. Memory constraints can be used most efficiently in cases where a C variable needs to be updated inside "asm" and you really don’t want to use a register to hold its value. For example, the value of idtr is stored in the memory location loc:

    asm("sidt %0\n" : :"m"(loc));

  3. Matching(Digit) constraints

    In some cases, a single variable may serve as both the input and the output operand. Such cases may be specified in "asm" by using matching constraints.

    asm ("incl %0" :"=a"(var):"0"(var));

    We saw similar examples in operands subsection also. In this example for matching constraints, the register %eax is used as both the input and the output variable. var input is read to %eax and updated %eax is stored in var again after increment. "0" here specifies the same constraint as the 0th output variable. That is, it specifies that the output instance of var should be stored in %eax only. This constraint can be used:

    • In cases where input is read from a variable or the variable is modified and modification is written back to the same variable.
    • In cases where separate instances of input and output operands are not necessary.

    The most important effect of using matching restraints is that they lead to the efficient use of available registers.

  4. Some other constraints used are:

    1. "m" : A memory operand is allowed, with any kind of address that the machine supports in general.
    2. "o" : A memory operand is allowed, but only if the address is offsettable. ie, adding a small offset to the address gives a valid address.
    3. "V" : A memory operand that is not offsettable. In other words, anything that would fit the `m’ constraint but not the `o’constraint.
    4. "i" : An immediate integer operand (one with constant value) is allowed. This includes symbolic constants whose values will be known only at assembly time.
    5. "n" : An immediate integer operand with a known numeric value is allowed. Many systems cannot support assembly-time constants for operands less than a word wide. Constraints for these operands should use ’n’ rather than ’i’.
    6. "g" : Any register, memory or immediate integer operand is allowed, except for registers that are not general registers.

    Following constraints are x86 specific.

    1. "r" : Register operand constraint, look table given above.
    2. "q" : Registers a, b, c or d.
    3. "I" : Constant in range 0 to 31 (for 32-bit shifts).
    4. "J" : Constant in range 0 to 63 (for 64-bit shifts).
    5. "K" : 0xff.
    6. "L" : 0xffff.
    7. "M" : 0, 1, 2, or 3 (shifts for lea instruction).
    8. "N" : Constant in range 0 to 255 (for out instruction).
    9. "f" : Floating point register
    10. "t" : First (top of stack) floating point register
    11. "u" : Second floating point register
    12. "A" : Specifies the `a’ or `d’ registers. This is primarily useful for 64-bit integer values intended to be returned with the `d’ register holding the most significant bits and the `a’ register holding the least significant bits.




"ir"은 조금 특별함.


  1. __asm__ __volatile__(
                          "   lock       ;\n"
                          "   addl %1,%0 ;\n"
                          : "=m"  (my_var)
                          : "ir"  (my_int), "m" (my_var)
                          :                                 /* no clobber-list */
                          );
    

    This is an atomic addition. We can remove the instruction ’lock’ to remove the atomicity. In the output field, "=m" says that my_var is an output and it is in memory. Similarly, "ir" says that, my_int is an integer and should reside in some register (recall the table we saw above). No registers are in the clobber list.



'Programming > Linux_Kernel' 카테고리의 다른 글

segment 와 paging 기법  (0) 2014.03.31
커널 API - IOCTL 함수 작성시 자료형의 검사  (0) 2014.03.28
Lock-free, cas  (0) 2014.03.24
linxu bash shell script 명령어  (0) 2014.03.19
linux 명령어 dd  (0) 2014.03.12