04 July 2009

Inline assembly in Linux

Basic inline
The format of basic inline assembly is very much straight forward.
Its basic form is:
asm("assembly code");

example:
asm("movl %ecx %eax"); /* moves the contents of ecx to eax */
__asm__("movb %bh (%eax)"); /*moves the byte from bh to the memory pointed by eax */

Extended inline
In extended assembly, we can also specify the operands.
Its basic format is:
asm ( assembler template 
: output operands /* optional */
: input operands /* optional */
: list of clobbered registers /* optional */
);

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

Constraints
+---+--------------------+
| 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 |
| m | memory operant |
+---+--------------------+

Constraint modifiers:
"=" : Means that this operand is write-only.
"&" : Means that this operand is an earlyclobber operand.

Information about more constraints are available here.

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.

asm("sidt %0\n" : :"m"(loc));
When the operands are in the memory, any operations performed on them will occur directly in the memory location.

asm ("incl %0" :"=a"(var):"0"(var));
Now the input and output operands are in the same register, EAX.
-----------------stringlen1.c-----------------
#include <unistd.h>

static inline size_t strlen1(const char * s)
{
register int __res;

/* EDI = &"STRING";
* EAX = 0;
* ECX = 0xFFFFFFFF;
*
* OUTPUT at ECX
*/

__asm__ __volatile__(
"repne\n\t"
"scasb\n\t"
"notl %0\n\t"
"decl %0"
:"=c" (__res): "D" (s),"a" (0), "0" (0xffffffff));
return __res;
}

int main()
{
char buff[] = "Hello world!!!";
int len = strlen1(buff);

printf("length of string \"%s\" is %d\n", buff, len);

return 0;
}
---------------------------------------------
gcc -o stringlen1 stringlen1.c
./stringlen1
length of string "Hello world!!!" is 14
---------------------------------------------

-----------------atomicinc.c-----------------
static __inline__ void atomic_inc(int *val)
{
__asm__ __volatile__(
"lock; incl %0"
:"=m" (*val)
:"m" (*val));
}

int main()
{
int value = 0;

printf("value = %d\n", value);
atomic_inc(&value);
printf("value = %d\n", value);

return 0;
}
--------------------------------------------------
gcc -o atomicinc atomicinc.c
./atomicinc
value = 0
value = 1
--------------------------------------------------

Reference:
80386 Instruction Set
http://www.ibm.com/developerworks/linux/library/l-ia.html
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html

No comments:

Post a Comment