2011-12-17 3 views
0

xchg 명령으로 스핀 록이 있습니다. C++ 함수는 잠글 리소스를 사용합니다. GCC에서의 인라인 어셈블리에서 C++ 참조 사용

다음

이 코드는 64 비트 인텔 시스템에 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는 당신에게 폴트되는 정확한 기계 명령어를 얻을 수있는 기능을 제공합니다. –

+0

현재 명령을 얻기 위해'print $ rip' 시도하십시오 – user685684

답변

7

첫째, 프로그램의 나머지는 64 비트 모드로 실행하고 64 비트 주소와 함께 작동하도록 컴파일되는 반면, 당신은 왜 당신의 어셈블리 코드에서 절단 된 32 비트 주소를 사용하는/포인터? 나는 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 ... 
+0

답해 주셔서 감사합니다. 하나의 수정은 movi가 movq로 대체해야하는 64 비트에 대한 것입니다. –

+0

네 말이 맞아, movl도 movq로 바꿔야 해. –

관련 문제