3

長年のMSVCユーザーで、gccは初めてです(我慢してください)。

Windows7でrubenvbバージョンのc++(件名のバージョンを参照、はい、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"-oiTot.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?-Sが私に嘘をついているのはなぜですか?

私が言ったように、私はgccを初めて使用するので、何か馬鹿げたことをしているだけなら、私に優しくしてください。ありがとう。

4

1 に答える 1

1

わかりました、私は自分の質問に答えたと思います。定義がどこにあるのかを調べさせてくれた Joachim PileBorg と、paramsを逆にすることはできないと指摘してくれた 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 のプロトタイプを見て、パラメータの 1 つがメモリでなければならないことを「知っていた」と推測してます。書き込まれたとおり、コードは 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 つの問題を報告して、(うまくいけば) 全員が修正されるようにすることができます。

于 2013-03-20T19:31:53.693 に答える