clangでカーネルコンパイル (Debian)

Linuxカーネルをclang 12でコンパイルすると、[LTO （リンク時最適化）](https://qiita.com/kaityo256/items/a822fc462a4de6ddd8e7) と [CFI](https://source.android.com/devices/tech/debug/kcfi?hl=ja) が使えるようになったという話があるので、Debianで www.kernel.org から持ってきたカーネルをコンパイルする手順です。以下の手順の前に、例えば `apt-get build-dep linux/sid` などで clangを使わずに `make bindeb-pkg` できる環境を予め用意して下さい。

# CLangのインストール
Debian Experimental/Sid/Testing から `clang`, `llvm`, `lld` パッケージをインストールします。

# Debian のカーネルコンパイル設定をインストール
Debian Experimental/Sid/Testing から `linux-config-5.15` （またはそれ以降）をインストールします

# コンパイル作業
以下を実行する。そうすると `*.deb` ファイルができるので `dpkg -i linux-image-何とか.deb` すればカーネルがインストールされる。`XFS` を `m` 以外にしないとエラーでコンパイルできなかった。`ld.lld-12` の実行には7GB程度のメモリと１時間程度の時間が必要だった（ラズベリーパイ４）。`ld.lld-13` では4GBに使用メモリ量が減った。

```shell
cd /var/tmp

arch=`dpkg --print-architecture`
if [ $arch = amd64 ]; then
    variant=amd64_none_amd64
    march='-march=native'
elif [ $arch = arm64 ]; then
    variant=arm64_none_arm64
    march='-mcpu=native'
elif [ $arch = armhf ]; then
    variant=armhf_none_armmp-lpae
    march='-mcpu=native'
else
    echo "Please find a suitable config of $arch."
    exit 1
fi

KVER=5.15.1
exec </dev/null >build-log-${KVER}.txt 2>&1
set -xe
wget -T 10 -c https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-${KVER}.tar.xz
tar Jxf linux-${KVER}.tar.xz
cd linux-${KVER}

# 最適化レベルを強めるなら以下の２行を有効にする
#sed -i 's/-O2/-O3/g' Makefile
#sed -i 's/-Os/-Oz/g' Makefile

# install linux-config-5.15 from sid or experimental
xzcat /usr/src/linux-config-5.15/config.${variant}.xz >.config
cat >>.config <<EOF
CONFIG_MCORE2=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=n
CONFIG_LTO_CLANG_FULL=y
CONFIG_TRIM_UNUSED_KSYMS=y
CONFIG_CFI_CLANG=y
CONFIG_CFI_CLANG_SHADOW=y
#CONFIG_CFI_PERMISSIVE=y
CONFIG_SHADOW_CALL_STACK=y
CONFIG_INIT_STACK_ALL_ZERO=y
CONFIG_VGA_SWITCHEROO=n
CONFIG_VGA_ARB=n
CONFIG_DEVPORT=n
CONFIG_DEVMEM=n
CONFIG_DEVKMEM=n
CONFIG_SND_OSSEMUL=n
CONFIG_ZONE_DEVICE=y
CONFIG_DEVICE_PRIVATE=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_PREEMPT=y
CONFIG_DEBUG_PREEMPT=n
CONFIG_HZ_100=y
CONFIG_LATENCYTOP=y
CONFIG_HYPERVISOR_GUEST=n
CONFIG_KVM_GUEST=n
CONFIG_PARAVIRT=n
CONFIG_PARAVIRT_TIME_ACCOUNTING=y
CONFIG_XEN=n
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_CLEAN_CACHE=y
CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y
CONFIG_UBSAN=y
CONFIG_UBSAN_SANITIZE_ALL=y
CONFIG_UBSAN_BOUNDS=y
CONFIG_UBSAN_ARRAY_BOUNDS=y
CONFIG_UBSAN_UNREACHABLE=y
CONFIG_UBSAN_SHIFT=y
CONFIG_UBSAN_OBJECT_SIZE=n
CONFIG_STACK_VALIDATION=y
CONFIG_WQ_WATCHDOG=y

CONFIG_XFS_FS=n
EOF

if [ $arch = armhf ]; then
  yes '' |
    chrt --batch 0 nice -19 /usr/bin/time -v make -j `nproc` ARCH=arm V=1 LLVM=1 LLVM_IAS=1 \
         KCFLAGS="-pipe ${march} -fintegrated-cc1 -mllvm -polly -mllvm -polly-ast-use-context -mllvm -polly-invariant-load-hoisting -mllvm -polly-opt-fusion=max -mllvm -polly-run-inliner -mllvm -polly-vectorizer=stripmine -mllvm -polly-run-dce" \
         LOCALVERSION=-clang13ltopolly \
         bindeb-pkg
else
  yes '' |
    chrt --batch 0 nice -19 /usr/bin/time -v make -j `nproc` V=1 LLVM=1 LLVM_IAS=1 \
         KCFLAGS="-pipe ${march} -fintegrated-cc1 -mllvm -polly -mllvm -polly-ast-use-context -mllvm -polly-invariant-load-hoisting -mllvm -polly-opt-fusion=max -mllvm -polly-run-inliner -mllvm -polly-vectorizer=stripmine -mllvm -polly-run-dce" \
         LOCALVERSION=-clang13ltopolly \
         bindeb-pkg
fi
```