異なるサイズのMOV
CoddyのAssemblyジャーニー「基礎」セクションの一部。レッスン 20/45。
すでにal(8ビット)とrax(64ビット)を使いました。でも、ほかのサイズもあります。レジスタによって保持できるデータ量は異なります。
x86-64のレジスタファミリー:
| レジスタ | サイズ | ビット数 | 用途 |
|---|---|---|---|
rax | 8バイト | 64ビット | 完全な数値、アドレス、システムコール番号 |
eax | 4バイト | 32ビット | raxの下位半分 |
ax | 2バイト | 16ビット | eaxの下位半分 |
al | 1バイト | 8ビット | axの下位半分(ビット0~7) |
ah | 1バイト | 8ビット | axの上位半分(ビット8~15) |
同じパターンは他のレジスタにも当てはまります:
| 64ビット | 32ビット | 16ビット | 8ビット(下位) |
|---|---|---|---|
rbx | ebx | bx | bl |
rcx | ecx | cx | cl |
rdx | edx | dx | dl |
rsi | esi | si | sil |
rdi | edi | di | dil |
サイズが重要な理由:
データを移動するときは、コピー元とコピー先のサイズを一致させる必要があります。一致しない場合、CPUは次のような動作をする可能性があります。
- データの一部だけをコピーする
- 不明なメモリから余分なバイトをコピーする
- エラーを引き起こす
サイズが一致する例:
mov rax, 1000 ; 64-bitから64-bitへ(問題なし)
mov eax, 1000 ; 32-bitから32-bitへ(問題なし)
mov ax, 1000 ; 16-bitから16-bitへ(問題なし)
mov al, 5 ; 8-bitから8-bitへ(問題なし)サイズが一致しない場合に起こること:
mov rax, 0x123456789ABC ; 64ビットの値
mov al, 0xFF ; alに0xFFが代入され、raxのほかのビットは変わらない8ビットまたは16ビットのレジスタ(al、ah、ax)への書き込みでは、そのビットだけが変更され、レジスタ全体の残りの部分はそのままです。32ビットレジスタへの書き込みは異なります。mov eax, 0xFFを実行するとビット32~63がクリアされるため、raxは0xFFになります。これにより、予期しない結果が生じることがあります。
安全のためのルール:
これまでのコースでは、メモリ内のデータはすべて1バイトです。そのため、al(raxではなく)を使います。
データを移動するときは、レジスターのサイズをメモリのサイズに合わせる必要があります。
- メモリが1バイトの場合 →
al、bl、clなどを使います。 - メモリが8バイトの場合 →
rax、rbx、rcxなどを使います。
第3章では、さまざまなメモリサイズについて学びます。
チャレンジ
次のデータアドレスはすでに作成されています:
source:1バイトの値(5)を格納destination:空き領域(1バイト)
次の処理を行うアセンブリの2行を書いてください:
sourceから値をalに読み込むalの値をdestinationに格納する
自分で試してみよう
section .data
msg db 'destination = '
msg_len equ $ - msg
section .bss
digit resb 1
section .text
global _start
_start:
; 学生のコードが最初に実行される(sourceから読み込み、destinationに格納する)
%include "solution.asm"
; destinationに格納された値を読み込む
mov al, [destination]
; その値を保存する
mov r12, rax
; "destination = "を出力する
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall
; 値を出力する
mov rax, r12
add rax, 48
mov [digit], al
mov rax, 1
mov rdi, 1
mov rsi, digit
mov rdx, 1
syscall
; 終了する
mov rax, 60
mov rdi, 0
syscallこのレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
基礎のすべてのレッスン
自分で練習してみよう: Assemblyプレイグラウンド