2024年1月にリリースされたバージョン6.7のLinuxカーネルには、IA32エミュレーション機能の有効/無効を切り替える「ia32_emulation」というカーネルパラメータ(カーネル起動オプション)が追加されました。それに合わせて、IA32エミュレーション機能をデフォルトで無効化する設定パラメータ「CONFIG_IA32_EMULATION_DEFAULT_DISABLED」も追加されています。
また、2024年3月にリリース予定のバージョン6.8のLinuxカーネルでは、IA32エミュレーション機能が無効化された状態でIA32プログラムが実行されると、同機能を有効化する方法をカーネルメッセージとして出力する変更が加えられます。
IA32エミュレーションとは
IA32エミュレーションとは、従来の32ビット版Linuxディストリビューションで使われていたIA32(32ビット命令セットアーキテクチャ)のLinuxプログラムを、x86-64版のLinuxカーネルで実行できるようにする機能です。同機能を有効にすると、32ビットプログラム向けのシステムコールやシグナルなどが利用可能になります。
2024年1月時点では、大部分のLinuxディストリビューションが同機能を有効化したカーネルを利用しています。それに加えて、32ビットプログラム向けのユーザーランド(共有ライブラリなど)を用意することで、32ビット版のディストリビューションと同様に32ビットプログラムを稼働できるようにしています。
x32 ABIとの違い
なお、バージョン3.4以降のx86-64版のLinuxカーネルでは、x32プログラムを実行可能にする「x32 ABI」という機能も利用可能です。
ここで言うx32プログラムとは、メモリーアドレスを32ビットに制限した命令だけを使う、特殊なバイナリ形式(elf32_x86_64)のプログラムのことです。IA32プログラムとは異なり、「x86-64 CPUに追加されたレジスタを利用可能」「64ビット演算が可能」などの特徴を持ちつつ、IA32プログラム並みのメモリー利用効率を実現できます。
ただし、x32プログラムは実際にはほとんど使われていません。そのため、2018年の末頃から、x32 ABI機能の廃止が議論されています。また、Ubuntuは、x32 ABI機能を無効化してバージョン5.17以降のLinuxカーネルを提供しています。
デフォルト無効で必要に応じて有効化という運用が可能に
IA32エミュレーション機能によって32ビットプログラムを利用できるのは便利ですが、問題がないわけではありません。32ビットプログラム向けのユーザーランドをメンテナンスするコストがかかりますし、メンテナンスをおろそかにするとセキュリティ上のリスクが生じる恐れがあります。特にエンタープライズ向けのディストリビューションでは、できればIA32エミュレーション機能は無効化したいところでしょう。しかし、32ビットプログラムをまったく動かせなくするのは、現状ではまだ難しい面があります。
バージョン6.7のLinuxカーネルに追加されたカーネルパラメータと設定パラメータを使えば、IA32エミュレーション機能をデフォルトで無効化しつつ、必要に応じてユーザーが有効化するという運用が可能になります。それには、カーネルを次の設定パラメータでビルドします。
CONFIG_IA32_EMULATION=y
CONFIG_IA32_EMULATION_DEFAULT_DISABLED=y
「make menuconfig」を実行して起動するツールで設定する場合には、「Binary Emulations」項目を選択して表示される次の画面で、「IA32 Emulation」「IA32 emulation disabled by default」の項目に「*」を付けます。
これにより、IA32エミュレーション機能は利用できるがデフォルトで無効という状態にできます。そして、32ビットプログラムを実行したい場合には、ブートローダーのカーネル設定行に次のカーネルパラメータを追加してLinuxを起動します(「on」の代わりに「y」を指定しても構いません)。
ia32_emulation=on
実際に動作を試してみる
バージョン6.8-rc1のカーネルを前述の設定パラメータでビルドし、それをUbuntu 22.04 LTS環境で動かして試してみました。
まず、サンプルプログラムをビルドするためのツール類を次のコマンドでインストールします。
$ sudo apt update
$ sudo apt install build-essential libc6-dev-i386
続いて、次のコードを「hello.c」というファイル名で保存します。
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Hello, World!\n");
exit(0);
}
保存したら、次のコマンドで32ビットプログラムとしてビルドして実行します。
$ gcc -m32 -o hello_ia32 hello.c
$ ./hello_ia32
-bash: ./hello_ia32: バイナリファイルを実行できません: 実行形式エラー
すると、このように実行形式エラーが表示されます。また、このときに「sudo dmesg」コマンドを実行すると、次のカーネルメッセージが表示されます。なお、このカーネルメッセージは、カーネル内のpr_notice_once()関数で出力されるので、最初に32ビットプログラムが実行されたときだけ表示されます。
32-bit emulation disabled. You can reenable with ia32_emulation=on
カーネルメッセージにあるように、「ia32_emulation=on」というカーネルパラメータを指定してみましょう。Ubuntuでは、/etc/default/grubファイルのGRUB_CMDLINE_LINUX行にカーネルパラメータを記述してから、次のコマンドを実行するとブートローダーの設定が変更されます。
$ sudo update-grub
Ubuntuを再起動してから、hello_ia32プログラムを実行してください。今度は問題なく動作します。
$ ./hello_ia32
Hello, World!
(おまけ)x32 ABIの動作を試したい場合
x32 ABIの動作を試したい場合には、「libc6-dev-x32」パッケージを追加でインストールしてから、次のコマンドでサンプルプログラムをビルドして実行します。
$ gcc -mx32 -o hello_x32 hello.c
$ ./hello_x32
バージョン6.8のLinuxカーネルの場合、CONFIG_X86_X32_ABIという設定パラメータに「y」を設定してビルドしていれば、x32 ABI機能が有効となり、プログラムを正常に実行できます。
コメント