1. 序章
今日、コンピュータは0と1で構成されるシーケンスを解釈して処理するだけで、非常に多くのことを実行するという考えが広く普及しています。 しかし、これがどのように機能するかを本当に理解するにはどうすればよいでしょうか。
1949年にElectronicDelayStorage Automatic Calculator(EDSAC)コンピューターに実装されたアセンブリ言語が最初に登場する前は、プログラマーは特定の操作ごとに数値コードを使用してプログラムを開発するという非直感的で徹底的な作業を行っていました。 このチュートリアルでは、アセンブリ言語を紹介します。
詳細に入る前に、プログラミング言語のレベルとコンピューターのアーキテクチャーがどのように見えるかを明確に理解する必要があります。
2. 理論の背景
このようなさまざまなアプリケーションにコンピューターを使用できる理由は、コンピューターが柔軟性があり、さまざまな種類のコードやパラダイムで中央処理装置(CPU)を使用して計算を格納および実行するようにプログラムできるためです。
2.1. プログラミング言語
抽象化とプログラミング言語のレベルを考慮すると、マシンコードの抽象化レベルは可能な限り低くなります。 これは、冒頭で述べた0と1のシーケンスです。 私たち人間は、何が起こっているのかをざっと見て理解することはできません。 反対に、これらの言語はコンピューターによって簡単に理解され、処理されます。
抽象化レベルで一歩進んでみましょう。これで、アセンブリ言語が配置されている低レベルのプログラミング言語ができました。 このレベルでは、より読みやすい一連の命令を使用してコードを作成できます。これらの命令は、大きな数ではなくニーモニックで表されます。 アセンブリコードをマシンコードに変換するには、アセンブラを使用します。
最後に、私たちの生活で使用する自然言語に近い高級プログラミング言語があります。 このグループでは、Java、Python、C++などの言語を見つけることができます。 このレベルで記述されたコードは、言語に応じて、コンパイラーまたはインタープリターによってマシンコードに変換されます。
2.2. コンピュータアーキテクチャ
私たちが使用するコンピューターのほとんどは、メモリユニット、算術/論理ユニット(ALU)、および制御ユニット(CU)を含むジョンフォンノイマンアーキテクチャに従って設計されたプロセッサで構築されています。
プログラムと同じスペースにデータを保存できるというのが主なアイデアです。こうすることで、マシンは両方をスピーディーに操作できるようになります。
メモリユニットにはいくつかのレジスタがあり、CPUが必要な操作を実行するために使用できる高速の一時メモリです。 アセンブリコードを詳しく見ていきます。レジスタを使用して目的の目標を達成する方法が明確になります。
3. コード例
CPUがレジスタの値をどのように変更するかを説明するために、2つの単純なMIPSアセンブリプログラムを、同じ目標を達成する高レベルの実装コードと比較します。
簡単にするためにMIPS言語を選択しましたが、Intel x86、ARM、SPARCなどのいくつかのアセンブリ言語が存在します。
まず、アセンブリコードで syscall メソッドを呼び出すと、システムがレジスタに格納されている内容に応じてアクションを実行することを明確にする必要があります。
アセンブリ用のHelloWorldバージョンから始めましょう。
.text # code section
.globl main # starting point: must be global
main:
li $v0,4 # code 4 loaded on the register v0 indicating that we will print a string
la $a0, msg # the address to the string is loaded on the a0 register
syscall # system routine will call the function to print string
li $v0,10 # code for exit is loaded on register v0
syscall # the syscall will finish the program
.data # data section
msg: .asciiz "Hello World!\n"
次に、HelloWorldアプリケーションのPythonコードバージョンを記述します。
print("Hello World")
2番目のexampleでは、整数を受け取り、1からの合計を返すコードを記述します。したがって、入力が4の場合、4 + 3 + 2 + 1 =であるため、出力は10になります。 10.10。
.text
.globl main
main:
li $v0,4 # code 4 loaded on the register v0 indicating that we will print a string
la $a0, msg1 # the address to the string msg1 is loaded on the a0 register
syscall # system routine is called and the string is printed
li $v0,5 # code 5 loaded to read a value from the user input
syscall
move $t0, $v0 # the value of N is stored on t0
li $t1, 0 # counter i initialized
li $t2, 0 # sum initialized to 0
loop: addi $t1, $t1, 1 # i = i + 1
add $t2, $t2, $t1 # sum = sum + i
beq $t0, $t1, exit # branch if equal: jump to exit if i != N, otherwise continue
j loop # Jump to loop
exit: li $v0, 4 # code 4 loaded on the register v0 indicating that we will print a string
la $a0, msg2 # the address to the string msg2 is loaded on the a0 register
syscall
li $v0,1 # code 1 loaded on the register v0 indicating that we will print a integer
move $a0, $t2 # the address to the sum to be printed is loaded on the a0 register
syscall
li $v0,4 # code 4 loaded on the register v0 indicating that we will print a string
la $a0, lf # the address to the string lf is loaded on the a0 register
syscall
li $v0,10 # exit
syscall
.data
msg1: .asciiz "\nNumber of integers N? "
msg2: .asciiz "\nSum = "
lf: .asciiz "\n"
Pythonでは、次のコードは同じ結果を出力します。
def example(n):
return sum(range(n+1))
n = int(input("Number of integers N? "))
print("Sum = ", example(n))
ループを使用してPythonコードのより複雑なバージョンを作成することもできますが、2つのコードの違いをさらに大きくするために、最後のコードに最適化されたバージョンを選択しました。
4. 結論
アセンブリ言語のみを使用して、3DモバイルゲームやWebページなどの複雑なアプリケーションを開発するのがどれほど難しいかを想像することができます。 2番目の例で見たように、単純なタスクは、高級言語の同じプログラムよりも7倍以上大きい行数のコードで実行されます。
リアルタイムで高性能な要件、または限られた計算能力さえも持つ組み込みシステムとアプリケーションは、通常、リソースを最適化し、CPUで何が起こるかを完全に制御するために、このような低水準言語で設計されます。