簡體   English   中英

x86 - 使用內聯匯編設置一個位

[英]x86 - setting a bit using inline assembly

我正在編寫一個函數,通過內聯匯編使用bts指令設置數字x中的第n位。 這是我的功能:

uint32_t set_bit_assembly(uint32_t x, uint32_t n)
{
    asm( "movl %1, %%eax; bts %0, %%eax;"
         :"=&r"(x)
         :"r"(n)
        );
    return x;
}

我希望變量'n'和'x'分別成為movlbts的第一個操作數。 但是當我編譯時,它需要'x'表示movl並完全忽略'n'。 (我嘗試交換%0和%1,這沒有幫助)。 你能告訴我哪里出錯了嗎? 下面是生成的匯編代碼:

00000043 <set_bit_assembly>:
  43:   55                      push   %ebp
  44:   89 e5                   mov    %esp,%ebp
  46:   83 ec 10                sub    $0x10,%esp
  49:   8b 55 0c                mov    0xc(%ebp),%edx
  4c:   89 d0                   mov    %edx,%eax
  4e:   0f ab c0                bts    %eax,%eax
  51:   89 45 fc                mov    %eax,-0x4(%ebp)
  54:   8b 45 fc                mov    -0x4(%ebp),%eax
  57:   c9                      leave  
  58:   c3                      ret    

如何在asm中使用bts指令

在你的代碼中,這一行:

bts %0, %%eax;  

應該替換為:

bts %%eax, %0;

說明

給定一般形式asm(“code”:outputs:inputs:clobbers)GCC在“代碼”中替換%0,%1和%2,並在冒號后保存參數。 BTS的定義是第一個操作數是位串,第二個是位索引。 所以解決方案似乎是:bts%0,%1你已經完成了你的代碼。 然而,這不是bts如何工作:bts想要將地址作為第二個操作數,並將要設置為第一個的位:bts%1,%0。 請在此處查看正確的用法。

好的解決方案

雖然您的代碼可以使用建議的更正,但有更好的選項,如下所示:

uint32_t set_bit_assembly2(uint32_t x, uint32_t n)
{
    asm( "bts %1,%0"
         :"+r"(x)
         :"r"(n)
        );
    return x;
}

正如@DavidWohlferd在評論中指出的那樣,我們應該使用“+ r”,因為x將由bts指令讀寫。

此外,可以通過使用符號 名稱來提高可讀性:

asm( "bts %[bit],%[value]"
     : [value] "+rm"(value) 
     : [bit] "r"(bit)
     :"cc");

另一種可能性是( 見本文 ):

uint32_t set_bit_assembly3(uint32_t x, uint32_t n)
{
    asm( "bts %1,%0": "+rm"(x) : "r"(n));
    return x;
}

進一步閱讀:

此頁面可能對想要使用bts的人非常感興趣: http//lxr.free-electrons.com/source/arch/x86/include/asm/bitops.h#L41

在這篇文章中, Peter Cordes解釋了為什么內存操作數上的bts對性能很糟糕。

暫無
暫無

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

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