GCC と Clang の両方に UndefinedBehaviorSanitizer が組み込まれています。これらのチェックの 1 つ、 alignment
、 -fsanitize=alignment
で有効にできます .実行時にポインターのアライメントをチェックし、アライメントされていないポインターが逆参照された場合は中止するコードを出力します。
次のオンライン ドキュメントを参照してください:
- https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
難しいので個人的にはやったことはありませんが、次の方法でできると思います:
x86_64 CPU (具体的には Intel Corei7 をチェックしましたが、他の CPU も同様だと思います) には、ミスアラインされたメモリ参照に対処するパフォーマンス カウンター MISALIGN_MEM_REF があります。
まず第一に、プログラムを実行し、Linux で「perf」ツールを使用して、コードが行ったミスアライメント アクセスの数を取得できます。
よりトリッキーで興味深いハックは、オーバーフロー時に割り込みを生成し、最初のアライメントされていないロード/ストアをオーバーフローさせるようにパフォーマンス カウンターをプログラムするカーネル モジュールを作成することです。カーネルモジュールでこの割り込みに応答しますが、プロセスにシグナルを送信します。
これにより、事実上、x86_64 が非整列アクセスをサポートしないコアに変わります。
ただし、これは単純ではありません。コード以外に、システム ライブラリもアライメントされていないアクセスを使用するため、それらを独自のコードから分離するのは難しいでしょう。
ちょうど質問を読んだところです アライメントされていないメモリアクセスは常にバスエラーを引き起こしますか?ウィキペディアの記事セグメンテーション フォールトにリンクしています。
この記事には、あまり一般的ではない Intel プロセッサ フラグ AC (別名アライメント チェック) についての素晴らしいリマインダーがあります。
そして、これを有効にする方法は次のとおりです (ウィキペディアのバスエラーの例から、x86-64 System V 用に修正されたレッドゾーンクロバーバグを使用して、これは Linux および MacOS で安全であり、基本的な asm から変換されますが、関数内では決して良い考えではありません:AC への変更を、メモリ アクセスに対して順序付けする必要があります。
#if defined(__GNUC__)
# if defined(__i386__)
/* Enable Alignment Checking on x86 */
__asm__("pushf\n orl $0x40000,(%%esp)\n popf" ::: "memory");
# elif defined(__x86_64__)
/* Enable Alignment Checking on x86_64 */
__asm__("add $-128, %%rsp \n" // skip past the red-zone, in case there is one and the compiler has local vars there.
"pushf\n"
"orl $0x40000,(%%rsp)\n"
"popf \n"
"sub $-128, %%rsp" // and restore the stack pointer.
::: "memory"); // ordered wrt. other mem access
# endif
#endif
有効にすると、/proc/cpu/alignment
の ARM アライメント設定と同じように機能します。 、回答を参照してください。整列されていないメモリアクセスをトラップするには?たとえば。
さらに、GCC を使用している場合は、-Wcast-align
を有効にすることをお勧めします。 警告。厳密なアラインメント要件 (ARM など) を持つターゲット用にビルドする場合、GCC はアラインされていないメモリ アクセスにつながる可能性のある場所を報告します。
ただし、memcpy およびその他の関数に対する libc の手書きの asm は依然として非整列アクセスを行うため、AC を設定することは x86 (x86-64 を含む) では実用的でないことが多いことに注意してください。 GCC は、ソースがアラインされていなくても、アラインされていないアクセスを行う asm を出力することがあります。 2 つの隣接する配列要素または構造体メンバーを一度にコピーまたはゼロにするための最適化として。