今回,Plamo-4.2 Linuxで NASMを使ってアセンブリ言語をやっていきます. Fedora Core5 も並行しなが検証していきますが, 説明は, ほとんど Plamo-4.2 でのアセンブリを対象にしています.『独習アセンブラ』では, 大半がDOSのアセンブリソースについて書いてありLinuxで検証するには本の中だけの説明ではアセンブラの初級者にはチッョト辛いものがあります.実際にソースを Linux 用に書き直し検証しながら現在進行形で進みます.(現在進行形のため途中で文章が修正されるかもしれませんが, 修正部分には訂正の斜線を引いておきます)
# cd /usr/local/src # tar jxvf nasm-0.98.39.tar.bz2 # cd nasm-0.98.39 # ./configure # make # make install ;(私はcheckinstallで入れました)
$ nasm -f elf hello.asm ;(Linux elfファイル形式の指定アセンブル) $ ld -s -o hello hello.o ;(アセンブルでできたオブジェクトファイルのリンク) $ ./hello ;(パスが通ってない場合は ./helloで実行)
※ 『独習アセンブラ』のリスト1.1から書かれているDOSのソースを Linux用に変換して記述していきます.
; dispchar.asmsection .data ; Plamo-4.03 Plamo-4.2 ではこれがないと セグメンテーション違反が発生(本来はセクション用)section .text global _start _start: mov eax, 0x0a31 ; 文字 "1"と改行 push eax ; スタックにバッファを設定 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力 > ディスプレィに表示) mov edx, 2 ; "1"の文字と改行の2文字出力指定 mov ecx, esp ; 書き込むバッファ int 0x80 ; システムコール,出力する pop eax ; push eaxでの eax回収 mov eax, 1 ; sys_exit mov ebx, 0 ; 終了ステータスコード int 0x80 ; システムコール,終了する
; hello.asm
;; アセンブル "nasm -f elf hello.asm "
;; リンク "ld -s -o hello hello.o "
;; 実行 "./hello "
section .data ; データセクションの定義
message db 'Hello, World', 0x0a
length equ $ -message ; 文字列の長さ
section .text
global _start ; エントリーポイント
_start:
mov ecx, message ; 文字列の先頭アドレス
mov edx, length ; 文字列の長さ
mov eax, 4 ; 出力(sys_write)
mov ebx, 1 ; ファイルハンドル(1=標準出力 > ディスプレィに表示)
int 0x80 ; システムコール,出力する
mov eax, 1 ; sys.exit
mov ebx, 0 ; 終了ステータスコード
int 0x80 ; システムコール,終了する
; hello_jmp.asm section .data ; データセクションの定義 message db 'hello, world', 0x0a section .text global _start ; エントリーポイント jmp _main ; ジャンプ _start: mov edx, message ; スタックにバッファを設定 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力 > ディスプレィに表示) _main: mov ecx, message ; 文字列 int 0x80 ; システムコール,出力する mov eax, 1 ; sys.exit mov ebx, 0 ; 終了ステータスコード int 0x80 ; システムコール,終了する
; OnePlusfive.asmsection .data ; Plamo-4.03 Plamo-4.2 ではこれがないとセグメンテーション違反が発生(本来はセクション用)section .text global _start _start: mov eax, 1 ; eaxに"1"を移動 add eax, 5 ; eaxの値に"5"を加える add eax, 0x0a30 ; eaxの値の数の文字コードと改行 push eax ; スタックにバッファを設定 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力) mov edx, 2 ; 1文字出力することを指定 mov ecx, esp ; 書き込むバッファ int 0x80 ; システムコール,出力する pop eax ; eaxの回収 mov eax, 1 ; sys_exit mov ebx, 0 ; 終了ステータスコード int 0x80 ; システムコール,終了する
; hw.asm section .data ; データセクションの定義 message db 'hello, world', 0x0a section .text global _start _start: mov al, [message] ; messageの先頭文字 "h" mov ah, [message+7] ; messageの8番目"w" push eax ; スタックにバッファを設定 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力)mov edx, 3 ; "h""w"の文字と改行の3文字出力指定mov edx, 2 ; 二文字の出力の指定 mov ecx, esp ; 書き込むバッファ int 0x80 ; システムコール,出力する pop eax ; eaxの回収 call newline ; 改行用のcall mov eax, 1 ; sys_exit mov ebx, 0 ; 終了ステータスコード mov 0x80 ; システムコール,終了する newline: ; 以下改行用サブルーチン mov dl, 0x0a ; push edx ; mov eax, 4 mov ebx, 1 mov ecx, esp mov edx, 1 int 0x80 pop edx ret
; xchg.asm
section .data ; データセクションの定義
message db 'Hello, World', 0ah
length equ $ -message ; 文字の長さ
section .text
global _start
_start:
mov edx, length ; 文字列の長
mov cl, [message] ; 以下の3行でmsgとmsg+1の内容を入れ換える
xchg cl, [message+1] ;
mov [message], cl ;
mov ecx, message ; 出力する文字の指定
mov ebx, 1 ; ファイルハンドル(1=標準出力)
mov eax, 4 ; 出力(sys_write)
int 0x80 ; システムコール,出力する
mov eax, 1 ; sys_exit
mov ebx, 0 ; 終了ステータスコード
int 0x80 ; システムコール,終了する
; push_pop.asmsection .datasection .text global _start _start: mov al, 0x31 ; "1" mov ah, 0x0a ; 改行 ;mov eax, 0x0a31 ; pop入れ替え検証用と改行 push edx ; スタックにバッファを設定 push eax ; スタックにバッファを設定 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力) mov ecx, esp ; 書き込むバッファ mov edx, 2 ; 1文字と改行出力の指定 int 0x80 ; システムコール,出力する pop edx ; 普通は pop eaxとする pop eax ; 普通は pop edxとする ; 最初 edxにあった値は eaxに ; 最初 eaxにあった値は edxに入る mov eax, 1 ; sys_exit mov ebx, 0 ; 終了ステータスコード int 0x80 ; システムコール,終了する
; jmp.asm ;; [ Ctrl ]key + [ c ]key で無限ループ解除section .datasection .text global _start _start: label: ; ジャンプの指定場所(無限ループ) mov eax, 0x40 ; @ 記号 push eax ; スタックにバッファを設定 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力) mov ecx, esp ; 書き込むバッファ mov edx, 1 ; 1文字出力することを指定 int 0x80 ; システムコール,出力する pop eax ; eaxの回収 jmp label ; labelへジャンプ mov eax, 1 ; プログラム終了(sys_exit) mov ebx, 0 ; 終了ステータスコード int 0x80 ; システムコール,終了する
; jnz.asmsection .datasection .text global _start _start: mov al, 0x41 ; "A" アルファベット文字 dispchr: ; ジャンプの場所 push eax ; スタックにバッファを設定 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力) mov ecx, esp ; 書き込むバッファ mov edx, 1 ; 1文字出力することを指定 int 0x80 ; システムコール,出力する pop eax ; eaxの回収 inc al ; alをインクリメントする cmp al, 0x5b ; alと0x5bを比べる jnz dispchr ; ZFがゼロならジャンプ call newline ; 改行用のcall mov eax, 1 ; プログラム終了(sys_exit) mov ebx, 0 ; 終了ステータスコード int 0x80 ; システムコール,終了する newline: ; 以下改行用サブルーチン mov dl, 0x0a ; push edx ; mov eax, 4 mov ebx, 1 mov ecx, esp mov edx, 1 int 0x80 pop edx ret
; jecxz.asm
section .data
message db 'Hello, World', 0x0a ; 文字列と改行(LF)
length equ $ -message ; 文字列の長さ
section .text
global _start
_start:
mov ecx, 5 ; 5回カウントする
doit: ; ジャンプの場所
push ecx ; スタックにバッファを設定
mov eax, 4 ; 出力(sys_write)
mov ebx, 1 ; ファイルハンドル(1=標準出力)
mov ecx, message ; 書き込むバッファ
mov edx, length ; 文字列を出力する
int 0x80 ; システムコール,出力する
pop ecx ;※ snowfieldさんのご指摘によりpop ecxを追加 2010/04/24
dec ecx ; ecxを1だけ減らす
jecxz endquit ; ecxがゼロならジャンプ
jmp doit ; doitへジャンプ
endquit:
mov eax, 1 ; プログラム終了(sys_exit)
mov ebx, 0 ; 終了ステータスコード
int 0x80 ; システムコール,終了する
; loop.asm
section .data
message db "Hello, World", 0x0a
length equ $ -message
section .text
global _start
_start:
mov ecx, 5 ; 5回繰り返す
doit: ; ここへloop
push ecx ; スタックにバッファを設定
mov eax, 4 ; 出力(sys_write)
mov ebx, 1 ; ファイルハンドル(1=標準出力)
mov ecx, message ; 文字列の先頭アドレス
mov edx, length ; 文字列の長さ
int 0x80 ; システムコール,出力する
pop ecx ; ecxの回収
loop doit ; doitへloopする
mov eax, 1 ; プログラム終了(sys_exit)
mov ebx, 0 ; 終了ステータスコード
int 0x80 ; システムコール,終了する
; loopdl.asmsection .datasection .text global _start _start: mov al, 0x41 ; "A" アルファベット文字 mov ah, 0x0a ; doit: ; ここへloop push eax ; スタックにバッファを設定 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力) mov ecx, esp ; 書き込むバッファ mov edx, 2 ; 文字出力することを指定 int 0x80 ; システムコール,出力する pop eax inc al ; alをインクリメント cmp al, 0x5b ; alと " [ "を比較する loopne doit ; doitへloopする mov eax, 1 ; プログラム終了(sys_exit) mov ebx, 0 ; 終了ステータスコード int 0x80 ; システムコール,終了する
; loopne.asm
section .data
message db 'Hello,Assembler', 0x0a
length equ $ -message
section .text
global _start
_start:
mov ecx, 5 ; 5回まわす
doit: ; ここへloop
push ecx ; スタックにバッファを設定
mov eax, 4 ; 出力(sys_write)
mov ebx, 1 ; ファイルハンドル(1=標準出力)
mov ecx, message ; 文字列の先頭アドレス
mov edx, length ; 文字列の長さ
int 0x80 ; システムコール,出力する
pop ecx ; ecxの回収
cmp ecx, 3 ; ecxと 3を比較する
loopne doit ; doitへloopする
mov eax, 1 ; プログラム終了(sys_exit)
mov ebx, 0 ; 終了ステータスコード
int 0x80 ; システムコール,終了する
; swapbd.asmsection .datasection .text global _start _start: mov dl, 0x31 ; dl="1" mov bl, 0x41 ; bl="A" mov al, 0x0a ; 改行 call swapbd ; BXとDXの内容を入れ替える push eax ; スタックにバッファを設定 push ebx ; 〃 push edx ; 〃 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力) mov ecx, esp ; 書き込むバッファ mov edx, 0x0a ; 出力と改行指定 int 0x80 ; システムコール.,出力する pop eax ; eaxを回収 pop ebx ; ebx 〃 pop edx ; edx 〃 mov eax, 1 ; プログラム終了(sys_exit) mov ebx, 0 ; 終了ステータスコード int 0x80 ; システムコール,終了する swapbd: ; ebxとedxの内容を入れ替えるサブルーチン push eax ; 現在のeaxの内容を保存しておく mov eax, edx ; mov edx, ebx ; mov ebx, eax ; pop eax ; eaxの内容を復元する ret ;
; putch.asm
section .data
chr db 0
section .text
global _start
_start:
mov [chr], byte 41h ; "A"
call putch
mov [chr], byte 42h ; "B"
call putch
mov [chr], byte 43h ; "C"
call putch
mov eax, 1 ; プログラム終了(sys_exit)
mov ebx, 0 ; 終了ステータスコード
int 0x80 ; システムコール,終了する
putch: ; chrの文字を出力するサブルーチン
mov dl, [chr] ; 出力する文字をdlに移動
push eax ; 現在のeaxの内容を保存する
push edx ; 現在のedxの内容を保存する
mov eax, 4 ; 出力(sys_write)
mov ebx, 1 ; ファイルハンドル(1=標準出力)
mov ecx, esp ; 書き込むバッファ
mov edx, 1 ; 文字出力することを指定
int 0x80 ; システムコール,出力する
pop edx ; edxの内容を復元
pop eax ; eaxの内容を復元
ret
; subprint.asm
section .data
message1 db 'Hello, World', 0x0a
message2 db 'Good, Job', 0x0a
section .text
global _start
_start:
mov edx, message1
call print
mov edx, message2
call print
mov eax, 1 ; プログラム終了(sys_exit)
mov ebx, 0 ; 終了ステータスコード
int 0x80 ; システムコール,終了する
print: ; edxの文字列を出力するサブルーチン
push eax ; 現在のeaxの内容を保存する
mov eax, 4 ; 出力(sys_write)
mov ebx, 1 ; ファイルハンドル(1=標準出力)
mov ecx, message1 ; 文字列出力指定
mov edx, 23 ; 文字と改行の数の指定
int 0x80 ; システムコール,出力する
pop eax ; axの内容を復元
ret
; stack.asmsection .datasection .text global _start _start: mov dl, 0x41 ; "A" push edx call putchar pop edx mov dl, 0x42 ; "B" push edx call putchar pop edx mov dl, 0x0a ; 改行 push edx call putchar pop edx mov eax, 1 ; プログラム終了(sys_exit) mov ebx, 0 ; 終了ステータスコード int 0x80 ; システムコール,終了する putchar: ; スタックの文字を出力する 以下サブルーチン push ebp mov ebp, esp sub esp, 0x4 ; ローカルスタックスベース mov ebx, [ebp+8] ; 最初のパラメータ mov [ebp-4], ebx ; 出力する文字をebpに移動 mov eax, 4 ; 出力(sys_write) mov ebx, 1 ; ファイルハンドル(1=標準出力) mov ecx, esp ; 書き込むバッファ mov edx, 1 ; 文字出力することを指定 int 0x80 ; システムコール,出力する mov esp, ebp ; "sub sp,0x40"を取り消す pop edp ; espの内容を復元 ret
; inpch.asm
section .text
global _start
_start:
push eax ; スタックにバッファを設定
mov eax, 3 ; 入力(sys_read)
mov ebx, 0 ; ファイルデスクリプタ
mov ecx, esp ; 読み込むバッファ
mov edx, 1 ; 読み込むバイト数
int 0x80 ; システムコール,入力する
pop eax ; eaxの復帰
mov eax, 4 ; 出力(sys_write)
mov ebx, 1 ; ファイルハンドル(1=標準出力)
mov ecx, esp ; 書き込むバッファ
mov edx, 1 ; 出力の指定
int 0x80 ; システムコール,出力する
mov eax, 1 ; プログラム終了(sys_exit)
mov ebx, 0 ; 終了ステータスコード
int 0x80 ; システムコール,終了する
; inps.asm
section .text
global _start
_start:
push eax ; スタックにバッファを設定
mov eax, 3 ; 入力(sys_read)
mov ebx, 0 ; ファイルデスクリプタ
mov ecx, esp ; 読み込むバッファ
mov edx, 20 ; 文字列の長さ
int 0x80 ; システムコール,入力する
pop eax
push eax
mov eax, 4 ; 出力(sys_write)
mov ebx, 1 ; ファイルハンドル(1=標準出力)
mov ecx, esp ; 書き込むバッファ
mov edx, 1 ; 出力の指定
int 0x80 ; システムコール,出力する
pop eax
mov eax, 1 ; プログラム終了(sys_exit)
mov ebx, 0 ; 終了ステータスコード
int 0x80 ; システムコール,終了する