The simplest possible case is something like this:
asm ( "nop" ); /* on an x86 */ asm ( "move r0, r0" ); /* on an ARM */These examples are simple because these "nop" instructions do not affect registers or memory. In other words, they have no side effects. As soon as you start using registers or doing things that the compiler may need to know about, you really need to sit down and learn the whole business. The above links are pretty good.
If you actually want to use this code (such as for a short delay of some such) you will probably need to add the word "volatile" after the "asm" or the compiler will optimize it away. Essentially the word "volatile" tells the optimizer to keep its hands off.
asm volatile ( "nop" );You can also use __asm__ and __volatile__ if you think there may be name conflicts with your code.
asm ( "A" : O : I : C );Where:
asm("mov %0, %1, ror #1" : "=r" (result) : "r" (value)); /* ARM assembler */In this statement, %0 refers to the first item encountered, not in the "A" section, but in the "O, I, C" list that follows. The man bad thing here is the confusion about numbering. Here %0 corresponds to "result" and %1 corresponds to "value". Here, "result" and "value" are variables in the C code.
Also note in passing that in ARM assembler data flows from right to left, whereas in X86 assembler, data flows from left to right.
The new way avoids all the confusion about numbering. Each "connection" is given a name. It looks like this (ARM assembly here):
asm("mov %[res], %[val], ror #1" : [res] "=r" (result) : [val] "r" (value));Here the symbols "res" and "val" specify what corresponds to what between the "A" section and the "O, I, C" sections to the right of it. The fancy name for these is "symbolic operand names" and they live in their own isolated name space and have nothing to do with C variable names. Here again, "result" and "value" are variables in the C code.
GCC supports both of these methods so that old code need never die.
"r1", "r4", "cc" "esp", "memory"
The following transfers the contents of the ESP register (stack pointer) to a C variable "sp".
asm("movl %%esp, %0\n" :"=r"(sp));Here are a pair to read and write the x86 "cr8" register, to and from a C variable "val".
asm volatile("movq %%cr8,%0" : "=r" (val)); asm volatile("movq %0,%%cr8" :: "r" (val) : "memory");The following are from arch/x86/include/asm/pci_x86.h. The first supplies the C variable "pos" and reads into "val". The second supplies both "pos" and "val". Notice that the letter "a" indicates the EAX register is being used.
asm volatile("movl (%1),%%eax" : "=a" (val) : "r" (pos)); asm volatile("movl %%eax,(%1)" : : "a" (val), "r" (pos) : "memory");
You used to see a lot more inline assembly hidden inside macros, but that seems to have fallen out of vogue.
/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ static inline void rep_nop(void) { asm volatile("rep; nop" ::: "memory"); }And for the person who endures to the end, here is a bonus: a routine to read the x86 timestamp counter on a 32 bit processor: Compare this to the first example that reads the value of the stack pointer. Here the big difference is the "A" (not to be confused with "a"). This is x86 specific and pertains to 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. Just about custom made for the 64 bit TSC counter, eh?
static inline unsigned long long read_tsc (void) { unsigned long long val; asm volatile("rdtsc" : "=A" (val) ); return val; }
Tom's Computer Info / tom@mmto.org