【アセンブリ言語】C言語コンパイルしてアセンブリ言語を解読していく の変更点


#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
pitan_prof.png
プログラミングや音MADやらが趣味

最新のページ

最新の5件
2024-06-26
  • 【アセンブリ言語】C言語コンパイルしてアセンブリ言語を解読していく
2024-05-29 2024-05-14 2024-05-08 2024-04-25

[もっと見る]

タグ

[もっと見る]

人気のページ

人気の5件

カウンター

合計: 68
今日: 2
昨日: 0
オンライン: 5
  編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS