■目次
アセンブリ言語 入門アセンブリ言語 メモアセンブリ言語 実践C言語で書いたソースコードをアセンブリ言語に変換C言語で作成した実行ファイルをアセンブリ言語に変換
■アセンブリ言語 入門
アセンブリ言語の概要 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 以降のメモでは、主に以下のページを参考にしている 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 … アセンブリ言語ソースファイルを作成
.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! 参考までに、C言語からwriteシステムコールを呼び出す場合は以下のようになる 引数の意味は、アセンブリ言語でシステムコールを呼び出す場合と同じになっている $ 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言語ソースファイルを作成
#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! ■オブジェクトファイルのバイナリデータを確認&編集 vimでバイナリを表示し、値を変更したい - rderaログ http://d.hatena.ne.jp/rdera/20081022/1224682665 $ 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