C言語 ifがCPU上で動く仕組みをアセンブリで追う


## 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となる。
`jne`は`ZF=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となる。
`je`は`ZF=1`の場合にラベル先へ移動する。
つまり、一致する場合は`L2`へ跳ぶ
一致しない場合は`mov	DWORD PTR -12[rbp], 4`を実行する。

## 完全なコード(参考)
長いので折り畳みます
<details>
<summary>ifeq.c</summary>

```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;
}
```
</details>


<details>
<summary>ifeq.s</summary>

```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"
```
</details>

<details>

<summary>ifneq.c</summary>

```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;
}
```
</details>

<details>
<summary>ifneq.s</summary>

```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"

```
</details>

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