Hello World

1. はじめに

まずは最初に定番のHello Worldにしたいと思います。一文字づつASCIIコードから・・・としたいところですが、もう少し簡単に出力する内容から始めます。

2. Hello World

まずはソースコードを紹介します。

コメント行)
”;“で始まる行は、行末まではコメント行となりまして、実行されません。
ファイルの先頭にはファイル名とLinux上での実行方法を記載しています。

コマンド)
$nasm :『アセンブリ』ファイルを『アセンブラ』してオブジェクトファイルを作成します。
$ld : 実行可能ファイルを作成します。

2.1. 変数の宣言(section .data)

section .data は変数宣言をしています。

hlw は変数名です。そして、
db は、データサイズです。dbは8bit(1byte)、dwは16bit(2byte)、ddは32bit(4byte)、dqは64bit(8byte)を表します。
文字列を宣言する事ができ、『0x0a』は”0x”は16進数である事を表現しており、”0a”はASCIIコードで改行を表現します。 文字列と0x0aの間のカンマは出力されません。あくまで”!“と”0x0a”はつながってます。

2.2. 処理部分の宣言(section .text)

19行目のglobal で始まる箇所プログラムの実行開始位置です。”start”と言うラベルからプログラムが始まっています。
22行目のsys_write の行は、『出力する』ためのコマンド(=1)を『rax』と言うレジスタと呼ばれる箱に設定しています。
23行目のstdoutの行は、『どこに出力』するかを『rdi』と言うレジスタに設定しています。

mov rsi の行は、『Hello World!0x0a』を定義したメモリの最初の番地をレジスタ『rsi』に設定します。
mov rdx,13 は『Hello World!』(ASCIIコードでは1文字1byteのため)12byteと改行(0x0a)の1byteを足した13byteを設定します。
syscall で『出力する』コマンドが実行されます。

31行目の『exit』のラベルの次は、レジスタ『rax』に『終了する』ためのコマンド(=60)を設定します。
レジスタ『rdi』には正常である事を伝える0(=Success)を設定します。syscallで『終了』が実行されます。

実行すると

$Hello World!

が表示されます。

3. 1行ずつ実行

プログラムは一瞬で実行されます。1行づつ実行を確認しながらみるために、デバッグ用のツールを利用します。
gdbでブレイクポイントを設定するため、

global _start
_start

の2行を

global main
main

に変更します。

また実行するためのコマンドは以下のようになります。

$nasm -f elf64 hello_world64.asm
$gcc -o hello_world64 hello_world64.o
$gdb hello_world64
GNU gdb (Ubuntu X.X.X-Xubuntu・・・)
(省略)
(gdb)

と表示されるとデバッグ可能な状態になります。

(gdb)break main

と実行して、ブレイクポイント(停止箇所)を設定します。

(gdb)run
starting program: /home/XXXXX/XXXXX/hellow_word64
Breakpoint 1, 0x000000099999 in main ()
(gdb)

と表示されます。

(gdb)info registers

このコマンドを実行することでレジスターの値に何が入っているかが確認可能です。

info registers result

(gdb)stepi
0x0000000000004004f5   in main()
(gdb)info registers
(省略)

また、stepiで1行ずつ実行して、info registersで各レジスタの値を確認できます。