[英]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;
}
因此,使用的約束是: q
, r
和g
。
q
表示只能選擇eax
, ecx
, edx
或ebx
。 這是因為set*
指令必須寫入8位可尋址寄存器( al
, ah
,...)。 使用b
在%b0
裝置,用最低8位部分( al
, cl
,...)。 m
或g
; 將r
用於至少一個操作數。 g
(通用)。 另外,在上述的例子中,我選擇使用g
(而不是r
用於a
因為引用通常作為存儲器指針來實現,所以使用r
約束將要求第一復制指涉到寄存器,然后復制回來。 使用g
,可以直接更新指示對象。
至於為什么你的原始版本用加法值覆蓋你的c
,那是因為你在輸出槽中指定了=m
,而不是(比方說) +m
; 這意味着允許編譯器為輸入和輸出重用相同的內存位置。
在您的情況下,這意味着兩個結果(因為相同的內存位置用於b
和c
):
c
被b
的值覆蓋(添加的結果)。 c
變為1(並且b
也可能變為1,具體取決於代碼的生成方式)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.