#author("2024-06-26T17:17:41+09:00","default:pitablog","pitablog") #author("2024-06-26T17:19:52+09:00","default:pitablog","pitablog") * 【アセンブリ言語】Cをコンパイルしてアセンブリを解読していく [#s686fa73] //#seo(description,テンプレ) //#seo(keywords,テンプレ) #splitbody{{ LEFT: &tag(情報技術,プログラミング,コンパイラ言語,アセンブリ言語,C言語); #split RIGHT:&size(13){投稿日: 2024-06-24 (月)}; }} #bcontents ※この記事は素人の私がコンパイルをしてアセンブリ言語を解読するだけです。間違えてたらコメ欄で指摘してくださると助かります。 ** 0. MinGW を入れる [#i8841cb4] これは別の記事で紹介しますたぶん ** 1. Cのソースを準備する [#ke570e4d] 「test.c」として保存した #include <stdio.h> int main(void) { int a = 5; int b = 2; a -= 1; b *= 2; int c = a + b; printf("%d", c); return 0; } ** 2. コンパイルだけをする [#n7f3dd91] コマンドプロンプトなどで以下のコマンドを実行した。 gcc -S test.c -S とはアセンブラファイルを生成する(コンパイルまでのみの処理)というオプション ** 3. アセンブラファイルを開く [#tbd8a3f9] test.c が入っているフォルダに test.s が生成されていた。 .file "test.c" .text .def __main; .scl 2; .type 32; .endef .section .rdata,"dr" .LC0: .ascii "%d\0" .text .globl main .def main; .scl 2; .type 32; .endef .seh_proc main main: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $48, %rsp .seh_stackalloc 48 .seh_endprologue call __main movl $5, -4(%rbp) movl $2, -8(%rbp) subl $1, -4(%rbp) sall -8(%rbp) movl -4(%rbp), %edx movl -8(%rbp), %eax addl %edx, %eax movl %eax, -12(%rbp) movl -12(%rbp), %eax movl %eax, %edx leaq .LC0(%rip), %rcx call printf movl $0, %eax addq $48, %rsp popq %rbp ret .seh_endproc .ident "GCC: (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project) 8.1.0" .def printf; .scl 2; .type 32; .endef これを解読していく。 ** 4. アセンブラファイルを解読する [#f3145372] *** 基本的な各命令の説明 [#t7a1b2bb] |~命令名|~意味|~備考|h |mov|代入|mov 値 代入先| |add|加算|add 数値 加算先| |sub|減算|sub 数値 減算先| |imul|乗算|imul 数値 乗算先| |idiv|除算|idiv 数値 除算先| |sal|左シフト(2倍)|sal シフト先| |call|関数呼び出し|call 関数名| |ret|返る|呼び出された前の処理の位置に戻る| $(数値)は10進数の数字(普段使う数字)です。 つまり、$6 は 6 ということになります。 ※2倍のときはimulではなくsalが使われるので注意 *** mainの処理 [#f5756dca] 上記の各命令の説明と照らし合わせて紐解きます。 LC0はprintの引数のラベルのようです .LC0: .ascii "%d\0" .text .globl main .def main; .scl 2; .type 32; .endef .seh_proc main main: は main関数の中身となっている 前処理は省いて実際にmainの処理だけに注目してみた # レジスタ-4に5を代入(a = 5) movl $5, -4(%rbp) # レジスタ-8に2を代入(b = 2) movl $2, -8(%rbp) # レジスタ-4から1を減算(a -= 1) subl $1, -4(%rbp) # レジスタ-8の値を左にシフト(b *= 2) sall -8(%rbp) # edxにレジスタ-4の値を代入 movl -4(%rbp), %edx # eaxにレジスタ-8の値を代入 movl -8(%rbp), %eax # eaxにedxの値を加算(a + b) addl %edx, %eax # eaxの値をレジスタ-12に代入(c = 加算結果) movl %eax, -12(%rbp) # レジスタ-12の値をeaxに代入 movl -12(%rbp), %eax # eaxの値をedxに代入 movl %eax, %edx leaq .LC0(%rip), %rcx call printf movl $0, %eax addq $48, %rsp popq %rbp ret ** コメント [#mf183f2a] #pctrlcmt &size(10){キーワード: C言語, プログラミング言語, コンパイラ言語, アセンブリ言語, コンパイル, アセンブラ, 解読, 読み方};
Pitan |
![]() |
プログラミングや音MADやらが趣味 |
[もっと見る]
[もっと見る]