簡體   English   中英

gcc內聯匯編錯誤“ mov的操作數類型不匹配”

[英]gcc inline assembly error “operand type mismatch for mov”

//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");       
}

在這里,我想從交換焦x ,並存儲在y ,與同為yx 我已經通過將movl更改為mov來編譯了這些指令,但是沒有成功。 編譯/鏈接的問題在哪里?

這是在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'

要進一步簡化它(比user35443更簡單):

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

快看 沒有代碼! 是的,這確實有效。

解釋這是如何工作的:

編譯器構建代碼時,它會跟蹤每個寄存器中的值。 因此,如果將這些作為對asm的輸入:

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

編譯器將選擇一個寄存器並將* x放入其中,然后選擇一個寄存器並將* y放入其中,然后調用您的asm。 但是它也跟蹤哪個寄存器中有什么變量。 如果有某種方式告訴編譯器它要做的就是開始將兩個寄存器視為相反的變量,那么我們將被置位。 這就是這段代碼的作用:

  1. 說“ = r”(* x)意味着我們將要覆蓋* x中的值,這意味着我們會將值放入寄存器中。
  2. 說“ 0”(* y)意味着在輸入到asm時,編譯器必須將* y的值放入與輸出參數#0使用的寄存器相同的寄存器中。

因此,在不使用任何實際匯編指令的情況下,我們已告知編譯器交換這兩個值。

我們不能完全免費獲得此功能,因為編譯器必須在調用asm之前將值加載到寄存器中。 但是既然如此,那一定要發生……

實際更新內存如何? 編譯器將(如有必要)將這些值從寄存器寫回內存。 而且,由於它知道哪個寄存器中包含什么變量,因此所有操作均按預期進行。

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

您不能將值從32位寄存器移動到單字節存儲位置。 t在堆棧上, x在其他位置,但是兩者的訪問方式相同。 其他方面的問題類似。 您應該只移動一個字節。

嘗試這樣的事情,但是還有更多的方法可以做到(我還沒有嘗試過,請閱讀下文):

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"); 

整個過程可以簡化為:

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");

movl %%eax, %0; 

完全廢話! 因此,您嘗試通過%eax寄存器更改0常數。這是不可能的。 多年前在fortran中。 之后,所有程序的行為都將變得不可預測。 由於避免了這種情況,所以引入了任何標識都不能以數字開頭的規則。 但是你嘗試去做。 報錯很好。 你可能是另一個意思

movl %0, %%eax; 

將zerro設置為eax。 所以最好再做一個代碼

xorl %%eax, %%eax;

好多了!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM