X86アセンブラ/基本的なFAQ

出典: フリー教科書『ウィキブックス(Wikibooks)』
ナビゲーションに移動 検索に移動

このページでは、アセンブリ言語でのプログラミング初心者の基本的なFAQについて答えよう。

アセンブラとは[編集]

※ 原著には無い日本版独自の節です。

コンピュータのプログラムを機械語(0b100111010101010のようなコード)にすることをアセンブルといいます[1]

なお、機械語を4ケタごとに区切って、16進数に置き換える場合も有ります。(0100 1110 1010 1010 のようなコードを、4 E A A のように。さらに 4E AA と2ケタごとに16進数をまとめることもある)[2]

しかし、このような数字のコードは見づらいため、その直前の段階で、

mov ax, bx

push d

などのような、内容の分かりやすいコードに対応させることにしました。このような、機械語に一対一に対応する英単語に近い単語[3]に対応させたプログラムの表記法をアセンブリ言語といいます。 もともと、製造業などで、最終組み立ての工程をアセンブルと言っていました。つまり、もともとアセンブルとは、アセンブリ言語の書かれたコードから機械語への組み立てを意味します。

さて、コンピュータのアセンブリ言語は、さすがに機械語(0と1の羅列)よりかは内容が分かりやすいとはいえ、アセンブリ言語ですら、人間には長く、全体像が分かりづらいという欠点がありました。 たとえば、画面に文字を出力するための命令ですら、アセンブリ言語による命令文を何個も並べる必要がありました。 そこで、プログラム言語というものが考えだされ、たとえば画面に文字を出力する命令を print と1単語であらわすと決めたり等の工夫をした言語が考え出され、よく使う命令は、1個か2個の命令に言い換えるプログラム言語が登場しました。 そのようなプログラム言語の代表例が、C言語やBASICというものです。 現代の教育では、プログラム言語のほうが子供に分かりやすいからか、アセンブリ言語の教育よりも先にプログラム言語を教えますが、歴史的にはアセンブリ言語のほうが早く登場しました。 こういう開発の歴史的な経緯があるため、人によっては用語の使い方で、プログラム言語とアセンブリとは、区別して別々のものとして分類することもよくあります。 いっぽうで、アセンブリ言語を扱う職業の人と、BASICやCなどのプログラム言語を扱う人の職業は同じで「プログラマー」という職業名だからか、アセンブリ言語もプログラム言語の一種として分類することもあります。 このため、区別するための用語が必要になり、C言語やBASICなどのような、より抽象的(機械語とは、1対1に対応していないというような意味)なプログラム言語のことを「高水準プログラム言語」というようになりました。 なので、対するアセンブリ言語のことを「低水準プログラム言語」などのように言って区別する場合もあります。 ここでいう高水準/低水準とは、「機械語に遠いか近いか?」という意味で、品質等の善し悪しのことではありません。 機械語から遠いほうが高水準言語high-level programming language: こうすいじゅんげんご、高級言語とも)です。機械語に近いほうが低水準言語low-level programming language: ていすいじゅんげんご、低級言語とも)です。 なので、BASICやC言語などのほうが『高水準』です。アセンブリ言語は『低水準』です。 さて、機械語に変換することをアセンブラとは、アセンブリ言語で書かれたコードを機械語に変換するソフトウェアです。 さて、コンピュータは機械語で動いているので、つまり、どんなプログラム言語であっても、そのプログラムを実際に機械語に変換する必要があります。

高水準言語を低水準言語に変換したり、あるいは高水準言語を機械語に変換することを、コンパイルといいます。要するに、C言語やBASICなどで書かれたプログラムのコードを、実際にパソコンで動くアプリケーションにするための作業がコンパイルです。 さて、コンパイルをするソフトウェアのことをコンパイラといいます。 print という命令文のあるプログラム言語を、そのプログラム言語の規則にもとづいてコードが正しく書かれていることを前提に、さらにコードをコンパイルして機械語による(コンピュータへの)命令に変換する事で、ようやく、ソフトウェアとして動作するようになるわけです。 なお、アセンブラ本体には、C言語でいうところの「変数」の機能は無いです。なので、アセンブラで変数を使いたい場合は、アセンブラを使って、変数の機能を持つものをプログラマーが実装する必要があります。

コンピュータはアセンブリ言語をどのように読んで理解するのか?[編集]

コンピュータは実際のところ読みも、理解も、何もそれ自体ではしないが、しかしこういう答えが求められている訳ではないだろう。事実は、コンピュータはあなたの書いたアセンブリ言語を読むことはできないということである。アセンブラがアセンブリ言語を機械語と呼ばれる2進数の情報の形に変換し、コンピュータはそれを使って動作するのである。コードがアセンブルされていないならば、それはコンピュータにとって全く意味不明である。

アセンブリ言語のそれぞれの命令は、通常ただ一つの機械語に対応しているので白紙と鉛筆とアセンブリ命令のリファレンスブックだけがあれば、「ごく普通の人」でもこの作業(ハンドアセンブル)を実行することができる。実際、コンピュータが使われだした最初の頃は、これは一般的にされていたことであって、基本的なコンピュータプログラムのいくつかにとっては「ハンドアセンブル」するというのは必要なことであった。このころの古典的な例としては、スティーブ・ウォズニアックによるものがある。彼にとっての最初のApple Iコンピュータで使うために、Integer BASICインタプリタの全てを6502機械語にハンドアセンブルした。しかし、覚えておいてほしいのだが、商業的に配布されたソフトウェアのためにこのような作業がされたのは、非常にめずらしいことであるから話題になるのである。本当にほんの少しのプログラマが、実際に少数の命令についてハンドアセンブルをした経験を持っているにすぎないし、経験があるとしても学校の宿題としてやったことがあるに過ぎない。

WindowsとDOSとLinuxでアセンブリ言語は同じなのか?[編集]

この質問への答えはイエスであり、ノーでもある。基本的なx86機械語はプロセッサにのみ依存する。x86バージョンのWindowsとLinuxは明らかにx86機械語で作られている。x86アセンブリ言語でのプログラミングはLinuxとWindowsとで少し異なっている。

  1. Linuxが動作している環境では、最も一般的なアセンブラはAT&T記法を採用するGASアセンブラか、MASMに似た記法を採用するNASMという名前でも知られるNetWideアセンブラである。
  2. Windowsが動作している環境では、最も一般的なアセンブラはMASMであり、インテル記法が採用されている。
  3. 使用可能なソフトウェア割り込みとその機能はWindowsとLinuxで異なっている。
  4. 使用可能なライブラリはWindowsとLinuxで異なっている。

同じアセンブラを使うならば、基本的なアセンブリコードはオペレーティングシステムによらず基本的には同じである。 しかし、Windowsと連携するならば、Linuxと連携する場合とコードは異なったものとなる。

どのアセンブラがベストか?[編集]

簡単に答えると、どのアセンブラも他のどのアセンブラよりも似たり寄ったりであり、個人の好みの問題である。

もう少し詳しく答えると、アセンブラはそれぞれの利点と欠点がある。あなたがGAS構文しか知らないとしたら、あなたは多分GASを使いたがるであろう。インテル文法を知っておりWindowsマシンで仕事をしているのであれば、MASMを使いたくなるかもしれない。MASMやGASの癖や複雑さが好きでないならば、FASMやNASMを使いたくなるかもしれない。この本では第2節でそれぞれのアセンブラの違いを扱う。

アセンブリ言語を知る必要があるか?[編集]

ほとんどのコンピュータに関連する作業をするためにアセンブリ言語を知る必要はないが、知っておけば役に立つ。アセンブリ言語を学ぶことは、新しいプログラミング言語を学ぶということではない。新しくプログラミングを始めようとするとき(プロジェクトがブートローダやデバイスドライバ、カーネルでなければ)、アセンブリ言語はやっかいものとして避けられるだろう。例外は、絶対的にパフォーマンスが重要であったり、コンパイラが最適でないコードを生成する場合である。しかし覚えておいてほしいのは、不完全な最適化は全ての悪の根源である。ただし、最適化技術が理解されており最初から計画されていれば、計算量が重要となるリアルタイムなタスクでは簡単に十分な最適化が実施できる。

しかし、アセンブリ言語を学ぶことによってコンピュータがその内部でどのように働いているのかについての詳細な見識を得ることができる。C言語やAdaといった高水準言語でプログラムを書いても、コードは全て最終的にはコンピュータの実行できる機械語の命令に変換される必要がある。プロセッサが何ができるかについて正確に理解することは、最も基本的なレベルにおいて、高水準言語でプログラミングをする際の助けとなる。

コードにはどのようにフォーマットを使うべきか?[編集]

ほとんどのはアセンブリコードの命令は、それぞれを各行に書き改行で分けている。また、ホワイトスペースが命令、オペランドなどを分けるのに使われる。正確に言えば、コードにどのようなフォーマットを採用すべきかは、あなたにまかされている。しかし、一般的な方法というものはいくつかある。


一つは全てを1行ずつ書く方法である。

Label1:
mov ax, bx
add ax, bx
jmp Label3
Label2:
mov ax, cx
...

もう一つは、ラベルを最初の列に書き、命令をそれ以降の列に書く方法である。

Label1: mov ax, bx
        add ax, bx
        jmp Label3
Label2: mov ax, cx
...

ほかにも、ラベルで1行を使い、命令を少しインデントして書く方法もある。

Label1:
   mov ax, bx
   add ax, bx
   jmp Label3
Label2:
   mov ax, cx
...

これらに加えて、ラベルを最初の列に書き、命令を以降の列に書くが、ラベルには別の行を使う方法もある。

Label1:
        mov ax, bx
        add ax, bx
        jmp Label3
Label2:
        mov ax, cx
...

本当にたくさんの書き方があるが、アセンブリプログラマが一般的に従っているルールがいくつかある。

  1. ラベルは、他のプログラマがどこにラベルがあるかはっきり分かるように書く。
  2. 構造(インデント)はコードが読みやすいようにする。
  3. コメントを使い、何をしているのか説明する。アセンブリ・コードの意味は、すぐにははっきりしないことが多いからである。

インラインアセンブラ[編集]

※ 日本版独自の節です。

アセンブラはC言語に組み込んで使うこともできる。このように、C言語プログラムに組み込んで使うアセンブラのことをインライン アセンブラ( Inline assembler)という。

C言語コンパイラの種類によってインライン アセンブラの呼び出し方の文法が少々違う。インライン アセンブラについて、詳しくは Wikibooks『C言語/おわりに』で説明する。

本書では、インラインアセンブラには深入りしない。

  1. ^ 尚、この数字の羅列は説明のためにデタラメに書いた数字であるので、覚えるべきは0と1が使われていて並んでいるという事だけである。それ以外には特に覚えるべきことは無い。
  2. ^ 尚、この数字は説明のためにデタラメに書いた数字であるので、覚えるべきは16進数への変換と、4ケタごとに区切ったり2ケタごとに区切る事だけである。それ以外には、特に覚えるべきことは無い。
  3. ^ ニーモニックと呼びます。