この章では、コンパイラ、リンカ、デバッガについて説明します。この章の内容は次のとおりです。
SunOS 4 から Solaris 7 に移行する開発者にとって最も大きな変更点は、C コンパイラがバンドルされなくなったことです。コンパイラをバンドルしない理由の 1 つに、動的なカーネルがあります。動的なカーネルでは、必要に応じて自動的にデバイスが追加されるので、カーネルの再構築にコンパイラを使用する必要がありません。
Sun WorkShop(TM) には、ANSI C 互換コンパイラのほか、拡張されたデバッグ機能とプログラム開発環境があります。このコンパイラは、Solaris 7 のネイティブオブジェクト形式である 実行形式リンク形式から成る ELF 形式で実行可能ファイルを作成します。lint と lint ライブラリも Sun WorkShop の一部として提供されています。 lint と lint ライブラリも Sun WorkShop の一部として提供されます。
Sun WorkShop については、http://www.sun.com にアクセスしてください。
『Making the Transition to ANSI C』は、バンドル製品の SunOS 4 C コンパイラとアンバンドル製品の Sun WorkWhop C コンパイラのそれぞれによって実装される C 言語の違いを解説しています。一方のコンパイラ用のソースを他方に移植するときに参照してください。このマニュアルは、http://docs.sun.com の Sun WorkShop Compiler C 4.2 AnswerBook Collection で閲覧できます。
Sun WorkShop C コンパイラのオプションフラグ -Xs は、K&R C と ANSI C で動作が異なる言語構成要素について警告します。この特別なフラグについては、『C User's Guide』を参照してください。このマニュアルは、http://docs.sun.com の Sun WorkShop Compiler C 4.2 AnswerBook Collection でも閲覧できます。
このリリースではリンクエディタ ld(1) に対していくつかの変更があります。最も重要な変更は新しい ELF のファイルフォーマットを処理する機能です。
ライブラリと実行可能プログラムを構築するには、リンカを直接起動することよりもコンパイラドライバによる方法をお勧めします。コンパイラは、リンカが必要とする多数のファイルを自動的に供給します。
ライブラリを混合することはできません - 32 ビットプログラムは 32 ビットライブラリ、64 ビットプログラムは 64 ビットライブラリとリンクする必要があります。ELF32 オブジェクトは他の ELF32 オブジェクト、ELF64 オブジェクトは他の ELF64 オブジェクトとリンクします。
新しいリンカでリネームされたオプションもあれば同じものもあり、また不要になったオプションもあります。表 15-1 では SunOS 4 の ld を Solaris 7 の ld コマンドと比較します。
表 15-1 に続く節で、リンク作業がオプションの相違によってどのように影響を受けるかについて説明します。
表 15-1 ld オプションの比較
SunOS 4 のオプション |
Solaris 7 での変更 |
注 |
---|---|---|
-align datum |
-M mapfile |
mapfile と異なるセクションの使用 |
-assert definitions |
デフォルト |
|
-assert nodefinitions |
-znodefs |
警告ではなく重大なエラーを発行 |
-assert nosymbolic |
-zdefs |
警告ではなく重大なエラーを発行 |
-assert pure-text |
-ztext |
警告ではなく重大なエラーを発行 |
-A name |
変更なし |
dlopen(3X) とdlclose(3X) はこの動作に接近可能 |
-Bdynamic |
-Bdynamic |
共用ライブラリの取り込みにのみ適用される。動的にリンクされた実行可能プログラムを構築するには -dy (デフォルト) を使用。「実行可能ファイルの作成」を参照。 |
-Bnosymbolic |
-zdefs |
|
-Bstatic |
-dn & -Bstatic |
動的なリンカを完全に除去するには、-dn オプションを指定しなければならない。アーカイブライブラリを取り込むために動的モードで -Bstatic を使用 (トグルとして使用。「実行可能ファイルの作成」を参照)。 |
-Bsymbolic |
-Bsymbolic |
このオプションを付けて-assert nosymbolic も取得する。 |
-d -dc -dp |
デフォルト |
オフに設定するには、SVR4 で -b オプションを使用しなければならない。 |
-D hex |
-M mapfile |
mapfile には、希望する結果を達成するためにいろいろなメカニズムが含まれる。 |
-e entry |
-e entry |
|
no -e |
-G |
共有オブジェクトを作成する。 |
-lx[.v] |
-lx |
共用ライブラリのメジャー番号が示すバージョンだけが現在サポートされている。 |
-Ldir |
-Ldir |
dir は実行可能プログラムに記録されない。かわりに、-R オプションを使用。 |
-M |
-m |
|
-n |
デフォルト |
SVR4 の実行可能プログラムのフォーマットは、ディスクイメージを -n として圧縮 |
-N |
変更なし |
|
-o name |
-o name |
|
-p |
デフォルト |
-M mapfile で取り消し可能。 |
-r |
-r |
|
-S |
変更なし |
|
-s |
-s |
|
-t |
変更なし |
|
-T hex |
-M mapfile |
mapfile には、希望する結果を達成するためにいろいろなメカニズムが含まれる。 |
-Tdata hex |
-M mapfile |
mapfile には、希望する結果を達成するためにいろいろなメカニズムが含まれる。 |
-u name |
-u name |
|
-x |
変更なし |
|
-X |
変更なし |
|
-y sym |
変更なし |
|
-z |
デフォルト |
Solaris 7 で共用ライブラリを作成するには、-G オプションを指定する必要があります。SunOS 4 では、-e オプションなしの場合、共用ライブラリを作成することをリンカが自分で判断します。Solaris 7 では共用ライブラリがエントリポイントを持つ可能性があるため、このオプションは使用できなくなりました。
-Bdynamic と -Bstatic オプションはまだ利用できますが、その動作はかなり異なります。現在では、これらのオプションは実行可能バインディングではなくライブラリのインクルードを指します。実行可能バインディングは、Solaris 7 で新しい -dy と -dn オプションでのみ排他的に設定されます。-dy オプションがデフォルトです。これは、動的にリンクされた実行可能ファイルを作成するために必要です。-dn オプションは、静的にリンクされた実行可能ファイルを作成するために必要です。
-Bdynamic と -Bstatic オプションは、-dy オプションを使用したときだけ適用されます。 -Bdynamic はリンクエディタに共用ライブラリを含めるように指示し、-Bstatic はアーカイブライブラリを含めるように指示します。これらのオプションは、次の -Bdynamic または -Bstatic オプション指定が現れるまで、-l 引数を管理する切り替え (トグル) として機能します。
次の例に、同様の実行可能プログラムを作成するのに使用できる SunOS 4 と Solaris 7 コマンドを示します。
sunos4.1% ld Bstatic test.o -lx
libx.a を使用して、静的な実行可能ファイルを作成する。
sunos5.x% ccdn test.o -lx
libx.a を使用して、静的な実行可能ファイルを作成する。
sunos4.1% ld Bdynamic test.o -lx
libx.so を使用して、動的な実行可能ファイルを作成する。
sunos5.x% cc test.o -lx
libx.so を使用して、動的な実行可能ファイルを作成する。
sunos4.1% ld Bdynamic test.o Bstatic -lx
libx.a を使用して、動的な実行可能ファイルを作成する。
sunos5.x% cc test.o Bstatic -lx
libx.a を使用して、動的な実行可能ファイルを作成する。
SunOS 4 では、-L オプションを付けて指定したディレクトリはリンク時に検索され、その情報は実行時に使用するために保持されていました。この動作は現在では、 -L と -R オプションに分けられています。 -L オプションはリンク時に検索するディレクトリを指定し、-R オプションはリンカに対して、実行時に使用するために保持する検索パスを指示します。詳細については、「検索パスの規則」を参照してください。
-Bdynamic と -Bstatic オプションと同様に、 -L オプションの位置には意味があります。これは、それに続く -l オプションにだけに適用されます。
動的リンカと実行時リンカが SunOS 4 リンカによって使用されたのとは異なるアルゴリズムを使って検索パスを決定します。
以下の例では、SunOS 4 と Solaris 7 の動的リンカおよび実行時リンカの検索パスを比較します。Solaris 7 では、リンクエディタと実行時リンカの検索パスは LD_LIBRARY_PATH
設定値の影響を受けることに注意してください。ただし、実行時リンカでは、プログラムが LD_LIBRARY_PATH
を設定しないで共用ライブラリを検索できるほか、共用ライブラリのローディングがさらに効率的になります。したがって、Solaris 7 では $ORIGIN
を代用することをお勧めします。prog がインストールされた位置からの組み込みライブラリの相対パスを指定してプログラムをビルドしなければならないからです。 たとえば、.../package/bin/prog は、.../package/lib/libmine.so.1 を使用します。
SunOS 4 リンカ検索パス
リンクエディタ: -L, LD_LIBRARY_PATH
, /usr/lib, /usr/local/lib
実行時リンカ: LD_LIBRARY_PATH
, -L, /usr/lib, /usr/local/lib
LD_LIBRARY_PATH
=dirlist1 がある Solaris 7 リンカ検索パス
リンクエディタ: -L, dirlist1, /usr/ccs/lib, /usr/lib
実行時リンカ: dirlist1, -R, /usr/lib
LD_LIBRARY_PATH
=dirlist1, dirlist2) がある Solaris 7 リンカ検索パス
リンクエディタ: dirlist1, -L, dirlist2, /usr/ccs/lib, /usr/lib
Solaris 7 リンカは、$ORIGIN
を使ってパスを検索します。
実行時リンカ: -R, $ORIGIN/../lib
また、Solaris 7 では、LD_LIBRARY_PATH_ 64
は LD_LIBRARY_PATH
の 64 ビット専用バージョンです。
SunOS 4 は、共用ライブラリに対してメジャーとマイナーの両方のバージョン番号をサポートしていました。Solaris 7 は、メジャーバージョン番号だけをサポートします。バイナリ互換性のサポートについては、メジャーおよびマイナーバージョン番号は SunOS 4 共用ライブラリで認識されます。これらのライブラリは、SunOS 4 ソフトウェアにあったのと同じメジャーおよびマイナーバージョン番号を保持するために必要となります。
表 15-2 は、SunOS 4 および Solaris 7 の共用ライブラリのバージョンを示します。
表 15-2 共用ライブラリの例
SunOS 4 |
Solaris 7 |
---|---|
libc.so.1.7 |
libc.so.1 |
libdl.so.1.0 |
libdl.so.1 |
SunOS 4 システムソフトウェアにおいては、 -l オプションを指定した場合、build environment linker はメジャーおよびマイナー番号をともに持つライブラリを検索しました。たとえば、-ldl を指定した場合、ライブラリ、libdl.so.1.0 がリンクされます。Solaris 7 環境では、メジャー番号はサポートされていますが、デフォルトのリンクエディタはバージョン番号を無視します。前の例では、build envrionment linker は現在では libdl.so と特定のバージョンのファイルを指すシンボリックリンクを検索します。
リンカによって参照された時、デフォルトでは、動的に実行可能なオブジェクトまたは共有オブジェクト中の dependency レコードは関連する共有オブジェクトのファイル名です。依存性の指定をより一貫した方法にするために、共有オブジェクトは実行時に参照されるべきファイル名をそれ自身に記録することができます。これはライブラリファイルをリンクする時に -h オプションによって指定します。
Solaris 7 では、シンボリックリンクはほとんどのライブラリに対して作成されています。メジャー番号をつけて新しい共用ライブラリを構築し、それから最もよく使用するライブラリのバージョンを指すシンボリックリンクを作成してください。
新しいユーティリティの dump(1) (「ファイルのバックアップと復元」を参照) により、オブジェクトファイルのデバッグ、または静的および動的リンクのチェックが容易になります。dump -L オプションは、実行可能プログラムに含まれる実行時リンカに必要な情報を表示します。この情報は、ELF ファイルの動的セクションに含まれます。 RPATH
エントリは、ld. の -R オプションにより指定された検索パスを表示します。
例を以下に示します。
libx.so.1 から libx.so へのリンクを作成します。
examples% cc -G -o libx.so.1 -h libx.so.1 libx.o examples% cp libx.so.1 /mylibs examples% ln -s /mylibs/libx.so.1 /mylibs/libx.so examples% dump -Lv libx.so.1 libx.so.1: **** DYNAMIC SECTION INFORMATION **** .dynamic : [INDEX] Tag Value [1] INIT 0x3b8 [2] FINI 0x3f4 [3] SONAME libx.so.1 [4] HASH 0x94 [5] STRTAB 0x33c [6] SYMTAB 0x14c [7] STRSZ 0x62 [8] SYMENT 0x10 [9] PLTGOT 0x10404 [10] PLTSZ 0xc [11] PLTREL 0x7 [12] JMPREL 0x3ac [13] RELA 0x3a0 [14] RELASZ 0x18 [15] RELAENT 0xc |
ライブラリが他の動的ライブラリを必要とするときは、次の例に示すように、RPATH
と共に動的ライブラリを指定するようにします。
次の例では prog.c をコンパイルし、(前の例で構築された) libx.so を動的にリンクし、バイナリが実行のためカレントディレクトリ情報を保持するように指定します。この例は、コンパイル済みプログラムの prog.c についての dump 出力を示します。ここで、前の例の SONAME
フィールドに格納された情報は、prog により NEEDED
として示されます。prog が実行されると、libx.so.1 は、libx.so でも、異なるバージョンにリンクされます。
examples% cc -o prog prog.c -L/mylibs -R/mylibs -lx example% dump -Lv prog prog: **** DYNAMIC SECTION INFORMATION **** .dynamic : [INDEX] Tag Value [1] NEEDED libx.so.1 [2] NEEDED libc.so.1 [3] INIT 0x1b1ac [4] FINI 0x1b248 [5] RPATH /mylibs [6] HASH 0x100e8 [7] STRTAB 0x17f90 [8] SYMTAB 0x12be0 [9] STRSZ 0x31e1 [10] SYMENT 0x10 [11] DEBUG 0x0 [12] PLTGOT 0x2b25c [13] PLTSZ 0x30 [14] PLTREL 0x7 [15] JMPREL 0x1b180 [16] RELA 0x1b174 [17] RELASZ 0x3c [18] RELAENT 0xc |
dbx と dbxtool は、デフォルトのシステムソフトウェアには含まれません。アンバンドル製品の Sun WorkShop には、これらの改良版が含まれています。
adb と kadb は、Solaris 7 オペレーティングシステムにバンドルされていて、SunOS 4 のツールと同じ機能を提供します。kadb はマルチプロセッサで使用できるよう改良されました。kadb のプロンプトにはプロセッサ ID が表示されます。以下の例では、プロセッサ ID が 0 になっています。
Solaris 7 環境で容易にカーネルのデバッグを行うには、次のようにします。
savecore を使用可能にします (/etc/init.d/sysetup ファイルの savecore 行のコメントを解除します)。
kadb 下でブートします (システムクラッシュ時に $c と入力します)。
adb と crash を使用します。
adb は、64 ビット用として次のように拡張されています。
?、/、= 修飾子に対応する拡張形式文字。K は、long 型またはポインタを 16 進形式で出力するために使用されます (32 ビットプログラムでは 4 バイト、64 ビットプログラムでは 8 バイトを表示) 。
64 ビット SPARC マクロのパス: /usr/lib/adb/sparcv9 と /usr/platform/platformname/lib/adb/sparcv9。
以下の kadb マクロは、マルチスレッドカーネルといっしょに使用すると特に有効です。
現在のスレッドを表示します。現在のスレッドポインタは、SPARC グローバルレジスタ g7 です。
kadb[0]: <g7$<thread |
threadlist は、システム内のすべてのカーネルスレッドのスタックトレースを表示します。このリストは非常に長くなることがあります。
kadb[0]: $<threadlist |
mutex は、所有スレッドのアドレスを表示します。この例では、グローバルで危険なドライバ mutex を使用しています。
kadb[0]: unsafe_driver$<mutex |
kadb[0]: moddebug/W 0x80000000 |
moddebug は、モジュールのロードを監視できるようにします。デバッグ専用に使用する moddebug の有効な値については、<sys/modctl.h> の最後を参照してください。
稼働中のカーネルをデバッグするには、次のコマンドを使用します。
# adb -k /dev/ksyms /dev/mem |
/dev/ksyms は、稼働中のカーネルの完全な名前を含む擬似デバイスです。
truss は、実行したシステムコール、受信シグナル、ハードウェア障害などを追跡するために開発された新しいユーティリティです。truss には、 エントリを有効にして追跡対象のプロセスで実行されたユーザーレベルの関数呼び出しを終了するオプションのほか、フォークされたプロセスの追跡やマルチスレッドプロセスの処理のように SunOS 4 の trace(1) コマンドにない大幅な改良も加えられています。
また、truss は、プロセスのシステムコール、シグナル、ハードウェア障害を追跡します。このユーティリティには、エントリを有効にして、追跡対象のプロセスで実行されたユーザーレベルの関数呼び出しの追跡を終了する新しいオプションが追加されています。
次の例は、date コマンドの追跡結果を要約したものです。-c オプションを指定すると、truss は行単位の追跡を表示せず、システムコール、シグナル、フォルトの回数をカウントして、その合計を表示します。
example% truss -c date Fri Sep 18 14:31:30 PDT 1992 syscall seconds calls errors _exit .00 1 read .00 7 write .00 1 open .03 12 close .00 12 time .00 1 brk .01 4 lseek .00 1 fstat .00 4 ioctl .00 1 execve .00 1 mmap .01 17 munmap .00 8 ---- --- --- sys totals: .05 70 0 usr time: .03 elapsed: .28 |
truss オプションの詳細については、truss(1) のマニュアルページを参照してください。Solaris 7 ではこの他に pmap(1) のような proc(4) を基本としたデバッグツールが数多く用意されています。