第4回 メインフレームLinuxの実装(後編)
メインフレームはLinuxにとって新しいハードウェアアーキテクチャでした。そのアーキテクチャ特有の実装を詳しく解説します(編集局)
日本アイ・ビー・エム株式会社
システムズ&テクノロジー・エバンジェリスト
北沢 強
2008/10/23
前回は、「メインフレームLinuxの実装(前編)」と題して、メインフレームという、Linuxにとって新しいアーキテクチャへどのように移植を行ったのかを、歴史的背景を踏まえて解説しました。今回の後編では、メインフレームハードウェア特有の実装について解説します。
メインフレームLinuxの仕様を知る
Linuxの仕様において、アーキテクチャごとの違いを体系的かつ簡単に確認する方法としては、The Linux Foundationから公開されている「LSB(Linux Standard Base)」の仕様書を見るのが近道でしょう。
LSBは、さまざまなディ ストリビューション間での差異をなくすための標準化を目的としています。共通なものは「Generic」として定義され、IA32、IA64、PPC32、PPC64、S390、S390X、AMD64という7つのアーキテクチャについて、Genericからの差分が仕様書としてまとめられています。この文書を見れば、そのアーキテクチャがGenericとどれだけ違うのかが分かります。あるいは、例えばIA64とS390Xを比較するような場合に、アーキテクチャ間の差異を見るときにも便利です。
また、プロセッサ・アーキテクチャごとに詳細な実装方法を記述しているのが「ELF(Executable and Linking Format)」と「ABI(Application Binary Interface)」の仕様書です。ELFは実行用バイナリのファイル形式を規定するもので、アーキテクチャに依存する情報をファイルのヘッダに含まれるように標準化したものです。ABIはOSとアプリケーション・インターフェイスを規定するものであり、アプリケーション(バイナリ形式)を実行する環境について定義しています。
メインフレームLinuxについては、「ELF ABI Supplement」として1つにまとめられた文書が公開されています。これを見れば、ほかのアーキテクチャとの実装方法の違いが一目瞭然です。オープンソースの世界には、「ソースコードを見れば仕様や機能が分かるでしょ」という職人かたぎのエンジニアも多いとは思いますが、このような標準化のための仕様書というのは、体系的に理解するには便利でしょう。
■アーキテクチャを説明したマニュアル
メインフレームのプロセッサ・アーキテクチャについては、「z/Architecture Principles of Operation(SA22-7832)」(通称:ピーオー)というマニュアルに記述されています。
このマニュアル、実は1000ページ以上ある分厚いものなのですが、メインフレーム・プロセッサ仕様がすべて克明に書かれています。アセンブラでプログラミングするときはもちろん、トラブル時の問題判別やテストをするときなどにも必須となるものです。筆者が入社した20年前はメインフレーム全盛の時代。「SEはこのピーオーをすべて頭にたたき込め!」といわれ、この分厚いマニュアルを枕にして寝たという同輩も多かったのです。
このマニュアルは、アーキテクチャの説明書として、プロセッサ内部の構成と各部の説明、プログラム実行と内部の動き、すべてのハードウェア命令の説明、入出力の仕組みと入出力命令の説明などが記述されています。Linuxをメインフレームに移植するうえで、最も参照したのがこのマニュアルであり、これがなければ移植は不可能でした。
レジスタの使い方
レジスタはメモリよりも高速ですから、限られた数のレジスタをいかに効率的に使うかはパフォーマンスに大きく影響します。また、レジスタは命令セットとも密に関係し、アーキテクチャごとに使われ方が異なります。
64ビットアドレッシングに対応した2000年以降のメインフレームには、16個の汎用レジスタと16個のIEEE浮動小数点レジスタ、16個の制御レジスタと16個のアクセスレジスタがあり、Linuxではこれらのレジスタそれぞれについて用途を決めて使うようにしています。汎用レジスタ「R2」は戻り値、「R14」は戻りアドレス、「R15」はスタックポインタの代用として使う、というように、レジスタの使い方のルールを決めています。これらは前述のELF ABI Supplementの中に記述されています。
ちなみに、従来のメインフレーム上のアセンブラでは、R15を戻り値やエントリアドレスに使うのがルールでしたから、昔からアセンブラを書いてきた方は戸惑うかもしれません。また、メインフレームには長きにわたりスタックの実装がありませんでしたので(スタック命令については後述)、スタックのエミュレーションをするため、スタックポインタとしてR15を使っています。
ほかのアーキテクチャに比べると、レジスタの数は決して多くありません。しかしメインフレームは、CISCプロセッサとして高機能な命令で処理を行うため、レジスタを多くは必要としなかったという経緯もあり、64ビット対応した現在であっても44年前と同じ16個の汎用レジスタで賄っています。
メインフレームになかった命令
ほかのアーキテクチャにはあるのにメインフレームではサポートしていなかったハードウェア命令としては、「相対ジャンプ命令」と「スタック命令」が挙げられます。いずれも、IA32などのアーキテクチャにおいては多用される命令です。
1. 相対ジャンプ命令
相対ジャンプ命令は、ジャンプする距離が短ければ命令長を短く実装できることや、オブジェクトコードの中で絶対アドレスを考慮しなくてよいため、リロケータブル(Position independent addressing)なバイナリを作りやすいというメリットがあります。
メインフレームは40年前から仮想メモリを実装しており、アドレスは仮想アドレスで管理していたため、リロケータブルである必要性はありませんでした。一方、UNIXやLinuxではリロケータブルなバイナリである必要があるため、メインフレームでは1997年のモデルからハードウェア命令として相対ジャンプ命令が追加されました。
相対ジャンプ命令は、人間がアセンブラで記述すると、飛び先のアドレス計算を間違えてしまうなど、バグの原因となる危険性が否定できません。しかし、gccなどのコンパイラによって自動生成される限りは間違える可能性もなく、メインフレームのアーキテクチャに取り込むときには大きな問題はありませんでした。メインフレームLinuxでは、この相対ジャンプ命令を多用しています。
2. スタック命令
IA32のスタックセグメントやスタックポインタ、PUSH、POPのようなスタック命令もメインフレームにはありませんでした。
スタックは一時的な退避メモリとして使い勝手がよく、1命令でメモリ操作とアドレス操作を行ってくれるため、パスレングスや消費サイクル数の観点でもメリットがあります。特に、Cコンパイラによる生成コードはスタック命令を多用する傾向にあり、Linuxにおけるコードモデルでも、Prolog/Epilogで当たり前のようにスタック命令が使われています。
スタック命令は使いやすくメリットも多いのですが、便利な半面、脆弱(ぜいじゃく)な面もあります。スタックは、レジスタやデータの退避のみならずアドレスの退避にも使われますし、スタック領域は有限であるため、あふれてしまう危険性があります。かといって、いちいちスタックのチェックをしていたら、パフォーマンス劣化につながります。この脆弱性を突かれて、スタックオーバーフローによるroot権限奪取など、システム攻撃の標的になりやすい側面もあります。
メインフレームでは2005年まで、スタック命令をハードウェアで実装していませんでした。スタックの便利さよりも、メモリ管理の脆弱性を問題視していたためです。基幹業務で定型処理中心の、メインフレームというキッチリ管理された世界では、スタックのようなメモリの使い方は許されなかったのかもしれません。
メインフレームでは、ジョブ(プログラム)を実行するときには、どれだけのメモリとCPU時間を使うか申告してから実行します。申告したリソース量を超えて使うことはできません。
これに対し、Linuxもそうですが、オープン系OSでは、CPU能力もメモリも、プログラムが要求すれば要求しただけ使える「使ったもの勝ち」の世界です。ただ、リソースが足りなくなってトラブルに陥る危険性もはらんでいます。
一方、メインフレームでは厳しく管理されていますから、使いたいだけ勝手に使うというのは許されません。リソースを厳密に管理することで、リソース不足やメモリリークなどのトラブルを未然に防ぐことができますし、安定稼働を続けることができるのです。
メインフレームLinuxでは、アーキテクチャとしてメモリ管理の脆弱性を作らないという意図から、スタック操作をエミュレーションによって実装しました。それは、オーバーヘッドでもあり、初期のメインフレームLinuxのパフォーマンス劣化とバイナリサイズ増の原因でもあったのですが、半面、IA32などのスタックとは異なりメモリ管理が厳密であるため、スタック操作における弱点を強化できるというメリットもあります。
1/3 |
|
||||||
|
- 【 pidof 】コマンド――コマンド名からプロセスIDを探す (2017/7/27)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、コマンド名からプロセスIDを探す「pidof」コマンドです。 - Linuxの「ジョブコントロール」をマスターしよう (2017/7/21)
今回は、コマンドライン環境でのジョブコントロールを試してみましょう。X環境を持たないサーバ管理やリモート接続時に役立つ操作です - 【 pidstat 】コマンド――プロセスのリソース使用量を表示する (2017/7/21)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、プロセスごとのCPUの使用率やI/Oデバイスの使用状況を表示する「pidstat」コマンドです。 - 【 iostat 】コマンド――I/Oデバイスの使用状況を表示する (2017/7/20)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、I/Oデバイスの使用状況を表示する「iostat」コマンドです。
|
|