2017-01-27 1 views
3

저는 여전히 g ++ 인라인 어셈블러에 어려움을 겪고 있으며 사용법을 이해하려고합니다.g ++에서 간단한 디스 어셈블 된 코드를 이해하려고 시도했습니다.

는 여기에서 코드 조각을 채택했습니다 http://asm.sourceforge.net/articles/linasm.html은 (GCC 정보 파일의 섹션 "C 표현식 피연산자와 어셈블러 지침"에서 인용) 내가 사용하지 최적화를 컴파일 한

static inline uint32_t sum0() { 
    uint32_t foo = 1, bar=2; 
    uint32_t ret; 
    __asm__ __volatile__ (
     "add %%ebx,%%eax" 
     : "=eax"(ret)    // ouput 
     : "eax"(foo), "ebx"(bar) // input 
     : "eax"     // modify 
    ); 
    return ret; 
} 

:

g++ -Og -O0 inline1.cpp -o test 

디스 어셈블 된 코드 나 퍼즐 :

(gdb) disassemble sum0 
Dump of assembler code for function sum0(): 
    0x00000000000009de <+0>: push %rbp     ;prologue... 
    0x00000000000009df <+1>: mov %rsp,%rbp    ;prologue... 
    0x00000000000009e2 <+4>: movl $0x1,-0xc(%rbp)  ;initialize foo 
    0x00000000000009e9 <+11>: movl $0x2,-0x8(%rbp)  ;initialize bar 
    0x00000000000009f0 <+18>: mov -0xc(%rbp),%edx  ; 
    0x00000000000009f3 <+21>: mov -0x8(%rbp),%ecx  ; 
    0x00000000000009f6 <+24>: mov %edx,-0x14(%rbp)  ; This is unexpected 
    0x00000000000009f9 <+27>: movd -0x14(%rbp),%xmm1  ; why moving variables 
    0x00000000000009fe <+32>: mov %ecx,-0x14(%rbp)  ; to extended registers? 
    0x0000000000000a01 <+35>: movd -0x14(%rbp),%xmm2  ; 
    0x0000000000000a06 <+40>: add %ebx,%eax    ; add (as expected) 
    0x0000000000000a08 <+42>: movd %xmm0,%edx   ; copying the wrong result to ret 
    0x0000000000000a0c <+46>: mov %edx,-0x4(%rbp)  ; "  " "  "  " " 
    0x0000000000000a0f <+49>: mov -0x4(%rbp),%eax  ; "  " "  "  " " 
    0x0000000000000a12 <+52>: pop %rbp     ; 
    0x0000000000000a13 <+53>: retq 
End of assembler dump. 

예상대로 sum0() 함수는 잘못된 값을 반환합니다.

의견이 있으십니까? 무슨 일 이니? 그것을 올바르게 얻는 방법?

- 편집 - 은 @MarcGlisse의 의견을 바탕으로, 나는 시도 :

static inline uint32_t sum0() { 
    uint32_t foo = 1, bar=2; 
    uint32_t ret; 
    __asm__ __volatile__ (
     "add %%ebx,%%eax" 
     : "=a"(ret)    // ouput 
     : "a"(foo), "b"(bar)  // input 
     : "eax"     // modify 
    ); 
    return ret; 
} 

내가 다음 봤는데 튜토리얼이 잘못된 것 같습니다. 출력/입력 필드의 "eax"는 레지스터 자체를 의미하지는 않지만 abbrev 테이블의 e, a, x 약어를 의미합니다.

어쨌든, 나는 여전히 올바르게하지 않습니다. 위의 코드는 컴파일 오류를 발생시킵니다. 'asm'피연산자에는 불가능한 제약 조건이 있습니다.

이유가 표시되지 않습니다.

+0

최적화를 사용하면 더 쉽게 이해할 수 있습니다. –

+0

"eax"는 자신이 생각하는 것을 의미하지 않으며 "a"를 원합니다. 그리고 출력물이 구석 구석을 표시 할 필요가 없습니다. –

+1

좀 더 자세히 읽으십시오 : "출력이 마비 된 것으로 표시 할 필요가 없습니다". –

답변

2

x86 용 확장 인라인 어셈블리 제약은 official documentation에 나열되어 있습니다.
complete documentation도 읽을만한 가치가 있습니다.

볼 수 있듯이 제약 조건은 모두 단일 문자입니다. foo FO
제약 "EAX는"세 가지 제약 조건을 지정

a
   The a register.

x
   Any SSE register.

e
   32-bit signed integer constant, or ...

당신이 eax가 거기 입력 피연산자를 넣을 수 없습니다 사방에서 공격하고 xmm0을 선택합니다 것을 GCC를 이야기하고 있기 때문에.

When the compiler selects the registers to use to represent the input operands, it does not use any of the clobbered registers

proper constraint is simply "a".
클로버 (및 "cc"를 추가)에서 eax (상단 비트가 0으로 설정되어 있기 때문에 rax이어야 함)을 제거해야합니다.

+0

고마워요! 결과 코드를 보여주기 위해 질문을 편집했습니다. – Chocksmith

+0

@Chocksmith Glad가 도움이 될 것입니다. 그러나 귀하가 수정 한 내용은 귀하의 문제가 해결되었다는 의사 소통을 위해 필요한 모든 것만 받아 들일 때 내 답변을 표시하는 것처럼 중복됩니다. 나는 SO 지침서를 준수하도록 편집을 롤백하고 있습니다. 그것은 또한 미래의 독자들에게 같은 문제를 안겨줍니다. –

관련 문제