0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C言語引数の受け渡し処理をアセンブリ上で観察

Posted at

元となるソース

demo.c
//#include<stdio.h> /* debug */

// demo.c
int add(int a, int b, int c, int d) {
    return a + b + c + d;
}

int main() {
    int result = add(1, 2, 3, 4);
//	printf("result = %d",result); /* debug */
    return result;
}

コンパイル方法

gcc -S -masm=intel -o demo.s demo.c
オプション 意味
S アセンブリ言語へ変換
masm=intel 初期設定のAT&T記法ではなくintel記法
o 出力ファイル名を指定

※AT&T記法で書かれたアセンブリ言語は個人的に読みづらいのでintel記法を設定しています。

生成されたアセンブリのコード

※注釈を付けています

demo.s
	.file	"demo.c"
	.intel_syntax noprefix
	.text
	.globl	add
	.def	add;	.scl	2;	.type	32;	.endef
	.seh_proc	add
add:
	push	rbp
	.seh_pushreg	rbp
	mov	rbp, rsp
	.seh_setframe	rbp, 0
	.seh_endprologue
	mov	DWORD PTR 16[rbp], ecx ;第1引数 int a
	mov	DWORD PTR 24[rbp], edx ;第2引数 int b
	mov	DWORD PTR 32[rbp], r8d ;第3引数 int c
	mov	DWORD PTR 40[rbp], r9d ;第4引数 int d
	mov	edx, DWORD PTR 16[rbp] ;edx = a;
	mov	eax, DWORD PTR 24[rbp] ;eax = b;
	add	edx, eax               ;edx = edx + eax
	mov	eax, DWORD PTR 32[rbp] ;eax = c
	add	edx, eax               ;edx = edx + eax
	mov	eax, DWORD PTR 40[rbp] ;eax = d
	add	eax, edx               ;eax = eax + edx
	;↑mainでは返り値をeaxから取り出す。明示的にreturnしている訳ではない。
	pop	rbp
	ret
	.seh_endproc
	.globl	main
	.def	main;	.scl	2;	.type	32;	.endef
	.seh_proc	main
main:
	push	rbp
	.seh_pushreg	rbp
	mov	rbp, rsp
	.seh_setframe	rbp, 0
	sub	rsp, 48
	.seh_stackalloc	48
	.seh_endprologue
	call	__main
	mov	r9d, 4 ;引数格納
	mov	r8d, 3 ;引数格納
	mov	edx, 2 ;引数格納
	mov	ecx, 1 ;引数格納
	call	add ;add関数呼び出し
	mov	DWORD PTR -4[rbp], eax
	mov	eax, DWORD PTR -4[rbp]
	add	rsp, 48
	pop	rbp
	ret
	.seh_endproc
	.def	__main;	.scl	2;	.type	32;	.endef
	.ident	"GCC: (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r3) 14.2.0"

コンパイル後のアセンブリ分析

mainからaddへの変数引き渡しはレジスタr9d,r8d,edx,ecxを通じて行われていることが分かります。

	mov	r9d, 4 ;
	mov	r8d, 3 ;
	mov	edx, 2 ;
	mov	ecx, 1 ;

add側ではそれぞれのレジスタから値を取りだしスタックへ格納しています。

	mov	DWORD PTR 16[rbp], ecx
	mov	DWORD PTR 24[rbp], edx
	mov	DWORD PTR 32[rbp], r8d
	mov	DWORD PTR 40[rbp], r9d

GDBを用いてスタックの中身を確認

C:\Users\nanasi\kansuasm>gcc -g -O0 -Wl,--disable-dynamicbase demo.c -o demo_debug.exe
C:\Users\nanasi\kansuasm>gdb demo_debug.exe
オプション 意味
O0 最適化レベル0。C言語の順序通りにコンパイル。未使用変数の削除無し
masm=intel メモリアドレスをランダムにする機能を停止する
Wl つけた方がよい???(理解してません)
o 出力ファイル名を指定

GDB上での操作

(gdb) set disassembly-flavor intel 初期設定のAT&T記法ではなくintel記法
(gdb) disassemble add add関数に対応するコードのアドレス及びアセンブリのコードが見られる

image.png

add関数の処理が終わった後のスタックの中身を確認したいので
0x00000001400016f4 <+36>: pop rbp
の位置にブレイクポイントを設置しプログラムを実行。

gdbコマンド.bash
(gdb) break *0x00000001400016f4 ブレイクポイントを設置
(gdb) run ブレークポイントまで実行
(gdb) x/dw $rbp+16 値を確認する
(gdb) x/dw $rbp+24
(gdb) x/dw $rbp+32
(gdb) x/dw $rbp+40

image.png
するとmain関数から渡した1,2,3,4がきちんと代入されていることが分かります。

動作環境

Windows10 Version 10.0.19045.5737
gcc version 14.2.0
GNU gdb (GDB for MinGW-W64 x86_64, built by Brecht Sanders, r3) 16.2

スタックの操作や構造は後日研究して又記事を上げます。
今回は観察なのでまとまりが無いかもしれませんがご容赦下さい。

0
0
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?