2013-03-20 5 views
3

gcc를 처음 사용하는 MSVC 사용자가 많습니다._BitScanForward64는 C++에서 잘못된 대답을 반환합니다. exe (rubenvb-4.7.2-release)

저는 Windows 7에서 C++의 rubenvb 버전을 사용하고 있습니다 (예 : 64 비트 용). _BitScanForward64를 사용하는 데 문제가 있습니다. 일부 샘플 코드는 다음과 같습니다

int __cdecl main(int argc, char* argv[]) 
{ 
    DWORD d = (DWORD)atoi(argv[1]); 

    DWORD ix, ix2; 
    ix2 = _BitScanForward64(&ix, d); 
    printf("bsf %u %u\n", ix, ix2); 
} 

내가 컴파일 오전 :

"C :. \ 프로그램 파일 \ gcc2 \ mingw64 빈 \의 C \ ++ exe 인"-o iTot.exe -mno-MS- bitfields -march = native -momit-leaf-frame-pointer -mwin32 -Os -fomit-frame-pointer -m64 -msse4 -mpopcnt -D WINDOWS main.cpp

매개 변수 8을 사용하여 iTot.exe를 실행할 때, _BitScanForward64가 ix를 3으로 설정할 것으로 예상했습니다. MSVC가하는 일입니다. 그러나 IX는 0과 IX2는 어셈블러보고, 또한 1

이다, 나는 다음을 참조하십시오 상황에서

bsfq QWORD PTR 44[rsp],rax # MEM[(volatile LONG64 *)&ix], Mask 

, 왜 GCC 힘 메모리 쓰기 + 여기 읽을 수 있습니까? 그래서

, 몇 가지 질문이 :

  1. _BitScanForward64 어떻게 든 다른 GCC에서 호출 할 건가요? 만약 내가 잘못 부르고있다면 MSVC와의 비 호환성이 고통이 될지라도 알아두면 좋을 것입니다.
  2. _BitScanForward64 내장 함수가 메모리 쓰기를 강제 실행하는 이유는 무엇입니까?
  3. -S에서 어셈블러 출력을 보았을 때 생성되는 코드에 아무런 이상이 없습니다. 그러나, 사용 objdump.exe -d -Mintel, 나는 그것이 오히려 이상 (작동하는 것처럼 보인다)이 ASM 코드를 사용하는 것보다, 실제로 반대를 생산 참조 :

    BSF의 RAX, QWORD PTR [RSP + 0x2c]

WTF? 왜 나 한테 거짓말하는거야?

내가 말했듯이, 나는 gcc를 처음 사용하기 때문에, 만약 내가 바보 같은 짓을하고 있다면, 나와 친하게 지내라. 감사.

+1

0x2c = 44, 그렇지 않습니까? 또한'-S'는 기본적으로 AT & T 구문으로 출력을 생성하며 objdump의 출력은 x86 CPU, 인텔에 대한보다 일반적인 구문을 생성합니다. 이 두 개는 피연산자 순서가 다릅니다. –

+1

'_BitScanForward64' 함수를 선언하는 올바른 헤더를 포함합니까? 그렇지 않으면 컴파일러는 함수가 무엇인지, 인수가 무엇인지, 무엇을 반환하는지 알지 못하며, 제대로 작동하지 않는 코드를 생성 할 가능성이 높습니다. –

+0

@alexey : 나는 내가 읽은 것이기 때문에 int를 출력하도록 objdump를 설정했다. 나는 또한 인텔을 출력하기 위해 C++ -S를 설정했다. 그들은 둘 다 인텔을 출력하기 때문에 결과가 같을 것이라고 기대했습니다. 디버거 (VS)에서 .exe 파일을 열 때 동일한 (잘못된) 코드가 표시되는데, 이는 의심 할 여지없이 printf가 BitScanForward가 잘못된 대답을 반환하는 이유를 설명합니다. –

답변

1

좋아, 내 자신의 질문에 대답했다고 생각합니다. 정의를 어디에서 보았는지 Joachim PileBorg와 Alexham Frunze는 일 수 없다고 지적했습니다.

권위있는 말을하기에는 gcc가 너무 익숙하지 만 winnt.h의 _BitScanForward64에 대한 정의는 매우 잘못된 것 같습니다.

현재 정의 :

__CRT_INLINE BOOLEAN _BitScanForward64(DWORD *Index,DWORD64 Mask) { 
    __asm__ __volatile__("bsfq %1,%0" : "=r" (Mask),"=m" ((*(volatile LONG64 *)Index))); 
    return Mask!=0; 
} 

내 정의 :

__CRT_INLINE BOOLEAN BSF(DWORD *Index,DWORD64 Mask) { 
    LONG64 t; 
    __asm__ ("bsfq %0,%1" : "=r" (Mask),"=r" (t)); 
    *Index = t; 
    return Mask!=0; 
} 

주 = 행 =의 m의 (불필요한) 휘발성 bsfq하는 파라미터의 반전, 변화의 제거 r, 등등. 기본적으로,이 정의는 컴파일 될 수있는 것처럼 잘못되었습니다.

나는이 BitScanForward64에 대한 프로토 타입을 보았고, 매개 변수 중 하나가 기억해야했다 것을 "알고 있었다"및 BSF는 P2 때문이다 메모리 할 수있는 유일한 사람부터, 그건 쓴 사람을 추측하고있어 그들이 한 일. 작성된대로 코드는 p2의 작성되지 않은 내용을 읽고 비트를 스캔합니다. 그것은 컴파일되지만 잘못된 대답을 생성합니다.

그래서 순서대로 내 질문을합니다 :

  1. 아니, 내가 잘못 호출되지 않았습니다. winnt.h의 정의가 잘못되었습니다. 실제로 비슷한 파일 (_BitScanForward, _BitScanForward64, _BitScanReverse, _BitScanReverse64 등)이있는 파일이있을 수 있습니다.
  2. winnt.h의 코드가 잘못되어 메모리를 강제로 쓰게됩니다. 제안 된 변경으로 인해 메모리 액세스가 강제로 적용되지 않습니다.
  3. -S 출력 파일을 잘못 쓰고 있습니다 (objdump가 맞습니다).

    call atoi 
    lea rcx, .LC0[rip] 
    /APP 
    # 7 "m.cpp" 1 
    bsfq rax,rdx 
    /NO_APP 
    call printf 
    

을 그리고 이것은 실행 파일에 실제로 무엇되지 않습니다 : 위의 내 정의를 사용하여 생산하고 있습니다. 나는 시스템 헤더 파일을 수정하는 방법에 대한 흥분 아니에요 동안

bsfq rdx,rax 

, 그 여기 내 대답이 될 것 나타납니다 : 실제 실행 파일 (올바른) 정의가 포함되어 있습니다. 누구든지이 문제를보고 할 수있는 방법과 위치를 알고 있다면 (내가 언급했듯이 reubenvb를 사용하고있다.)이 두 가지 문제를보고 할 수있다. (잘하면이 문제는 모두에게 해결된다.)