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

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

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

アセンブラとは[編集]

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

コンピュータのプログラムを機械語(0100111010101010のようなコード)にすることをアセンブルといいます。(※ なお、この数字の羅列は説明のためにデタラメに書いた数字であるので、覚えるべきは0と1が使われていて並んでいるという事だけである。それ以外には特に覚えるべきことは無い。)

なお、機械語を4ケタごとに区切って、16進数に置き換える場合も有ります。(0100 1110 1010 1010 のようなコードを、4 E A A のように。さらに 4E AA と2ケタごとに16進数をまとめることもある)。(※ なお、この数字は説明のためにデタラメに書いた数字であるので、覚えるべきは16進数への変換と、4ケタごとに区切ったり2ケタごとに区切る事だけである。それ以外には、特に覚えるべきことは無い。)

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

move a,b

とか

push d

などのような、内容の分かりやすいコードに対応させることにしました。このような、機械語を英単語っぽい単語に対応させたコードをアセンブリ言語といいます。 また、人間が読んで分かりやすくなったコードのことをニーミニックといい、アセンブリ言語はニーモニックの例だといわれています。


もともと、製造業などで、最終組み立ての工程をアセンブルと言っていました。つまり、もともとアセンブルとは、組み立てのような意味でした。

そのことからか、コンピュータでも、プログラムを使えるようにする最後のほうの処理に機械語への変換が行われるので、機械語への変換をアセンブルと呼ぶようになったのでしょう。


さて、コンピュータのアセンブリ言語は、さすがに機械語(0と1の羅列)よりかは内容が分かりやすいとはいえ、アセンブリ言語ですら、人間には長く、全体像が分かりづらいという欠点がありました。たとえば、画面に文字を出力するための命令ですら、アセンブリ言語による命令文を何個も並べる必要がありました。

そこで、プログラム言語というものが考えだされ、たとえば画面に文字を出力する命令を print あるいは printf と1単語であらわすと決めたり等の工夫をした言語が考え出され、よく使う命令は、1個か2個の命令に言い換えるプログラム言語が登場しました。そのようなプログラム言語の代表例が、C言語やBASCというものです。(なお、BASICのほうがC言語よりも古い。なので頭文字に注目すると Assemble, Basic ,C というふうにABC順になっている。)

現代の教育では、プログラム言語のほうが子供に分かりやすいからか、アセンブリ言語の教育よりも先にプログラム言語を教えますが、もともとはアセンブリ言語のほうが古かったのです。


ともかく、こういう開発の歴史的な経緯があるため、人によっては用語の使い方で、プログラム言語とアセンブリとは、区別して別々のものとして分類することもよくあります。

いっぽうで、アセンブリ言語を扱う職業の人と、BasicやCなどのプログラム言語を扱う人の職業は同じで「プログラマー」という職業名だからか、アセンブリ言語もプログラム言語の一種として分類することもあります。

このため、区別するための用語が必要になり、C言語やBASICなどのような、より抽象的(機械語とは、1対1に対応していないというような意味)なプログラム言語のことを「高級プログラム言語」というようになりました。

なので、対するアセンブリ言語のことを「低級プログラム言語」などのように言って区別する場合もあります。

ここでいう高級/低級とは、「機械語に遠いか近いか?」という意味です。けっして品質の善し悪しのことではないです。

機械語から遠いほうが『高級』言語です。機械語に近いほうが『低級』言語です。

なので、BASICやC言語などのほうが『高級』です。アセンブリ言語は『低級』です。


現代日本では「低級」という、品質の高低との誤解を防ぐためか、たとえば画像処理ソフトの「レイヤー」機能などの画像の重ね合わせ機能の類推からか、「低級」の代わりに「低レイヤー」という場合もあります。


さて、機械語に変換することをアセンブラとは、この機械語周辺の変換機器、変換ソフトウェアのことを言います。

高級プログラム言語をアセンブリ言語に変換したり、あるいはアセンブリ言語を機械語に変換したりする機械・ソフトウェアのことを、アセンブラといいます。


さて、コンピュータは機械語で動いているので、つまり、どんなプログラム言語であっても、そのプログラムを実際に機械語に変換する必要があります。

高級言語を低級言語に変換したり、あるいは高級言語を機械語に変換することを、コンパイルといいます。要するに、C言語やBasicなどで書かれたプログラムのコードを、実際にパソコンで動くアプリケーションにするための作業がコンパイルです。

普通、高級言語から機械語までの変換の順番は、

高級言語 →アセンブリ言語 → 機械後 

の順序で変換しているだろう、とプログラマーたちには考えられています。

つまり、あまり高級言語を直接に機械語に変換することは無いと考えられています。高級言語は、まずアセンブリ言語に変換するのを仲介して、そのあとにアセンブリ言語から機械語に変換するのだろうと、プログラマーたちには考えられています。(ただし真相は不明。なぜなら大手OSメーカー(マイクロソフト社やアップル社などの)が内部仕様を非公開にしているので不明)。


さて、コンパイルをする装置のことをコンパイラといいます。要するに、コンパイラを使えば、C言語やBasicなどで書かれたプログラムのコードが、実際にパソコンで動くようになります。

コンパイルしてなければ、単なる英単語の羅列です。 つまり、けっして、パソコンに「print A」と書いただけで、パソコンは画面にAだけを表示してくれません。

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言語/おわりに』で説明する。

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