從C語言到彙編(三)if語句

if
從最簡單的if語句開始。

#include <stdio.h>
int main(void)
{
	int a;
	scanf("%d",&a);
	
	if((a&1)==0)
	{
		printf("is even!");
	}
	return 0;
}

最簡單的if語句如上。我們將其轉化爲彙編。

.section .rodata
	.LC0:.string "%d"
	.LC1:.string "is even!"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $4,%esp
	leal -4(%ebp),%eax
	pushl %eax
	pushl $.LC0
	call scanf
	addl $8,%esp
	
	movl -4(%ebp),%eax
	andl $1,%eax
	cmpl $0,%eax
	jne .L1
	
	pushl $.LC1
	call printf
	addl $4,%esp
	
.L1:
	
	movl $0,%eax
	leave
	ret

最新用到的指令。

指令 基於 描述
cmpl S2,S1 S1-S2 比較

注意這裏的S2是減數,S1是被減數,與我們使用的慣例是相反的。
cmpl 指令會將S1減去S2,但只設置條件碼,不改變參數的值。
條件碼
除了整數寄存器,CPU還維護着一組單個位的條件碼寄存器,它們描述了最近的算數運算或邏輯運算操作的屬性。常用的條件碼有:
CF:進位標誌。
ZF:零標誌。
SF:符號標誌。
OF:溢出標誌。
跳轉

指令 跳轉條件 描述
jmp Label 1 直接跳轉
jmp *Operand 1 間接跳轉
je Label ZF 相等/零
jne Label ~ZF 不相等/非零
js Label SF 負數
jns Label ~SF 非負數
jg Label (SF^OF)&ZF 大於(有符號>)
jge Label ~(SF^OF) 大於等於(有符號>=)
jl Label SF^OF 小於(有符號<)
jle Label (SF^OF) ZF
ja Label CF&ZF 超過(無符號>)
jae Label ~CF 超過或相等(無符號>=)
jb Label CF 低於(無符號<)
jbe Label CF ZF

movl -4(%ebp),%eax 將a的值放入%eax中,andl $1,%eax 將1的值與%eax的值相與。cmpl $0,%eax比較%eax與0,jne .L1不相等則跳轉.L1處,如果相等則執行printf(“is even!”)。
這裏要說明,(a&1)==0 被翻譯爲不等於0則跳轉,否則繼續執行,這是慣例,因爲當if語句爲if-else if-else時,這樣寫才能便於翻譯。

以上條件是一條關係語句,他也可以是邏輯語句。

#include <stdio.h>
int main(void)
{
	int a;
	scanf("%d",&a);
	
	if(a>=0&&a<=100)
	{
		printf("ok!");
	}	
	
	return 0;
}

彙編代碼

.section .rodata
	.LC0:.string "%d"
	.LC1:.string "ok!"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $4,%esp
	leal -4(%ebp),%eax
	pushl %eax
	pushl $.LC0
	call scanf
	addl $8,%esp
	
	cmpl $0,-4(%ebp)
	jl .L1
	cmpl $100,-4(%ebp)
	jg .L1
	
	pushl $.LC1
	call printf
	addl $4,%esp
	
.L1:
	
	movl $0,%eax
	leave
	ret

下面分析一下彙編代碼與c代碼的聯繫。
cmpl $0,-4(%ebp) jl .L1 如果a<0則跳出if語句。直接執行下面語句,這與邏輯與的短路相匹配。如果a>=0這繼續執行。
cmpl $100,-4(%ebp) jg .L1 如果a>100則跳出if語句。直接執行下面語句,如果a<=100這繼續執行printf(“ok!”)。

再看邏輯或。

#include <stdio.h>
int main(void)
{
	int a;
	scanf("%d",&a);
	
	if(a<0||a>100)
	{
		printf("bad!");
	}
	return 0;
}

彙編代碼

.section .rodata
	.LC0:.string "%d"
	.LC1:.string "bad!"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $4,%esp
	leal -4(%ebp),%eax
	pushl %eax
	pushl $.LC0
	call scanf
	addl $8,%esp
	
	cmpl $0,-4(%ebp)
	jl .L1
	cmpl $100,-4(%ebp)
	jle .L2
.L1	
	pushl $.LC1
	call printf
	addl $4,%esp
	
.L2:
	
	movl $0,%eax
	leave
	ret

下面分析一下彙編代碼與c代碼的聯繫。
cmpl $0,-4(%ebp) jl .L1 如果a<0,則跳轉到if語句執行。否則繼續執行條件判斷。
cmpl $100,-4(%ebp) jg .L2 如果a<=100,這跳出if語句,否則執行if語句。
這裏也可以看出邏輯或的短路性質。

if-else
先看C語言代碼。

#include <stdio.h>
int main(void)
{
	int a;
	scanf("%d",&a);
	
	if(a&1==0)
	{
		printf("even\n");
	}else
	{
		printf("odd\n");
	}
	return 0;
}

看彙編代碼

.section .rodata
	.LC0:.string "%d"
	.LC1:.string "even\n"
	.LC2:.string "odd\n"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $4,%esp
	leal -4(%ebp),%eax
	pushl %eax
	pushl $.LC0
	call scanf
	addl $8,%esp
	
	movl -4(%ebp),%eax
	andl $1,%eax
	cmpl $0,%eax
	jne .L1
	
	pushl $.LC1
	call printf
	addl $4,%esp
	jmp .L2
.L1:
	pushl $.LC2
	call printf
	addl $4,%esp	
.L2:
	movl $0,%eax
	leave
	ret

如果a&1!=0則執行.L1—執行printf(“odd\n”),
否則執行printf(“even\n”),執行完後,執行jmp跳轉到.LC2,離開if-else語句。

if-else if-else
先看代碼。

#include <stdio.h>
int main(void)
{
	int a;
	scanf("%d",&a);
	if(a>100)
	{
		printf("bad\n");
	}else if(a>=90)
	{
		printf("A\n");
	}else if(a>=80)
	{
		printf("B\n");
	}else
	{
		printf("C\n");
	}
	return 0;
}

彙編代碼

.section .rodata
	.LC0:.string "%d"
	.LC1:.string "bad\n"
	.LC2:.string "A\n"
	.LC3:.string "B\n"
	.LC4:.string "C\n"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $4,%esp
	leal -4(%ebp),%eax
	pushl %eax
	pushl $.LC0
	call scanf
	addl $8,%esp
	
	cmpl $100,-4(%ebp)
	jle .L1
	pushl $.LC1
	call printf
	addl $4,%esp
	jmp .L2
.L1:
	cmpl $90,-4(%ebp)
	jl .L3
	pushl $.LC2
	call printf
	addl $4,%esp
	jmp .L2
.L3:
	cmpl $80,-4(%ebp)
	jl .L4
	pushl $.LC3
	call printf
	addl $4,%esp
	jmp .L2
.L4:
	pushl $.LC4
	call printf
	addl $4,%esp	
.L2:
	movl $0,%eax
	leave
	ret
	
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章