简体   繁体   中英

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

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. eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM