2011-12-17 112 views
0

我使用xchg指令自旋鎖定。 C++函數需要資源被鎖定。在GCC內聯彙編中使用C++引用

以下是這個代碼是一個64位Intel機器上編譯gcc 4.5.2 -masm=intel代碼

void SpinLock::lock(u32& resource) 
{ 
    __asm__ __volatile__ 
     (
      "mov  ebx, %0\n\t" 
"InUseLoop:\n\t" 
      "mov  eax, 0x01\n\t"  /* 1=In Use*/ 
      "xchg eax, [ebx]\n\t" 
      "cmp  eax, 0x01\n\t" 
      "je  InUseLoop\n\t" 
      :"=r"(resource) 
      :"r"(resource) 
      :"eax","ebx" 
     ); 
} 

void SpinLock::unlock(u32& resource) 
{ 
    __asm__ __volatile__ 
     (
       /* "mov DWORD PTR ds:[%0],0x00\n\t" */ 
       "mov ebx, %0\n\t" 
       "mov DWORD PTR [ebx], 0x00\n\t" 
       :"=r"(resource) 
       :"r"(resource) 
       : "ebx"    
     );  
} 

objdump爲上述功能產生以下組件。執行鎖定操作時

0000000000490968 <_ZN8SpinLock4lockERj>: 
    490968:  55      push %rbp 
    490969:  48 89 e5    mov %rsp,%rbp 
    49096c:  53      push %rbx 
    49096d:  48 89 7d f0    mov %rdi,-0x10(%rbp) 
    490971:  48 8b 45 f0    mov -0x10(%rbp),%rax 
    490975:  8b 10     mov (%rax),%edx 
    490977:  89 d3     mov %edx,%ebx 

0000000000490979 <InUseLoop>: 
    490979:  b8 01 00 00 00   mov $0x1,%eax 
    49097e:  67 87 03    addr32 xchg %eax,(%ebx) 
    490981:  83 f8 01    cmp $0x1,%eax 
    490984:  74 f3     je  490979 <InUseLoop> 
    490986:  48 8b 45 f0    mov -0x10(%rbp),%rax 
    49098a:  89 10     mov %edx,(%rax) 
    49098c:  5b      pop %rbx 
    49098d:  c9      leaveq 
    49098e:  c3      retq 
    49098f:  90      nop 


0000000000490990 <_ZN8SpinLock6unlockERj>: 
    490990:  55      push %rbp 
    490991:  48 89 e5    mov %rsp,%rbp 
    490994:  53      push %rbx 
    490995:  48 89 7d f0    mov %rdi,-0x10(%rbp) 
    490999:  48 8b 45 f0    mov -0x10(%rbp),%rax 
    49099d:  8b 00     mov (%rax),%eax 
    49099f:  89 d3     mov %edx,%ebx 
    4909a1:  67 c7 03 00 00 00 00 addr32 movl $0x0,(%ebx) 
    4909a8:  48 8b 45 f0    mov -0x10(%rbp),%rax 
    4909ac:  89 10     mov %edx,(%rax) 
    4909ae:  5b      pop %rbx 
    4909af:  c9      leaveq 
    4909b0:  c3      retq 
    4909b1:  90      nop 

代碼轉儲核心。

這裏有什麼嚴重錯誤嗎?

問候, -J

+0

GDB讓你得到該斷層的精確機器指令的能力。 – 2011-12-17 08:23:29

+0

試試`print $ rip`獲取當前指令 – user685684 2011-12-17 08:49:16

回答

7

首先,你爲什麼用你的彙編代碼截斷的32位地址,而程序的其餘部分被編譯在64位模式下執行,並與64位地址操作/指針?我指的是ebx。爲什麼不是rbx

其次,你爲什麼試圖從彙編代碼中返回一個值爲"=r"(resource)?您的功能使用xchg eax, [ebx]mov DWORD PTR [ebx], 0x00更改了內存中的值,並返回void。刪除"=r"(resource)

最後,如果你在SpinLock::lock()拆卸仔細一看,你看不出來有點怪ebx

mov %rdi,-0x10(%rbp) 
mov -0x10(%rbp),%rax 
mov (%rax),%edx 
mov %edx,%ebx 
<InUseLoop>: 
mov $0x1,%eax 
addr32 xchg %eax,(%ebx) 

在這段代碼中,ebx價值,這是一個地址/指針,不不是直接來自函數的參數(rdi),參數首先與mov (%rax),%edx取消引用,但是爲什麼?如果你扔掉所有令人困惑的C++參考資料,在技術上,函數接收到一個指向u32的指針,而不是指向u32的指針,因此不需要額外的解引用。

問題是在這裏:"r"(resource)。它必須是"r"(&resource)

小32位的測試應用程序演示了此問題:

#include <iostream> 

using namespace std; 

void unlock1(unsigned& resource) 
{ 
    __asm__ __volatile__ 
    (
     /* "mov DWORD PTR ds:[%0],0x00\n\t" */ 
     "movl %0, %%ebx\n\t" 
     "movl $0, (%%ebx)\n\t" 
     : 
     :"r"(resource) 
     :"ebx"    
    );  
} 

void unlock2(unsigned& resource) 
{ 
    __asm__ __volatile__ 
    (
     /* "mov DWORD PTR ds:[%0],0x00\n\t" */ 
     "movl %0, %%ebx\n\t" 
     "movl $0, (%%ebx)\n\t" 
     : 
     :"r"(&resource) 
     :"ebx"    
    );  
} 

unsigned blah; 

int main(void) 
{ 
    blah = 3456789012u; 
    cout << "before unlock2() blah=" << blah << endl; 
    unlock2(blah); 
    cout << "after unlock2() blah=" << blah << endl; 

    blah = 3456789012u; 
    cout << "before unlock1() blah=" << blah << endl; 
    unlock1(blah); // may crash here, but if it doesn't, it won't change blah 
    cout << "after unlock1() blah=" << blah << endl; 
    return 0; 
} 

輸出:

before unlock2() blah=3456789012 
after unlock2() blah=0 
before unlock1() blah=3456789012 
Exiting due to signal SIGSEGV 
General Protection Fault at eip=000015eb 
eax=ce0a6a14 ...