I have a lot of trouble to make it work:
I have tried the following ways:
uint32_t reverseBits(volatile uint32_t n) {
uint32_t i = n;
__asm__ (".intel_syntax\n"
"xor eax, eax \n"
"inc eax \n"
"myloop: \n"
"shr %0, 1 \n"
"adc eax, eax \n"
"jnc short myloop \n"
"mov %1, %0 \n"
: [i] "=r"(i), [n] "=r"(n));;
return n;
}
I would get:
Line 11: Char 14: error: unknown token in expression
"shr %0, 1 \n"
^
<inline asm>:5:5: note: instantiated into assembly here
shr %edx, 1
^
So apparently the compiler replace %0
by %register
, but still keeping '%'
...
I hence decided to replace %0
with edx
and %1
with ecx
:
uint32_t reverseBits(volatile uint32_t n) {
uint32_t i = n;
__asm__ (".intel_syntax\n"
"xor eax, eax \n"
"inc eax \n"
"myloop: \n"
"shr edx, 1 \n"
"adc eax, eax \n"
"jnc short myloop \n"
"mov ecx, edx \n"
: [i] "=r"(i), [n] "=r"(n));;
return n;
}
And get the resulting error:
AddressSanitizer:DEADLYSIGNAL
=================================================================
==31==ERROR: AddressSanitizer: SEGV on unknown address 0x0001405746c8 (pc 0x00000034214d bp 0x7fff1363ed90 sp 0x7fff1363ea20 T0)
==31==The signal is caused by a READ memory access.
#1 0x7f61ff3970b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
AddressSanitizer can not provide additional info.
==31==ABORTING
I suspect that the compiler optimize things and inline the called function (so not ret), but still clueless about how I could do.
NB: I can't change the compiler from clang to gcc because it's not me but a distant server using clang 11. I also have already read this link but it is pretty old (2013), I would be surprised if things have not changed since then.
edit: Following the excellent answer of Peter Cordes I was able to make it work a little better:
uint32_t reverseBits(volatile uint32_t n) {
uint32_t i = n;
__asm__ (".intel_syntax noprefix\n"
"xor rax,rax \n"
"inc rax \n"
"myloop: \n"
"shr %V0, 1 \n"
"adc eax, eax \n"
"jnc short myloop \n"
"mov %V0, rax \n"
".att_syntax"
: [i] "=r"(i));;
return i;
}
However two things:
1/ I had to change eax
to rax
as %V0
takes 64 bits (r13
), which is weird because i
should only account for 32 bits (uint32_t).
2/ I don't get the desired output:
input is : 00000010100101000001111010011100
output is: 93330624 (00000101100100000001110011000000)
expected: 964176192 (00111001011110000010100101000000)
NB: I tested "mov %V0, 1 \n"
and rightfully get 1
as the output, which proves that the substitution somehow works.