gpt4 book ai didi

c++ - _BitScanForward64 在 c++.exe (rubenvb-4.7.2-release) 中返回错误答案

转载 作者:可可西里 更新时间:2023-11-01 09:34:36 26 4
gpt4 key购买 nike

MSVC 老用户,gcc 新手(请多多包涵)。

我在 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-帧指针-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会在这里强制进行内存write+read?

那么,有几个问题:

  1. 在 gcc 下 _BitScanForward64 是否应该以某种方式被调用?如果我只是说错了,那将是一件好事(尽管与 MSVC 的不兼容会很痛苦)。
  2. 为什么 _BitScanForward64 内在函数强制内存写入?
  3. 盯着 -S 的汇编程序输出,我看不出生成的代码有任何问题。但是,使用 objdump.exe -d -Mintel,我发现它并没有使用上面的 asm 代码(这似乎可行),它实际上产生了相反的结果:

    bsf rax,QWORD PTR [rsp+0x2c]

WTF?为什么 -S 对我撒谎?

就像我说的,我是 gcc 的新手,所以如果我只是在做一些愚蠢的事情,请对我温柔一点。谢谢。

最佳答案

好的,我想我已经回答了我自己的问题。感谢 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;
}

注意(不需要的)volatile 的移除,bsfq 参数的反转,从 =m 到 =r 的变化,等等。基本上,看起来这个定义是错误的,但仍然可以编译。

我猜写这篇文章的人看了 BitScanForward64 的原型(prototype)并“知道”其中一个参数必须是内存,并且因为唯一一个可以是 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 个问题,这样(希望)每个人都能得到修复。

关于c++ - _BitScanForward64 在 c++.exe (rubenvb-4.7.2-release) 中返回错误答案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15517340/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com