clangのオプションで便利に使ってるもの


clang で特にリリースビルドではなくてプログラムの間違いを探したいときに使っているコマンドラインオプションです。clang 13で確認。いつかgccで対応する記事を書きたい…

一般的オプション

-ftrivial-auto-var-init=pattern
未初期化の自動変数や自動配列を変な値で初期化する。これで未初期化関連の誤りをかなり見つけられる
-D_FORTIFY_SOURCE=2
glibcのエラーチェックを有効にする
-pipe -fuse-ld=lld -fintegrated-as -fintegrated-cc1
LLVMリンカーやclang内蔵アセンブラを用いる
-Wall -Wextra
警告をたくさん出す。-O1以上の最適化を指定しないと未使用変数を教えてもらえない
-Wtautological-compare -Wsign-compare
変な比較に警告をする
-gfull -fstandalone-debug -gdwarf-5 -gz
デバッグ情報を目一杯付加する。デバッグ情報をDWARFバージョン5形式で書き出し圧縮する
-O3 -mllvm -polly
最大限の最適化
-march=native または -mcpu=native
clangを動作させているCPUに合わせた最適化を行う。インテル系CPUのときはmarchを用いる

LTO (Link Time Optimization関連)

-flto=full -fwhole-program-vtables -fforce-emit-vtables -fvirtual-function-elimination
LTOを使う
-ffunction-sections -fdata-sections -Wl,--gc-sections
使われていない関数や大域変数を削除する
-faddrsig -Wl,--icf=all
重複している同一のコードをまとめる。LLVMリンカーでしか使えない

スタック保護関連

-fstack-protector-all -fstack-clash-protection
stack-clash-protectionはインテルCPUのみ
-fsanitize=safe-stack
アドレスサニタイザーとは同時に使えない
-fsplit-stack
関数ごとにスタックを分ける。LLVMリンカーでは使えない

サニタイザー関連

エラーが起きたときの動作

-fno-sanitize-recover=all サニタイザーがエラーを見つけたらプログラムを終了する。

CFI

-fsanitize=cfi -fvisibility=hidden CFIの使用にはLTOが必須

未定義動作サニタイザ

-fsanitize=undefined -fsanitize=integer 整数型のオーバーフロー・アンダーフローや配列範囲外アクセスを教えてくれる。実行時の環境変数として UBSAN_OPTIONS="print_stacktrace=1:abort_on_error=0" を指定するとスタックトレースを表示してくれる

アドレスサニタイザー

-fsanitize=address -fsanitize-address-use-after-scope -fsanitize-address-use-after-return=always -fsanitize-address-use-odr-indicator -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-common ポインタ関連の色々なエラーを実行時に教えてくれる。実行時の環境変数に ASAN_OPTIONS="detect_leaks=1:strict_init_order=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_string_checks=1:detect_invalid_pointer_pairs=2:use_odr_indicator=1:abort_on_error=0" を設定するとよりしっかり誤りを探してくれる。-D_FORTIFY_SOURCE と両立しない ため -U_FORTIFY_SOURCE を付けたほうがよい

Linuxにおける実行ファイル生成

-Wl,-z,noexecstack
自動変数や自動配列がある領域をプログラムとして実行できなくする
-fPIE -pie -fno-plt -Wl,-z,relro,-z,now
アドレス空間配置のランダム化を行う。これらのオプションの説明はpartialRELRO/fullRELRO、あるいは-fno-pltの話を参照

静的リンク (static link)

-static -static-libsan -static-pie を適当なところに付加する。アドレスサニタイザーの静的リンクをしてくれないから、コマンドラインの最後に -lasan をつける