2013-03-20 79 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个问题,所以(希望),这对每个人都是固定的。