Memo

メモ > 技術 > プログラミング言語: Assembly

アセンブリ言語 入門
アセンブリ言語の概要 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 … アセンブリ言語ソースファイルを作成
.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

Advertisement