I came across a code that looks like this:
asm volatile (
# [...]
"movl $1200, %%ecx;"
# [...]
);
I know what movl $1200, %ecx does in x86. but I was confused by why there are two percent signs.
GCC inline assembly uses %0, %1, %2, etc. to refer to input and output operands. That means you need to use two %% for real registers.
Check this howto for great information.
It depends
if there is a colon : after the string, then it is an extended asm, and %% escapes the percent which could have especial meanings as mentioned by Carl. Example:
uint32_t in = 1;
uint32_t out = 0;
asm volatile (
"movl %1, %%eax;"
"inc %%eax;"
"movl %%eax, %0"
: "=m" (out) /* Outputs. '=' means written to. */
: "m" (in) /* Inputs. No '='. */
: "%eax"
);
assert(out == in + 1);
otherwise, it will be a compile time error, because without colon it is a basic asm which does not support variable constraints and does not need or support escaping %1. E.g.:
asm volatile ("movl $1200, %ecx;");
works just fine.
Extended asm is more often used since it is much more powerful.
This helps GCC to distinguish between the operands and registers. operands have a single % as prefix. '%%' is always used with registers.
Related
This question already has answers here:
Why we need Clobbered registers list in Inline Assembly?
(1 answer)
For temporary registers in the asm statement, should I use clobber or dummy output?
(1 answer)
How to specify clobbered bottom of the x87 FPU stack with extended gcc assembly?
(1 answer)
Closed 8 months ago.
I just learned clobber usage through these docs(https://gcc.gnu.org/onlinedocs/gcc-7.5.0/gcc/Extended-Asm.html) as well as previous questions.
I also read another introduction post.
The description in the post is:
Its purpose is to inform the compiler that the registers in the
Clobbers list will be implicitly modified by the assembly code in the
asm statement. Since the registers in Clobbers will be implicitly
modified by the assembly code in the asm statement, the compiler will
not use the registers specified in Clobbers when selecting registers
for input operands and output operands, thus avoiding logical errors
such as data overwriting.
In actual use, I still have some confusion.
If I specify the registers used by input and output, do I still need to write clobber? I saw an example introducing clobber.
#include <stdio.h>
int inc2(int src) {
int dst;
asm("mov %1, %0\n\t"
"mov $3, %%eax\n\t"
"add $1, %0"
: "=r"(dst)
: "r"(src));
return dst;
}
int inc3(int src) {
int dst;
asm("mov %1, %0\n\t"
"mov $3, %%eax\n\t"
"add $1, %0"
: "=r"(dst)
: "r"(src)
: "%eax");
return dst;
}
int main(int argc, char *argv[]) {
printf("inc2: %d\n", inc2(1));
printf("inc3: %d\n", inc3(1));
}
The above example outputs are 2 and 4 respectively. The reason is that the eax register is used in mov $3, %eax in the src2 function, and eax is also selected as the input register.
If clobber is used to indicate which registers should not be selected as input registers, if I explicitly instruct, is there no need to write clobber?
For example
int inc4(int src) {
int dst;
asm("mov %%rcx, %%rax\n\t"
"add $1, %%rax"
: "=a"(dst)
: "c"(src)
: );
return dst;
}
In the above example, the input register is explicitly ecx and the output is explicitly eax. Is it possible that by this method I can avoid writing clobber altogether? Or should the registers modified in assembly be marked?
I have seen some use of inline assembly in some open source code, but it is not consistent with my understanding. But these codes are written by very professional people and widely used by many people. I think it's very precise. I would like to analyze some of how to write inline assembly canonically through these examples.
(1) Why does the two functions below clobber include edx and ecx? Is it because the output register (=a) selects eax, so the clobber does not need to be full of eax? There are no input parameters in this function, only one output. What is the significance of marking these two registers?
static inline uint32_t rdtscp() {
uint32_t rv;
asm volatile ("rdtscp": "=a" (rv) :: "edx", "ecx");
return rv;
}
static inline uint32_t memaccesstime(void *v) {
uint32_t rv;
asm volatile (
"mfence\n"
"lfence\n"
"rdtscp\n"
"mov %%eax, %%esi\n"
"mov (%1), %%eax\n"
"rdtscp\n"
"sub %%esi, %%eax\n"
: "=&a" (rv): "r" (v): "ecx", "edx", "esi");
return rv;
}
Thanks!
I'm trying to learn how to use inline assembly in C code.
I have created a small program that should add two integers:
int main(){
int a=1;
int b=2;
asm( "movl %0, %%r8d;"
"movl %1, %%r9d;"
"addl %%r8d, %%r9d;"
"movl %%r9d, %1;"
: "=r" (a)
: "r" (b)
:"%r8","%r9" );
printf("a=%d\n",a);
return 0;
}
The aim was to load a and b into the registers %r8 and %r9, add them, and then put the output back in a.
However this program prints a=2 instead a=3. I'm not sure if the problem is in the inline technique or in the assembly itself.
There are two issues here:
First: The "=r" constraint you use for the output operand a indicates to the compiler that the operand is write-only — it is allowed to assume that the initial value is not needed. This is definitely not the case for your code! Change the qualifier to "+r" to let the compiler know that the initial value is important.
Second: You are moving the result to the wrong register! The target %1 of the last movl is the register corresponding to b, not a. You want %0.
Fixed:
asm(
"movl %0, %%r8d;"
"movl %1, %%r9d;"
"addl %%r8d, %%r9d;"
"movl %%r9d, %0;"
: "+r" (a)
: "r" (b)
: "%r8", "%r9"
);
//quick inline asm statements performing the swap_byte for key_scheduling
inline void swap_byte(unsigned char *x, unsigned char *y)
{
unsigned char t;
asm("movl %1, %%eax;"
"movl %%eax, %0;"
:"=r"(t)
:"r"(*x)
:"%eax");
asm("movl %1, %%eax;"
"movl %%eax, %0;"
:"=r"(*x)
:"r"(*y)
:"%eax");
asm("movl %1, %%eax;"
"movl %%eax, %0;"
:"=r"(*y)
:"r"(t)
:"%eax");
}
Here I am trying to swap the char from x and store in y, and the same for y to x.
I have compiled these instructions by changing movl to mov but with no success. Where is the problem in compiling/linking?
Here is the output from compiling in cygwin:
$ gcc rc4_main.c -o rc4ex
/tmp/ccy0wo6H.s: Assembler messages:
/tmp/ccy0wo6H.s:18: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:18: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:26: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:26: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:34: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:34: Error: operand type mismatch for `mov'
To simplify it even more (than user35443):
asm("" : "=r" (*x), "=r" (*y) : "1" (*x), "0" (*y));
Look ma! No code! And yes, this really works.
To explain how this works:
When the compiler is building the code, it keeps track of what value is in each register. So if had these for inputs to asm:
"r" (*x), "r" (*y)
The compiler will pick a register and put *x in it, then pick a register and put *y in it, then call your asm. But it also keeps track of what variable is in which register. If there were just some way to tell the compiler that all it had to do was start treating the two registers as the opposite variables, then we'd be set. And that's what this code does:
Saying "=r" (*x) means that we are going to be overwriting the value in *x, that that we will be putting the value into a register.
Saying "0" (*y) means that on input to the asm, the compiler must put the value of *y into the same register as is being used by output parameter #0.
So, without using any actually assembly instructions, we have told the compiler to swap these two values.
We don't get this quite "for free" since the compiler must load the values into registers before calling the asm. But since that has to happen anyway...
What about actually updating memory? The compiler will (if necessary) write these values from the registers back to memory. And since it knows what variable is in which register, all works as expected.
unsigned char t;
asm("movl %1, %%eax;"
"movl %%eax, %0;"
:"=r"(t) /* <--here */
:"r"(*x) /* <-- and here */
:"%eax");
You can not move a value from a 32-bit register to a single-byte memory location. t is on the stack and x is somewhere else, but both are accessed in the same way. Problems on the other lines are similar. You should move only a byte.
Try something like this, but there are more ways to do it (I haven't tried that, read below):
unsigned char t;
asm("movb %1, %%al\n"
"movb %%al, %0\n"
:"=r"(t)
:"r"(*x)
:"%al");
asm("movb %1, %%al\n"
"movb %%al, %0\n"
:"=r"(*x)
:"r"(*y)
:"%al");
asm("movb %1, %%al\n"
"movb %%al, %0\n"
:"=r"(*y)
:"r"(t)
:"%al");
The whole procedure can be simplified into this:
asm("movb (%1), %%al\n"
"movb (%2), %%ah\n"
"movb %%ah, (%1)\n"
"movb %%al, (%2)\n"
: /* no outputs for compiler to know about */
: "r" (x), "r" (y)
: "%ax", "memory");
line
movl %%eax, %0;
is full nonsence! So you try to change 0 constant by %eax register It's impossible. In fortran many years ago It was. After that all programs will behave quite unpredictable. Since to avoid that was introduce the rule that any identificatot can't begin with number. But You try do it. It's well to get error. You maybe mean another
movl %0, %%eax;
to set zerro to eax. So better do another code
xorl %%eax, %%eax;
is much better!
I have this code
int64_t ret;
char *fmt = "\n\n\n%s\n\n\n";
char *s;
s = kmalloc(13, GFP_KERNEL);
memcpy(s, "Hello world!\0", 13);
__asm__ __volatile__ (
"movq %2, %%rdi;"
"movq %1, %%rsi;"
"movq $2, %%rax;"
"call printk;"
"movq %%rax, %0;"
: "=r" (ret)
: "r" (s), "r" (fmt)
:
);
__asm__ __volatile__ (
"movq %0, %%rdi;"
"movq $1, %%rax;"
"call kfree;"
:
: "r" (s)
:
);
return ret;
which crashes on the kfree call. It must be something silly, but I can't find out what it is. What is the problem?
EDIT: "Crashes" == The kernel module triggers an Oops.
EDIT: It seems to work just fine if I use m instead of r. But why?
You should look at the generated assembly code (use -S option to gcc) to see exactly what is happening.
I am guessing that the problem is that you didn't specify the correct clobbers for the printk block. Remember that certain registers may be freely used by a called function. The compiler doesn't process the contents of the inline asm block, so it doesn't know it has a call inside. It expects that registers not specified as output or clobber will come out unchanged from the asm block. Thus, I assume the compiler caches the variable s in a register that is destroyed by the printk or your use of rax, rdi and rsi which you also don't tell the compiler. Note that there are specific register constraints, so you could use those instead of moving the arguments around in assembly.
Also note that rax (actually al) is only used for varargs and stdargs functions, and even then it should just contain the number of arguments passed via sse vector (xmm) registers, not the total number. See the x86-64 ABI docs for more information.
Finally, if you really want to write asm code, you should consider writing standalone asm module instead of C if possible. You could save yourself some headache. See this question for an example.
can somebody please explain what exactly this function is doing, I tried to google it, but found nothing:
long __res; //some variable
__asm__ volatile (
"movl $244, %%eax;"
"movl %1, %%ebx;"
"movl %2, %%ecx;"
"movl %3, %%edx;"
"int $0x80;"
"movl %%eax,%0"
: "=m" (__res) //from here can't understand
: "m" (a), "m" (b) , "m" (c)
: "%eax","%ebx","%ecx", "%edx",
);
thanks in advance for any explanation
Taking this step by step:
long __res; //some variable
__asm__ volatile (
"movl $244, %%eax;"
... system calls for 32-bit x86 Linux are selected by the value in %eax. This is the number of the get_thread_area syscall. See arch/x86/include/asm/unistd_32.h (in recent kernels at least) for the list of syscall numbers. (Note: syscall numbers are not the same between 32-bit and 64-bit.)
"movl %1, %%ebx;"
"movl %2, %%ecx;"
"movl %3, %%edx;"
... parameters to system calls are passed in registers. For 32-bit x86, up to five parameters are passed in registers, in the order %ebx, %ecx, %edx, %esi, %edi (the 6th argument, for the few syscalls that need it, is passed on the user stack). %1, %2, %3 refer to the 2nd, 3rd and 4th items mentioned in the "constraints" for the inline assembler (see below).
(This seems slightly odd, by the way: the get_thread_area syscall only needs one argument...)
"int $0x80;"
... invokes the syscall.
"movl %%eax,%0"
... syscalls return a result in %eax; the %0 refers to the first item mentioned in the constraints.
: "=m" (__res) //from here can't understand
... "constraints" tell gcc where it can put the input and output values that are used and produced by the inline assembler block. This first section (after the first :) is for outputs. "=m" here says that __res should be held in memory ("m") and that it is write-only, i.e. any previous value will be overwritten ("="). Operands in constraints can be referred to by numbers in the inline assembly block (e.g. %0), starting from 0 for the first to appear.
: "m" (a), "m" (b) , "m" (c)
... this next section is for inputs. This says that they will all be placed in memory.
: "%eax","%ebx","%ecx", "%edx",
... this final section indicates "clobbered" registers, i.e. those that will be overwritten as a result of code inside the inline assembler block. GCC will put the inline assembler block into the middle of other code that it generates, but it doesn't know what the instructions inside the block actually do - so you have to tell it that any values that may have been in those registers before the block will no longer be valid afterwards.
);
That function is performing a syscall (due to the x86 int 0x80).
The part you flagged is the GCC inline assembler helpers - which allows GCC to change the placeholders (%0-%3) to actual values as given by a C name, in this case, __res, a, b, c.
You can read about the exact inline assembler syntax here:
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
You can find all the info you need about the gcc inline assembly syntax here:
http://www.ibm.com/developerworks/linux/library/l-ia.html