memologue RSSフィード

書いている人

日記というよりは備忘録、ソフトウェア技術者の不定期メモ。あるいはバッドノウハウ集。プライベートで調査した細々した諸々のスナップショット。嘘が散りばめられています。ISO/IEC 14882(C++)とPOSIX, GCC, glibc, ELFの話ばかりで、WindowsやMacの話はありません。特に記載がなければLinux/x86とILP32が前提です。時間の経過と共に古い記事は埋もれてしまいます。検索エンジンから飛んできた場合は、ページ内検索をご利用いただくかgoogleキャッシュを閲覧してみてください。技術的な記事を書きためる場所として使っています。言及してもらえると喜びます。主要な記事の一覧を書いておきます:

にんきコンテンツ: [GCC] mainを一度も呼ばないばかりか蹂躙する / Binary2.0 Conference 2006 発表資料 / C++ で SICP / ついカッとなって実行バイナリにパッチ / hogetrace - 関数コールトレーサ

昔のPOSIX関係の記事: シグナルの送受に依存しない設計にしよう / シグナルハンドラで行ってよい処理を知ろう / マルチスレッドのプログラムでのforkはやめよう / スレッドの「非同期キャンセル」を行わない設計にしよう / スレッドの「遅延キャンセル」も出来る限り避けて通ろう / マルチスレッドプログラミングの「常識」を守ろう / C++でsynchronized methodを書くのは難しい / シグナルハンドラからのforkするのは安全か? / g++ の -fthreadsafe-statics ってオプション知ってます? / 非同期シグナルとanti-pattern / localtimeやstrtokは本当にスレッドセーフにできないのか / UNIXの規格について / マルチスレッドと共有変数 - volatile?なにそれ。 / type punning と strict aliasing / アセンブラで遊ぶ時に便利なgdb設定 / 最近の記事は一覧から

2005-12-27

[][] GCCの-ftrapv

gcc -ftrapv


最近のGCC(>=3.x)には-ftrapvというオプションがあって、これを有効にすると「符号あり整数同士の加算・減算・乗算でオーバーフロー/アンダーフローが発生したとき、プロセスをabort()」してくれます。例えば、INT_MAX + 1 とか INT_MIN - 1 とか INT_MIN * (-1) なんて計算をしようとすると、即abort()してくれるようになるわけです*1。符号無し整数の場合はチェックされませんのでご注意。


さて、

int test_trap(int a, int b)
{
 int d = a + b;
 int e = a - b;
 int f = d * e;
 return f;
}

こんなコードを gcc -ftrapv -fverbose-asm -S すると、

test_trap:
       pushl   %ebp    #
       movl    %esp, %ebp      #,
       subl    $24, %esp       #,
       subl    $8, %esp        #,
       pushl   12(%ebp)        # b
       pushl   8(%ebp) # a
       call    __addvsi3       #
       addl    $16, %esp       #,
       movl    %eax, -12(%ebp) # tmp60, d
       subl    $8, %esp        #,
       pushl   12(%ebp)        # b
       pushl   8(%ebp) # a
       call    __subvsi3       #
       addl    $16, %esp       #,
       movl    %eax, -8(%ebp)  # tmp61, e
       subl    $8, %esp        #,
       pushl   -8(%ebp)        # e
       pushl   -12(%ebp)       # d
       call    __mulvsi3       #
       addl    $16, %esp       #,
       movl    %eax, -4(%ebp)  # tmp62, f
       movl    -4(%ebp), %eax  # f, D.1171
       leave
       ret

こういう出力になります。3つのcall命令に注目してください。addl/subl/mullといったCPUの加減乗命令のかわりに、関数が呼ばれています。これらの関数はlibgcc2.a の中にあり、ソースコードは、gcc-4.0.2/gcc/libgcc2.c です。__addvsi3 の実装は次のような感じ。

SItype
__addvsi3 (SItype a, SItype b)
{
 const SItype w = a + b;

 if (b >= 0 ? w < a : w > a)
   abort ();

 return w;
}

オーバーフロー時にabort()というのは完全にハードコードで、挙動を変更することはできないようですし、パフォーマンスの問題もあるので、最終製品での使用は難しいかもしれません。でも、デバッグにはよさそうですね。

VC++ /RTC


詳しく調べていませんが、VC++には/RTCという似たようなオプションがあるそうです。

*1:最後のヤツは処理系のINT_MINの絶対値のほうがINT_MAXの絶対値よりも大きい場合(ISO Cの規格は2の補数を使う処理系でもそれを要請していない)に限りますけどね。x86/LinuxはINT_MINのほうが大きいです。詳しくはC99の§ 5.2.4.2.1 および 6.2.6.2 を参照のこと

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証