PoiNtEr->: Inline-Assembly

                             Difference between a dream and an aim. A dream requires soundless sleep, whereas an aim requires sleepless efforts.

Search This Blog

Monday, April 16, 2012

Inline-Assembly



We can instruct the compiler to insert the code of a function into the code of its callers, to the point where actually the call is to be made. Such functions are inline functions. Sounds similar to a Macro? Indeed there are similarities.
What is the benefit of inline functions?
This method of inlining reduces the function-call overhead. And if any of the actual argument values are constant, their known values may permit simplifications at compile time so that not all of the inline function’s code needs to be included. The effect on code size is less predictable, it depends on the particular case. To declare an inline function, we’ve to use the keyword inline in its declaration.
Inline assembly is important primarily because of its ability to operate and make its output visible on C variables. Because of this capability, "asm" works as an interface between the assembly instructions and the "C" program that contains it.
Programming Languages 


There are some things to note when using inline assembler in C program, firstly, most of C compiler uses the AT&T format, not the Intel format that most people are used to. In the AT&T format, the operands are reversed. If you use a register as an operand, prefix it with % and immediate values get a $. You also have to add a suffix to the instructions to specify the size of the operands.
movl %ecx, %ebx
Notice the 'l' at the end of mov. This specifies that the instruction is working on 32 bit operands. 'w' indicates that the instruction is using 16 bit operands and 'b' for 8 bit.
So, with all that under your belt, how do you actually add it into your code? You use the asm keyword. It takes the following form.
asm("instructions" : outputs : inputs : clobber list);
You don't actually need to use the last three, but for longer code you will need them. Let's see what they do.
asm volatile("
 pushl %%eax
 movl %1, %%eax
 movl %2, %%ebx
 addl %%ebx, %%eax
 movl %%eax, %0
 popl %%eax"
 : "=g" (i)
 : "g" (j), "g" (k)
 : "bx" );
Wow. Let's go through that piece of code step by step. The actual code, as you can probably figure out, adds j and k and puts the output in i. Firstly, what's with the '%%'? If you have any inputs or outputs, then you must put %% before your register names. Next up, the input list. Who is 'g'? G simply tells the compiler to put the argument anywhere. You can then reference them in order, %0 is i, %1 is j and %2 is k. '=g' tells the compiler that it is output. We put ebx into the clobbered list because it gets clobbered.


Clobber List



Some instructions clobber some hardware registers. We have to list those registers in the clobber-list, ie the field after the third ’:’ in the asm function. This is to inform gcc that we will use and modify them ourselves. So gcc will not assume that the values it loads into these registers will be valid. We shoudn’t list the input and output registers in this list. Because, gcc knows that "asm" uses them (because they are specified explicitly as constraints). If the instructions use any other registers, implicitly or explicitly (and the registers are not present either in input or in the output constraint list), then those registers have to be specified in the clobbered list.

Volatile ...?


If you are familiar with kernel sources or some beautiful code like that, you must have seen many functions declared as volatile or __volatile__ which follows an asm or __asm__. I mentioned earlier about the keywords asm and __asm__. So what is this volatile?
If our assembly statement must execute where we put it, (i.e. must not be moved out of a loop as an optimization), put the keyword volatile after asm and before the ()’s. So to keep it from moving, deleting and all, we declare it as
asm volatile ( ... : ... : ... : ...);
Use __volatile__ when we have to be verymuch careful.
If our assembly is just for doing some calculations and doesn’t have any side effects, it’s better not to use the keyword volatile. Avoiding it helps gcc in optimizing the code and making it more beautiful.

Example C Program:

//make value of b equal to value of a
#include<stdio.h>
int main(int argc,char *argv)
{
 int a=10, b;
asm volatile("movl %1, %%eax;movl %%eax, %0;":"=r"(b):"r"(a) :"%eax" );       
printf("%d\n",b);
}


No comments:

Post a Comment