<!doctype linuxdoc system>

<article>

<title>The Linux ELF HOWTO
<author>Daniel Barlow <tt>&lt;daniel.barlow@sjc.ox.ac.uk&gt;</tt>
<date>v1.01, June 1995
<trans>こじまみつひろ (1995/07/14) <tt>&lt;kojima@komae.denken.or.jp&gt;</tt>

<abstract>
この文書は、あなたの Linux システムで ELF バイナリフォーマットのプログ
ラムをコンパイルし、実行可能にするための方法について説明しています。こ
の文書は大きく 3 つの部分に分かれ、(1) ELF とは何か、アップグレードす
べきか否か、(2) どのように ELF へアップグレードするか、(3)アップグレー
ドしたら何ができるようになるか、について論じています。
</abstract>

<toc>

<sect> ELF とは何か？ 簡単な紹介
<p> 
ELF(Executable and Linking Format) とは元々 USL(Unix System
Laboratries) で開発されたバイナリファイルのフォーマット形式のひとつで、
現在では Solaris と System V Release 4 が採用しています。Linux が今ま
で使っていた a.out 形式に比べてずっと柔軟性に富むので、去年、
GCC と C ライブラリの開発者たちは、Linux でも標準のバイナリフォーマッ
トを ELF にすることに決め、ELF への移行を開始しました。

「ずっと柔軟性に富む」というのは、平均的なアプリケーションプログラマにとっ
て次の 2 つの利点があります。

<itemize>

<item> ELF 形式を使うと共有ライブラリがずっと簡単に作れます。たいてい、
すべてのオブジェクトファイルを -fPIC オプションを付けてコンパイルして、
以下のようにリンクするだけですみます。

<tscreen><verb> gcc -shared -Wl,-soname,libfoo.so.y -o libfoo.so.y.x *.o 
</verb></tscreen>

ちょっと複雑に見えるかも知れませんが、a.out フォーマットで共有ライブラ
リを作るのに比べると、ずっと簡単になっています。a.out フォーマットで共
有ライブラリを作る場合、ライブラリに将来必要になるであろう全てのデータ
について、そのアドレススペースを確保しておく必要があります。そして、そ
のアドレススペースが他の人が作っているライブラリと競合しないように登録
しておかねばなりませんでした(このあたりの話は
<url url="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.16.tar.gz">
の 20 ページくらいのドキュメントに詳しく書いてあります)

<item> 動的ローディング(プログラムが実行時に必要なモジュールをロードす
ること)がずっと簡単にできる。Perl 5 と Python がこの機能を使っているプ
ログラムの代表例です。この機能を super-fast MUD に使おう、というアイデ
アも出されています。この場合、追加するコードは別にコンパイルしてモジュー
ル化しておき、実行しているプログラムを終了・再起動しなくてもモジュール
をロードすることで新しい機能を追加することを目指しています。

</itemize>

<p>

ELF を使うと少し遅くなる、という反論もあります。議論を聞いていると、2% 
から 5% くらい遅くなるらしいのですが、私の知っている限りでは、きちんと
テストした人はいないようです。もし両者を比較しているテストを御存知なら
ば、ぜひ私に教えてください。

遅くなる原因は ELF のライブラリコードがポジションインデペンデント(コン
パイル時の <tt>-fPIC</tt> オプション)になっているからで、オフセットを
記憶するためにレジスタが 1 つ使われるので、その分変数を記憶しておくレ
ジスタが減るためです。特に 80x86 CPU では、汎用レジスタが少ないために
影響が出やすいようです。

<sect1> ELF とは何ではないか

<p>

ELF にするとどうなるかについて、多くの人が誤解している点があります。

<descrip>
<tag>ELF にしても、SVR4 や Solaris のプログラムが動くわけではありません</tag>

<!-- 
Although it's the same binary `container' as SVR4 systems use, that
doesn't mean that SVR4 programs suddenly become runnable on Linux.
It's analogous to a disk format  you can keep Linux programs on
MSDOS or Minix-format disks, and vice versa, but that doesn't mean
that these systems become able to run each others' programs.  SVR4
uses a different system call convention to Linux, and the system calls
have different semantics and are numbered differently anyway.
-->

確かに、バイナリを入れている「器」は SVR4 が使っているものと同じですが、
だからといって SVR4 のプログラムが ELF を使えば突然 Linux で利用可能に
なるわけではありません。この関係はプログラムとディスクフォーマットによ
く似ています。つまり、Linux のプログラムを MSDOS や Minix 形式のディス
クに保存したり、MSDOS や Minix のプログラムを Linux の形式のディスクに
保存することは可能ですが、だからといって、それぞれのシステムが他のシス
テムのプログラムを動かせるわけではありません。SVR4 は Linux とは異な
るシステムコールの使い方をしていますし、同じシステムコールでもその意味
が違っていたり、違う番号に割りあてられていたりします。

<tag>ELF を使えば、プログラムが小さくなるわけでも速くなるわけでもありません</tag>

<!-- 
You may well end up with smaller binaries anyway, though, as you can
more easily create shared libraries of common code between many
programs.  In general, if you use the same compiler options and your
binaries come out smaller than they did with a.out, it's more likely
to be fluke or a different compiler version.  As for `faster', I'd be
surprised.  Speed increases could turn up if your binaries are
smaller, due to less swapping or larger functional areas fitting in
cache.
-->

多くのプログラムの間で共通するコードをまとめて共有ライブラリを作ること
が簡単になったおかげで、積極的にライブラリ化することでバイナリコードの
サイズを小さくすることはできるかも知れませんけど。一般的に言って、同じ
コンパイラオプションを使って、出来たバイナリが a.out に比べて小さくなっ
た場合、単なる偶然かコンパイラのバージョンが違っているせいでしょう。も
し「速くなった」なら、ちょっとびっくりします。もっとも、バイナリが(簡
単に作れる共有ライブラリを使って)小さくなったなら、スワッピングも少な
くなるし、キャッシュに使える領域も広くなるので速くなるかも知れません。

<!-- 
<tag/It doesn't require that you replace every binary on your system/
-->

<tag/全てのバイナリを入れ変える必要はありません/

ここに書いてある手順にしたがえば、ELF と a.out の双方をコンパイルして
動かすことのできるシステムを作ることが可能です。将来リリースされるプロ
グラムは ELF 用にコンパイルされているはずですが、これもコマンドライン
のスイッチで変更可能です。もし ELF と a.out のプログラムを同時に動かそ
うとするならば、メモリを多少浪費することになります。また、C ライブラリも 
ELF 用と a.out 用の 2 種をインストールしておく必要があります。もっとも、
6MB のメモリで普通に使うかぎり、ELF と a.out が並存することによるスピー
ドの低下には気づかない、という報告も聞いています(8Mb だと、もっと気づ
かないでしょう)ので、あまり気にする必要はないでしょう。だって、普段か
ら Emacs や静的リンクされた Mosaic/Netscape のような膨大なメモリを食う
プログラムを使っているでしょ :-)

<tag/ELF はトールキンとも Pratchett とも、Keebler とも、神話学とも関係ありません/
<p>
少なくとも、この文脈においては、、 と言っておけば充分でしょう。

</descrip>

<sect1> なぜ ELF へ移行すべき(すべきでない)か

<p> 
ELF を使えるようにシステムをアップグレードするのには、主に 2 つの理由
があります：まず第一に、上述したようにプログラムがずっと柔軟にできるこ
と。第二に、第一とも関連しますが、だれもが ELF へ移行しようとしている
から。将来の C ライブラリや GCC は ELF 用のみがリリースされますし、そ
れ以外のプログラムの開発者たちも ELF の方へ進むはずです。

対称性にとってうれしいことに、現時点では ELF へ移行しない方がいいのに
も 2 つの理由があります。第一に、ELF はまだ開発の途中にあることです。
いくかのパッケージ(カーネルを含め)は、ELF としてコンパイルするためにパッ
チが必要ですし、まだまだバグも残っているでしょう。例えば、Linus 自身が 
ELF に乗りかえるまで待つ、というのも一つの手です。

&lsqb;訳注：linux 1.3.7 で kernel の ELF 化のパッチが正式に採用
されました。1.3.7 以降のカーネルでは make config の際にカーネルを ELF 
化するかどうかの選択が可能です。&rsqb;

二つ目の理由は、ここに記してあるインストールの手順は比較的簡単な作業で
すが(新しいソフトウェアをダウンロードする時間を除けば、一時間もあれば
充分でしょう)、それぞれの段階でもしエラーが起きればシステムの起動が不
可能になることです。共有ライブラリをバージョンアップする必然性がなく、
<tt>ldconfig</tt> や <tt>ldd</tt> といったコマンドに悩まされてもいない
なら、ELF で固めたディストリビューションが出るまで待って、バックアップ
を取った上で ELF 版の linux を再インストールし、必要な部分のみ戻す方が
いいかも知れません。その上で、(ダメになってもいい機械を使って)この文書
を読んで、勉強してみるのもいいかも知れません。

それでもやりますか？

<sect> インストール

<sect1> 背景

<p> 
ここに示す移行手順の目的は、a.out と ELF の双方をコンパイルして動かす
ことのできるシステムを構築することです。そのためには双方のプログラムが
適切な共有ライブラリを見つけられなければなりません。このためには、他の
いくつかのシステムがやっているように、単純に `<tt>/lib</tt> と 
<tt>/usr/lib</tt> そしてコンパイル時に指定されたディレクトリを全て探す'
という方法よりも多少なりともスマートな方法が必要です。

linux でライブラリを探すのに使われるプログラムは <tt>/lib/ld.so</tt> 
です。コンパイラもリンカも出力するプログラムにはライブラリへの絶対パス
は埋めこみません。その代りに、必要なライブラリ名と <tt>ld.so</tt> への
絶対パスを埋めこんでおき、実行時に <tt>ld.so</tt> に適切なライブラリを
選択させるようにしています。これがきわめて重要な機能になります -- すな
わち、<tt>ld.so</tt> にライブラリを探すべき新しいディレクトリを正しく
教えてやれば、<em>プログラムをコンパイルしなおさなくても</em> ライブラ
リを別のディレクトリへ移動させることが可能だ、ということです。この点が、
以下に示すディレクトリの入れかえ操作の鍵になります。

上記から導かれる結論として、<tt>ld.so</tt> を削除したり移動させたりす
れば、<em>動的リンクを使っているプログラムは全て機能しなくなる</em>、
ということがわかります。これは良くないこと(Bad Thing)である、と一般に
考えられています。

ELF には ELF 用の動的ローダーが用意されています。これは 
<tt>/lib/ld-linux.so.1</tt> で、ELF プログラムに対して <tt/ld.so/ とまっ
たく同じ機能を果します。<tt/ld-linux.so.1/ も a.out 用の <tt/ld.so/ と
同じ設定ファイルとプログラム(<tt/ldd/, <tt/ldconfig/,
<tt>/etc/ld.so.conf</tt>)を利用します。

ですから、基本的な計画としては、ELF 用の開発環境(コンパイラ、インクルー
ドファイル、ライブラリ)を、今 a.out 用の環境がある 
<tt>/usr/{bin,lib,include}</tt> に置き、a.out 用の環境を 
<tt>/usr/i486-linuxaout/{bin,lib,include}</tt> に移す、ということにな
ります。<tt>/etc/ld.so.conf</tt> にライブラリが見つかるはずの場所を全
て書いておけば、<tt>ldconfig</tt> は ELF と a.out を自動的に区別します
ので、適切なライブラリを選択することができます。ライブラリを置くべき場
所には多くの例外があります；詳しくは次の警告(caveats)の項を見てく
ださい。

<sect1> 始める前に --- 注意と警告
<p>
<itemize>

<item> ELF 形式のバイナリフォーマットを使うには 1.1.52 より新しいカー
ネルが必要です。1.3.0 から 1.3.2 までのカーネルにはバグがあって ELF を
使うことができません。開発用カーネルである 1.3 のシリーズを使ってるな
ら、最新のものを使うようにしてください。1.3.3 以降なら大丈夫、1.2.10
(現時点での最新の安定版カーネル)でも大丈夫です。

<item> Slackware のレスキューディスクのような boot/root ディスクを用意
しておきましょう。多分必要ないでしょうが、もし必要になってしまった時に
用意してなければ、地団駄を踏むはめになります。

<item> <tt>/usr</tt> や <tt>/usr/lib</tt> を <tt>/</tt>パーティション
とは違うパーティションに取っている場合は<em>特に注意してください</em>。
そのような場合、<tt>/bin</tt> と <tt>/sbin</tt> にあるプログラムが使っ
ているライブラリをチェックして、それらをルートパーティションのどこか、
例えば <tt>/lib-aout</tt>、に置いておく必要があります。この点に関して
は後に適切なところでもう一度触れることにします。

<!-- 
If you have been following the ELF development, you may have
ELF libraries in <tt>/lib/elf</tt> (usually <tt>libc.so.4</tt> and
co).  Applications that you built using these should be rebuilt, then
the directory removed.  There is no need for a <tt>/lib/elf</tt>
directory!  It was used for a time during ELF development, but how it
ended up as a standard directory in Slackware installs, who knows?
-->

<item> もし、ELF の開発を追いかけていたなら、<tt>/lib/elf</tt> に ELF 
用のライブラリ(通常は libc.so.4 など)があるかも知れません。これらのラ
イブラリを使うアプリケーションは再コンパイルする必要があります。その上
でこのディレクトリは削除しましょう。もはや<tt>/lib/elf</tt> ディレクト
リは不要です。このディレクトリは ELF の開発時のためのもので、Slackware 
のインストール時の標準ディレクトリになるなんてことはないでしょう。

<!-- 
Some old programs don't use <tt/ld.so/, so any libraries that
they depend on cannot be moved.  There may or may not be a problem
here.  Use <tt/ldd/ to determine which these libraries are.  If the
program depends only on <tt/libc.so.4/ and/or <tt/libm.so.4/, there is
no problem, as these libraries continue to reside in <tt>/lib</tt>.
If it depends on X in any way, shape, or form, you're also safe: to be
old enough not to use <tt/ld.so/ it would have to have been compiled
with a pretty old version of the X libraries, and both the major
version number and directory placement of the X libraries has changed
since then.
-->

<item> いくつかの古いプログラムは <tt/ld.so/ を使っていません。ですか
ら、それらの使っているライブラリは移動することができません。この点は問
題になるかも知れないし、ならないかも知れません。<tt/ldd/ を使って、ど
ういうライブラリを使っているのかチェックしてください。もし使っているの
が <tt/libc.so.4/ と/あるいは <tt/libm.so.4/ だけならば、これらのライ
ブラリは <tt>/lib</tt> に残されるので問題はありません。もし X 関連のラ
イブラリで、shape や form についてのライブラリのみの場合も大丈夫です。
<tt>ld.so</tt> を使わないくらい古いプログラムでは、ずいぶん古いバージョ
ンの X のライブラリを使うようにコンパイルされているはずなので、当時の 
X のライブラリのメジャー番号もディレクトリの位置も今のものとは違ってい
ますから。

もし動かせない a.out ライブラリと ELF ライブラリが同じバージョン番号で、
同じ場所に必要な場合、ELF ライブラリをどこか別の場所に移して、そのディ
レクトリを <tt>/etc/ld.so.conf</tt> に書いておきます。

<!-- 
If your system is old enough that you still have shared libraries with
dates in the filenames then you're obviously a Linux God(tm) and
should be advising <em/me/ on the appropriate course of action at this
point :-)  Answers to the address in the title of this HOWTO.
-->

もし使っているシステムがきわめて古くて、ファイル名に日付が入っているよ
うな共有ライブラリを使っているなら、あなたは明らかに Linux God(tm) の
一人であり、この点に関しては私に正しい方法を教えてくださいますようお
願いします :-) 回答は、この HOWTO のタイトルにあるアドレスまで。

<item> 最近の Linux では `FSSTND(ファイルシステムスタンダード)' に従っ
て標準的なファイルシステムは配置されるようになってきましたが、そうでな
いシステムもまだまだあることでしょう。もし以下の説明で 
`<tt>/sbin/</tt><em>何たら</em>' を使うようになっているのに、自分のシ
ステムには <tt>/sbin</tt> ディレクトリが無い場合、それらのプログラムは 
<tt>/bin</tt> か <tt>/etc</tt> にあるはずです。

</itemize>

<sect1> 必要なものは、、、

<p> 以下のパッケージは、<url
url="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/"> や <url
url="ftp://sunsite.unc.edu/pub/Linux/GCC/"> から入手可能です。両サイト
とも多くの場所にミラーされていますので、可能なかぎり近くにあるミラーサ
イト&lsqb;日本ならば<url
url="ftp://ftp.iij.ad.jp/pub/linux/sunsite/GCC/"> や <url
url="ftp://ftp.spin.ad.jp/pub/linux/sunsite.unc.edu/GCC/"> など &rsqb;
から探してください。その方があなたにとっても、みんなに取っても結局速
く入手できることになります。

以下に示すパッケージ(リストにあがっているバージョンかより新しいもの)が
必要です。これらをダウンロードして、それぞれに附属のリリースノートを読
んでみてください：リリースノートはたいてい 
<tt/release./<em/packagename/ という名前になっています。以下に示してい
るバージョンよりも新しいバージョンを入手した場合、必ずリリースノートに
目を通してください。それら新しいバージョンではインストールの方法が変っ
ているかも知れません。

<itemize>

<item> <tt/ld.so-1.7.3.tar.gz/ --- 新しい動的リンカ

<item> <tt/libc-5.0.9.bin.tar.gz/ --- ELF 形式の共有ライブラリの実行イ
メージで、C 用のライブラリとその仲間たち(m(数学ライブラリ), termcap,
gdbm などなど)と対応する静的ライブラリ、これらを使ってプログラムをコン
パイルするのに必要なインクルードファイルなどが入っています。

<item> <tt/gcc-2.7.0.bin.tar.gz/ --- ELF 対応の C コンパイラ。新しいディ
レクトリ・レイアウトを理解する a.out 対応の C コンパイラも入っています。

<item> <tt/binutils-2.5.2l.17.bin.tar.gz/ --- Linux 用にパッチをあてた 
GNU のバイナリ操作用プログラム。<tt/gas/, <tt/ld/, <tt/strings/ などが
入っています。C コンパイラが機能するためには必須のプログラムです。

</itemize>

<sect1> ファイルシステムの再構成

<p> 

えーっと、あらかじめ注意しておきますが、以下で私が `削除する' と言った
ら、自動的に `バックアップしてから削除する' と読みかえてください :-)な
お、これらの指示は ELF で苦しんだことの無い人々向けのものです。すでに
苦しんだことのある人は、適当に読み換えるに充分な知性を備えていることで
しょうから。さあ始めましょう。

<enum>

<item>
HDD を <tt>/</tt> パーティションと <tt>/usr</tt> パーティションに分け
ている場合、多少の注意が必要です。起動時に <tt>/usr</tt> がマウントさ
れる以前に動くプログラムを全てチェックするか <tt>/usr</tt> が読み出せ
なくなったらどうなるか試してみてください。そして、それらのプログラムが
必要とするライブラリは <tt>/lib-aout</tt> に置きます。

実はそれほど難しい話ではありません。単に、

<tscreen><verb>
$ ldd /sbin/* /bin/* /etc/* >/tmp/list.txt
</verb></tscreen>

とやって、<tt>/tmp/list.txt</tt> を調べ、実行可能プログラムではないファ
イルについてのエラーは無視し、どのライブラリが使われているかメモしてお
きます。それらのライブラリがルートパーティションに必要となるライブラリ
です。このリストは保存しておきましょう。

<item>a.out 関係のファイルを移すための新しいディレクトリを作ります。

<tscreen><code>
mkdir -p /usr/i486-linuxaout/bin
mkdir -p /usr/i486-linuxaout/include
mkdir -p /usr/i486-linuxaout/lib
mkdir /lib-aout
</code></tscreen>

<item>
ソースコードを置いているディレクトリで、動的リンカ <tt/ld.so-1.7.3/ パッ
ケージを展開して、展開された直後の <tt>ld.so-1.7.3/instldso.sh</tt> ス
クリプトを読んでみましょう。もし、本当に標準的なシステムを使っているな
ら、<tt>sh instldso.sh</tt> を実行するだけでインストールすることもでき
ますが、もし何か標準的でないものを使っているなら、手動でインストールす
る必要があります。`何か標準的でないもの'とは、、

<itemize>

<item>
シェルとして zsh を使っている(zsh のあるバージョンでは 
<tt/&dollar;VERSION/ という変数を定義しており、それが <tt/instldso.sh/ 
を混乱させます)

<item>
<tt>/lib/elf</tt> から <tt>/lib</tt> へシンボリックリンクを張っている
(こうすべき理由はないのですが、もし ELF の開発を追いかけていたなら、こ
うしているかも知れません)

</itemize>

などです。

<tt>/etc/ld.so.conf</tt> を修正して、<tt>/usr/i486-linuxaout/lib</tt> 
を加え(必要ならば <tt>/lib-aout</tt> も加え)、<tt>/sbin/ldconfig -v
</tt> を再実行して、新しいディレクトリを探しているかチェックします。

<item>
libc と libm 以外のすべての a.out 形式のライブラリを探し出し、
<tt>/usr/*/lib</tt> から <tt>/usr/i486-linuxaout/lib</tt> か 
<tt>/lib-aout</tt> へ移します。<tt>/lib/ld.so</tt> は動かしたり、削除
したり、その他一切いじってはいけません！

一つのパーティションしか切っていない人なら、以下のコマンドで必要な作業
の大部分がまかなえるはずです。

&lsqb;訳注：以下の mv &lsqb; lib*.so* except for libc.so* and libm.so*
&rsqb; /usr/i486-linuxaout/lib の部分は libc.so* と libm.so* 以外の 
lib*.so* を移動させる、という意味です。zsh だと似たような構文で実行で
きるそうですが、(t)csh, bash では手動で移動させる必要があると思います
&rsqb;

<tscreen><code>
cd /lib
mv *.o *.a *.sa /usr/i486-linuxaout/lib
mv [ lib*.so* except for libc.so* and libm.so* ] /usr/i486-linuxaout/lib
cd /usr/lib
mv *.o *.a *.so* *.sa /usr/i486-linuxaout/lib
cd /usr/X11R6/lib
mv *.o *.a *.so* *.sa /usr/i486-linuxaout/lib
cd /usr/local/lib
mv *.o *.a *.so* *.sa /usr/i486-linuxaout/lib
</code></tscreen>

<tt>/lib</tt> にある <tt>libc.so*</tt> と <tt/libm.so*/、<tt/ld.so/ 以
外の、上記の各ディレクトリにある全てのライブラリファイルとオブジェクト
ファイル(<tt/*.o/) を移動させるまで、<em>次に進んではいけません</em>。
<tt/libc.so*/ と <tt/libm.so*/ は古いプログラムを動かすのに必要で 
<tt/ld.so/ は全てのプログラムを動かすためにまだ必要です。

<item> もし <tt>/usr/lib/ldscripts</tt> ディレクトリがあれば削除します。

<item> <tt>/usr/bin</tt> にある(<tt/ld86/ と <tt/as86/ 以外の)全ての 
<tt/ld/ と <tt/as/ のコピーを削除します。

<item>
あるバージョンの GNU tar はシンボリックリンクされたファイルを扱う際に
問題が生じることが知られています。そのため、libc のイメージファイルを
インストールする前に、/usr/include へ行っていくつかのファイルを削除す
る必要があるかも知れません。

<!-- 
This is icky.  Many packages (such as ncurses) are installed into
<tt>/usr/include</tt> by distribution maintainers and are <em>not</em>
supplied with the C library.  Backup the /usr/include tree, use
<tt>tar tzf</tt> to see what's in the file before untarring it, and
delete the directories that it actually fills.  Then untar the
<tt>libc-5.0.9.bin.tar.gz </tt> package from root.
-->

これは面倒くさい仕事ですが、<tt>/usr/include</tt> にのみインストールさ
れ、対応する C ライブラリが<em>ない</em>パッケージ(例えば ncurses) も
いくつかあるので仕方ありません。まず /usr/include 以下をバックアップし
て、<tt>tar tzf</tt> して、あらかじめどういうファイルが入っているか確
認しましょう。実際にファイルが書きこまれるディレクトリを削除した上で、
libc-5.0.9.bin.tar.gz をルートディレクトリから展開します。

<item> 以上で、ELF の実行形式を動かすために必要なファイルを全てインス
トールできました。医学の専門家によると、VDU ワーカーは定期的に休憩を取っ
てスクリーンの前から離れるべきだそうです。ちょうどいいタイミングですか
ら、ここで一休みしましょう。

<item> さぁ、いよいよ ELF プログラムをインストールします。まず 
binutuils パッケージをインストールします。<tt> tar -xvzf
binutils-2.5.2l.17.bin.tar.gz -C /</tt> とするのが最善の方法の一つです。

<item> <tt>/usr/lib/gcc-lib/{i486-linux, i486-linuxelf,
i486-linuxaout}/</tt> 以下にあるファイルをバックアップした上で削除しま
す。そして、gcc-2.7.0.tar.gz をルートディレクトリから展開します。

</enum>

これで<bf>お終い！</bf> 以下に簡単なテスト法を示します。

<tscreen><code>
$ gcc -v
Reading specs from /usr/lib/gcc-lib/i486-linux/2.7.0/specs
gcc version 2.7.0
$ gcc -v -b i486-linuxaout
Reading specs from /usr/lib/gcc-lib/i486-linuxaout/2.7.0/specs
gcc version 2.7.0
$ ld -V
ld version cygnus/linux-2.5.2l.14 (with BFD cygnus/linux-2.5.2l.11)
  Supported emulations:
   elf_i386
   i386linux
   i386coff
</code></tscreen>

次は、伝統的な ``Hello, world'' プログラムを試してみましょう。オプショ
ン無しの gcc だけでコンパイルしたり -b i486-linuxaout オプションを付け
てコンパイルしたりして、a.out と ELF の両コンパイラが正しく設定されて
いるかチェックしてください。

<tscreen><code>
$ cat >hello.c
main() { printf("hello, world\n"); }
^D
$ gcc -o hello hello.c
$ file hello
hello: ELF 32-bit LSB executable i386 (386 and up) Version 1
$ ./hello
hello, world
$ gcc -o hello -b i486-linuxaout hello.c
$ file hello
hello: Linux/i386 demand-paged executable (QMAGIC) not stripped
$ ./hello
hello, world

</code></tscreen>


<sect1> よくあるエラー

<p> 

この節では、皆さんから寄せられた問題を集めようと思っています。あらかじ
め連絡していただければ、お名前は公表しません :-)

<descrip>
<tag><tt> no such file or directory: /usr/bin/gcc </tt></tag>

<tt>/usr/bin/gcc</tt> はちゃんとありますよね？その場合、ELF 用の動的ロー
ダーである <tt>/lib/ld-linux.so.1</tt> がインストールされていないか、
何らかの理由で読み出せなくなっています。インストールするか、前節の 
step 3 のあたりをチェックしてください。

<tag><tt> not a ZMAGIC file, skipping </tt></tag>

このエラーメッセージは <tt>ldconfig</tt> からのものです。古いバージョ
ンの ld.so を使っているようなので、新しいものを入手してください。前節
の step 3 をもういちど見てください。

<tag><tt> bad address </tt></tag>

ELF フォーマットのプログラムが全てこのエラーになるときは 1.3.0 から 
1.3.3 までのカーネルを使っているはずです。1.3.3 以上にアップグレードす
るか 1.2.x を使いましょう。

</descrip>

<sect> ELF でプログラムを作るには

<sect1> 普通のプログラムの場合

<p> 

ELF 形式でプログラムを作るには <tt>gcc</tt> を普通に使うだけです。
a.out 形式でコンパイルするには <tt>gcc -b i486-linuxaout</tt> としてく
ださい。

<!-- 
<tscreen><code>
$ cat >hello.c
main() { printf("hello, world\n"); }
^D
$ gcc -o hello hello.c
$ file hello
hello: ELF 32-bit LSB executable i386 (386 and up) Version 1
$ ./hello
hello, world
</code></tscreen>

This is perhaps an appropriate time to answer the question ``if a.out
compilers default to producing a program called <tt>a.out</tt>, what
name does an ELF compiler give its output?''.  Still <tt>a.out</tt>,
is the answer.  Boring boring boring ... <tt> :-)</tt>
-->

そろそろ ``もし a.out 形式のコンパイラがデフォルトで生成する実行プログ
ラムの名前が <tt>a.out</tt> なら、ELF コンパイラがデフォルトで生成する
プログラムの名前は何と言うの？''という問いに答えましょう。やっぱり 
<tt>a.out</tt> 、というのが答えなんです。残念でしたか <tt> :-)</tt>

<sect1> ライブラリの作り方

<p> 

共有ライブラリとして libfoo.so を作る基本的な手順は以下の通りです。

<tscreen><code>
$ gcc -fPIC -c *.c
$ gcc -shared -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0 *.o
$ ln -s libfoo.so.1.0 libfoo.so.1
$ ln -s libfoo.so.1 libfoo.so
$ export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
</code></tscreen>

これで <tt>libfoo.so.1.0</tt> と言う共有ライブラリができ、ld が識別す
べきリンク(<tt>libfoo.so</tt>) も張られ、動的リンカも見つけることがで
きます(<tt>libfoo.so.1</tt>)。テストのために、このプログラムのあるディ
レクトリを <tt/LD_LIBRARY_PATH/ に追加しています。

もし作った共有ライブラリがちゃんと動くようなら、適切な場所、例えば
<tt>/usr/local/lib</tt> にでも移して、必要なリンクを張りましょう。
<tt>libfoo.so</tt> が <tt>libfoo.so.1</tt> を指すようにリンクを張って、
マイナーバージョンナンバーが変わる度に update しなくても済むようにして
おきましょう。<tt/libfoo.so.1/ から <tt/libfoo.so.1.0/ へのリンクは 
<tt>ldconfig</tt> によって、たいていのシステムでは起動時に更新されるよ
うにっています。

<tscreen><code>
$ su
# cp libfoo.so.1.0 /usr/local/lib
# /sbin/ldconfig
# ( cd /usr/local/lib ; ln -s libfoo.so.1 libfoo.so )
</code></tscreen>

<!-- 
<p>Also see <url url="patches/elf-ncurses.html">building ncurses in
elf</a>, which could also be called ``Subverting other peoples' 
Makefiles to build shared libraries''.
-->

<sect1> 動的ローディングを使うプログラム

<p> 

この問題については H J Lu 作の「ELF プログラミングドキュメント」と 
ld.so パッケージに附属の <tt>dlopen(3)</tt> のマニュアルページにくわし
く解説してあります。ここでは簡単な例を示すに留めましょう。以下のプログ
ラムを <tt>-ldl</tt> オプションを付けてリンクしてみてください。

<tscreen><code>
#include <dlfcn.h>
#include <stdio.h>

main()
{
  void *libc;
  void (*printf_call)();

  if(libc=dlopen("/lib/libc.so.5",RTLD_LAZY))
  {
    printf_call=dlsym(libc,"printf");
    (*printf_call)("hello, world\n");
  }

}
</code></tscreen>

<sect1> デバッグ

<!-- This needs exploring more fully at some stage -->

<p> 

お手持ちの <tt/gdb/ は ELF プログラムに対しても特に変更なしで動くはず
です(たいていの場合)。しかし、tsx-11 の <tt/GCC/ディレクトリにある新し
いバージョンの gdb は動的ローディングにも対応し、ELF 形式のコアにも対
応しているそうです。


しかしながら、この文書を書いている時点では、ELF プログラムがコアダンプ
するためにはカーネルにパッチを当てる必要があります。問題が多少専門的に
なるので、この文書ではそこまで扱いません。

<sect> パッチとバイナリ

<p> 
以上で ELF 形式のプログラムをコンパイルして動かすのに必要な作業は全て
すみました。お好みならここで読むのをやめても結構です。

美的観点(neatness)やメモリの使用を最小限にするために、既存のプログラム
を ELF 形式で再コンパイルしたくなるかも知れません。ほとんどのエンドユー
ザー向けのプログラムはごく簡単にコンパイルできます；しかし、いくつかの
プログラムでは a.out 環境に強く依存しているため、以下のようなエラーを
出すことがあります。

<itemize>

<item>
<!-- 
Different underscore conventions in the assembler: in an a.out
executable, external labels get <tt>_</tt> prefixed to them; in an ELF
executable, they don't.  This makes no difference until you start
integrating hand-written assembler: all the labels of the form
<tt>_foo</tt> must be translated to <tt>foo</tt>, or (if you want to
be portable about it) to <tt/EXTERNAL(foo)/ where <tt/EXTERNAL/ is
some macro which returns either its argument (if <tt/__ELF__/ is
defined) or <tt/_/ concatenated with its argument if not.
-->

アセンブラのアンダスコア(<tt/_/)の使いかたの違い：a.out 形式の実行ファ
イルでは、外部の関数や変数のラベルには <tt/_ / が頭に付いていました；
一方、ELF 形式の実行ファイルにはアンダスコアが付きません。これは手書き
のアセンブラコードを混ぜて使わないかぎり、特に問題にはなりません： 
<tt>_foo</tt> 形式のラベルをすべて <tt>foo</tt> に変換するか、あるいは
(両方の環境でコンパイル可能にしたければ) <tt/EXTERNAL/ というマクロを
定義して <tt/EXTERNAL(foo)/ という形にします。ここで <tt/EXTERNAL/ い
うマクロは (<tt/__ELF__/ が定義されていれば) そのまま引数を返し、さも
なくば <tt/_/ を前につけて引数を返すようなものです。

<item>
libc5 と libc 4 の違い。例えば locale とのインタフェースが変更されてい
ます。

<item>
アプリケーションやコンパイルの過程が、使用しているバイナリ形式に依存す
る場合 -- 例えば emacs では実行形式を作る際にメモリイメージをディスク
へダンプするので、実行ファイルのフォーマットについての知識が必要になり
ます。

<item>
アプリケーション自身が共有ライブラリだったり、共有ライブラリを含む場合
(X11 が典型的な例)。これらについては ELF の方法で共有ライブラリを作る
ように(Makefile などを)変更しなければなりません。

</itemize>

以上を踏まえて、以下に示す 2 つのリストを作成しました。前者(アップグレー
ド)は既に公式リリースが ELF に対応しているソフト(すなわち ELF 用にコンパ
イルするためには新しいバージョンを手に入れればいいもの)で、後者(パッチ)
は第三者が出している ELF 用のパッチが必要なソフトです。

<sect1> アップグレード
<p>
<itemize> 

<!-- 
<item> 
<bf>Dosemu</bf>.  Modulo the three or four cuurrent dosemu
development trees (don't ask, just join the linux-msdos mailing list),
dosemu runs with ELF.  You'll need to monkey with the Makefile.
Current versions of dosemu are available from <url
url="ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/">
-->

<item> <bf>dosemu</bf> 開発中のいくつかのバーション以外では(どのバージョ
ンかは聞かないこと。linux-msdos のメーリングリストに参加してください)、
dosemu は ELF で動きます。Makefile をちょっといじる必要があります。
dosemu の最新バージョンは <url
url="ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/"> にあります。

<item> <bf>Emacs</bf> Emacs はちょっと変ったやり方で作成されます。
Emacs はまず最小限の機能しか持たないバージョンを起動して、必要な lisp 
コードを読みこんだ上でディスクへダンプし、実行形式にしています。Emacs
19.29 は ELF 環境で起動されているかどうかを判断し、正しいやり方を自動
的に選択します(XEmacs については後者のリストを見てください)

<item> <bf>perl 5.001</bf> perl 5.001 と ``公式・非公式'' パッチ群は特
に変更しなくても ELF システムでコンパイルでき、動的ローディングにも対
応しています。perl に対する各種のパッチは <tt>ftp.metronet.com</tt> か 
<tt>ftp.wpi.edu </tt>から入手できます。

<item> <bf>util-linux 2.2</bf> に入っている <tt/cal/ プログラムは動き
ません。2.4 以降のもの(<url
url="ftp://tsx-11.mit.edu/pub/linux/packages/utils" name="version
2.4">)にアップグレードしてください。

<item> <bf>XFree86</bf> XFree86 は多数の共有ライブラリを含むので、ELF 
ライブラリを作るためには多少の変更が必要としても驚くにはあたりません。
完全なバイナリディストリビューションが以下のサイトから入手可能です。
<url url="ftp://ftp.beckman.uiuc.edu/pub/linux/X11/"> あるいは <url
url="ftp://ftp.mcc.ac.uk/pub/linux/ALPHA/XFree86-3.1.1-ELF-3/">。

<!--
<item> <bf>XView</bf>.  This <url url="patches/xview">mail message</a>
announces XView binaries and patches for ELF and libc 5.
-->

</itemize>

<sect1> パッチ
<p>
<itemize>
<item> <bf>e2fsutils</bf> Second Extended File System 用のユーティリティ
を共有ライブラリとしてコンパイルするには、<url
url="http://sable.ox.ac.uk/~jo95004/patches/e2fsutils.diff"> にあるパッ
チが必要です。e2fs の作者 Remy Card によると、``この ELF 用のパッチは
多分 e2fsck と関連ツールの次のバージョンには含まれるはず'' ということ
です。

<item> <bf>file</bf> そのままでも動きますが、<url
url="http://sable.ox.ac.uk/~jo95004/patches/file.diff"> のパッチを当て
れば ELF バイナリの stripped や mixed-endian も識別することが可能にな
ります。

<item> <bf>カーネルそのもの</bf> カーネルについては 2 つの論点がありま
す。(a) ELF バイナリを動かすことが可能かどうか(この点については、カー
ネルのコンパイル時(<tt/make config/ 時)に ``Kernel support for ELF
binaries'' に `Y' と答えれば可能です)、(b)カーネルを ELF 形式でコンパ
イルできるかどうか。(b)については一般的には `no' です。ですから、カー
ネルのコンパイル時には a.out 形式を使うように Makefile に修正を加える
必要があります。Makefile の<tt>CC</tt> と <tt>LD</tt> の定義を以下のよ
うにしてください。

<tscreen><code>
LD      =ld -m i386linux
CC      =gcc -b i486-linuxaout -D__KERNEL__ -I$(TOPDIR)/include
</code></tscreen>

(b) に対する別の解として、H J Lu のパッチを当てれば、カーネルを ELF 形
式でコンパイルするこのも可能です(このパッチで ELF 形式のプログラムに 
core dump させることも可能になります)。このパッチはごく近い将来に 1.3 
のカーネルに取りこまれるはずですが、<tt/ps/ とそれに関連するユーティリ
ティ用に <tt/psupdate/ プログラムが namelist をサポートするように hack 
する必要があります。

&lsqb;訳注：上でも書きましたが、1.3.7 以降のカーネルでは ELF 化パッチ
が公式リリースに取りこまれました。カーネルを ELF で作成するか否かは 
<tt>make config</tt> 時に指定できます&rsqb;

<item> <bf>SVGATextMode</bf> には簡単な調整が必要です。以下に示す diff 
を切り出して patch として当てるか、ファイルを直接手で修正してください。

<tscreen><code>
--- SVGATextMode-0.7.orig/XFREE/os-support/assyntax.h	Sun Feb 26 18:58:15 1995
+++ SVGATextMode-0.7/XFREE/os-support/assyntax.h	Thu Mar 30 07:52:03 1995
@@ -211,7 +211,7 @@
 #endif /* ACK_ASSEMBLER */
 
 
-#if (defined(SYSV) || defined(SVR4)) && !defined(ACK_ASSEMBLER)
+#if (defined (__ELF__) || defined(SYSV) || defined(SVR4)) && !defined(ACK_ASSEMBLER)
 #define GLNAME(a)       a
 #else
 #define GLNAME(a)       CONCAT(_,a)
</code></tscreen>

<item> <bf/XEmacs/  
XEmacs 19.11 に <url
url="http://sable.ox.ac.uk/~jo95004/patches/xemacs.diff"> のパッチをあ
ててみてください。

</itemize>

<sect> その他の情報

<p> 
<itemize>
<item>
自分からは投稿しなくても linux-gcc のメーリングリストに参加することは、
ELF 化がどのように進行しているのかを知るための最善の方法です。忘れない
で欲しいのですが、このメーリングリストは Usenet とは違い、開発者の連絡
用のものであり、開発上の問題以外を質問する場ではありません。メーリング
リストへの参加方法は <tt>help</tt> と書いたメールを 
<tt>majordomo@vger.rutgers.edu</tt> へ送ってください。

<item> 
Bobby Shmit が運営している <url 
url="http://www.intac.com/~cully/elf.html" name="ELF upgrade experience"> web
ページも参考になるでしょう。

<item>
GCC-FAQ(<url url="ftp://sunsite.unc.edu/pub/Linux/docs/faqs/GCC-FAQ.html"
name="GCC-FAQ">) には ELF についてのより一般的な開発上の情報と技術的な
詳細が説明されています。

<item>
tsx-11(<url
url="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ELF.doc.tar.gz"
name="tsx-11">) には ELF のフォーマットを解説した ELF.doc.tar.gz があ
ります。この文書が ELF のフォーマットを理解し、直接バイナリオブジェク
トを扱う類いのプログラムを書き直したりデバッグするのに最善の資料でしょ
う。

<item>
H J Lu がまとめた ELF に関するドキュメントが<url name="ELF: From The
Programmer's Perspective"
url="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/elf.latex.tar.gz">に
あります。H J Lu はプログラマの視点から有益で詳細な ELF に関するプログ
ラミング情報をまとめています。もし Latex が使えないなら、Postscirpt 版
もあります。

<item> 
<tt/ld.so/ パッケージに附属の <tt/dlopen(3)/ のマニュアルページ

</itemize>

<sect> Copyright

<p>
This document is copyright (C) 1995 Daniel Barlow
<tt/&lt;daniel.barlow@sjc.ox.ac.uk&gt;/ It may be reproduced and
distributed in whole or in part, in any medium physical or electronic,
as long as this copyright notice is retained on all copies. Commercial
redistribution is allowed and encouraged; however, the author would
like to be notified of any such distributions.

この文書の著作権(C)は Daniel
Barlow<tt/&lt;daniel.barlow@sjc.ox.ac.uk&gt;/ が所有しています。この著
作権表示が全てのコピーに残されるかぎり、あらゆる物理的、電子的媒体を用
いて、全体、あるいは部分的にコピー、配布することが可能です。商業的な配
布も可能で、奨励します；しかし、商業的に利用する場合は連絡してくれるこ
とを望みます。

All translations, derivative works, or aggregate works incorporating
any Linux HOWTO documents must be covered under this copyright notice.
That is, you may not produce a derivative work from a HOWTO and impose
additional restrictions on its distribution. Exceptions to these rules
may be granted under certain conditions; please contact the Linux
HOWTO coordinator at the address given below.

翻訳やこの文書から派生した仕事、あるいはあらゆる種類の Linux HOWTO ド
キュメントと共に集積する仕事にもこの著作権は適用されます。すなわち、
HOWTO から派生した文書に対して配布に制限を加えることはできません。この
ルールに対する例外も一定の条件の元で許可されます。下記に示す Linux
HOWTO のコーディネーターに連絡してください。

In short, we wish to promote dissemination of this information through
as many channels as possible. However, we do wish to retain copyright
on the HOWTO documents, and would like to be notified of any plans to
redistribute the HOWTOs.

簡単に言うと、我々は可能な限りのチャンネルを通じてここに示した情報を普
及させたいと願っています。しかしながら HOWTO 文書に著作権を付けている
のは、HOWTO を再配布する計画について報せて欲しいと思っているからです。

If you have questions, please contact Greg Hankins, the Linux HOWTO
coordinator, at <tt/gregh@sunsite.unc.edu/ via email, or at +1 404 853
9989.

質問があれば、Linux HOWTO のコーディネーターである Greg Hankins に連絡
してください。e-mail のアドレスは <tt/gregh@sunsite.unc.edu/ 、電話な
ら +1 404 853 9989 です。

</article>

