トラック
/
Lean
Lean
/
演習
/
アセンブル
アセンブル

アセンブル

上級

説明

この演習では、x86-64アセンブリ言語にヒントを得た小さな言語の構文と実行モデルを定義します。

目標は、制約された環境の中でコードがどのように書かれ、解析され、実行されるかを定式化することです。

実行モデル

アセンブリのコードは、特別な構文の中に書きます。

let program := assemble!(
    -- assembly code here
)

この構文は、アセンブリのコードを実行して値を返す関数を模したプログラムを生成しなければなりません。 このプログラムは、次の構文で呼び出します。ここでa、b、cなどは引数です。

let result := program(a, b, c, ...)

引数と戻り値はすべて_64ビットの符号付き整数_です。 引数は最大_6個_までです。

レジスタ

戻り値とすべての引数はレジスタで渡されます。 この言語では、次のレジスタを扱えるようにします。

レジスタ 役割
rdi 1番目の引数
rsi 2番目の引数
rdx 3番目の引数
rcx 4番目の引数
r8 5番目の引数
r9 6番目の引数
rax 戻り値

レジスタの初期値は0です。ただし、関数に引数を渡すために使われる場合は除きます。

たとえば次のプログラムでは、rdiが10、rsiが-20で初期化され、それ以外のレジスタはすべて0です。

program(10, -20)

プログラムの戻り値は常にraxに格納されます。

Note

レジスタ名は_大文字と小文字を区別しません_。 つまり、rax、RAX、rAxはすべて同じレジスタを指します。

アセンブリのコード

アセンブリのコードの各行は、次の2つの形式のいずれかです。

  • ラベルは、一部の命令が使うプログラム内の特定の位置を示します。
  • 命令は、プログラムが実行する操作を表します。

何らかの命令で変更されない限り、プログラムの実行の流れは上から順に進みます。 つまり、ある行の実行が完全に終わってから、その次の行が実行されます。

ラベル

ラベルは次の構文で書きます。

<label>:

ラベルはどのレジスタの値も変えません。命令から使えるようにコード内の特定の位置を示す以外に、プログラムに影響を与えることはありません。

Note

ラベルは_大文字と小文字を区別します_。 つまり、Start、start、sTartはすべて異なるラベルです。

2オペランド命令

ほとんどの命令は次の構文で書きます。

<opcode> <destination>, <source>

opcodeは実行する操作を表し、destinationとsourceのオペランドの値を使います。 操作の結果はdestinationオペランドに格納されます。

たとえばadd命令は、destinationとsourceのオペランドの値を足し、その結果をdestinationオペランドに格納します。

destinationオペランドは_常に_レジスタですが、sourceオペランドはレジスタまたはリテラルの数値です。

プログラムが扱えるようにする命令は次のとおりです。

オペコード 実行される操作
mov destination := source
add destination := destination + source
sub destination := destination - source
mul destination := destination * source
div destination := destination / source
xor destination := destination ^^^ source
and destination := destination &&& source
or destination := destination ||| source
shl destination := destination <<< source
shr destination := destination >>> source

これらに加えて、2オペランドのcmp命令も扱えるようにします。

この命令はどのレジスタも変更しません。代わりにdestinationとsourceのオペランドを比較し、プログラムの内部状態を次の3つのいずれかに設定します。

  • destination > sourceのとき、より大きい
  • destination == sourceのとき、等しい
  • destination < sourceのとき、より小さい

この状態を内部的にどう保持するかは自由です。

1オペランド命令

プログラムの流れを変え、実行をコードの別の位置に移す命令があります。 これらは_ジャンプ_命令と呼ばれます。

いずれもオペランドを1つだけ取ります。これはジャンプ先、つまり実行を続けるコード上の位置を示すラベルです。

<opcode> <label>

jmp命令は_常に_、対象のラベルへジャンプします。

その他のジャンプ命令は、プログラムの内部状態が特定の値に設定されているときだけジャンプします。 そのため、通常はcmp命令の後に続きます。

プログラムが扱えるようにするジャンプ命令は次のとおりです。

命令 実行される操作
jmp 無条件ジャンプ。常にジャンプします
je 内部状態が_等しい_ときにジャンプします
jl 内部状態が_より小さい_ときにジャンプします
jg 内部状態が_より大きい_ときにジャンプします
Note

命令のオペコードは、2オペランドでも1オペランドでも、大文字と小文字を区別しません。 つまり、add、ADD、aDdはすべて同じ命令を指します。

GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
Lean Exercism

アセンブルを始める準備はできましたか?

Exercismに登録すれば、100個の演習、そして本物の人間によるメンタリングとともに、Leanを学んでマスターできます。すべて無料です。