asm error: "operand type mismatch for `rol'" with multiple input operands

2

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.

c
gcc
assembly
operands
asked on Stack Overflow Nov 4, 2018 by NdFeB • edited Nov 4, 2018 by NdFeB

1 Answer

3

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.

answered on Stack Overflow Nov 4, 2018 by NdFeB • edited Nov 4, 2018 by NdFeB

User contributions licensed under CC BY-SA 3.0