2013-03-20 45 views
3

很長時間MSVC用戶,gcc新手(非常感謝)。_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:\ Program Files文件\ GCC2 \ mingw64 \ BIN \ 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所做的。然而,九是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,我看到,而不是使用上述(其似乎將工作)的彙編代碼,它實際上所產生的反向:

    BSF RAX,QWORD PTR [RSP + 0x2c]

WTF?爲什麼-S對我撒謊?

就像我說的,我是gcc的新手,所以如果我只是在做一些愚蠢的事情,請對我溫柔。謝謝。

+1

0x2c = 44,不是嗎?另外,'-S'默認生成AT&T語法的輸出,而objdump的輸出產生了更爲典型的x86 CPU(intel)語法。兩者在操作數的順序上有所不同。 – 2013-03-20 07:08:36

+1

你是否包含聲明'_BitScanForward64'函數的正確頭文件?否則,編譯器將不知道該函數是什麼,它需要什麼參數以及它返回什麼,並且很可能會生成無法正常工作的代碼。 – 2013-03-20 07:10:59

+0

@alexey:我特意配置objdump來輸出intel,因爲這是我讀的。我還配置了C++ -S來輸出intel。由於他們都在輸出英特爾,我預計結果是一樣的。當我在調試器(VS)中打開.exe文件時,我看到相同(錯誤)的代碼,這無疑解釋了爲什麼printf顯示BitScanForward返回錯誤答案。 – 2013-03-20 07:35:30

回答

1

好的,我想我已經回答了我自己的問題。感謝Joachim PileBorg讓我看看定義在哪裏,而Alexey 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; 
} 

注除去(不需要的)揮發性的,該參數的逆轉bsfq,變化的從= m至= 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),我可以報告這2個問題,所以(希望),這對每個人都是固定的。