簡體   English   中英

GCC內聯匯編:約束

[英]GCC inline assembly: constraints

我很難理解角色約束在GCC內聯匯編(x86)中的作用。 我已經閱讀了手冊 ,它准確地解釋了每個約束的作用。 問題在於,即使我理解每個約束的作用,我也很少理解為什么要使用一個約束而不是另一個約束,或者它可能帶來什么。

我意識到這是一個非常廣泛的話題,所以一個小例子應該有助於縮小焦點。 以下是一個簡單的asm例程,它只添加了兩個數字。 如果發生整數溢出,則將值1寫入輸出C變量。

 int32_t a = 10, b = 5;
 int32_t c = 0; // overflow flag

 __asm__
 (
  "addl %2,%3;"        // Do a + b (the result goes into b)
  "jno 0f;"            // Jump ahead if an overflow occurred
  "movl $1, %1;"       // Copy 1 into c
  "0:"                 // We're done.

  :"=r"(b), "=m"(c)    // Output list
  :"r"(a), "0"(b)     // Input list
 );

現在這個工作正常,除了我必須隨意擺弄約束,直到我讓它正常工作。 最初,我使用了以下約束:

  :"=r"(b), "=m"(c)    // Output list
  :"r"(a), "m"(b)     // Input list

請注意,我使用b的“m”約束而不是“0”。 這有一個奇怪的副作用,如果我用優化標志編譯並調用該函數兩次,由於某種原因,加法運算的結果也會存儲在c 我最終讀到了“ 匹配約束 ”,它允許您指定變量將用作輸入和輸出操作數。 當我將"m"(b)改為"0"(b)它起作用了。

但我真的不明白為什么你會使用一個約束而不是另一個約束。 我的意思是,是的,我知道,“R”是指變量應該是在寄存器和“m”意味着它應該是在內存中-但我真的不明白什么選擇一個對另一個的影響是,為什么加如果我選擇某種約束組合,則操作無法正常工作。

問題:1)在上面的示例代碼中,為什么b上的“m”約束導致c被寫入? 2)是否有任何教程或在線資源更詳細地介紹約束?

這里有一個例子可以更好地說明為什么你應該仔細選擇約束(與你的功能相同,但也許更簡潔一點):

bool add_and_check_overflow(int32_t& a, int32_t b)
{
    bool result;
    __asm__("addl %2, %1; seto %b0"
            : "=q" (result), "+g" (a)
            : "r" (b));
    return result;
}

因此,使用的約束是: qrg

  • q表示只能選擇eaxecxedxebx 這是因為set*指令必須寫入8位可尋址寄存器( alah ,...)。 使用b%b0裝置,用最低8位部分( alcl ,...)。
  • 對於大多數雙操作數指令,至少有一個操作數必須是寄存器。 所以不要兩者都使用mg ; r用於至少一個操作數。
  • 對於最后的操作數,無論是寄存器還是內存都沒關系,所以使用g (通用)。

另外,在上述的例子中,我選擇使用g (而不是r用於a因為引用通常作為存儲器指針來實現,所以使用r約束將要求第一復制指涉到寄存器,然后復制回來。 使用g ,可以直接更新指示對象。


至於為什么你的原始版本用加法值覆蓋你的c ,那是因為你在輸出槽中指定了=m ,而不是(比方說) +m ; 這意味着允許編譯器為輸入和輸出重用相同的內存位置。

在您的情況下,這意味着兩個結果(因為相同的內存位置用於bc ):

  • 添加沒有溢出:然后, cb的值覆蓋(添加的結果)。
  • 添加確實溢出:然后, c變為1(並且b也可能變為1,具體取決於代碼的生成方式)。

暫無
暫無

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

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