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言語 ifがCPU上で動く仕組みをアセンブリで追う

Posted at

Cのif文はどうやってCPUで動く? アセンブリ上での表現

等号

ifeq.c
	int a=1;
	int b=2;
	int c=3;
	if(a==b){
		c=4;
	}
	c=5;
ifeq.s
	mov	DWORD PTR -4[rbp], 1
	mov	DWORD PTR -8[rbp], 2
	mov	DWORD PTR -12[rbp], 3
	mov	eax, DWORD PTR -4[rbp]
	cmp	eax, DWORD PTR -8[rbp]
	jne	.L2
	mov	DWORD PTR -12[rbp], 4
.L2:
	mov	DWORD PTR -12[rbp], 5

不等号

ifneq.c
	int a=1;
	int b=2;
	int c=3;
	if(a!=b){
		c=4;
	}
	c=5;
ifneq.s
	mov	DWORD PTR -4[rbp], 1
	mov	DWORD PTR -8[rbp], 2
	mov	DWORD PTR -12[rbp], 3
	mov	eax, DWORD PTR -4[rbp]
	cmp	eax, DWORD PTR -8[rbp]
	je	.L2
	mov	DWORD PTR -12[rbp], 4
.L2:
	mov	DWORD PTR -12[rbp], 5

分析

if(a==b) の場合は jne
if(a!=b) の場合は je
へ変換されています。

フラグレジスタ

jne及びjeの動作を理解するにはフラグレジスタの理解が欠かせません。
x86CPUにはフラグレジスタと呼ばれる特殊なレジスタがあり、各ビットにはそれぞれ異なる意味が割り当てられています。

代表的なビット構成は次のとおりです(一部省略):

|ID|VIP|VIF|AC| OF| DF| IF| TF| SF| ZF| 0| AF| 0| PF| 1| CF|

ZF(Zero Flag) は6番目のビットです。
ZF = 1 の場合は「直前の演算結果が 0(等しい)」を意味します。
je(jump if equal)= ZF が 1 ならラベル先へ移動
jne(jump if not equal)= ZF が 0 ならラベル先へ移動

if(a==b)

	mov	eax, DWORD PTR -4[rbp] ; 変数 a
	cmp	eax, DWORD PTR -8[rbp] ; 変数 b
	jne	.L2
	mov	DWORD PTR -12[rbp], 4
.L2:
	mov	DWORD PTR -12[rbp], 5

cmp命令にて変数a及びbを比較し、一致した場合はZF=1となる。
jneZF=0の場合にラベル先へ移動する。
つまり、一致しない場合はL2へ跳ぶ
一致した場合はmov DWORD PTR -12[rbp], 4を実行する。

if(a!=b)

	mov	eax, DWORD PTR -4[rbp] ; 変数 a
	cmp	eax, DWORD PTR -8[rbp] ; 変数 b
	je	.L2
	mov	DWORD PTR -12[rbp], 4
.L2:
	mov	DWORD PTR -12[rbp], 5

cmp命令にて変数a及びbを比較し、一致ない場合はZF=0となる。
jeZF=1の場合にラベル先へ移動する。
つまり、一致する場合はL2へ跳ぶ
一致しない場合はmov DWORD PTR -12[rbp], 4を実行する。

完全なコード(参考)

長いので折り畳みます

ifeq.c
ifeq.c
#include <stdio.h>

int main() {
	int a=1;
	int b=2;
	int c=3;
	if(a==b){
		c=4;
	}
	c=5;
	return 0;
}
ifeq.s
ifeq.s
	.file	"ifeq.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], 1
	mov	DWORD PTR -8[rbp], 2
	mov	DWORD PTR -12[rbp], 3
	mov	eax, DWORD PTR -4[rbp]
	cmp	eax, DWORD PTR -8[rbp]
	jne	.L2
	mov	DWORD PTR -12[rbp], 4
.L2:
	mov	DWORD PTR -12[rbp], 5
	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"
ifneq.c
ifneq.c
#include <stdio.h>

int main() {
	int a=1;
	int b=2;
	int c=3;
	if(a!=b){
		c=4;
	}
	c=5;
	return 0;
}
ifneq.s
ifneq.s
	.file	"ifneq.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], 1
	mov	DWORD PTR -8[rbp], 2
	mov	DWORD PTR -12[rbp], 3
	mov	eax, DWORD PTR -4[rbp]
	cmp	eax, DWORD PTR -8[rbp]
	je	.L2
	mov	DWORD PTR -12[rbp], 4
.L2:
	mov	DWORD PTR -12[rbp], 5
	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"

コンパイル.bash
gcc -S -masm=intel ifeq.c -o ifeq.s
gcc -S -masm=intel ifneq.c -o ifneq.s
0
0
0

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?