Practice1 Explanation - GawinGowin/libasm GitHub Wiki

Practice1: Hello World プログラムの詳細解説

課題文

目標: x86-64アセンブリ言語を使って「Hello, World!」を標準出力に表示するプログラムを作成する

要件:

  1. NASMアセンブラを使用してx86-64アセンブリで実装
  2. システムコールを使用して標準出力に文字列を出力
  3. プログラムは正常に終了すること
  4. 出力する文字列は「Hello, World!」+ 改行文字

ファイル名: practice1.s

コンパイル・実行手順:

nasm -f elf64 practice1.s -o practice1.o
ld practice1.o -o practice1
./practice1

期待する出力:

Hello, World!

なぜこの練習を行うのか

学習目的

  1. アセンブリの基本構造理解

    • セクション(.data, .text)の概念
    • プログラムエントリポイント(_start)の理解
    • 基本的なアセンブリファイル構造の習得
  2. システムコールの基礎

    • Linux システムコールの呼び出し方法
    • レジスタを使った引数渡し
    • システムコール番号の理解
  3. 開発環境の確認

    • NASM アセンブラの使用方法
    • リンカの動作確認
    • 実行可能ファイルの生成プロセス

コード詳細解析

; practice1.s - Hello World
section .data
    msg db 'Hello, World!', 0xA
    len equ $ - msg

section .text
    global _start

_start:
    ; write システムコール
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, len
    syscall
    
    ; exit システムコール
    mov rax, 60
    mov rdi, 0
    syscall

セクション構造の解説

.data セクション

section .data
    msg db 'Hello, World!', 0xA  ; 文字列データ + 改行文字
    len equ $ - msg              ; 文字列の長さを計算

重要なポイント:

  • db (define byte): 1バイトずつデータを定義
  • 0xA: 改行文字(LF: Line Feed)
  • $: 現在の位置を示すシンボル(アセンブラが現在のメモリアドレスを表す)
  • equ: 定数定義(アセンブル時に計算される)

$ - msgの詳細説明:

  • $: 現在の位置(この行の位置)のアドレス
  • msg: 文字列の開始アドレス
  • $ - msg: 現在位置から文字列開始位置を引く = 文字列の長さ(バイト数)

なぜ長さが計算できるのか: dbは1バイトずつデータを定義するため、文字列の各文字が順番にメモリに配置されます:

アドレス  データ     説明
0x1000   'H'        msg のアドレス (開始位置)
0x1001   'e'        
0x1002   'l'        
...      ...        
0x100D   0xA        改行文字
0x100E   ←          $ (len行の現在位置)

結果: $ - msg = 0x100E - 0x1000 = 14バイト = 文字列の長さ

.text セクション

section .text
    global _start

役割:

  • 実行可能コードを格納
  • global _start: リンカに_startラベルを公開
  • _start: プログラムのエントリポイント

システムコール詳細

writeシステムコール

mov rax, 1      ; システムコール番号 (sys_write)
mov rdi, 1      ; ファイルディスクリプタ (stdout)
mov rsi, msg    ; バッファのアドレス
mov rdx, len    ; 書き込むバイト数
syscall         ; システムコール実行

レジスタの役割:

  • rax: システムコール番号(1 = sys_write)
  • rdi: 第1引数(ファイルディスクリプタ)
  • rsi: 第2引数(バッファポインタ)
  • rdx: 第3引数(バイト数)

exitシステムコール

mov rax, 60     ; システムコール番号 (sys_exit)
mov rdi, 0      ; 終了ステータス (0 = 正常終了)
syscall         ; システムコール実行

学習効果

この練習で身につくスキル

  1. 基本的なアセンブリ構文

    • セクション分け
    • ラベルの使用
    • 命令の書き方
  2. システムプログラミングの基礎

    • システムコールインターフェース
    • ファイルディスクリプタの概念
    • 標準出力への書き込み
  3. 開発フロー

    • アセンブル → リンク → 実行の流れ
    • デバッグの基本手順

よくある間違いと対処法

1. リンクエラー

# 間違い: global _start が未定義
ld: warning: cannot find entry symbol _start

対処法: global _start を必ず記述

2. セグメンテーションフォルト

# 原因: exit システムコールの省略
Segmentation fault (core dumped)

対処法: プログラム終了時に必ずexitシステムコールを呼ぶ

3. 出力されない

# 原因: 長さ計算の間違い
len equ msg - $  ; これは間違い
len equ $ - msg  ; これが正しい

次のステップへの準備

この練習を完了すると:

  • アセンブリファイルの基本構造が理解できる
  • システムコールの呼び出し方法がわかる
  • 開発環境が正しく設定されていることが確認できる

これらの基礎知識は、次のPractice2(数値計算)で必要となります。