アセンブリ言語

アセンブリ言語とは、コンピュータに何をすべきかを直接指示することができるプログラミング言語のことです。アセンブリ言語は、コンピュータが理解できるマシンコードとほぼ同じですが、数字の代わりに単語を使用しています。コンピュータはアセンブリプログラムを直接理解することはできません。しかし、プログラムの単語をその単語が表す数字に置き換えることで、プログラムを簡単にマシンコードに変えることができます。そのようなプログラムをアセンブラと呼びます。

アセンブリ言語で書かれたプログラムは、通常、命令で構成されており、プログラムを実行しているときにコンピュータが実行する小さなタスクです。プログラマがコンピュータに何をすべきかを指示するために命令を使用するため、命令と呼ばれています。命令に従うコンピュータの部分がプロセッサです。

コンピュータのアセンブリ言語は低レベルの言語であり、コンピュータが直接理解できる単純なタスクを行うためにしか使用できないことを意味します。より複雑なタスクを実行するためには、複雑なタスクの一部である単純なタスクをそれぞれコンピュータに伝えなければなりません。例えば、コンピュータは画面に文章を印刷する方法を理解していません。むしろ、アセンブリで書かれたプログラムは、文章を印刷するための小さなステップをすべて行う方法をコンピュータに伝えなければならない。

このようなアセンブリプログラムは、多数の命令で構成されており、人間にとっては非常に単純で基本的なことを行うことができます。このため、人間がアセンブリプログラムを読むことは困難です。対照的に、高レベルのプログラミング言語では、PRINT "Hello, world!"のような単一の命令で構成されている場合がありますが、これはコンピュータに小さなタスクをすべて実行するように指示します。

アセンブリ言語の開発

コンピュータ科学者が最初にプログラム可能な機械を作ったとき、彼らは直接機械語でプログラムしました。機械語を書くのは非常に難しく、時間もかかったので、最終的にはアセンブリ言語が作られました。アセンブリ言語の方が人間にとっては読みやすく、速く書くことができますが、それでも人間の言語を真似しようとする高レベルのプログラミング言語に比べれば、はるかに使いにくいのです。

マシンコードでのプログラミング

マシンコードでプログラムするには、プログラマーは各命令が2進法(または16進法)でどのように見えるかを知る必要があります。コンピュータがマシンコードの意味をすぐに理解するのは簡単ですが、プログラマーにとっては難しいことです。それぞれの命令にはいくつかの形式があり、そのすべてが人間には数字の束のように見えます。マシンコードを書いているときに誰かがミスをしても、コンピュータが間違ったことをしたときにしか気づかない。ほとんどの人はマシンコードを見ただけでは何を意味しているのか分からないので、間違いを発見するのは難しい。マシンコードがどのようなものかの例。

05 2A 00

この16進数のマシンコードは、x86コンピュータのプロセッサに、アキュムレータに42を足すように指示します。マシンコードを知っている人でも、これを読んで理解するのは非常に難しい。

アセンブリ言語の代わりに使用する

アセンブリ言語では、各命令はニーモニックと呼ばれる短い単語として書かれ、その後に数字などの他のものが続きます。ニーモニックは、プログラマがコンピュータに何かをするように指示するために必要なマシンコードの正確な数字を覚えておく必要がないように使用されます。アセンブリ言語のニーモニックの例としては、データを追加する add、データをある場所から別の場所に移動する mov などがあります。ニーモニック」は一般的ではない言葉なので、命令タイプや単なる命令というフレーズが代わりに使われることもありますが、間違って使われることもしばしばあります。最初の単語の後に続く単語や数字は、何をするかについてのより多くの情報を与えます。例えば、add に続くものは、何を二つのものを一緒に追加するか、mov に続くものは、何を移動するか、どこに置くか、ということです。

例えば、前節(05 2A 00)のマシンコードは、アセンブリでは次のように書くことができます。

,42追加します。

アセンブリ言語は、プログラマーが実際にプログラムが使用するデータをより簡単に記述することも可能です。ほとんどのアセンブリ言語は、数字とテキストを簡単に作成するためのサポートを持っています。マシンコードでは、正、負、10進数のような異なるタイプの数字は、それぞれ手動で2進数に変換しなければならず、テキストは数字として一度に1文字ずつ定義しなければなりませんでした。

アセンブリ言語は、マシンコードの抽象化と呼ばれるものを提供します。アセンブリを使用する場合、プログラマーは数字がコンピュータにとってどのような意味を持つのかの詳細を知る必要はなく、アセンブラがそれを計算してくれます。アセンブリ言語では、プログラマはマシンコードで使用できるプロセッサのすべての機能を使用することができます。この意味で、アセンブリ言語は非常に優れた稀有な特徴を持っています:抽象化しているもの(マシンコード)と同じ表現能力を持ちながら、はるかに使いやすくなっています。そのため、マシンコードがプログラミング言語として使われることはほとんどありません。

分解とデバッグ

プログラムが完成したとき、プログラムはすでにマシンコードに変換されているので、プロセッサが実際に実行できるようになっています。しかし、プログラムにバグ(間違い)がある場合、プログラマーはマシンコードの各部分が何をしているのかを知ることができるようにしたいと思うことがあります。ディスアセンブラは、プログラムのマシンコードをはるかに理解しやすいアセンブリ言語に変換することで、プログラマーがそのようなことをするのを助けるプログラムです。マシンコードをアセンブリ言語に変換するディスアセンブラは、アセンブリ言語をマシンコードに変換するアセンブラとは逆のことをします。

コンピュータ組織

コンピュータがどのように構成されているか、非常に低いレベルでどのように動作しているように見えるかを理解することは、アセンブリ言語プログラムがどのように動作するかを理解するために必要です。最も単純なレベルでは、コンピュータには3つの主要な部分があります。

  1. データや命令を保持するメインメモリまたはRAM。
  2. 命令を実行してデータを処理するプロセッサと
  3. 入力と出力(I/Oと略されることもあります)は、コンピュータが外部と通信し、メインメモリの外にデータを保存して、後でデータを取り戻せるようにするものです。

主なメモリ

ほとんどのコンピュータでは、メモリはバイトに分割されています。各バイトには8ビットが含まれています。また、メモリ内の各バイトにはアドレスがあり、これはそのバイトがメモリ内のどこにあるかを示す数字です。メモリ内の最初のバイトは0のアドレスを持ち、次のバイトは1のアドレスを持ちます。メモリをバイトに分割すると、各バイトが一意のアドレスを取得するため、バイトアドレスが可能になります。バイトメモリのアドレスは、バイトの1ビットを参照するために使用することはできません。バイトは、アドレスを指定できるメモリの最小の部分です。

アドレスはメモリ内の特定のバイトを指しますが、プロセッサはメモリの数バイトを一列に並べて使用することができます。この機能の最も一般的な使用法は、2 バイトまたは 4 バイトを一列に並べて数値(通常は整数)を表現することです。シングルバイトも整数を表すために使用されることがありますが、8ビットの長さしかないため、28または256の異なる値を保持することができます。1 行に 2 バイトまたは 4 バイトを使用すると、可能な値の数はそれぞれ 216、65536、または 232、4294967296 になります。

プログラムが文字や数字、その他の何かを表すためにバイトや複数のバイトを一列に並べて使用する場合、それらのバイトはすべて同じものの一部であるため、オブジェクトと呼ばれます。オブジェクトはすべて同じメモリのバイトに格納されているにもかかわらず、それらは「型」を持っているかのように扱われ、バイトがどのように理解されるべきかを示します。マシンコードもまた、命令として解釈される型と考えることができます。型の概念は、オブジェクトに何ができて何ができないのか、オブジェクトのバイトをどのように解釈するのかを定義するので、非常に重要です。例えば、正数オブジェクトに負数を格納することは無効ですし、整数オブジェクトに分数を格納することは無効です。

マルチバイトオブジェクトを指す(そのアドレスである)アドレスは、そのオブジェクトの最初のバイト、つまりアドレスが最も低いバイトへのアドレスです。余談ですが、一つ注意すべき重要なことは、オブジェクトのアドレスからは、オブジェクトのタイプやサイズを知ることはできないということです。実際、オブジェクトを見ただけでは、そのオブジェクトがどのような型なのかを知ることすらできません。アセンブリ言語のプログラムは、どのメモリアドレスにどのオブジェクトが格納されているか、そのオブジェクトがどのくらいの大きさなのかを追跡する必要があります。このようなプログラムは、オブジェクトの型が安全なものだけを実行するので、型安全です。そうでないプログラムは、おそらく正しく動作しません。ほとんどのプログラムは、オブジェクトの型を明示的に記憶しているわけではなく、一貫してオブジェクトにアクセスしているだけであることに注意してください。

プロセッサ

プロセッサは命令を実行(実行)し、それはマシンコードとしてメインメモリに格納されます。ほとんどのプロセッサは、メモリにアクセスして記憶することができるだけでなく、現在処理中のオブジェクトを保持するための、小さくて高速な固定サイズのスペースをいくつか持っています。これらのスペースはレジスタと呼ばれています。プロセッサは通常、3種類の命令を実行しますが、中にはこれらを組み合わせた命令もあります。以下に x86 アセンブリ言語における各タイプの例を示します。

メモリを読み書きする命令

次の x86 アセンブリ言語命令は、アドレス 4096 (16 進数では 0x1000) のバイトから、2 バイトのオブジェクトを 'ax' と呼ばれる 16 ビットのレジスタに読み出す (ロードする)。

        mov ax, [1000h]

このアセンブリ言語では、数字(またはレジスタ名)の周りの角括弧は、その数字を使用すべきデータへのアドレスとして使用することを意味します。データを指すためにアドレスを使用することをインダイレクトと呼びます。この次の例では、角括弧を使用せずに、別のレジスタ bx に実際に値 20 が読み込まれています。

        mov bx, 20

インダイレクトを使用していないため、実際の値そのものをレジスタに入れています。

オペランド (ニーモニックの後に来るもの) が逆順に現れる場合、メモリから何かをロードする命令は、それをメモリに書き込む代わりに、メモリから何かをロードします。

        mov [1000h], ax

ここでは、アドレス 1000h のメモリは ax の値を取得します。この例が前の例の直後に実行された場合、1000hと1001hの2バイトは20の値を持つ2バイトの整数になります。

数学的または論理的な演算を行う命令

引き算のようなことをする命令もあれば、しないような論理演算をする命令もあります。

この記事の前のマシンコードの例は、アセンブリ言語ではこのようになります。

        軸を追加します

ここでは、42とaxを足し合わせて、その結果をaxに戻します。x86アセンブリでは、このようにメモリアクセスと数学演算を組み合わせることも可能です。

        軸を追加, [1000h]

1000h に格納されている 2 バイト整数の値を ax に加算し、その答えを ax に格納します。

        またはax, bx

この命令は、レジスタ ax と bx の内容の OR を計算し、その結果を ax に格納します。

次の指示を決める指示

通常、命令はメモリに現れた順に実行されますが、これはアセンブリコードにタイプされた順です。プロセッサは、それらの命令を次々と実行するだけです。しかし、プロセッサが複雑なことをするためには、与えられたデータが何であるかに応じて異なる命令を実行する必要があります。プロセッサが何かの結果に応じて異なる命令を実行する能力を分岐と呼ぶ。次の命令をどうするかを決める命令を分岐命令と呼ぶ。

この例では、ある辺の長さの正方形を塗るのに必要な塗料の量を計算したいとします。しかし、規模の経済性を考慮して、100×100の正方形を塗るのに必要な塗料の量よりも少ない塗料は売ってくれません。

塗りたい正方形の長さに基づいて必要な塗料の量を把握するために、彼らはこのステップのセットを思いつきます。

  • 辺の長さから100を引く
  • 答えが0よりも小さい場合は、辺の長さを100に設定します。
  • 辺の長さを自乗する

このアルゴリズムは、axが辺の長さである次のコードで表現できます。

        mov bx, ax     サブBX         JGE継続する    mov ax, 100 continue. マルチアクス

この例ではいくつかの新しいものが紹介されていますが、最初の2つの命令はおなじみです。axの値をbxにコピーし、bxから100を引きます。

この例の新しいものの一つはラベルと呼ばれるもので、一般的にアセンブリ言語に見られる概念です。ラベルはプログラマが望むものであれば何でも構いません(命令の名前でない限り、アセンブラを混乱させることになります)。この例では、ラベルは 'continue' です。これはアセンブラによって命令のアドレスとして解釈されます。この例では mult ax のアドレスです。

もう一つの新しい概念は、フラグの概念である。x86プロセッサでは、多くの命令がプロセッサ内に「フラグ」を設定し、次の命令が何をするかを決定する際に使用することができます。この場合、bxが100より小さかった場合、subは結果が0より小さかったというフラグを設定します。

次の命令は jge で、'Jump if Greater than or Equal to' の略です。これは分岐命令です。プロセッサのフラグが結果がゼロ以上であることを指定した場合、次の命令に進むのではなく、継続ラベルの命令にジャンプします。

この例は正常に動作しますが、ほとんどのプログラマが書くようなものではありません。減算命令は正しくフラグをセットしていますが、操作する値を変更しているため、axをbxにコピーする必要がありました。ほとんどのアセンブリ言語では、渡された引数を変更せずに、それでも正しくフラグを設定する比較命令が可能であり、x86アセンブリも例外ではありません。

        CMP100      JGE継続する    mov ax, 100 continue. マルチアクス

今、axから100を引き算して、その数が0より小さいかどうかを見て、それをaxに代入するのではなく、axは変更されていないままになっています。フラグの設定も同じで、ジャンプも同じ状況で行われます。

入力と出力

入力と出力はコンピューティングの基本的な部分ですが、アセンブリ言語で行われる方法は一つではありません。これは、I/Oがどのように動作するかは、どのようなプロセッサを搭載しているかだけでなく、コンピュータのセットアップや実行しているオペレーティングシステムに依存するからです。例のセクションでは、Hello Worldの例ではMS-DOSのオペレーティングシステムの呼び出しを使用し、その後の例ではBIOSの呼び出しを使用しています。

アセンブリ言語でI/Oを行うことは可能です。確かに、アセンブリ言語は一般的にコンピュータができることは何でも表現できます。しかし、アセンブリ言語には常に同じことをする追加や分岐の命令があっても、アセンブリ言語には常にI/Oをする命令はありません。

注意すべき重要なことは、I/Oがどのように動作するかは、プロセッサがどのように動作するかの一部ではないので、どのようなアセンブリ言語にも含まれていないということです。

アセンブリ言語と移植性

アセンブリ言語が直接プロセッサによって実行されているわけではないにもかかわらず - マシンコードは実行されています。各プロセッサファミリは、それぞれ異なる機能、命令、命令が何をすることができるかのルール、どのような命令の組み合わせがどこで許されるかのルールをサポートしています。このため、異なるタイプのプロセッサには、依然として異なるアセンブリ言語が必要とされています。

アセンブリ言語の各バージョンはプロセッサファミリーに縛られているため、移植と呼ばれるものが欠けています。移植性があるもの、あるいは移植性があるものは、あるタイプのコンピュータから別のタイプのコンピュータに簡単に転送することができます。他のタイプのプログラミング言語は移植性がありますが、アセンブリ言語は一般的に移植性がありません。

アセンブリ言語とハイレベル言語

アセンブリ言語は、プロセッサのすべての機能を簡単に使用することができますが、いくつかの理由から、現代のソフトウェアプロジェクトでは使用されていません。

  • 簡単なプログラムをアセンブリで表現するのは手間がかかります。
  • マシンコードほどエラーが発生しやすい言語ではありませんが、アセンブリ言語ではエラーに対する保護はまだほとんどありません。ほとんどすべてのアセンブリ言語は型の安全性を強制していません。
  • アセンブリ言語は、モジュール化のような優れたプログラミングの実践を促進しません。
  • 個々のアセンブリ言語命令はわかりやすいが、それを書いたプログラマの意図が何なのかはわかりにくい。実際、プログラムのアセンブリ言語は非常に理解しにくいため、企業は人々が自分のプログラムを分解する(アセンブリ言語を手に入れる)ことを心配していません。

これらの欠点の結果、Pascal、C、およびC++のような高レベル言語が、ほとんどのプロジェクトで代わりに使用されています。これらの言語を使用することで、プログラマはプロセッサに何をすべきかを逐一指示することを気にする必要がなく、より直接的にアイデアを表現することができます。高レベルと呼ばれるのは、プログラマが同じ量のコードで表現できるアイデアがより複雑になるからです。

コンパイルされた高レベル言語でコードを書くプログラマは、コンパイラと呼ばれるプログラムを使って自分のコードをアセンブリ言語に変換します。コンパイラはアセンブラに比べて書くのが大変です。また、高レベル言語は、プログラマがプロセッサのすべての機能を使用できるとは限りません。これは、高レベル言語がすべてのプロセッサファミリをサポートするように設計されているからです。1種類のプロセッサしかサポートしないアセンブリ言語とは異なり、高レベル言語は移植性に優れています。

コンパイラはアセンブラよりも複雑ですが、何十年にもわたってコンパイラを作り、研究してきた結果、非常に優れたものになりました。今では、ほとんどのプロジェクトでアセンブリ言語を使う理由はあまりありません。

プログラム例

x86アセンブリで書かれたハローワールドプログラム。

adosseg .model small .stack 100h .data hello_message db 'Hello, World!',0dh,0ah,'$' .code main proc mov ax,@data mov ds,ax mov ah,9 mov dx,offset hello_message int 21h mov ax,4C00h int 21h main endp end main

NASM x86アセンブリで書かれたBIOS割り込みを使って、画面に数字を表示する機能。モジュラーコードはアセンブリで書くことができますが、余分な労力がかかります。行のセミコロンの後に来るものはコメントであり、アセンブラでは無視されることに注意してください。アセンブリ言語のコードにコメントをつけることは非常に重要です。

; void printn(int number, int base); printn. プッシュ BP    ムーヴ  BPSP       押す             押す    BX    押す    CX    押す    ディーエックス    押す         ムーヴ      si, 0   ムーヴ  , [bp + 4]         ムーヴ  cx, [bp + 6]   ; ベースのgloop. inc                      ; 文字列の長さ   ムーヴ  dx, 0          ゼロdx かみ    CX            ベースで割る     センチメント     ディーエックス           ; ge 10ですか? jge          付け足す dx, '0'        ; dxにゼロを追加します。 跳ねっ返り       anum num.      追加        dx, ('A'-10)   ; 16進数の値は、dx - 10'A'を追加します プッシュ ディーエックス           ; dxをスタックに置く。    cmp  アックス0             続けるべきか?    じゅね  グループ    ムーヴ  ビーエックス             ; 割込みのtloopに使用します。     ポップ                ; その値を取得します。    ムーヴ  嗚呼            割り込みのために インスタント     10h               書込み文字       衰退                  文字を取り除く    jnz  トゥループ          ポップ       ポップ  ディーエックス    ポップ  CX    ポップ  BX    ポップ          ポップ  BP    後退者  4

質問と回答

Q:アセンブリ言語とは何ですか?


A:アセンブリ言語とは、コンピュータに直接指示を出すことができるプログラミング言語です。コンピュータが理解できる機械語コードとほぼ同じですが、数字の代わりに単語を使用している点が異なります。

Q:コンピュータはどのようにしてアセンブリプログラムを理解するのですか?


A:コンピュータはアセンブリプログラムを直接理解することはできませんが、プログラムの単語をそれが表す数字に置き換えることで、プログラムを機械語に変えることは簡単にできます。この作業は、アセンブラを使って行われます。

Q:アセンブリ言語の命令とは何ですか?


A:アセンブリ言語の命令は、コンピュータがプログラムを実行する際に行う小さな作業です。コンピュータに何をすべきかを指示するため、命令と呼ばれています。この命令を実行するコンピュータの部分をプロセッサと呼びます。

Q:アセンブリ言語とはどのようなプログラミング言語ですか?


A:アセンブリ言語は低レベルのプログラミング言語です。つまり、コンピュータが直接理解できるような単純な作業にしか使えません。より複雑な作業を行うためには、各作業を個々の構成要素に分解し、それぞれの構成要素に対して個別に指示を与える必要があります。

Q:高級言語とどう違うのですか?


A:高級言語では、PRINT "Hello, world!"のような単一のコマンドで、アセンブリプログラムのように個別に指定しなくても、それらの小さなタスクをすべて自動的に実行するようにコンピュータに指示することができます。このため、多くの命令からなるアセンブリプログラムよりも、高級言語の方が人間にとって読みやすく、理解しやすいのです。

Q:なぜ、人間がアセンブリプログラムを読むのは難しいのでしょうか?


A:画面に何かを印刷したり、データに対して計算をしたりといった、人間の言葉で表現すると非常に基本的で単純に見えるような複雑な作業を行うためには、個々の命令をたくさん指定しなければならないので、一つの命令を構成するコードの行数が多くなり、コンピュータが内部でどのように動いているかを知らない人間が、その中で起こっていることを解釈してついていくことが難しくなるからです。

AlegsaOnline.com - 2020 / 2023 - License CC3