思いつく方法としては以下のようなものがあります。
内部リンケージにする
外部リンケージを持つ関数が使われるかどうかはコンパイル時にわかりませんのでコンパイラは勝手に除去することができません。 逆に言えば内部リンケージを持つ関数が使われるかどうかはコンパイル時に把握できる可能性があります。
関数定義に static
を付けた上で最適化を有効にしておけばコンパイル時点でデッドコードは除去され、もちろん最終的な実行ファイルに含まれることはありません。
不要セクションの除去
リンカは不要なセクションを除去する機能を持っている場合があります。 関数が個別のセクションに配置されるようにコンパイルした上でリンク時に不要セクションを除去するオプションを付ければ不要な関数は実行ファイルに含まれることはありません。
具体的な手順は以下の URL で説明しているのを見つけたので参考にしてください。
http://blog.kmckk.com/archives/2601869.html
ただし、ターゲットによっては使えないことがあります。 例えば Windows では使えないようです。
リンク時最適化を有効にする
通常は各コンパイル単位ごとにコンパイルしてからリンクするという手順がとられますが、コンパイル時にコード生成の手前の状態にまで留めておき、全部のコンパイル単位をリンカが融合してから再びコンパイラに差し戻すという機能を GCC は持っています。
コンパイル単位をまたいだ最適化が有効になりますのでどこが使われているか把握が可能になり、デッドコードとして除去できます。