アセンブリ言語 入門
アセンブリ言語の概要
1週間で学ぶIT基礎の基礎 - 【5分で覚えるIT基礎の基礎】だれでも一度はアセンブラを学んでおこう!---目次:ITpro
http://itpro.nikkeibp.co.jp/article/COLUMN/20061215/257090/
アセンブリ言語入門
http://wisdom.sakura.ne.jp/programming/asm/
アセンブラ入門
http://www5c.biglobe.ne.jp/~ecb/assembler/assembler00.html
ざっくりアセンブラ入門 - Qiita
https://qiita.com/kazukichi/items/201b0c7fdf3d3aa576c7
アセンブラに手を出してみる - Qiita
https://qiita.com/edo_m18/items/83c63cd69f119d0b9831
アセンブリに触れてみよう - Qiita
https://qiita.com/kaito_tateyama/items/89272098f4b286b64115
アセンブラをゼロから作って自作コンパイラをアセンブルするまで(日記)
https://zenn.dev/dqneo/articles/012faee0b220fa
アセンブラへの道 - Qiita
https://qiita.com/kaizen_nagoya/items/46f2333c2647b0e692b2
アセンブラへの道(2) - Qiita
https://qiita.com/kaizen_nagoya/items/2a0bd88216bc51278be5
以降のメモでは、主に以下のページを参考にしている
Linuxをはじめよう!:アセンブリをやってみよう! 0x100
http://blog.livedoor.jp/hiroumauma/archives/1385003.html
アセンブリ言語 メモ
■機械語(マシン語)
CPUが理解できる、2進数の命令(電気信号の高低)
具体的には以下のようなコード
01010101 10001001 11100101
桁が多くなりすぎて人間には読みづらいため、通常は16進数で扱う
55 89 e5
■アセンブリ
アセンブリ … アセンブリ言語のこと
アセンブラ … アセンブリ言語を機械語に翻訳する処理系のこと
アセンブル … アセンブリ言語を機械語に翻訳すること
機械語とアセンブリの命令は一対一なので、単純に以下のように置換できる
55 … pushl %ebp
89 … movl %esp,
e5 … %ebp
よって「55 89 e5」は以下の意味となる
pushl %ebp
movl %esp, %ebp
単純な置換なので、コンピュータの仕組みを理解してプログラミングする必要がある。環境にもベッタリと依存する
このような言語を「低級言語」と呼ぶ。C言語など、環境に依存しにくくした言語を「高級言語」と呼ぶ
■記法
アセンブリには2つの記法がある
大きくは変わらないが、書き方が少し異なる
Intel記法 ... コンパイラNASMが扱う記法。Intel社が開発した
AT&T記法 ... コンパイラGASが扱う記法。AT&T社が開発した
Linuxのgccがディスアセンブルで書き出すコードと互換性があるため、以降こちらを使う
■レジスタ
CPUの内部にある、小型記憶装置。電源を切るとデータは消える
レジスタのサイズが32ビットなら「32ビットのCPU」と呼ばれる
汎用レジスタ(プログラマがいじってもいいレジスタ)
eax … アキュムレータ。何に使ってもよい
ebx … ベースレジスタ。32ビット環境ではeax同様
ecx … カウントレジスタ。ループカウンタなどに使う
edx … データレジスタ。データ格納などに使う
esi … ソースインデックス。メモリアドレス格納などに使う
edi … ディスティネーションインデックス。esi同様
ebp … ベースポインタ
esp … スタックポインタ
セグメントレジスタ
cs ... コードセグメント
ds ... データセグメント
ss ... スタックセグメント
es ... エクストラセグメント
fs
gs
フラグレジスタ
eflags … フラグ。各種状態が基本一ビットずつ入っている
命令ポインタ
eip … インストラクションポインタ。次に実行すべきコードのアドレスが入っている
■レジスタの名前
32ビット環境では eax, ebx, ecx, edx となっているが、
16ビット環境ではeを除いて ax, bx, cx, dx となっている
64ビット環境ではeがrになり rax, rbx, rcx, rdx となっている
eax, ebx, ecx, edx に限り、下位16ビットの ax, bx, cx, dx を
上記8ビットを ah, bh, ch, dh、下位8ビットを al, bl, cl, dl に分けることができる(「h」と「l」はそれぞれ「high」「low」の意味)
■システムコール
OSの機能を呼び出す
各レジスタに決められた値をセットし、int命令を使うことで呼び出せる
eax にシステムコール番号、ebx, ecx, edx には第1引数〜第3引数(にあたるもの)をセットする
以下は msg を表示(標準出力に書き込み)する例
movl $4, %eax ... writeシステムコール番号は4
movl $1, %ebx ... 標準入力は0、標準出力は1、標準エラー出力は2
movl $msg, %ecx ... 出力するデータの先頭アドレス
movl $13, %edx ... 出力バイト数(msgの長さ)
int $0x80 ... 割り込み命令。システムコールの実行は80(16進数)
アセンブリ言語 実践
$ vi test.s … アセンブリ言語ソースファイルを作成
参考までに、C言語からwriteシステムコールを呼び出す場合は以下のようになる
引数の意味は、アセンブリ言語でシステムコールを呼び出す場合と同じになっている
.data # ここから文字列
msg: # ラベル
.string "Hello,world!\n" # 「.string」は「文字列を置く」という宣言(「asciz」と書いても同じ)
.text # ここから機械語
.globl main # 「main」ラベルを外部から参照できるようにする(コンパイラGASはmainラベルから実行する)
main: # ラベル
movl $4, %eax # writeシステムコール
movl $1, %ebx # 標準出力
movl $msg, %ecx # 出力するデータの先頭アドレス
movl $13, %edx # 出力バイト数
int $0x80 # システムコール実行
movl $1, %eax # exitシステムコール
movl $0, %ebx # 正常終了
int $0x80 # システムコール実行
$ gcc -o test test.s … 実行ファイルを作成
$ ll … 実行ファイルを確認
合計 12
-rwxrwxr-x 1 refirio refirio 6267 10月 22 14:47 2017 test
-rw-rw-r-- 1 refirio refirio 162 10月 22 14:47 2017 test.s
$ ./test … プログラムを実行
Hello,world!
$ vi test.c … C言語ソースファイルを作成
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char msg[] = "Hello,world!\n";
write(1, msg, sizeof(msg));
return 0;
}
C言語で書いたソースコードをアセンブリ言語に変換
$ vi test.c … C言語ソースファイルを作成
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
$ gcc -S test.c … アセンブリ言語ファイルを作成(test.s が作成される)
$ cat test.s … アセンブリ言語ファイルの内容を確認
.file "test.c"
.section .rodata
.LC0:
.string "Hello, world!"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
call puts
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)"
.section .note.GNU-stack,"",@progbits
$ as -o test.o test.s … アセンブリ言語ファイルからオブジェクトファイルを作成(test.o が作成される)
$ gcc -o test test.o … リンクして実行ファイルを作成(test が作成される)
$ ./test … プログラムを実行
Hello, world!
C言語で作成した実行ファイルをアセンブリ言語に変換
■準備(C言語でプログラムを作成)
$ vi test.c … C言語ソースファイルを作成
■オブジェクトファイルのバイナリデータを確認&編集
vimでバイナリを表示し、値を変更したい - rderaログ
http://d.hatena.ne.jp/rdera/20081022/1224682665
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
$ gcc -c test.c … オブジェクトファイルを作成
$ gcc -o test test.o … リンクして実行ファイルを作成
$ gcc -o test test.c … 上記2行は、まとめてこのようにも書ける
$ ./test … プログラムを実行
Hello, world!
$ vi -b test.o … ファイルをバイナリモードで開く
:%!xxd … 16進数形式に変換する。その後、必要に応じて編集する
:%!xxd -r … テキスト形式に戻す
:wq … 保存して終了
「Hello, world!」テキストに相当するバイナリデータを書き換えて、
書き換えた後の test.o から実行ファイルを作ると、確かに実行時に出力されるテキストが変わる
また、実行ファイル test のバイナリを編集すれば、即座に実行結果が変更される
ただし、オブジェクトファイルに比べると大量のデータになっている
諸々のファイルがリンクされて実行ファイルが作成されるため、だと思われる
■オブジェクトファイルを逆アセンブル
※「Hello, world!」というテキストが見当たらない?
でも「オブジェクトファイルのバイナリデータを確認&編集」の方法で「Hello, world!」の場所は判るので、比較すれば該当箇所は判るかも
Windowsプログラマに贈るLinuxプログラミング入門 - 第14回 gccをもっと詳しく知ろう:ITpro
http://itpro.nikkeibp.co.jp/article/COLUMN/20090330/327214/
$ objdump -d test.o … test.oを逆アセンブル
test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: bf 00 00 00 00 mov $0x0,%edi
9: e8 00 00 00 00 callq e <main+0xe>
e: b8 00 00 00 00 mov $0x0,%eax
13: c9 leaveq
14: c3 retq
■実行ファイルを逆アセンブル
※オブジェクトファイルに比べると大量のデータになっている
相変わらず「Hello, world!」というテキストが見当たらない?
「オブジェクトファイルのバイナリデータを確認&編集」の方法で「Hello, world!」の場所は判るので、比較すれば該当箇所は判るかも
$ objdump -d test … testを逆アセンブル
test: file format elf64-x86-64
Disassembly of section .init:
0000000000400358 <_init>:
400358: 48 83 ec 08 sub $0x8,%rsp
40035c: e8 5b 00 00 00 callq 4003bc <call_gmon_start>
400361: e8 ea 00 00 00 callq 400450 <frame_dummy>
400366: e8 d5 01 00 00 callq 400540 <__do_global_ctors_aux>
40036b: 48 83 c4 08 add $0x8,%rsp
40036f: c3 retq
Disassembly of section .plt:
0000000000400370 <__libc_start_main@plt-0x10>:
400370: ff 35 6a 04 20 00 pushq 0x20046a(%rip) # 6007e0 <_GLOBAL_OFFSET_TABLE_+0x8>
400376: ff 25 6c 04 20 00 jmpq *0x20046c(%rip) # 6007e8 <_GLOBAL_OFFSET_TABLE_+0x10>
40037c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000400380 <__libc_start_main@plt>:
400380: ff 25 6a 04 20 00 jmpq *0x20046a(%rip) # 6007f0 <_GLOBAL_OFFSET_TABLE_+0x18>
400386: 68 00 00 00 00 pushq $0x0
40038b: e9 e0 ff ff ff jmpq 400370 <_init+0x18>
Disassembly of section .text:
0000000000400390 <_start>:
400390: 31 ed xor %ebp,%ebp
400392: 49 89 d1 mov %rdx,%r9
400395: 5e pop %rsi
400396: 48 89 e2 mov %rsp,%rdx
400399: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40039d: 50 push %rax
40039e: 54 push %rsp
40039f: 49 c7 c0 a0 04 40 00 mov $0x4004a0,%r8
4003a6: 48 c7 c1 b0 04 40 00 mov $0x4004b0,%rcx
4003ad: 48 c7 c7 74 04 40 00 mov $0x400474,%rdi
4003b4: e8 c7 ff ff ff callq 400380 <__libc_start_main@plt>
4003b9: f4 hlt
4003ba: 90 nop
4003bb: 90 nop
00000000004003bc <call_gmon_start>:
4003bc: 48 83 ec 08 sub $0x8,%rsp
4003c0: 48 8b 05 09 04 20 00 mov 0x200409(%rip),%rax # 6007d0 <_DYNAMIC+0x190>
4003c7: 48 85 c0 test %rax,%rax
4003ca: 74 02 je 4003ce <call_gmon_start+0x12>
4003cc: ff d0 callq *%rax
4003ce: 48 83 c4 08 add $0x8,%rsp
4003d2: c3 retq
4003d3: 90 nop
4003d4: 90 nop
4003d5: 90 nop
4003d6: 90 nop
4003d7: 90 nop
4003d8: 90 nop
4003d9: 90 nop
4003da: 90 nop
4003db: 90 nop
4003dc: 90 nop
4003dd: 90 nop
4003de: 90 nop
4003df: 90 nop
00000000004003e0 <__do_global_dtors_aux>:
4003e0: 55 push %rbp
4003e1: 48 89 e5 mov %rsp,%rbp
4003e4: 53 push %rbx
4003e5: 48 83 ec 08 sub $0x8,%rsp
4003e9: 80 3d 20 04 20 00 00 cmpb $0x0,0x200420(%rip) # 600810 <completed.6352>
4003f0: 75 4b jne 40043d <__do_global_dtors_aux+0x5d>
4003f2: bb 30 06 60 00 mov $0x600630,%ebx
4003f7: 48 8b 05 1a 04 20 00 mov 0x20041a(%rip),%rax # 600818 <dtor_idx.6354>
4003fe: 48 81 eb 28 06 60 00 sub $0x600628,%rbx
400405: 48 c1 fb 03 sar $0x3,%rbx
400409: 48 83 eb 01 sub $0x1,%rbx
40040d: 48 39 d8 cmp %rbx,%rax
400410: 73 24 jae 400436 <__do_global_dtors_aux+0x56>
400412: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
400418: 48 83 c0 01 add $0x1,%rax
40041c: 48 89 05 f5 03 20 00 mov %rax,0x2003f5(%rip) # 600818 <dtor_idx.6354>
400423: ff 14 c5 28 06 60 00 callq *0x600628(,%rax,8)
40042a: 48 8b 05 e7 03 20 00 mov 0x2003e7(%rip),%rax # 600818 <dtor_idx.6354>
400431: 48 39 d8 cmp %rbx,%rax
400434: 72 e2 jb 400418 <__do_global_dtors_aux+0x38>
400436: c6 05 d3 03 20 00 01 movb $0x1,0x2003d3(%rip) # 600810 <completed.6352>
40043d: 48 83 c4 08 add $0x8,%rsp
400441: 5b pop %rbx
400442: c9 leaveq
400443: c3 retq
400444: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1)
40044b: 00 00 00 00 00
0000000000400450 <frame_dummy>:
400450: 48 83 3d e0 01 20 00 cmpq $0x0,0x2001e0(%rip) # 600638 <__JCR_END__>
400457: 00
400458: 55 push %rbp
400459: 48 89 e5 mov %rsp,%rbp
40045c: 74 12 je 400470 <frame_dummy+0x20>
40045e: b8 00 00 00 00 mov $0x0,%eax
400463: 48 85 c0 test %rax,%rax
400466: 74 08 je 400470 <frame_dummy+0x20>
400468: bf 38 06 60 00 mov $0x600638,%edi
40046d: c9 leaveq
40046e: ff e0 jmpq *%rax
400470: c9 leaveq
400471: c3 retq
400472: 90 nop
400473: 90 nop
0000000000400474 <main>:
400474: b8 04 00 00 00 mov $0x4,%eax
400479: bb 01 00 00 00 mov $0x1,%ebx
40047e: b9 fc 07 60 00 mov $0x6007fc,%ecx
400483: ba 0d 00 00 00 mov $0xd,%edx
400488: cd 80 int $0x80
40048a: b8 01 00 00 00 mov $0x1,%eax
40048f: bb 00 00 00 00 mov $0x0,%ebx
400494: cd 80 int $0x80
400496: 90 nop
400497: 90 nop
400498: 90 nop
400499: 90 nop
40049a: 90 nop
40049b: 90 nop
40049c: 90 nop
40049d: 90 nop
40049e: 90 nop
40049f: 90 nop
00000000004004a0 <__libc_csu_fini>:
4004a0: f3 c3 repz retq
4004a2: 66 66 66 66 66 2e 0f data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
4004a9: 1f 84 00 00 00 00 00
00000000004004b0 <__libc_csu_init>:
4004b0: 48 89 6c 24 d8 mov %rbp,-0x28(%rsp)
4004b5: 4c 89 64 24 e0 mov %r12,-0x20(%rsp)
4004ba: 48 8d 2d 53 01 20 00 lea 0x200153(%rip),%rbp # 600614 <__init_array_end>
4004c1: 4c 8d 25 4c 01 20 00 lea 0x20014c(%rip),%r12 # 600614 <__init_array_end>
4004c8: 4c 89 6c 24 e8 mov %r13,-0x18(%rsp)
4004cd: 4c 89 74 24 f0 mov %r14,-0x10(%rsp)
4004d2: 4c 89 7c 24 f8 mov %r15,-0x8(%rsp)
4004d7: 48 89 5c 24 d0 mov %rbx,-0x30(%rsp)
4004dc: 48 83 ec 38 sub $0x38,%rsp
4004e0: 4c 29 e5 sub %r12,%rbp
4004e3: 41 89 fd mov %edi,%r13d
4004e6: 49 89 f6 mov %rsi,%r14
4004e9: 48 c1 fd 03 sar $0x3,%rbp
4004ed: 49 89 d7 mov %rdx,%r15
4004f0: e8 63 fe ff ff callq 400358 <_init>
4004f5: 48 85 ed test %rbp,%rbp
4004f8: 74 1c je 400516 <__libc_csu_init+0x66>
4004fa: 31 db xor %ebx,%ebx
4004fc: 0f 1f 40 00 nopl 0x0(%rax)
400500: 4c 89 fa mov %r15,%rdx
400503: 4c 89 f6 mov %r14,%rsi
400506: 44 89 ef mov %r13d,%edi
400509: 41 ff 14 dc callq *(%r12,%rbx,8)
40050d: 48 83 c3 01 add $0x1,%rbx
400511: 48 39 eb cmp %rbp,%rbx
400514: 72 ea jb 400500 <__libc_csu_init+0x50>
400516: 48 8b 5c 24 08 mov 0x8(%rsp),%rbx
40051b: 48 8b 6c 24 10 mov 0x10(%rsp),%rbp
400520: 4c 8b 64 24 18 mov 0x18(%rsp),%r12
400525: 4c 8b 6c 24 20 mov 0x20(%rsp),%r13
40052a: 4c 8b 74 24 28 mov 0x28(%rsp),%r14
40052f: 4c 8b 7c 24 30 mov 0x30(%rsp),%r15
400534: 48 83 c4 38 add $0x38,%rsp
400538: c3 retq
400539: 90 nop
40053a: 90 nop
40053b: 90 nop
40053c: 90 nop
40053d: 90 nop
40053e: 90 nop
40053f: 90 nop
0000000000400540 <__do_global_ctors_aux>:
400540: 55 push %rbp
400541: 48 89 e5 mov %rsp,%rbp
400544: 53 push %rbx
400545: 48 83 ec 08 sub $0x8,%rsp
400549: 48 8b 05 c8 00 20 00 mov 0x2000c8(%rip),%rax # 600618 <__CTOR_LIST__>
400550: 48 83 f8 ff cmp $0xffffffffffffffff,%rax
400554: 74 19 je 40056f <__do_global_ctors_aux+0x2f>
400556: bb 18 06 60 00 mov $0x600618,%ebx
40055b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
400560: 48 83 eb 08 sub $0x8,%rbx
400564: ff d0 callq *%rax
400566: 48 8b 03 mov (%rbx),%rax
400569: 48 83 f8 ff cmp $0xffffffffffffffff,%rax
40056d: 75 f1 jne 400560 <__do_global_ctors_aux+0x20>
40056f: 48 83 c4 08 add $0x8,%rsp
400573: 5b pop %rbx
400574: c9 leaveq
400575: c3 retq
400576: 90 nop
400577: 90 nop
Disassembly of section .fini:
0000000000400578 <_fini>:
400578: 48 83 ec 08 sub $0x8,%rsp
40057c: e8 5f fe ff ff callq 4003e0 <__do_global_dtors_aux>
400581: 48 83 c4 08 add $0x8,%rsp
400585: c3 retq