1
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言語 for whileアセンブリ上で違いはあるのか x86

Posted at

以下のコードをそれぞれアセンブリ言語へコンパイルします。

Cソース

同条件下で比較するため為、両者の書き方を出来るだけ近づけました。

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

int main() {
	int a=0;
	for(int i=0;i<7;i++){
		a+=i;
	}
	//printf("result = %d",a); /* debug */
    return 0;
}
whileasm.c
//#include<stdio.h> /* debug */

int main() {
	int a=0;
	int i=0;
	while(i<7){
		a+=i;
		i++;
	}
	//printf("result = %d",a); /* debug */
    return 0;
}

コンパイル

C:\Users\nanasi\loopasm>gcc -S -masm=intel -o forasm.s forasm.c
C:\Users\nanasi\loopasm>gcc -S -masm=intel -o whileasm.s whileasm.c
forasm.s
	.file	"forasm.c"
	.intel_syntax noprefix
	.text
	.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	DWORD PTR -4[rbp], 0
	mov	DWORD PTR -8[rbp], 0
	jmp	.L2
.L3:
	mov	eax, DWORD PTR -8[rbp]
	add	DWORD PTR -4[rbp], eax
	add	DWORD PTR -8[rbp], 1
.L2:
	cmp	DWORD PTR -8[rbp], 6
	jle	.L3
	mov	eax, 0
	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"
whileasm.s
	.file	"whileasm.c"
	.intel_syntax noprefix
	.text
	.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	DWORD PTR -4[rbp], 0
	mov	DWORD PTR -8[rbp], 0
	jmp	.L2
.L3:
	mov	eax, DWORD PTR -8[rbp]
	add	DWORD PTR -4[rbp], eax
	add	DWORD PTR -8[rbp], 1
.L2:
	cmp	DWORD PTR -8[rbp], 6
	jle	.L3
	mov	eax, 0
	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"

比較

1行づつ確認するのは難しい為winmergiを用いて比較します。

無題.png
無題1.png

なんということでしょう。ソース名以外は完全に一致しました。
実際forとwhileを使う時にはプログラムの書き方も異なってくると思いますが、forとwhile自体にはあまり差が無いようです。

分析

せっかくアセンブリ言語へ変換したので中身を読んでみます。

    ;...前略
	mov	DWORD PTR -4[rbp], 0 ; int a=0 変数aはrbp-4に格納
	mov	DWORD PTR -8[rbp], 0 ; int i=0 変数iはrbp-8に格納
	jmp	.L2 ; 先ずL2へ跳びcmp命令でi<7の条件に当てはまるかを確認する
.L3: ;L3ラベルの処理がfor文の中身に相当
	mov	eax, DWORD PTR -8[rbp] ; eax = i 
	add	DWORD PTR -4[rbp], eax ; a = a + eax
	add	DWORD PTR -8[rbp], 1   ; i++
.L2:
	cmp	DWORD PTR -8[rbp], 6 ; i==6 ならば L3へ跳ぶ(iがintの場合 i<7  i<=6 と等価)
	jle	.L3
	mov	eax, 0   ; return 0main関数の戻り値はeax経由で返す
	;後略...

以下の流れになっていることが分かりました。

スタックへ変数a,iを格納
ラベルL2にてi==6の判定を行う
i<=6の場合ラベルL3の中でa+=i及びi++を実行
iが7になったら終了
eaxにmain関数の返り値0を格納

eaxが本当に返り値を表していることの根拠
https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170

Return values
A scalar return value that can fit into 64 bits, including the __m64 type, is returned through RAX. Nonscalar types including floats, doubles, and vector types such as __m128, __m128i, __m128d are returned in XMM0. The state of unused bits in the value returned in RAX or XMM0 is undefined.
(機械翻訳:64ビットに収まるスカラー戻り値(__m64型を含む)はRAXレジスタを通じて返されます。浮動小数点数(float/double)やベクトル型(__m128、__m128i、__m128dなど)を含む非スカラー型はXMM0レジスタに返されます。RAXまたはXMM0で返される値のうち、使用されなかったビットの状態は未定義です。)

eaxとraxはビット数が違うだけで同じレジスタです。(よね?)

以上

1
0
2

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
1
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?