"r"
means you are specifying %0
to be a register (as an input). (val)
means you are specifying that the register should contain the value of val
. So the compiler will allocate a register and make sure it contains val
. For x86_64 the first argument for the function will be in %edi
/%rdi
, and that is what %0
will expand to.
I stand corrected...
...if the function is not inlined, val
will be passed in edi
/rdi
but might be shuffled around before the asm
, but the "r"
will cause the compiler to arrange for it to be in some register for the asm
. (See the effect of -O0, below).
Also a function which is not declared/defined to be inline may be inlined, at higher levels of optimization.
I note that it is only possible to read/write CR0
to/from a general purpose register and then only at privilege level 0. @PeterCordes notes that a "memory"
clobber would probably a Good Idea. Clearly, changing CR0
can have really exciting side effects !
When I tried this at -O0
I found that a simple inline
was ignored, and the function compiled for x86_64 to:
lcr0:
pushq %rbp
movq %rsp, %rbp
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
movl %eax,%cr0
nop
popq %rbp
ret
I guess that gcc_inline
may include __attribute__((__always_inline__))
, in which case even at -O0
lcr0
is inlined -- but with lots of lovely stack business. This time for x86:
main:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl 12(%ebp), %eax
movl (%eax), %eax
movl (%eax), %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl %eax,%cr0
nop
movl $0, %eax
leave
ret