"r"
означает, что вы указываете %0
как регистр (как вход). (val)
означает, что вы указываете, что регистр должен содержать значение val
. Таким образом, компилятор выделит регистр и убедится, что он содержит val
. Для x86_64 первый аргумент функции будет в %edi
/ %rdi
, и это то, что %0
расширится до.
Я исправлен ...
... если функция не встроена , val
будет передано в edi
/ rdi
, но может быть перетасовано до asm
, но "r"
вызовет компилятор, чтобы он был в каком-то регистре для asm
. (См. Эффект -O0 ниже).
Также может быть встроена функция, которая не объявлена / не определена как встроенная, на более высоких уровнях оптимизации.
Я отмечаю, что это возможно только чтение / запись CR0
в / из регистра общего назначения, а затем только на уровне привилегий 0. @PeterCordes отмечает, что "memory"
clobber, вероятно, будет хорошей идеей. Очевидно, что изменение CR0
может иметь действительно захватывающие побочные эффекты!
Когда я попытался сделать это на -O0
, я обнаружил, что простой inline
был проигнорирован, и функция, скомпилированная для x86_64 для:
lcr0:
pushq %rbp
movq %rsp, %rbp
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
movl %eax,%cr0
nop
popq %rbp
ret
Я полагаю, что gcc_inline
может включать __attribute__((__always_inline__))
, и в этом случае даже в -O0
lcr0
встроено - но с большим количеством прекрасных стековых бизнесов. На этот раз для 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