1. アセンブリ言語によるプログラム

最初のプログラム

ここでは NASMというアセンブラで直接 Linux カーネルのシステムコールを 使うプログラムを作成していきます.

まず最初に Linux でアセンブラ(nasm) を使ったプログラムを紹介します. 例によって,hello, world を表示するものです.

  ;------------------------------------
  ; hello.asm
  ;------------------------------------
  section .text
  global _start

  msg             db   'hello, world', 0x0A
  msglen          equ  $ - msg

  _start:
                  mov    ecx, msg
                  mov    edx, msglen
                  mov    eax, 4
                  mov    ebx, 1
                  int    0x80
                  mov    eax, 1
                  mov    ebx, 0
                  int    0x80
  ;------------------------------------

アセンブル,リンクは以下のコマンドで行います.

   nasm -f elf hello.asm
   ld -s -o hello hello.o

./hello で実行できます.

同等のプログラムの C バージョンは

  /* hello.c */
  #include <stdio.h>
  int main(int argc, char* argv[]) {
      puts("hello, world\n");
      return 0;
  }

gcc -o helloc hello.c でコンパイル. ./helloc で実行できます.

C のほうが分かり易いですよね.

面倒なアセンブラでプログラムを作成して何がウレシイのでしょうか? ではプログラムの大きさを比較してみましょう.

  -rwxr-xr-x    1 jun      users         452 Apr  5 00:13 hello
  -rwxr-xr-x    1 jun      users       11309 Apr  5 00:17 helloc

コンパイラに最適化を指定してみます.

  $ gcc -O2 -o helloc hello.c
  $ ls -l
  -rwxr-xr-x    1 jun      users       11277 Apr  5 00:17 helloc

ストリップして余計な情報をのぞくと

  $ strip helloc
  $ ls -l helloc
  -rwxr-xr-x    1 jun      users        2912 Apr  5 00:18 helloc

かなり小さくなりました.

しかし,シェアドライブラリというものが存在します.

  $ ldd helloc
          libc.so.6 => /lib/libc.so.6 (0x40017000)
          /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

/lib/libc.so.6 が何かを調べてみるとシンボリックリンクです.

  $ ls -l  /lib/libc.so.6
  lrwxrwxrwx    1 root     root   13 Mar  3 01:03 /lib/libc.so.6 -> libc-2.1.2.so*

シンボリックリンク先のファイルを調べます.

  $ ls -l  /lib/libc-2.1.2.so
  -rwxr-xr-x    1 root     root      4021488 Sep  8  1999 /lib/libc-2.1.2.so*

4Mバイトもある巨大なファイルが実行時に必要です.

シェアドライブラリを使用しないでライブラリの必要な部分だけをを実行ファイル に含めるような設定でコンパイルした場合には

  $ gcc -O2 --static -o helloc hello.c
  $ ls -l helloc
  -rwxr-xr-x    1 jun      users      923630 Apr  5 00:18 helloc

ストリップすると

  $ strip helloc
  $ ls -l helloc
  -rwxr-xr-x    1 jun      users      201348 Apr  5 00:18 helloc

200kバイトにもなりますが,次のようにシェアドライブラリは不要です.

  $ ldd helloc
          not a dynamic executable

このスタティックリンク版の helloc の実行に必要なのは Linux カーネルのみです. ディストリビューションには関係無くどこでも実行できます.

この hello.c のようなごく小さいプログラム1つだけの場合には,スタティック リンクしたほうが小さくなりますが,多くのプログラムを使う場合(Linux の ディストリビューション全体のように) には,シェアドライブラリを使用する ダイナミックリンクが全体として圧倒的に小さくなります.

さて,452 バイトの hello は シェアドライブラリを使っているのでしょうか?

  $ ldd hello
          not a dynamic executable

したがってアセンブラで作成した場合の実行プログラムのサイズは,C で作成した 場合の 1/450 になっています.

もう一度,hello.asm を見てみましょう.

  ;------------------------------------
  ; hello.asm
  ;------------------------------------
  section .text
  global _start

  msg             db   'hello, world', 0x0A
  msglen          equ  $ - msg

  _start:
                  mov    ecx, msg       ; 文字列の場所を指定
                  mov    edx, msglen    ; 文字列の長さを設定
                  mov    eax, 4         ; 出力のシステムコール
                  mov    ebx, 1         ; 標準出力を指定
                  int    0x80           ; システムコール実行
                  mov    eax, 1         ; 終了のシステムコール
                  mov    ebx, 0         ; 正常終了の 0 に設定
                  int    0x80           ;  システムコール実行
  ;------------------------------------

今回はこの例では, プログラムを終了させるシステムコールと文字列を表示 するシステムコールの2つを使っています.

eax にシステムコール番号を設定してソフトウェア割込み(int 0x80) を することで,カーネルの持つ強力な機能を使うことができます.

Linux上でアセンブラを使ってプログラムする場合,libc の関数を使用する 方法もありますが,ここではシステムコールを直接呼び出してプログラムする 方法をとります.

MS-DOSでアセンブラ(MASM, TASMなど)を使ったことがある人には簡単と思います. さらに MS-DOSの場合と大きくちがって,どんなプログラムを実行してもリブート する必要が無いことでしょう. 無限ループや暴走もカーネルで制御できます.

アセンブリ言語の欠点として

  1. わかりにくい.
  2. 大規模なプログラムが作成しにくい.
  3. メンテナンスが困難.
  4. 最近のコンパイラは,人がアセンブラで直接記述するより良いコードを生成する場合が多い (といわれる).
  5. 情報が少ない .
  6. 慣れるほど面倒になる.

一方,アセンブラを使う利点

  1. CPU を支配できる.
  2. コンパイラより高速なコードを書ける (場合も実は多い).
  3. 文法が簡単である.
  4. バイナリ (実行できるプログラム) が小さい.
  5. まったく新しい OS を作るには必須の知識である.
  6. ウイルスに負けない体力を養える.
  7. コンパイラインタプリタの作者になれる.
  8. Linux カーネルの機能を理解できる.
  9. C のポインタが簡単に理解できる.
  10. 人に自慢できる (かも ;-).

もし,興味がある場合,読み進んでください.