SSブログ

PowerPC code on Lion [日常のあれやこれや]

Mac OS X10.7 LionではそれまでサポートしてきたPowerPCで動くアプリは起動しなくなった。10.4以降10.6までPowerPCアプリのコードを解釈してIntelの命令に実行時に変換するRosettaという機能が働いていたけど、Lionでそれが削除されたためである。

僕はまだPowerPCアプリをたくさん使っている。典型的な例で言えば、PIXELA社のMPTV/U1Mというハードウェアテレビチューナは専用アプリがないとただのガラクタだけど、PIXELAがあっさりサポートをやめてしまったおかげで、そのアプリもLionでは動かないので本当にガラクタになってしまう(ひどい話だけど、どのみちテレビのアナログ放送が終われば同じことなので、これに関してはあきらめるしかない)。

このようなバージョンアップを望めないアプリ、あるいはバージョンアップのためには不本意なコストのかかるアプリがいくつかある。僕はできればLionに移行したいんだけど、こういったPowerPCアプリの問題があるのでできないでいる。では、LionでなんとかRosettaを動かすことはできないのか

誰かが試してすぐ失敗したように、単にLionにSnow LeopardのRosettaをコピーしてきても動かないのはあたりまえで、ハンドルとエンジンだけあっても車が動かないのと同じ。 なぜ、LionにRosettaをコピーするだけでは動かないのか。その技術的な説明をしてみる。

そもそも、10.4~10.6ではシステムのあらゆるものがUniversal Binary化されていた。これはもともとはPowerPCとIntelの2種類のハードウェアでOSを動作させるために必要な措置だった。

たとえば10.5 Leopardでは、/System/Library/Frameworksの中にあるフレームワークはすべてIntel32、64、PowerPC32、64ビットの4アーキテクチャのUniversal Binaryになっている。これはどちらのCPUを積んだハードでもOSとして機能するために必要だった(mach_kernelも同じUniversal Binaryになっている)。

さらに、アプリによっては/libや/usr/libなどのunixライブラリを呼んでいる場合もある。フレームワークによってはunixの機能を利用していたり、そのラッパになっていたりするものもあって、フレームワーク内部からも/usr/libにリンクされているものもある。実はこれらもすべてUniversal Binary化されていた。基本的にAppleがOSの一部として供給したライブラリはすべてUniversal Binaryである。

ハードウェアとしてのPowerPCでは起動できなくなった10.6 Snow Leopardでもフレームワーク(やライブラリ)はすべてIntel32、64、PowerPC32の3アーキテクチャUniversal Binaryになっている。これはソフトウェアとしてのPowerPCのコードを動かすために必要だった。IntelのCPUを積んだハードでPowerPCのアプリを立ち上げると、Rosettaが命令を逐次変換していく。アプリがフレームワークの機能を呼び出したとき、そのフレームワークのPowerPCのコードが呼ばれてやはりRosettaで変換されて実行が継続される。このおかげで、フレームワークを呼び出すときにエンディアンを入れ替えるかどうかや、バイナリをPowerPCのコードとして解釈し続けるかどうか、など気にする必要がなく、Rosettaの実装は簡単になる。

つまり、10.4〜5と10.6では同じUniversal Binaryでもその目的とするところが、実は違っていた。

このことからわかるように、10.6までのIntel Macで動いているPowerPCアプリは、アプリ自身のコードだけではなくユーザ側のプロセス全体(注記参照)がRosettaの上で解釈されることになる。これは無駄が多くて遅いけど、Rosettaの実装をシンプルにして、互換性を高めることに役立っていた。Rosettaエンジン単体ではなく、こういう部分も含めてごっそりと、10.7Lionでは落とされていることになる。

新しくLionにRosettaを実装する?

RosettaをLionにもほしいと思う人はいっぱいいるらしくて、たとえばLionRosettaなんていう開発プロジェクトができあがっている。が、実はこのプロジェクトは実質的に中身はカラっぽ(最近は名前をLionettaにするかで悩んでいる)で、上に書いたようなことさえ理解していない素人が人を集めりゃできるとでも思って作ったものらしい。

しかし、ほんとうにLion上でRosettaと同じ機能を持つものを作るには、すべてのライブラリと同じ動作をするPowerPCライブラリを作るか、あるいはDynamic linkされた外部のコードが呼ばれるのを実行時に監視して、そこでコード解釈とデータのエンディアンを切り替えるような非常にヘビーな処理を実装しないといけない。そのためにはフレームワークのAPIの引数のデータ構造をすべて知っている必要がある。さらに、スタックを直接操作するコードを書く必要が出る可能性もある。だとすると、コンパイラが出力するスタック操作と厳密に整合をとらないといけなくなって非常に煩わしい。これでは10.6以前でRosettaを実装するのにくらべて何十倍も大変な作業になる。

別のアプローチ

それよりも、Lionに簡易的な仮想環境を用意してやればRosettaは動くかもしれない。つまり
  • Snow Leopardに実装されたRosettaエンジン
  • Snow Leopardのフレームワーク、ライブラリのディレクトリツリーすべて
をLionにコピーしてきて、ダイナミックリンクするコードをLionのフレームワークではなく、別の場所にあるSnow Leopardのフレームワークやライブラリを指定できればいい。Rosettaそのものや、Snow LeopardのフレームワークがLionにない(削除された)Kernel呼び出しを使っていたらその時点でダメだけど、たぶんその可能性は低い。

もちろんたくさん問題はある。たとえばRosettaを使うプロセスのforkに特別な処理が必要で、Lionにはその機能がない、ということは十分考えられる。そのあたりはドキュメントはないけど、Darwinとして公開されているので、まじめにソースを読めばなんとかなるはず。それがわかればRosettaが使うプロセスのリソースを揃えた一種のSandboxを作ればいい。具体的な中身はまだ確認していないけど、LionにはアプリをSandbox化するための機能がそなわっているらしいので、その作業は簡単かもしれない。

また、ダイナミックリンクのときのシンボル解決がRosettaでは調整できないという可能性もある。つまり本来と違うディレクトリツリーのコードにリンクできないかもしれない。シンボルテーブルを埋めるのはリンクローダの仕事だけど、その実体がどこにあるかはOSが指定しているはずで、それもDarwinコードを見てSandbox化すればいい。Rosetta自身はDarwinの一部ではないので、公開されていない。したがってRosettaを使って起動するプロセスの詳細解析(リーバスエンジニアリング、あるいは簡単にクラックともいう)が必要になるかもしれないけど。

そもそもAppleがそういうコードの使いまわしをライセンス上許さない、という可能性もある。これはライセンス条項に「ダメ」と書かれていればそれまでだけど、ダメとは書かれていないとしても「かまわない」と書いてあるはずはないので、その場合条項を細かく分析しないといけなくなるかもしれない。

問題は多いけど、Rosettaそのものや、ましてライブラリを呼ぶたびにコードの解釈を切り替えるようなLionRosettaを実装するという技術的に高度な作業は避けることができる。

ということで、誰かやってくれないかなあ



注記:
最終的にはコードはOSを呼び出す。Mac OS Xの場合、入出力などはI/O Kitを経由するか、直接machメッセージを発行してkernelに処理を依頼する形をとる。libcなどにある入出力のシステムコールも、Mac OS Xではその中でunixの/devにあるファイルを読み書きする古いコードが、I/O Kitのメカニズムを使うように書き換えられている。基本的にこの部分は正確にmachメッセージをkernelとやり取りできれば、CPUのアーキテクチャにはよらない(もともとmachメッセージはネットワーク越しにも発行できる仕様だった)。したがってユーザランドのコードがすべてPowerPC(か、あるいはネイティブのIntel)になっていれば実行できる。

I/O Kitにはエンディアンの処理にまつわる微妙な問題が残るけど、最悪の場合でも、I/O Kitは公開されているのでUniversal BinaryにコンパイルしてLionに実装するという手が残されている。
nice!(1)  コメント(0)  トラックバック(0) 

nice! 1

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

献立08/18献立08/19 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。