gcc内联装配错误“mov的操作数类型不匹配”

时间:2021-12-26 03:18:04
//quick inline asm statements performing the swap_byte for key_scheduling
inline void swap_byte(unsigned char *x, unsigned char *y)
{
 unsigned char t;
 asm("movl %1, %%eax;"
     "movl %%eax, %0;"
     :"=r"(t)
     :"r"(*x)
     :"%eax");
 asm("movl %1, %%eax;"
     "movl %%eax, %0;"
     :"=r"(*x)
     :"r"(*y)
     :"%eax");
 asm("movl %1, %%eax;"
     "movl %%eax, %0;"
     :"=r"(*y)
     :"r"(t)
     :"%eax");       
}

Here I am trying to swap the char from x and store in y, and the same for y to x. I have compiled these instructions by changing movl to mov but with no success. Where is the problem in compiling/linking?

我在这里尝试从x交换char,并将其存储在y中,同样地交换到x中。我通过将movl更改为mov来编译这些指令,但是没有成功。编译/链接的问题在哪里?

Here is the output from compiling in cygwin:

cygwin编译输出如下:

$ gcc rc4_main.c -o rc4ex
/tmp/ccy0wo6H.s: Assembler messages:
/tmp/ccy0wo6H.s:18: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:18: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:26: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:26: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:34: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:34: Error: operand type mismatch for `mov'

3 个解决方案

#1


1  

unsigned char t;
asm("movl %1, %%eax;"
     "movl %%eax, %0;"
     :"=r"(t)  /* <--here */
     :"r"(*x)  /* <-- and here */
     :"%eax");

You can not move a value from a 32-bit register to a single-byte memory location. t is on the stack and x is somewhere else, but both are accessed in the same way. Problems on the other lines are similar. You should move only a byte.

不能将值从32位寄存器移动到单字节内存位置。t在堆栈上,x在其他地方,但两者都以相同的方式访问。其他线路上的问题也类似。你应该只移动一个字节。

Try something like this, but there are more ways to do it (I haven't tried that, read below):

尝试这样的方法,但是有更多的方法去做(我还没试过,请看下面):

unsigned char t;
asm("movb %1, %%al\n"
     "movb %%al, %0\n"
     :"=r"(t)
     :"r"(*x)
     :"%al");
asm("movb %1, %%al\n"
     "movb %%al, %0\n"
     :"=r"(*x)
     :"r"(*y)
     :"%al");
asm("movb %1, %%al\n"
     "movb %%al, %0\n"
     :"=r"(*y)
     :"r"(t)
     :"%al"); 

The whole procedure can be simplified into this:

整个过程可以简化为:

asm("movb (%1), %%al\n"
    "movb (%2), %%ah\n"
    "movb %%ah, (%1)\n"
    "movb %%al, (%2)\n"
    : /* no outputs for compiler to know about */
    : "r" (x), "r" (y)
    : "%ax", "memory");

#2


6  

To simplify it even more (than user35443):

进一步简化(超过user35443):

asm("" : "=r" (*x), "=r" (*y) : "1" (*x), "0" (*y));

Look ma! No code! And yes, this really works.

看马!没有代码!是的,这确实有效。

To explain how this works:

解释这是如何工作的:

When the compiler is building the code, it keeps track of what value is in each register. So if had these for inputs to asm:

编译器在构建代码时,会跟踪每个寄存器中的值。如果把这些输入到asm中

"r" (*x), "r" (*y)

“r”(* x),“r”(* y)

The compiler will pick a register and put *x in it, then pick a register and put *y in it, then call your asm. But it also keeps track of what variable is in which register. If there were just some way to tell the compiler that all it had to do was start treating the two registers as the opposite variables, then we'd be set. And that's what this code does:

编译器将选择一个寄存器并将*x放入其中,然后选择一个寄存器并将*y放入其中,然后调用asm。但它也会跟踪寄存器中的变量。如果有某种方法告诉编译器它需要做的就是把两个寄存器当作相反的变量,那么我们就会被设置,这就是代码的作用:

  1. Saying "=r" (*x) means that we are going to be overwriting the value in *x, that that we will be putting the value into a register.
  2. 说"=r" (*x)意味着我们将重写*x中的值,我们将把值放入寄存器中。
  3. Saying "0" (*y) means that on input to the asm, the compiler must put the value of *y into the same register as is being used by output parameter #0.
  4. 说“0”(*y)意味着在对asm的输入时,编译器必须将*y的值放入与输出参数#0使用的寄存器相同的寄存器中。

So, without using any actually assembly instructions, we have told the compiler to swap these two values.

因此,不使用任何实际的汇编指令,我们已经告诉编译器交换这两个值。

We don't get this quite "for free" since the compiler must load the values into registers before calling the asm. But since that has to happen anyway...

我们并不是完全“免费”获得这个值,因为编译器必须在调用asm之前将值加载到寄存器中。但既然这一切都必须发生……

What about actually updating memory? The compiler will (if necessary) write these values from the registers back to memory. And since it knows what variable is in which register, all works as expected.

那么更新内存呢?编译器将(如果需要)将这些值从寄存器写回内存。因为它知道哪个变量在哪个寄存器中,所有的工作都是预期的。

#3


-1  

line

movl %%eax, %0; 

is full nonsence! So you try to change 0 constant by %eax register It's impossible. In fortran many years ago It was. After that all programs will behave quite unpredictable. Since to avoid that was introduce the rule that any identificatot can't begin with number. But You try do it. It's well to get error. You maybe mean another

充满nonsence !所以你试着改变0常数%eax寄存器是不可能的。在很多年前的fortran语言中是这样的。在此之后,所有的程序都将表现得非常不可预测。为了避免这种情况,引入了任何标识符都不能以数字开头的规则。但你试着去做。有错误也无妨。也许你的意思是另一个

movl %0, %%eax; 

to set zerro to eax. So better do another code

将zerro设置为eax。所以最好再做一个代码

xorl %%eax, %%eax;

is much better!

要好得多!

#1


1  

unsigned char t;
asm("movl %1, %%eax;"
     "movl %%eax, %0;"
     :"=r"(t)  /* <--here */
     :"r"(*x)  /* <-- and here */
     :"%eax");

You can not move a value from a 32-bit register to a single-byte memory location. t is on the stack and x is somewhere else, but both are accessed in the same way. Problems on the other lines are similar. You should move only a byte.

不能将值从32位寄存器移动到单字节内存位置。t在堆栈上,x在其他地方,但两者都以相同的方式访问。其他线路上的问题也类似。你应该只移动一个字节。

Try something like this, but there are more ways to do it (I haven't tried that, read below):

尝试这样的方法,但是有更多的方法去做(我还没试过,请看下面):

unsigned char t;
asm("movb %1, %%al\n"
     "movb %%al, %0\n"
     :"=r"(t)
     :"r"(*x)
     :"%al");
asm("movb %1, %%al\n"
     "movb %%al, %0\n"
     :"=r"(*x)
     :"r"(*y)
     :"%al");
asm("movb %1, %%al\n"
     "movb %%al, %0\n"
     :"=r"(*y)
     :"r"(t)
     :"%al"); 

The whole procedure can be simplified into this:

整个过程可以简化为:

asm("movb (%1), %%al\n"
    "movb (%2), %%ah\n"
    "movb %%ah, (%1)\n"
    "movb %%al, (%2)\n"
    : /* no outputs for compiler to know about */
    : "r" (x), "r" (y)
    : "%ax", "memory");

#2


6  

To simplify it even more (than user35443):

进一步简化(超过user35443):

asm("" : "=r" (*x), "=r" (*y) : "1" (*x), "0" (*y));

Look ma! No code! And yes, this really works.

看马!没有代码!是的,这确实有效。

To explain how this works:

解释这是如何工作的:

When the compiler is building the code, it keeps track of what value is in each register. So if had these for inputs to asm:

编译器在构建代码时,会跟踪每个寄存器中的值。如果把这些输入到asm中

"r" (*x), "r" (*y)

“r”(* x),“r”(* y)

The compiler will pick a register and put *x in it, then pick a register and put *y in it, then call your asm. But it also keeps track of what variable is in which register. If there were just some way to tell the compiler that all it had to do was start treating the two registers as the opposite variables, then we'd be set. And that's what this code does:

编译器将选择一个寄存器并将*x放入其中,然后选择一个寄存器并将*y放入其中,然后调用asm。但它也会跟踪寄存器中的变量。如果有某种方法告诉编译器它需要做的就是把两个寄存器当作相反的变量,那么我们就会被设置,这就是代码的作用:

  1. Saying "=r" (*x) means that we are going to be overwriting the value in *x, that that we will be putting the value into a register.
  2. 说"=r" (*x)意味着我们将重写*x中的值,我们将把值放入寄存器中。
  3. Saying "0" (*y) means that on input to the asm, the compiler must put the value of *y into the same register as is being used by output parameter #0.
  4. 说“0”(*y)意味着在对asm的输入时,编译器必须将*y的值放入与输出参数#0使用的寄存器相同的寄存器中。

So, without using any actually assembly instructions, we have told the compiler to swap these two values.

因此,不使用任何实际的汇编指令,我们已经告诉编译器交换这两个值。

We don't get this quite "for free" since the compiler must load the values into registers before calling the asm. But since that has to happen anyway...

我们并不是完全“免费”获得这个值,因为编译器必须在调用asm之前将值加载到寄存器中。但既然这一切都必须发生……

What about actually updating memory? The compiler will (if necessary) write these values from the registers back to memory. And since it knows what variable is in which register, all works as expected.

那么更新内存呢?编译器将(如果需要)将这些值从寄存器写回内存。因为它知道哪个变量在哪个寄存器中,所有的工作都是预期的。

#3


-1  

line

movl %%eax, %0; 

is full nonsence! So you try to change 0 constant by %eax register It's impossible. In fortran many years ago It was. After that all programs will behave quite unpredictable. Since to avoid that was introduce the rule that any identificatot can't begin with number. But You try do it. It's well to get error. You maybe mean another

充满nonsence !所以你试着改变0常数%eax寄存器是不可能的。在很多年前的fortran语言中是这样的。在此之后,所有的程序都将表现得非常不可预测。为了避免这种情况,引入了任何标识符都不能以数字开头的规则。但你试着去做。有错误也无妨。也许你的意思是另一个

movl %0, %%eax; 

to set zerro to eax. So better do another code

将zerro设置为eax。所以最好再做一个代码

xorl %%eax, %%eax;

is much better!

要好得多!