この章では 64 ビットアプリケーション開発環境について説明します。構築環境、その他ヘッダーおよびライブラリの問題、コンパイラオプション、リンク、およびデバッグツールについて説明します。パッケージ処理に関するガイドラインも示します。
まず、オペレーティングシステムのバージョンが 32 ビットであるかあるいは 64 ビットであるかを確認する必要があります。使用しているバージョンが不明な場合は、64 ビットオペレーティングシステムを使用していると仮定します。バージョンを確認するには、第 3 章「32 ビットと 64 ビットインタフェースの比較」で説明した isainfo(1) コマンドを使用します。32 ビットオペレーティング環境を使用している場合でも、システムヘッダーファイルおよび 64 ビットライブラリがシステム上にあれば、64 ビットアプリケーションを構築することができます。
構築環境には、システムヘッダー、コンパイルシステム、およびライブラリが含まれています。これらのことについては、次の節で説明します。
1 組のシステムヘッダーが 32 ビットおよび 64 ビットのコンパイル環境をサポートします。64 ビットコンパイル環境用に別のインクルードパスを指定する必要はありません。
64 ビット環境をサポートするためにヘッダーに加えられた変更をより理解するには、ヘッダーの <sys/isa_defs.h> のさまざまな定義について理解しておくことをお薦めします。このヘッダー中には #define
が含まれており、それらは各命令セットアーキテクチャに対して設定されています。<sys/types.h> をインクルードすると、自動的に <sys/isa_defs.h> がインクルードされます。
次の表にあるシンボルは、コンパイル環境 (コンパイラ) によって定義されます。
シンボル |
説明 |
---|---|
__sparc |
SPARC ファミリーのプロセッサアーキテクチャのいずれかであることを示します。アーキテクチャには、SPARC V7、SPARC V8、および SPARC V9 があります。シンボルの sparc は、非推奨の __sparc の同義語です。 |
__sparcv8 |
『The SPARC Architecture Manual, Version 8』で定義されている 32 ビット SPARC V8 アーキテクチャを示します。 |
__sparcv9 |
『The SPARC Architecture Manual, Version 9』で定義されている 64 ビット SPARC V9 アーキテクチャを示します。 |
__x86 |
x86 ファミリーのプロセッサアーキテクチャのいずれかであることを示します。これらのアーキテクチャには 386、486、Pentium、AMD64、および EM64T プロセッサがあります。 |
__i386 |
32 ビット i386 アーキテクチャであることを示します。 |
__amd64 |
64 ビット amd64 アーキテクチャであることを示します。 |
__i386 および __amd64 は、相互に排他的です。シンボル __sparcv8 および __sparcv9 は相互に排他的で、シンボル __sparc が定義されているときにだけ意味があります。
次に示すシンボルは、上記のシンボルのいくつかの組み合わせから派生したものです。
シンボル |
説明 |
---|---|
_ILP32 |
int、long、およびポインタのサイズがすべて 32 ビットであるデータ型モデル |
_LP64 |
long およびポインタのサイズがすべて 64 ビットであるデータ型モデル |
シンボル _ILP32 および _LP64 も、相互に排他的です。
完全に移植性のあるコードを書くことが不可能で、32 ビットおよび 64 ビットのそれぞれに固有のコードが必要な場合は、_ILP32 または _LP64 を使って、コードを条件付きで切り替えるようにしてください。これによって、マシンに依存しないコンパイル環境にすることができ、アプリケーションをすべての 64 ビットプラットフォームに移植する際の移植性が高くなります。
Sun Studio C、C++、および Fortran のコンパイル環境が拡張され、32 ビットおよび 64 ビットアプリケーションの両方を作成できるようになりました。Sun Studio で提供される C コンパイラのリリース 10.0 は、64 ビットコンパイルをサポートします。
ネイティブコンパイルモードおよびクロスコンパイルモードがサポートされています。デフォルトのコンパイル環境は、これまでどおり 32 ビットアプリケーションを作成します。ただし、両モードともアーキテクチャに依存します。Sun コンパイラを使用して、x86 マシン上で SPARC オブジェクトを作成したり、 SPARC マシン上で x86 オブジェクトを作成することはできません。アーキテクチャやコンパイラのモードが指定されていない場合は、適宜 __sparcv8 または __i386 シンボルがデフォルトで定義され、この一部として _ILP32 も定義されます。これによって、既存のアプリケーションおよびハードウェアにおける相互運用性が高くなります。
Sun Studio 8 リリースから、cc(1) -xarch=generic64 フラグを使用して、64 ビットコンパイル環境を使用できるようにします。
これによって LP64 コードが含まれる ELF64 オブジェクトが生成されます。ELF64 とは、64 ビットのプロセッサおよびアーキテクチャをサポートする 64 ビットオブジェクトファイル形式のことです。一方、デフォルトの 32 ビットモードでコンパイルしたときは、ELF32 オブジェクトファイルが生成されます。
-xarch=generic64 フラグを使用すると、32 ビットまたは 64 ビットのシステムで 64 ビット コードを生成できます。32 ビットコンパイラを使用すると、32 ビットシステムで 64 ビットオブジェクトを作成できますが、その 64 ビットオブジェクトは 32 ビットシステムでは実行できません。64 ビットライブラリに対するライブラリパスを指定する必要はありません。-l または -L オプションを使用してライブラリまたはライブラリパスを追加指定し、そのパスが 32 ビットライブラリだけを指している場合は、リンカーはそれを検出し、エラーを出力してリンク処理を異常終了します。
コンパイラオプションの説明は、『Sun Studio 10: C ユーザーズガイド』を参照してください。
Solaris オペレーティングシステムには、32 ビットおよび 64 ビットの両コンパイル環境用の共有ライブラリが含まれています。
32 ビットアプリケーションは 32 ビットライブラリとリンクし、64 ビットアプリケーションは 64 ビットライブラリとリンクしなければなりません。64 ビットライブラリを使って 32 ビットアプリケーションを作成または実行することはできません。32 ビットライブラリは、これまでどおり /usr/lib および /usr/ccs/lib に置かれています。64 ビットライブラリは、適切な lib ディレクトリのサブディレクトリに置かれています。32 ビットライブラリの場所は変更されていないので、Solaris 2.6 以前のオペレーティングシステムで構築された 32 ビットアプリケーションとのバイナリの互換性があります。移植可能な Make ファイルは、64 シンボリックリンクを使用してライブラリのいずれかのディレクトリを参照します。
64 ビットアプリケーションを構築するためには 64 ビットライブラリが必要です。64 ビットライブラリは、32 ビットおよび 64 ビットの両環境で利用できるため、ネイティブコンパイルもクロスコンパイルも可能です。コンパイラとその他のツール (たとえば ld、ar、as など) は 32 ビットプログラムで、32 ビットまたは 64 ビットシステム上で 64 ビットプログラムを構築する機能があります。もちろん、32 ビットオペレーティング環境上のシステムで作成された 64 ビットプログラムは、32 ビット環境では実行できません。
リンカーは、32 ビットアプリケーションのままですが、ほとんどのユーザーはこのことを意識する必要がありません。通常リンカーはコンパイラドライバ (たとえば cc(1)) から間接的に呼び出されるからです。ELF32 オブジェクトファイルをリンカーへの入力として指定すると、リンカーは ELF32 出力ファイルを生成します。同様に、入力ファイルとして ELF64 オブジェクトファイルを指定すれば、ELF64 出力ファイルを生成します。ELF32 と ELF64 の入力ファイルを混在させて指定しようとしてもリンカーに拒絶されます。
SPARC。32 ビットおよび 64 ビットのアプリケーション用の動的リンカープログラムは、それぞれ /usr/lib/ld.so.1 と /usr/lib/sparcv9/ld.so.1 です。
x86。AMD64 アーキテクチャでは、32 ビットアプリケーションおよび 64 ビットアプリケーション用の動的リンカープログラムは、それぞれ /usr/lib/ld.so.1 と /usr/lib/amd64/ld.so.1 です。
これらの動的リンカーは両方とも、LD_LIBRARY_PATH 環境変数で指定された、コロンで区切られたディレクトリ名のリストを実行時に検索します。32 ビット動的リンカーは 32 ビットライブラリとだけ結合し、64 ビット動的リンカーは 64 ビットライブラリとだけ結合します。したがって、必要であれば 32 ビットおよび 64 ビットライブラリの両方を格納しているディレクトリを環境変数 LD_LIBRARY_PATH で指定することができます。
64 ビット動的リンカーの検索パスは、LD_LIBRARY_PATH_64 環境変数を使って完全に上書きする (優先させる) ことができます。
アプリケーションを配布し管理するための共通の手法として、関連するアプリケーションとライブラリを 1 つのディレクトリ階層に入れる手法があります。一般的に、アプリケーションが使用するライブラリは lib サブディレクトリに置き、アプリケーションそのものはベースディレクトリの bin サブディレクトリに置きます。このベースディレクトリは、Sun が配布するコンピューティングファイルシステムである NFSTM によりエクスポートし、クライアントマシンにマウントできます。環境によっては、オートマウンタとネームサービスを使用して、アプリケーションを配布し、すべてのクライアントにおいてアプリケーション階層のファイルシステムの名前空間を同じにすることもできます。そのような環境では、-R オプションをリンカーに指定してアプリケーションを構築できます。このオプションは、実行時に共有ライブラリを検索するディレクトリの絶対パス名を指定します。
ただし環境によっては、ファイルシステムの名前空間がうまく制御されず、開発者がデバッグ用のツール、つまり LD_LIBRARY_PATH 環境変数を使ってラッパースクリプトにライブラリの検索パスを指定するという手法を採用していました。これは不必要であり、$ORIGIN キーワードをリンカーの -R オプションに指定されたパス名に含めることができます。$ORIGIN キーワードは、実行可能プログラムそのものがあるディレクトリ名に実行時に展開されます。つまり、$ORIGIN からの相対パス名でライブラリディレクトリのパス名を指定できるということです。この結果、LD_LIBRARY_PATH をまったく設定しなくても、アプリケーションのベースディレクトリを移動することができるようになります。
この機能は 32 ビットおよび 64 ビットの両方のアプリケーションで利用できます。新しいアプリケーションを作成する場合に、LD_LIBRARY_PATH を正しく構成するユーザーやスクリプトに対する依存性を減らしたいときに、この機能を利用できます。
詳細は、『リンカーとライブラリ』を参照してください。
以降の節では 32 ビットおよび 64 ビットアプリケーションのパッケージ処理について説明します。
SPARC。新しいライブラリとプログラムの配置については、「32 ビット ライブラリと 64 ビット ライブラリ」に記載されている標準規則に従います。32 ビットライブラリは従来どおり同じ場所に置かれますが、64 ビットライブラリは、通常のデフォルトのディレクトリ内の、アーキテクチャに依存する特定のサブディレクトリに置くことをお薦めします。32 ビットおよび 64 ビットにそれぞれ固有のアプリケーションは、ユーザーにとって透過的な場所に置くようにしてください。
つまり、32 ビットライブラリは同じライブラリディレクトリに置き、64 ビットライブラリは適切な lib ディレクトリ下の sparcv9 サブディレクトリに置きます。
32 ビットまたは 64 ビット環境に固有のバージョンを必要とするプログラムは、上記とは多少異なり、通常置かれるディレクトリ下の sparcv7 または sparcv9 サブディレクトリに適宜置くことをお薦めします。
64 ビットライブラリは、適切な lib ディレクトリ下の amd64 サブディレクトリに置く必要があります。
32 ビット または 64 ビット 環境に固有のバージョンを必要とするプログラムは、通常置かれるディレクトリの下の i86 または amd64 サブディレクトリに適宜置くことをお薦めします。
「アプリケーション命名規則」を参照してください。
パッケージ処理の選択肢として、32 ビットおよび 64 ビットアプリケーション用にそれぞれパッケージを別々に作成するか、あるいは 32 ビットおよび 64 ビットバージョンを 1 つのパッケージにまとめるか、という問題があります。1 つのパッケージを作成する場合は、この章で説明しているサブディレクトリの命名規則をパッケージの内容に対して適用することをお薦めします。
32 ビットおよび 64 ビットのアプリケーションに対して foo32 や foo64 のような特定の名前を付ける代わりに、「ライブラリとプログラムの配置」で説明したように、32 ビットおよび 64 ビットアプリケーションをプラットフォーム固有の適切なサブディレクトリに置くことができます。このようにすると、次の項で説明しているラッパーを使用して、環境に応じて 32 ビットまたは 64 ビットのいずれかのアプリケーションを実行することができます。利点としては、プラットフォームに応じて適切なバージョンのアプリケーションが自動的に実行されるため、ユーザーは 32 ビットまたは 64 ビットのどちらであるかなどについて意識する必要がありません。
32 ビットおよび 64 ビット固有のバージョンのアプリケーションが必要な場合、シェルスクリプトラッパーを使うと、ユーザーがバージョンに関して意識する必要がなくなります。32 ビットおよび 64 ビットバージョンが必要な、Solaris オペレーティングシステムの多くのツールが、この例として当てはまります。ラッパーを利用すると、特定のハードウェアプラットフォーム上で実行可能な固有の命令セットを isalist コマンドを使って調べ、それに基づいて適切なバージョンのツールを実行させることができます。
次に、ネイティブ命令セットラッパーの例を示します。
#! /bin/sh CMD=`basename $0` DIR=`dirname $0` EXEC= for isa in `/usr/bin/isalist`; do if [-x ${DIR}/${isa}/${CMD}]; then EXEC=${DIR}/${isa}/${CMD} break fi done if [-z "${EXEC}"]; then echo 1>&2 "$0: no executable for this architecture" exit 1 fi exec ${EXEC} "${@}" |
この例には問題が 1 つあります。$0 引数が、その引数自身の実行可能プログラムに対する完全パス名であることを前提にしていることです。このような理由から、汎用的なラッパーである isaexec() が作成され、32 ビットおよび 64 ビット固有のアプリケーションの問題に対処しています。引き続きこのラッパーについて説明します。
isaexec(3C) は 32 ビット実行可能バイナリファイルです。1 つ前の節で説明したようなシェルスクリプトラッパー機能を実行しますが、その際引数リストも正確に保存します。実行可能プログラムの完全パス名は /usr/lib/isaexec ですが、この名前で実行するようには設計されていません。このプログラムでは、isalist(1) によって選択された複数のバージョンで存在するプログラムの主要な名前 (プログラム実行時にユーザーが使用する名前) にコピーされたり、リンク (シンボリックリンクではなくハードリンク) される可能性があります。
たとえば、SPARC 環境では、truss(1) コマンドは次の 3 つの実行可能ファイルとして存在します。
sparcv7 と sparcv9 サブディレクトリの実行可能プログラムは、実在する truss(1) 実行可能プログラムで、それぞれ 32 ビットおよび 64 ビットプログラムです。ラッパーファイルの /usr/bin/truss は、/usr/lib/isaexec にハードリンクされています。
x86 環境では、truss(1) コマンドは次の 3 つの実行可能ファイルとして存在します。
isaexec(3C) ラッパーは、完全に解決された、シンボリックリンクのない自分のパス名を、argv[0] 引数とは別に getexecname(3C) を使用して調べ、sysinfo(SI_ISALIST, ...) を使用して isalist(1) を取得します。そして、その結果得られた自分自身のディレクトリのサブディレクトリリストを調べ、自分の名前がある最初の実行可能ファイルに対して exec(2) を実行します。そのとき isaexec(3C) ラッパーは、引数ベクトルと環境ベクトルを変更せずに渡します。このようにして、argv[0] は最初に指定されたとおりに最終的なプログラムイメージに渡されます。サブディレクトリ名を含むように修正された完全パス名に変換された形ではありません。
ラッパーが存在する場合があるため、実行可能プログラムを他の場所に移動する際は注意が必要です。実際のプログラムではなく、ラッパーを移動してしまう可能性があります。
多くのアプリケーションでは、すでに起動ラッパープログラムを使用して、環境変数の設定、一時ファイルの消去、デーモンの起動などを行なっています。libc(3LIB) 内の isaexec(3C) インタフェースを利用すると、前述のようなシェルスクリプトラッパーの例で使用しているのと同じアルゴリズムを、カスタマイズしたラッパープログラムから直接呼び出すことができます。
Solaris 上で実行できる truss(1) コマンド、/proc ツール (proc(1))、および mdb などのすべてのデバッグツールが、64 ビットアプリケーションで動作するようにアップグレードされています。
これらのデバッグツールのうち、64 ビットアプリケーションをデバッグできる dbx デバッガは、Sun Studio ツール群の一部として入手できます。それ以外のツールはすべて Solaris リリースの中に含まれています。
これらのすべてのデバッグツールのオプションには変更がありません。64 ビットプログラムをデバッグするために、mdb では多数の拡張機能を使用できます。ポインタを間接参照するために「*」を使用すると、64 ビットプログラムに対しては 8 バイトを、32 ビットプログラムに対しては 4 バイトを参照します。さらに、次の修飾子を使用できます。
追加修飾子 ?、/、= : g (8) 符号なし 8 進数で 8 バイト表示 G (8) 符号付き 8 進数で 8 バイト表示 e (8) 符号付き 10 進数で 8 バイト表示 E (8) 符号なし 10 進数で 8 バイト表示 J (8) 16 進数で 8 バイト表示 K (n) pointer または long を 16 進数で印刷 32 ビットプログラムを 4 バイト表示、 64 ビットプログラムを 8 ビット表示する。 y (8) 日付形式で 8 バイト印刷 追加修飾子 ?、/ : M <value> <mask> 8 バイトの値に <mask> を適用し比較する。 「.」をマッチする位置へ移動する。 Z (8) 8 バイト書き込み