Environment: Debian 9.5 - gcc 6.3.0
I can't get an embedded assembly function to work when I try to use multiple InputOperands
.
I have the following code working (basic rol
function, 1 InputOperand
, predefined rol
operand):
#include <stdio.h>
#include <stdlib.h>
void asm_rol(int32_t* p_rolled)
{
__asm__ volatile
(
".intel_syntax noprefix;"
"rol %0, 1;"
:"=a"(*p_rolled)
:"a"(*p_rolled)
:"cc"
);
}
int main(int argc, char** argv)
{
int32_t test = 0x1;
asm_rol(&test);
printf("0x%08x\n", test);
return 0;
}
This prints 0x00000002
, and is the correct result of rol 0x1, 1
.
Now I don't understand why the following code does not compile. I think my usage of InputOperands
is bad:
#include <stdio.h>
#include <stdlib.h>
void asm_rol(int32_t* p_rolled, int16_t i)
{
__asm__ volatile
(
".intel_syntax noprefix;"
"rol %0, %1;"
:"=a"(*p_rolled)
:"a"(*p_rolled), "b"(i)
:"cc"
);
}
int main(int argc, char** argv)
{
int32_t test = 0x1;
asm_rol(&test, 1);
printf("0x%08x\n", test);
return 0;
}
gcc returns with the error:
resolve.c: Assembler messages:
resolve.c:6: Error: operand type mismatch for `rol'
I tried with int8_t
and int32_t
for i
, it does not change anything.
I must say that I'm new to embedded asm in C in this environment, I've only done some basic inline assembly with Visual Studio on Windows.
As Michael Petch said in the comments,
the only register that is allowed for a shifting instruction that controls the number of bits to shift is CL
He also provided the following solution:
void asm_rol(int32_t* p_rolled, int8_t i) { __asm__ volatile ( ".intel_syntax noprefix;" "rol %0, %1;" :"+a"(*p_rolled) :"cI"(i) :"cc" ); }
The c says to use the CL register (assuming you change the type of variable i to int8_t instead of int16_t. . The Capital-Eye (I) says the constraint can also be an immediate value between 0 and 32.
As Michael Petch and Peter Cordes pointed out in the comments, my code wasn't working because I was using %1
as rol
operand, but the correct variable was %2
. I did this mistake because I thought only the InputOperands
were referenced by %#
.
Some nice documentation was also provided by Michael Petch and Peter Cordes:
(...) machine constraints can be found here: gcc.gnu.org/onlinedocs/gcc/… under the i386 info
There's no reason to use inline asm for rotates. Best practices for circular shift (rotate) operations in C++
When debugging inline asm, you should look at the compiler-generated asm to see what it substituted into the template. e.g. godbolt.org is handy: How to remove "noise" from GCC/clang assembly output?. You can even do stuff like nop # %0 %1 %2 to just see what the compiler picked for all the operands, whether you reference them in the template or not. See also stackoverflow.com/tags/inline-assembly/info for more guides and examples.
User contributions licensed under CC BY-SA 3.0