<?xml version="1.0" encoding="UTF-8" ?><rdf:RDF 
  xmlns="http://purl.org/rss/1.0/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xml:lang="ja">
  <channel rdf:about="http://www26.atwiki.jp/funa_tk/">
    <title>組み込み Linux 開発の手引き</title>
    <link>http://www26.atwiki.jp/funa_tk/</link>
    <description>組み込み Linux 開発の手引き</description>

    <dc:language>ja</dc:language>
    <dc:date>2011-06-22T14:58:14+09:00</dc:date>

    <items>
      <rdf:Seq>
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/33.html" />
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/28.html" />
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/19.html" />
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/22.html" />
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/30.html" />
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/1.html" />
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/5.html" />
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/32.html" />
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/13.html" />
                <rdf:li rdf:resource="http://www26.atwiki.jp/funa_tk/pages/31.html" />
              </rdf:Seq>
    </items>
	
		
    
  </channel>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/33.html">
    <title>sparse</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/33.html</link>
    <description>
      #Contents()

* sparseプログラムについて

sparseプログラムは、Linuxカーネルで使用されているソースコードチェッカーです。
sparseプログラムは、静的にプログラムをチェックし、間違いがあれば警告を出してくれます。Linuxカーネルのソースコードにおいて、ユーザ空間へのポインタとカーネル空間へのポインタが混在してしまっていたのをチェックするために、Linusが2003年に最初に作ったみたいです。

sparseのソースコードは、[[こちら&gt;https://sparse.wiki.kernel.org/index.php/Main_Page]]

* 使い方
まだよく調べていませんが、sparce ソースコード名 とすればチェックしてくれるようです。
Linuxカーネルのソースコードに対してsparseしたいときには、make C=2 とします。

チェックされる項目は、manページに詳しく書いてありますが、少しだけ紹介すると
 ある変数が __attribute__((条件))という書式で定義されていたとき、その変数がちゃんと条件通りに正当に使用されているいるか
チェックしてくれるみたいです。

条件の種類は、
- noderef：*pointerのようにアスタリスクでポインタの先を参照しないこと。
- address_space(X)：Xというアドレス空間内でポインタが使用されていること。他のアドレス空間を指し示すポインタに代入したり、キャストしてはならない。
- force：とにかく強制的に実行する。上記の条件を無視してキャストしたり参照したりできる。

というものがあります。もっとありますが、知りたい方はmanページを参照してくださいませ。

* Linuxカーネルでは、どのように使われているのか？
__iomemは、
 __attribute__((noderef,address_space(2)))
となっていて、アドレス空間２以外での作業用途には使えないようになっています。また、*（アスタリスク)で参照できないようになっています。

また__userは、
 __attribute__((noderef,address_space(1)))
となっていて、アドレス空間１以外での作業には使えないようになっています。また、*（アスタリスク)で参照できないようになっています。

例えば、copy_to_userは次のように宣言されています。
 unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
なので、toというポインタは直接参照することもできませんし、他のアドレス空間へのキャストもダメということになります。

ちなみに、Linuxカーネルソースコード内で使われているアドレス空間ですが、
|アドレス空間名 | 空間番号|h
|カーネル空間|0|
|ユーザ空間|1|
|IO空間|2|

となっているみたいです。
もちろん、アドレス空間10みたいなのを使って問題ないです。もちろん、アドレス空間10の変数同士でしか、やりとり出来なくなります。

ところで、Linuxカーネルをコンパイルするときに、Cオプションをつけなかった場合、
 #define __user
 #define __iomem
というようにマクロ定義されるらしく、__userと__iomemは単純に消えるだけです。
なので、__userとかを頑張って使っていたとしてもCオプション使わなかったら、意味はありません。    </description>
    <dc:date>2011-06-22T14:58:14+09:00</dc:date>
  </item>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/28.html">
    <title>Linuxディストリビューション</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/28.html</link>
    <description>
      #Contents()

* Linuxディストリビューション

Linuxというのは、Linuxカーネル（オペレーティングシステム）のことです。そのため、厳密に言えば各種アプリケーションやライブラリ、設定ファイルなどはLinuxではありません。Linuxカーネルを単体で使っても、ユーザは何も嬉しくありません。Webサーフィンもできなければメールもできないからです。
そのため世界中の色々な人が、Linuxカーネルと様々なアプリケーションを組み合わせてユーザがすぐに利用できるような形で配布し始めました。これがLinuxディストリビューションです。世界中には色々なLinuxディストリビューションが存在し、少しずつ味付け（搭載されているアプリケーションやバージョン）が違います。あなたは、それらのLinuxディストリビューションから、自分あった好きなモノを選んで自分のＰＣにインストールすることになります。

初心者の方が一番悩むのが、どのLinuxディストリビューションをインストールすればよいか？という問題でしょう。
ここでは、それぞれのLinuxディストリビューションについて説明していきたいと思います。

** Ubuntu

Ubuntuは、Debian GNU/Linuxのパッケージングシステム(dpkg)を使った比較的新しいディストリビューションです。
Debianと違い、新しいアプリケーションを採用していますし、定期的なリリースサイクルを保っていますのでデスクトップ用途に使えます。
世界的に一番人気があり、他のディストリビューションに比べドキュメントも揃っています。
インストールCDからブートして、Knoppixのようにお試し動作をさせることができます。

** Fedora Core (バージョン7以降は、Coreが取れて「Fedora」となった)

Fedora Core(フェドラコア）またはFedora(フェドラ)は、日本で一番普及していたLinuxディストリビューションです。今現在はUbuntuにお株を奪われつつあるようです。このディストリビューションは、常に最新のアプリケーションを取り込んでいくというポリシーです。

** Red Hat Enterprise Linux

Red Hat社がリリースしている商用のLinuxディストリビューションです。手厚〜いサポートが受けられますし世界標準です。
優秀な技術者もそろっているので、重要な（？）Linuxの案件でこれを使うことによって、リスクを減らすことができます。
Fedora で安定動作したアプリケーションがこのRed Hat Enterprise Linuxに順次取り込まれるというポリシーです。

** CentOS

CentOSは、RedHat Enterprise Linuxと同じアプリケーションを採用しており、Red Hat Enterprise Linuxとの違いは、サポートがあるか・ないかの違いです。
Red Hat Enterprise Linuxを買うお金はないけれど、同じ環境で開発したいときに使えます。

** OpenSUSE

昔はSUSE Linux(スーゼ、スーザ）でしたが、Novell社に買収後、OpenSUSEと名称を変え完全にコミュニティベースでの開発に移行しました。
主にヨーロッパで人気のディストリビューションのようです。

** Vine Linux

古くから日本語強化に取り組んできたHed Hat系ディストリビューションです。昔はLinux上に日本語環境を構築するのに、かなりのスキルが必要だったので、インストール直後から日本語が何不自由なく使えたVine Linuxは人気がありました。今現在は他のディストリビューションでもインストール直後に日本語が使える状態になっているので、Vine Linuxを使うメリットが（個人的に）ないと思っています。昔はとてもお世話になりましたが・・。

** Debian GNU/Linux

Debian GNU/Linux(デビアン)は、独自のポリシーをもった（？）マニア向けのLinuxディストリビューションです。
古くてバグの少ない古いバージョンのアプリケーションを使うので、絶対に停止したくないサーバなどによく使われます。
日常のインターネット用デスクトップにも、使えないわけではないのですが、いかんせん古いアプリケーションを使いますので、「あの機能がねぇ！！」というのは日常茶飯事です。

** Gentoo Linux

マニア向けのLinuxです。
アプリケーションパッケージをインストールするときは、ソースコードをインターネット上からダウンロードして、コンパイルします。
いちいちソースコードからコンパイルするので、インストールに膨大な時間がかかります。しかし、コンパイルオプションを設定してコンパイルできるので、より自分の希望にあった環境をつくれます。

** PCLinuxOS

最近海外でかなり有名になってきているLinuxディストリビューションです。
聞いた話によると、細かいところまでしっかりと作り込まれたLinuxディストリビューションだそうです。
私は使ったことはありませんが、機会があればぜひ使ってみたいと思っています。

** Knoppix

CDからブートするLinuxディストリビューションとして一世を風靡しました。
試しにLinuxを使ってみたい人や、レスキュー用途に使われます。
ハードディスクにインストールしてしまうこともできます。

* まとめ

日本国内では、Ubuntu が有名で、インストールに関する資料も多いので初心者が一番最初にインストールするディストリビューションとして最適だと思われます。
次点としては、Fedora がよさそうです。
[[ディストロウォッチ&gt;http://distrowatch.com/index.php?language=JP]]では、ディストリビューションのランキングが見られます。ディストリビューション選択の参考になるでしょう。
インストールするディストリビューションが決まったら、[[Linuxインストール方法の種類]]を参考にインストールを開始してみましょう！！    </description>
    <dc:date>2010-10-12T19:21:49+09:00</dc:date>
  </item>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/19.html">
    <title>パーミッション</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/19.html</link>
    <description>
      #contents()

* パーミッション

Linuxで使われているファイルパーミッションは、非常に単純で簡単なものですが、本当に詳細を理解している人は少ないように感じられます。このページでは、Linuxを日常的に使っている方でも、ファイルパーミッションを整理できるような情報を提供したいと思います。

* ファイルパーミッションとディレクトリパーミッションは意味が違うことを認識せよ!

私が、パーミッションについて話をしている時によく感じるのですが、ファイルパーミッションとディレクトリパーミッションを混同している人が非常に多いです。ファイルパーミッションとディレクトリパーミッションは意味が全く異なるので、注意が必要です。

* ファイルパーミッション

「ls -l」コマンドで表示される「-rwxr-xr-x」というようなパーミッション表記について、一番左の文字「-」がファイルの種類、次の3文字「rwx」が所有者に対するパーミッション、次の3文字「r-x」がグループユーザに対するパーミッション、次の3文字「r-x」がその他のユーザに対するパーミッションを表します。

では「rwx」という各文字の意味についてまとめます。

| 文字の種類 | 説明 |
| r | ファイルを読める。「cat」や「more」、「less」で内容を表示できることを表します |
| w | ファイルに書ける。「vi」などで、編集・保存できることを表します |
| x | 実行できる。そのファイルを実行ファイルとして実行できることを表します |

ファイルパーミッションについては、ほとんどの人が理解していると思います。

* ディレクトリパーミッション

ファイルパーミッションは理解している人が多いのですが、ディレクトリパーミッションを理解している人は少ないように感じられます。ディレクトリパーミッションをファイルパーミッションと同じだと思っている人がいますが、これは大きな間違いです。

所有者/グループユーザ/その他のユーザ、それぞれに対してパーミッションを設定できるところまでは、ファイルパーミッションと同じです。しかし「rwx」に意味が全く違います。まとめてみましょう。

| 文字の種類 | 説明 |
| r | そのディレクトリに存在するファイル名を読める。ディレクトリ内で「ls」できることを表します |
| w | そのディレクトリにファイル・ディレクトリを作成・削除できる。ファイルを新規作成したり、「rm」できることを表します |
| x | そのディレクトリに入ることができる。「cd」で、そのディレクトリに入れることを表します |

どうでしょうか?ファイルパーミッションとは大きく異なることが分かりましたでしょうか。
新規に「mkdir」でディレクトリを作成した場合、通常は「drwxr-xr-x」というディレクトリパーミッションになりますが、これは作成したディレクトリ所有者は、そのディレクトリに入れて(x)、存在するファイル名を「ls」で表示できて(r)、ファイル作成・削除(w)できるということを表します。グループユーザとその他のユーザは、そのディレクトリに入れて(x)、存在するファイル名を「ls」で表示できるが、そのファイルを消したり、別の新しいファイルを作成することができないということになります。

ここで、重要なのが「x」というパーミッションです。このパーミッションがついていなければ、そのディレクトリに立ち入ることができないので、「x」パーミッションが許可されていない場合、たとえ「r」や「w」が許可されていても意味はありません。

ちなみに「x」が許されているだけで、「r」や「w」が設定されていない場合があります。これは、「cd」でそのディレクトリに移動して、「ls」などファイル名を確認はできないが、あらかじめファイル名を知っていれば、ちゃんと、そのファイルの内容を読み/書き/実行できます(本当に読み/書き/実行が本当にできるかどうかは、そのファイルのパーミッションによりますが(^-^)。。)

* まとめると

まとめると、ファイルパーミッションは、そのファイルの内容(コンテンツ)に対するパーミッション(読み書き実行)であり、ディレクトリパーミッションは、そのディレクトリに存在するファイルそのもの(コンテンツは含まない)に対するパーミッションということになります。

例えば、ディレクトリが「drwxrwxrwx」というパーミッションになっていて、その中にある重要ファイルのパーミッションが「-r--------」となっていても、そのファイルを完全に守っていることにはなりません。確かに誰にもそのファイルの中身をみられることはないのですが(自分だけ読める)、誰かが、そのファイルそのものを消すことは可能です。ディレクトリパーミッションを「drwxr-xr-x」に設定するか、またはファイル名すら知られたくないならば「drwx------」とするべきだったのです。

* その他の非常に興味深いパーミッション

Linuxには、上述のパーミッション以外にも次のような興味深いパーミッションが存在します。

|設定|設定できる対象|用途|
|スティッキービット|ディレクトリ|誰でも書き込めるが他人のものは削除できないディレクトリになる。（Drop Box用途）|
|セットUID| ファイル|ユーザー実行権限を一時的に昇格して実行できる|
|セットGUID|ファイル|グループ実行権限を一時的に昇格して実行できる|
|ユーザ権限継承|ディレクトリ|ディレクトリ内に作成したファイル・ディレクトリの所有ユーザをディレクトリと同じにする|
|グループ権限継承|ディレクトリ|ディレクトリ内に作成したファイル・ディレクトリの所有グループをディレクトリと同じにする|

では、下記に詳しく説明していきます。

**スティッキービット

ディレクトリパーミッションには、スティッキービットというビットを設定することができます。このビットを設定すると、凄く便利なことができます。

例えば、誰でも書き込めるディレクトリを作成したいとします。そのために、パーミッションを「drwxrwxrwx」としますよね。そうすると、その他のユーザのパーミッションに「w」がついているので、そのディレクトリにファイルを作成することができるようになるわけです。しかし、このパーミッション設定には思わぬ副作用があります。あるユーザが作成したファイルを、別のユーザが削除できてしまうのです。

この問題に対処するため、新しくパーミッションに機能が追加されました。それがスティッキービットです。このパーミッションを設定すると、誰でもファイルを作成できるが、別のユーザが作成したファイルを削除することはできないという特殊な状態を作ることができます。（もちろん自分の作成したファイルは削除できます）

「ls -l」コマンドの出力結果は「drwxrwxrwt」となり、その他のユーザの実行権のところが「t」となります。これがスティッキービットが設定されている状態です。例えば/tmpディレクトリは、システムの全てのユーザが一時ファイルを置くため、このビットが設定されています。

&amp;bold(){スティッキービットの設定のしかた}
 $ mkdir test
 $ chmod 1777 test
 $ ls -ld test
 drwxrwxrwt  2 user1 group1 4096  5月 30 10:54 test
 $

** セットUIDビット

システムに存在するパスワードファイル（/etc/shadow）について考えてみてください。一般ユーザにパスワードファイルを勝手に書き換えさせることはできませんので、パスワードファイルのパーミッションは、「-rw-------」となっています。しかし、一般ユーザは自分のパスワードを変更できなくてはいけません。ということは、一般ユーザがパスワードファイルを変更する権限がなくてはいけないということになり矛盾が生じます。

そういうときに便利な機能がこのセットUIDビットです。パスワードを変更するコマンドpasswdにこのセットUIDビットを設定することによって、passwdコマンドを実行した一般ユーザが一時的にpasswdコマンドの所有者と同じ権限を得ることができるようになります。

では、実際にpasswdコマンドについて見てみましょう。
 $ ls -l
 -rwsr-xr-x root root 4096  5月 30 10:54  /usr/bin/passwd
上記のパーミッションの「s」という文字がセットUIDビットが設定されているということを表します。上記のpasswdコマンドの場合、所有者がrootになっていますので、このコマンドを実行した一般ユーザは、一時的にroot権限を得ることが出来ます。その権限を使って、パスワードファイル/etc/shadowに保存されている自分のパスワードを書き換えることができるという訳です。

雑談ですが、もしpasswdコマンドに致命的なバグがあった場合、一般ユーザにroot権限を奪取されてしまう可能性があるので注意が必要です。セットUIDビットが設定されたコマンドを標的にしてバグを見つけ出し、root権限を得る方法をクラッキング用語で「ローカルバッファオーバーフロー」と呼び、一般的なクラッキング手法の一つとして色々な本に紹介されているぐらいです。セットUIDビットは非常に便利なのですが、反対に危険（リスク）も伴いますので、使用の際は十分に注意してください。

&amp;bold(){セットUIDビットの設定のしかた}
 $ ls -l test_command
 -rwxr-xr-x user1 group1 4096  5月 30 10:54 test_command
 $ chmod 4755 test_command
 $ ls -l test_command
 -rwsr-xr-x user1 group1 4096  5月 30 10:54 test_command

※ セットUIDビットの他に、セットGIDビットというビットもあります。セットGIDビットが設定されたコマンドを実行すると、一時的に、そのコマンドの所有グループの権限を得ることができるようになります。

&amp;bold(){セットGIDビットの設定のしかた}
 $ chmod 2755 test_command
 $ ls -l test_command
 -rwxr-sr-x user1 group1 4096  5月 30 10:54 test_command

** ユーザ権限継承

あるディレクトリAにこの設定をしておくと、そのディレクトリA以下に作成したファイル・ディレクトリの所有ユーザが、ディレクトリAと同じになるという設定をすることができます。たとえば、ディレクトリAの所有ユーザがrootのとき、この設定をすると、そのディレクトリA以下に別のユーザがファイルを作成すると、自動的に所有ユーザがrootになります。。。が、どうやらセキュリティ上危ないので、この設定ではLinuxで動作しないようです。

&amp;bold(){ユーザ権限継承の設定のしかた}
 $ ls -l test_directory
 drwxr-xr-x user1 group1 4096  5月 30 10:54 test_directory
 $ chmod 4755 test_directory
 $ ls -l test_directory
 drwsr-xr-x user1 group1 4096  5月 30 10:54 test_directory

** グループ権限継承

あるディレクトリAにこの設定をしておくと、そのディレクトリA以下に作成したファイル・ディレクトリの所有グループが、ディレクトリAと同じになるという設定をすることができます。たとえば、ディレクトリAの所有グループがgroup1のとき、この設定をすると、そのディレクトリA以下に別のユーザがファイルを作成すると、自動的に所有グループがgroup1になります。

&amp;bold(){グループ権限継承の設定のしかた}
 $ ls -l test_directory
 drwxr-xr-x user1 group1 4096  5月 30 10:54 test_directory
 $ chmod 2777 test_directory
 $ ls -l test_directory
 drwxrwsrwx user1 group1 4096  5月 30 10:54 test_directory
 $ cd test_directory
 $ su user2
 password: *******
 $ touch file
 $ mkdir directory
 $ ls -l
 -rw-r--r-- user2 group1 4096  5月 30 10:55 file
 drwxr-sr-x user2 group1 4096  5月 30 10:55 directory (ディレクトリの場合、さらにグループ継承が自動的に設定される）    </description>
    <dc:date>2010-09-26T15:19:31+09:00</dc:date>
  </item>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/22.html">
    <title>GNU開発ツール</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/22.html</link>
    <description>
      #contents()

* GNU開発ツール

Linux上でプログラムの開発を行うときには、GNU開発ツール(gccなど）を使うのが一般的です（もちろん、ほかの開発ツールを使う場合もあります）。
組み込みLinux開発を行う上では、GNU開発ツールに慣れ親しんでおくことが必須になります。

* gcc

gccはGNU開発ツールの中でもっとも重要なツールです。すでに知っている方も多いとは思いますが、プログラム言語をコンパイルするときに使うツールです。プログラムから最終的に実行ファイルを作成するためにgccが行うことは、必要なオプションとともに別のサブプログラム（cpp、cc1、as、collect2)を順番に呼び出すことです。

gccはコンパイルなどの処理を行わないことに注意してください。処理を行うのは、下記に示すサブプログラムです。

| プログラム名 | インプット | アウトプット | 説明 |
| &#039;&#039;cpp(プリプロセッサ)&#039;&#039; | hello.c | hello.i | プログラム内のマクロ（例えば #include &lt;stdio.h&gt; や、#define SIZE 16 など）を認識して置換などの処理を行います。|
| &#039;&#039;cc1(コンパイラ)&#039;&#039; | hello.i | hello.s | C言語で書かれたプログラムをCPUに応じたアセンブラコードに変換します。|
| &#039;&#039;as(アセンブラ)&#039;&#039; | hello.s | hello.o | アセンブラコードをCPUで直接実行できるマシン語に変換します。ただし、この時点ではメモリにロードされるアドレスが決定しておらず、実際には実行のできない未完成状態のマシン語となっています。この状態のファイルをオブジェクトファイルと呼びます。|
| &#039;&#039;collect2(ローダ)&#039;&#039; | hello.o | hello |複数のオブジェクトファイルやライブラリをリンクして（ロードされるアドレスを決定して）、最終的に実行ファイルを出力します。|

gccコマンドを-vオプション付きで実行すると、サブプログラムが呼び出される様子が分かります。

&amp;html(&lt;iframe width=&quot;90%&quot; height=&quot;500&quot; src=&quot;http://www26.atwiki.jp/funa_tk?cmd=upload&amp;act=open&amp;pageid=22&amp;file=v_output.txt&quot;&gt;  output&lt;/iframe&gt;)

ここで気づくと思うのですが、cc1、as、collect2は実行されているものの、cppがないということがわかります。調査してみた結果、実はコンパイラであるcc1にcppと同等のプリプロセッサ機能が含まれており、cc1の実行によって、プリプロセス処理とコンパイルを同時に行っているようです。もはやcppはいらないかもしれません。

また、上記のようにgccに-vオプションをつけてコンパイルすることによって、どのようなオプションが指定されて実際にコンパイルされているのか、どのようなライブラリがリンクされているのか、どのようなインクルードファイルが参照されているのかが、わかります。このオプションは覚えておくと便利です。

* glibc

glibcは数あるCライブラリの中でも最も有名なものです。glibcは、一般的なプログラムで用いられる便利な関数をまとめた物であり、glibcをldでリンクすることによって、格段にプログラミングが容易になります。たとえば、標準出力に文字を出力するprintf()関数などがglibcライブラリの中に入っています。

* スタートアップルーチン

プログラムには必ずmain()という関数がありますが、プログラムがメモリにロードされて一番最初に実行される関数はmain()関数ではありません。一番最初に実行される関数は_start()という関数なのです。で、その_start()という関数がどこにあるのかというと、それはcrt0.oというスタートアップルーチンの中に存在します。crt0.oというファイルはgccが勝手にリンクしてくれます。

* 共有ライブラリと静的ライブラリ 

ライブラリには、共有ライブラリと静的ライブラリが存在します。例えば、Ｃライブラリでいえば、共有ライブラリ版がlibc.soというファイルであり、静的ライブラリ版がlibc.aとなります。どちらも提供する関数に違いはありません。

では、どうして共有ライブラリと静的ライブラリがあるのでしょうか？

最初は静的ライブラリしかシステム上に存在していませんでした。標準出力にprintf()関数で「Hello, world!」と表示するプログラムは、printf()関数が定義されている静的Ｃライブラリlibc.aをリンクする必要があります。リンクすることによって、静的Ｃライブラリの中からprintf()関数の部分が切り出され、プログラムにそのprintf()関数が埋め込まれます（埋め込まれることによって、printf()関数が使用可能になります）。

このプログラムは正常に動作します。しかし、システムが成熟し色々なプログラムが動作し始めると問題がでてくるのです。

例えば、printf()関数を使うプログラムがシステム上で多数動作したとき、メモリ上には、全く同じprintf()関数のコードが複数存在してしまうのです。各プログラムの中にprintf()関数が埋め込まれているので当たり前ですね。はっきり言って、メモリの無駄使いです。また、printf()関数に何らかのバグがあった場合、printf()関数を使用する全てのプログラムを修正する必要がでてきます。これは非常に大変なことです。

そこで、共有ライブラリという概念が生まれました。上記の例でいえば、printf()関数を共有ライブラリという形でメモリ上に一つだけ配置しておき、それを各プログラムから共有しようとする考え方です。それによって、各プログラムには、printf()関数のコードを含める必要がなくなり、結果としてプログラムのサイズが減ります。また、printf()関数のバグがあったときは、共有ライブラリだけを修正すればいいのです。

現在のシステムは、共有ライブラリを使うように全てのプログラムがコンパイルされています。

&#039;&#039;プログラムのコンパイルの仕方&#039;&#039; 

** 共有ライブラリをリンクする場合
 $ gcc -o hello hello.c -lc
最後の「-lc」は共有Ｃライブラリを指定しています。もしlibcrypt.soというCryptライブラリ（暗号ライブラリ）の中のcrypt()関数を使いたい場合には、次のようにします。
 $ gcc -o crypt_test cypte_test.c -lcrypt
※ Cライブラリに関しては「-lc」を省略することも可能です。
 $ gcc -o hello hello.c
 は、
 $ gcc -o hello hello.c -lc
 と同じです。

** 静的ライブラリをリンクする場合
 $ gcc -o hello hello.c -lc --static
 または
 $ gcc -o hello hello.c --static

* buintils

binutilsというパッケージには、アセンブラであるasコマンドやローダであるld以外にも組み込みLinux開発を行う上で重要なコマンドが含まれています。ここで少し紹介したいと思います。

** readelf

readelfコマンドは、実行ファイル（ELF形式）のELFヘッダファイルの表示を行います。これによって、実行ファイルにどのようなセクションが含まれているかわかります。
 例：
 $ readelf -S hello

** objdump

実行ファイルをディスアセンブル（マシン語からアセンブラに逆変換）することができます。
 $ objdump -d hello
ディスアセンブル＋ソースコードも混ぜて表示したいときは、
 $ objdump -S hello
データセクションを眺めたいときは、
 $ objdump -j .data -s hello
 or
 $ objdump -sj .data hello
ELF形式のバイナリファイルではなくて、バイナリファイルを直接ディスアセンブルしたいときは、
 $ objdump -m i386 -b binary -D binary_file
バイナリファイルをただのデータ列として眺めたいときは、
 $ objdump -b binary -s binary_file
 or
 $ objdump -sb binary binary_file
バイナリファイルの0x44番地から始まるプログラムのディスアセンブルをしたいときは、
 $ objdump -m i386 -b binary -D --start-address=0x44 binary_file
オプション「-m」で指定できるアーキテクチャ一覧を知りたいときは、
 $ objdump --help
AT&amp;T形式ではなく、Intel形式のダンプを得たいときには、
 $ objdump -M intel binary_file

** objcopy

セクションを削除したり、ファイル形式の変換をすることができます。

単純にコピーする。cpコマンドと等価。
 $ objcopy input output
セクション .data を削除しつつ、コピーする。
 $ objcopy -R .data input output
ファイル形式をS-record形式にしつつコピーする。
 $ objcopy -O srec input output
オブジェクトのデバッグセクションと再配置情報をコピーしない。
 $ objcopy -S input output

* 参考文献
高林 哲著「Binary Hacks」オライリージャパン（2006）    </description>
    <dc:date>2009-06-24T17:11:42+09:00</dc:date>
  </item>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/30.html">
    <title>screenの便利な設定</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/30.html</link>
    <description>
      #contents()
* screenの設定
デフォルトのscreenの設定では使いにくいので、簡単ですがカスタマイズしてみました。
スクリーンショットは以下のような感じ。

&amp;ref(Screen.png)

ステータスバーに現在のディレクトリが表示されるので便利。
ディレクトリへのパスが長くなった場合には、「〜」という記号で途中が省略されます。
また、ホームディレクトリも「〜」で省略されます。

ちなみにエスケープキーは、Ctrl-AからCtrl-Qに変えてあります。

** ~/.screenrc
~/.screenrcに下記の記述をします。
 escape ^Qq
 vbell off
 bind w windowlist -b
 startup_message off
 caption always &quot;%{= wg} %-w%{=bu dr}%n %t%{-}%+w %= %{=b wb}%y/%m/%d %{=b wm}%c&quot;

** ~/bin/screen_minidir
~/bin/screen_minidirに次のような記述をします。
 #! /bin/bash
 
 echo -en &#039;\033k&#039;
 sdir=$(pwd | sed s#${HOME}#~#)
 dirlen=$(echo $sdir | wc -c)
 if [ $dirlen -gt 19 ] ; then
         ssdir=&quot;$(echo $sdir | cut -b 1-9)~$(echo $sdir | cut -b $(($dirlen-8))-$dirlen)&quot;
 else
         ssdir=&quot;$(echo $sdir)&quot;
 fi
 echo $ssdir
 echo -en &#039;\033\\&#039;

chmod 755 ~/bin/screen_minidirコマンドを実行して実行権限をつけておくことを忘れないでください。

** ~/.bashrc
~/.bashrcに下記記述を追加します。
 if [ &quot;$TERM&quot; = &quot;screen&quot; ]; then
         PROMPT_COMMAND=~/bin/screen_minidir
         stty start &#039;&#039;
 fi

簡単でしょ。    </description>
    <dc:date>2009-03-23T10:23:20+09:00</dc:date>
  </item>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/1.html">
    <title>トップページ</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/1.html</link>
    <description>
      #center(){&amp;ref(Title.jpg)}
* このページについて

このページでは半人前の組み込みLinuxの開発者である管理人が、組み込み Linux 開発のための手引きとなるような情報を公開していきたいと思います。

最近、組み込み Linux 開発が注目され始めていますが、ネット上にほとんど資料がないし、どこから初めて良いか分からない人が多いと思います。
そんな方々のための手助けになれれば嬉しいな、と思います!

なるべく頻繁に更新しようと思っているので、宜しくお願いします。

* 更新履歴
- 12/06 [[ソースコードチェッカーsparse&gt;sparse]] 新規追加 &amp;ref(new.gif)
- 12/06 [[バイナリファイル]] 新規追加 &amp;ref(new.gif)
- 11/05 [[スタックの使い方]] 詳しい説明を追加
- 11/04 [[スタックの使い方]] 単純なmain関数を例にしてスタックの使い方についての説明追加
- 10/31 [[Makefile]] シンプルなMakefileテンプレートを追加
- 10/26 [[screenの便利な設定]] 新規追加
- 10/09 [[Linuxディストリビューション]] Vine Linuxについて追加
- 9/30 [[端末について]] 追記
- 9/26 [[端末について]] 新規追加
- 9/20 [[10進数⇔16進数]] 修正 &amp; 追加
- 9/18 [[Linuxディストリビューション]] 新規追加
- 8/08 [[ライセンス]] BSDライセンスの説明を修正
- 8/08 [[サウンド]] LinusのLinuxの発音による確認方法の追記 
- 8/08 [[ライセンス]] BSDライセンスを追加
- 8/04 [[GCC拡張命令]] &amp;html(__attribute__((noreturn)))を追加
- 8/02 [[メモリチェック]] mallocの仕組みを追加
- 7/31 [[ライセンス]] 新規追加
- 7/30 [[組み込みLinuxとは]] 組み込みLinuxの特徴を追加
- 7/28 タイトルロゴ画像を追加
- 7/28 [[組み込みLinuxとは]] 新規追加
- 7/25 [[GNU開発ツール]] binutilsの便利ツールの使い方の項目を追加
- 7/24 [[GNU開発ツール]] 共有ライブラリ・静的ライブラリの項目を追加   
- 7/23 [[メモリチェック]] 新規作成
- 7/23 [[GNU開発ツール]] 修正&amp;gccの出力の添付
- 7/22 [[GNU開発ツール]] 修正&amp;プリプロセッサの項目を追加
- 7/20 [[GNU開発ツール]] 新規作成
- 7/05 [[サウンド]] OSS/Freeのlsmodの結果を追加
- 6/28 [[サウンド]] サウンド再生アプリを更新
- 6/28 [[ホットプラグの混乱]] 全体的に修正
- 6/13 [[ホットプラグの混乱]] 新規追加
- 6/11 [[サウンド]]ALSAサウンドドライバの解説追加
- 6/07 [[サウンド]]新規作成
- 6/05 [[パーミッション]]にセットUIDビットの解説追加
- 5/31 [[Initrd]]追加
- 5/30 [[パーミッション]]にスティッキービットの解説追加
- 5/24 [[ファイルシステム]]追加

----
本ページに記載されている内容につきまして、一切の責任は負いかねますのでご了承をお願いいたします。    </description>
    <dc:date>2008-07-27T19:53:07+09:00</dc:date>
  </item>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/5.html">
    <title>メニュー</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/5.html</link>
    <description>
      #center(){[[トップに戻る&gt;トップページ]]}
----
&amp;bold(){&amp;size(16){読み物}}
&amp;size(14){[[組み込みLinuxとは]]}
&amp;size(14){[[どこから始めればいいの?]]}
&amp;size(14){[[Linuxディストリビューション]]}
&amp;size(14){[[Linuxインストール方法の種類]]}
&amp;size(14){[[最も優れたエディタ&gt;エディタ]]}
----
&amp;bold(){&amp;size(16){Tips}}
&amp;size(14){[[バイナリファイル]]}
&amp;size(14){[[スタックの使い方]]}
&amp;size(14){[[端末について]]}
&amp;size(14){[[ライセンス]]}
&amp;size(14){[[GNU開発ツール]]}
&amp;size(14){[[GCC拡張命令]]}
&amp;size(14){[[パーミッション]]}
&amp;size(14){[[ホットプラグの混乱]]}
&amp;size(14){[[ファイルシステム]]}
&amp;size(14){[[Flash ROMについて&gt;Flash]]}
&amp;size(14){[[Initrd(イニシャルRAMディスク)&gt;Initrd]]}
&amp;size(14){[[サウンド]]}
&amp;size(14){[[インプットメソッド]]}
&amp;size(14){[[Makefile]]}
&amp;size(14){[[10進数⇔16進数]]}
----
&amp;bold(){&amp;size(16){プログラム}}
&amp;size(14){[[プログレスバー]]}
&amp;size(14){[[スタック&gt;stack]]}
&amp;size(14){[[メモリチェック]]}
&amp;size(14){[[ハードリンクをシンボリックに変更]]}
----
&amp;bold(){&amp;size(16){Linuxカーネル}}
&amp;size(14){[[sparseチェッカー&gt;sparse]]}
----
&amp;bold(){&amp;size(16){設定}}
&amp;size(14){[[screenの便利な設定]]}
----
&amp;bold(){&amp;size(16){訪問者}}
総計: &amp;counter()
昨日: &amp;counter(yesterday)
今日: &amp;counter(today)    </description>
    <dc:date>2007-12-06T10:06:01+09:00</dc:date>
  </item>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/32.html">
    <title>バイナリファイル</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/32.html</link>
    <description>
      #Contents()

* バイナリファイル

PCの中には、さまざまなファイルが存在します。たとえば、テキストファイルに始まり、実行ファイル、ライブラリ、画像ファイル、映像ファイルなどなど、数え切れないほどたくさん存在します。テキストファイルは、エディタで表示すれば内容がわかるのでいいのですが、それ以外のファイルはバイナリファイルとなっているため、エディタで開いても内容が全くわかりません。ここでは、それらバイナリファイルをうまく表示したり編集したりするためのツールの説明したいと思います。

* バイナリファイルの表示
** hexdumpコマンド
 hexdump -C バイナリファイル
バイナリファイルをダンプします。バイナリの表示に関しては、このコマンドで十分に対応できるので、覚えておきましょう。
** odコマンド
 od -Ax -tx1z バイナリファイル
バイナリファイルをダンプします。odコマンドはオプションがたくさんあり、非常に便利なのですが、オプションが増えて覚えづらいです。バイナリファイルを細かく制御しつつ表示したいときにmanをみながら使いましょう。通常の表示では、上記のhexdumpで事足りるはずです。

* バイナリファイルの編集
** Vimを使った方法

vimを使う方法を説明します。
たとえば、次のようなファイルがあるとします。
 user@debian:~$ cat binary
 &quot;3DUfw���user@debian:~$ 
catコマンドで中身を表示してみましたが、バイナリファイルなので化けちゃってます・・。
このバイナリファイルを上記で説明したhexdumpコマンドで表示してみましょう。
 user@debian:~$ hexdump -C binary
 00000000  11 22 33 44 55 66 77 88  99 aa                    |.&quot;3DUfw...|
 0000000a
 user@debian:~$ 
ほうほう、このようなファイルだったのですね！
では、このファイルの「66」というバイトの部分をffに書き換えたいとします。
ここでは、Vimを使った書き換え方法を説明します。

まず、「vim -b バイナリファイル」を実行してバイナリファイルを開きます。
 user@debian:~$ vi -b binary
すると、こんな感じでファイルが開きます。
 ^Q&quot;3DUfw&lt;88&gt;&lt;99&gt;&lt;aa&gt;
 ~
 ~
 ~
 ・・・（略）
化けちゃってますね〜。Vimはテキストファイルとして開くので、あたりまえですが。
ところで、Vimの-bオプションはバイナリ文字が存在しても正常にテキストファイルとしてファイルを開くオプションです。
ここで、「:%! xxd」というコマンドを打ちます。
すると、こんな感じになります。
 0000000: 1122 3344 5566 7788 99aa                 .&quot;3DUfw...
あとは、これの66というバイトの部分をffに変更するだけです。
ちなみに、「:%! (コマンド名）」という命令は、バッファ全体（命令の中の%の部分）の内容を続くコマンド(xxdコマンド）に入力として渡し、
xxdを実行して、なおかつ、そのxxdの出力結果をVimで編集するというコマンドです。
では、通常のVimの操作で66をffに書き換えてください。
 0000000: 1122 3344 55ff 7788 99aa                 .&quot;3DUfw...
編集し終わったら、「:%! xxd -r」コマンドを実行して、元の状態に戻します。
xxd -rというコマンドは、上記のような「番地: バイト列・・・」となっているファイルを入力として
受け取って、テキストファイルを出力するという動作をおこなうみたいですね。
 ^Q&quot;3DU&lt;ff&gt;w&lt;88&gt;&lt;99&gt;&lt;aa&gt; 
 ~
 ~
 ~
 ・・・（略）
あとは「:wq」なり「:x」なり「ZZ」なりで保存するだけです。

この方法を知っていると、バイナリファイルの中の特定の文字列や値を変更できるので、非常に重宝します。    </description>
    <dc:date>2007-12-06T02:01:59+09:00</dc:date>
  </item>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/13.html">
    <title>Linuxインストール方法の種類</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/13.html</link>
    <description>
      #contents()
* Linuxのインストール方法の種類

Linuxのインストールという言葉を聞いたとき、市販のPCにプリインストールされているWindowsを消して、Linuxをインストールすることを想像される方がいると思いますが、そのような事をする必要ありません。そんなことをすると、せっかく購入したWindowsを使わないということになるのでもったいないです。Linuxをインストールする方法には色々あって、それぞれ利点や欠点がありますので、よく考えてインストールすることをおすすめします。

ここでは、Linuxのインストール方法の種類に関して、ちょっとまとめたいと思います。

* Linuxのインストール方法の色々

Linuxをインストールする方法には下記のような方法があります。もちろん、これ以外にもありますし、これから先もっと便利なインストール方法が出現するでしょう。とりあえず、今私が分かっている範囲でまとめてみたいと思います。

** ピュアLinuxインストール

市販のWindows PCのWindowsを消去して、Linuxをインストールしてしまう方法です。これは、みなさんが想像しているLinuxのインストール方法だと思います。Windowsが全く使えなくなってしまうという点で、みなさんの多くがこれを避けたいと思っているでしょう。Windowsが大嫌いで、「俺はWindowsなんて使わないぜ!」っていう人や、貧乏な方(私を含む)がWindowsがプリインストールされていない空っぽのPCを購入した場合、このピュアLinuxインストール方法を選択します。

Windowsを既に持っている方は、この方法はオススメしません。せっかく自分でお金をだしてWindowsを購入しているのに、Windowsを使わないのはもったいないです。Windowsを持っている方は、WindowsもLinuxも両方使える状態にした方がいいでしょう。

特に組み込みLinuxの開発を行う場合、開発はLinuxだけで行うからWindowsはいらないんじゃないの?っていう人がいるかもしれませんが、Windowsでしか動作しないデバッグツールを使って組み込み開発を行う場合が多く、現実問題としてWindowsを手放すことはできません。

** デュアルブート(マルチブート)

これは、ハードディスクを複数のパーティションに分けて置いて(もしくは、複数のハードディスクを用意して)、WindowsとLinuxを両方ともインストールする方法です。どちらのOSを使うかは、電源ONした後のブートローダで選択することになります。

最近のハードディスクは容量が非常に大きいので、このインストール方法を選ぶのもアリです。ただ、ブートローダの設定やハードディスクのパーティションに関する知識が絡んでくるので、若干敷居が高いかもしれません。。

※注意事項として、例えばブートローダでWindowsを選択してブートした場合、Linuxを使うことはできません。Linuxを使いたい場合には、一度PCをリブートしてLinuxを選択して起動しなくてはいけません。つまりWindowsとLinuxを同時に使うことができないということになります。

** VMwareやVirtual PCなどの仮想PCソフトウェア

これは、VMware社のVMwareやMicrosoftのVirtual PCという仮想PCソフトウェアをWindowsにインストールして、その仮想PCにLinuxをインストールするという方法です。Windowsの上で仮想PCが動作し、その仮想PCソフト上でLinuxが動作することになります。WindowsとLinuxを同時に使うことができるので、私としてかなりオススメしたい方法です。VMwareやVirtual PCは、以前は一万円ぐらいしていましたが、最近無料になりました(^^)。

このインストール方法の欠点としては、WindowsとLinuxを同時に動作させることになるので、大容量のメモリや高速なCPUが必要になるということぐらいでしょうか。

** Cygwin

Linuxのインストールまではしたくないけれど、LinuxコマンドだけWindows上で使いたいっていう人には、これがお勧めです。インストールも簡単ですし。

** coLinux

上述のVMwareやVertualPCなどの仮想PCソフトウェアを使う場合には、Windows上で仮想PCソフトが動作し、さらにその仮想PC上でLinuxが動作するという3段構成になっていたのですが、coLinuxはWindows上で直接Linuxを動作させるという、すごいソフトウェアです。一時期凄く流行り私も以前この方法でLinuxをインストールしてました。現在はあまり聞かなくなっていますが、どうなってしまったのでしょうか?私の情報収集不足かもしれませんが。

** Knoppix (Linuxインストールとは関係ないが、比較のため)

これはLinuxをインストールせずに、ちょっとだけLinuxを使いたい、もしくはLinuxを試してみたいっていう場合に、Knoppixが入ったブータブルCD-ROM(CD-R)からLinuxを起動する方法です。Linuxをインストールする必要が全くなく、既存ハードディスクのデータに全く影響を及ぼさないため、非常に手軽です。

欠点は、なにか処理するたびにCDドライブにアクセスするので、非常に遅いことです。急いでいるときはかなりイライラします。CDが回る「キュイーン」っていう音がイライラを煽ります。

Linuxがどんなものか試すときや、レスキュー用途にしか使われないでしょう。

** インストールせず、別のLinuxマシンにログイン!

自分のマシンのリソースを一切使わず、別のマシンのリソースを使うわけですから便利な方法です。もちろん余っている別のPCが必要ですが。。余っているPCがあるならば、そのPCにLinuxインストールをして、そこへリモートログインするのがいいでしょう。
昔は、この方法を使っていましたが、最近OSの入っていない高速なノートPCを購入したので、Linuxをピュアインストールしてしまいました。。とても快適です。    </description>
    <dc:date>2007-12-05T13:08:25+09:00</dc:date>
  </item>
    <item rdf:about="http://www26.atwiki.jp/funa_tk/pages/31.html">
    <title>スタックの使い方</title>
    <link>http://www26.atwiki.jp/funa_tk/pages/31.html</link>
    <description>
      #Contents()
* main関数のスタックの使い方

Ｃ言語でのプログラミングに関する情報は、ネット上で数多く議論されているようですが、Ｃ言語で書かれたプログラムがgccによって、どのようなアセンブラ言語にコンパイルされるのか？ということについては、情報が少ないと思います。
スタックの使われ方に注目しながら、まとめてみたいと思います。

次のような単純なＣ言語のプログラムがあるとします。
#pre(){{
#include &lt;stdio.h&gt;

int add(int arg1, int arg2)
{
        return arg1 + arg2;
}

int main(int argc, char *argv[])
{
        int a;
        int b;
        int ret;

        a = 3;
        b = 5;

        ret = add(a, b);

        return ret;
}
}}

このプログラムをgccでコンパイルし、
 $ gcc -o main main.c
逆アセンブルしてみると、次のようになりました。
#pre(){{
$ objdump -d main
・・・
08048344 &lt;add&gt;:
 8048344:       55                      push   %ebp
 8048345:       89 e5                   mov    %esp,%ebp
 8048347:       8b 45 0c                mov    0xc(%ebp),%eax
 804834a:       03 45 08                add    0x8(%ebp),%eax
 804834d:       5d                      pop    %ebp
 804834e:       c3                      ret    

0804834f &lt;main&gt;:
 804834f:       8d 4c 24 04             lea    0x4(%esp),%ecx
 8048353:       83 e4 f0                and    $0xfffffff0,%esp
 8048356:       ff 71 fc                pushl  -0x4(%ecx)
 8048359:       55                      push   %ebp
 804835a:       89 e5                   mov    %esp,%ebp
 804835c:       51                      push   %ecx
 804835d:       83 ec 18                sub    $0x18,%esp
 8048360:       c7 45 f0 03 00 00 00    movl   $0x3,-0x10(%ebp)
 8048367:       c7 45 f4 05 00 00 00    movl   $0x5,-0xc(%ebp)
 804836e:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048371:       89 44 24 04             mov    %eax,0x4(%esp)
 8048375:       8b 45 f0                mov    -0x10(%ebp),%eax
 8048378:       89 04 24                mov    %eax,(%esp)
 804837b:       e8 c4 ff ff ff          call   8048344 &lt;add&gt;
 8048380:       89 45 f8                mov    %eax,-0x8(%ebp)
 8048383:       8b 45 f8                mov    -0x8(%ebp),%eax
 8048386:       83 c4 18                add    $0x18,%esp
 8048389:       59                      pop    %ecx
 804838a:       5d                      pop    %ebp
 804838b:       8d 61 fc                lea    -0x4(%ecx),%esp
 804838e:       c3                      ret    
 804838f:       90                      nop
・・・
}}
単純なＣプログラムが、何故このような難解なアセンブラにコンパイルされてしまうのでしょうか？少しずつ紐解いてみましょう。

** main関数が呼び出される前
main関数が呼び出される直前のスタックは次のような状態になっています。
&amp;ref(before_main.png)
スタックには、呼び出し元へのリターンアドレス（呼び出し元へ戻るために必要）とmain関数に渡された引数がスタックにのっかっている状態となっています。
この図には書いてありませんが、argcの下には、argvの情報が格納されています。
**プロローグフェーズ
gccでコンパイルした場合、必ずプロローグというフェーズがあります。このフェーズでは、スタックを利用する準備をします。主に、各種レジスタの保存や設定をおこないます。
main関数の中の下記の６行が、このプロローグフェーズに該当します。
 804834f:       8d 4c 24 04             lea    0x4(%esp),%ecx   ※ ECXレジスタが呼び出し元が用意したスタックを指すようにする。
 8048353:       83 e4 f0                and    $0xfffffff0,%esp ※ スタックを16バイト境界に揃える（注：何故これが必要なのか分からない）
 8048356:       ff 71 fc                pushl  -0x4(%ecx)       ※ リターンアドレスをコピーする（注：何故これが必要なのか分からない。プログラム動作上、これは無くてもいいはず）
 8048359:       55                      push   %ebp             ※ EBPレジスタに入っていた値を保存する
 804835a:       89 e5                   mov    %esp,%ebp        ※ EBPレジスタに現在のESP(スタックポインタ)の値をセットする
 804835c:       51                      push   %ecx             ※ ECXレジスタを保存する
上記の命令を実行した後の、スタックの状態は次のようになります。
&amp;ref(prologue.png)
空き領域ができてしまっていますが、これは、スタックを16バイト境界に揃えたためです。なぜgccは16バイト境界にスタックを揃えているのか現在のところ分かりません。
** ローカル変数の確保フェーズ
main関数では、a、b、そしてretというローカル変数を使用していますので、そのための領域をスタックに確保しなければいけません。
 804835d:       83 ec 18                sub    $0x18,%esp       ※ローカル変数の確保
 8048360:       c7 45 f0 03 00 00 00    movl   $0x3,-0x10(%ebp) ※ 変数aに3を代入
 8048367:       c7 45 f4 05 00 00 00    movl   $0x5,-0xc(%ebp)  ※ 変数bに5を代入
この３行がローカル変数の確保フェーズ＆初期化フェーズに該当します。
スタックの状態は次のようになります。
&amp;ref(allocate_locals.png)
** add関数の呼び出し
add関数を呼び出す為の準備および実際に呼び出します。下記５行が該当します。
 804836e:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048371:       89 44 24 04             mov    %eax,0x4(%esp)
 8048375:       8b 45 f0                mov    -0x10(%ebp),%eax
 8048378:       89 04 24                mov    %eax,(%esp)
 804837b:       e8 c4 ff ff ff          call   8048344 &lt;add&gt;
call命令を呼び出すと自動的に、スタックにリターンアドレスが積まれるので、この段階でのスタックの状態は次のようになります。
&amp;ref(call_add.png)
使われていない空き領域が発生しているのが分かると思います。これは、ローカル変数の確保フェーズで領域を確保しすぎたためです。なぜ0x18バイト確保したのでしょうか？0x14バイトを確保したほうがきっちりと必要な分だけスタックを使えるのでメモリの節約になると思うのですが・・。謎です。ちなみに、コンパイル時に「-O2」という最適化オプションをつけたところ、このような無駄な空き領域はなくなりましたし、他にも凄いメモリ節約をしたアセンブラを生成してくれました。興味のある方は試してみてください(^-^)。
** add関数から戻る
add関数から戻ってきたら、結果をスタックに確保してあるretの領域に保存します。
また、return命令で値を呼び出し元に返すために、EAXレジスタに保存しておきます。関数は返り値をEAXレジスタを介して呼び出し元に返します。
 8048383:       8b 45 f8                mov    -0x8(%ebp),%eax
** ローカル変数を解放する。
確保しておいたローカル変数領域は、呼び出し元に制御を移すまえに完全に消去しておきます。ローカル変数は、定義した関数内でのみ有効ということが良くわかるでしょう。
 8048386:       83 c4 18                add    $0x18,%esp
** エピローグフェーズ
呼び出し元に戻る前に保存しておいたレジスタを復帰し、その後、ret命令で呼び出し元の関数へ戻ります.
 8048389:       59                      pop    %ecx            ※ ECXレジスタの復帰
 804838a:       5d                      pop    %ebp            ※ EBPレジスタの復帰
 804838b:       8d 61 fc                lea    -0x4(%ecx),%esp ※ ESP（スタックポインタ）の復帰
 804838e:       c3                      ret                    ※ 呼び出し元へ戻る

* このページを書いていて思ったこと
gccは、-O2などの最適化オプションをつけなくては、めちゃくちゃ馬鹿みたいですね。プログラムを生成するときには、できるだけ-O2オプションをつけておいた方がよさそうです。    </description>
    <dc:date>2007-11-06T13:03:32+09:00</dc:date>
  </item>
  </rdf:RDF>

