從C語言到彙編(二)位運算

從C語言到彙編(二)算術運算

存儲程序式計算機以二進制來表示數據和指令。所以,我們可以對二進制位進行一些操作。
這些操作包括了與(&),或(|),異或(^),取反(~),算術左移(<<),邏輯左移(<<),算術右移(>>),邏輯右移(>>)。

與運算 0 1
0 0 0
1 0 1

可以用與操作來屏蔽某些位。

#include <stdio.h>
int main(void)
{
	int a=100;
	int b=0xfffffff0;
	int c=a&b;   //相當於a減去a%16的值
	printf("value=%d\n",c);
	
	c=a&0xfffffff0;
	printf("value=%d\n",c);
	
	return 0;
}

彙編代碼

.section .rodata
	.LC0:.string "value=%d\n"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $12,%esp
	movl $100,-4(%ebp);a
	movl $0xfffffff0,-8(%ebp);b
	movl -4(%ebp),%eax
	andl -8(%ebp),%eax
	movl %eax,-12(%ebp);c
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl -4(%ebp),%eax
	andl $0xfffffff0,%eax
	movl %eax,-12(%ebp)
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl $0,%eax
	leave
	ret

movl $100,-4(%ebp) 將a賦值爲100,movl $0xfffffff0,-8(%ebp) 將b賦值爲0xfffffff0,movl -4(%ebp),%eax 賦值a爲%eax,andl -8(%ebp),%eax b與%eax(a)的值相與,並將結果放入%eax中,movl %eax,-12(%ebp) 將與的結果放入c中。
andl $0xfffffff0,%eax 將0xfffffff0與%eax相與,並將結果放入%eax中。
用到的指令有

指令 效果 描述
AND S,D D<-D&S

或運算 0 1
0 0 1
1 1 1

可以用於設置某些位。

#include <stdio.h>
int main(void)
{
	int a=0xfffffff0;
	int b=0xe;
	int c=a|b;   //相當於a減去a%16的值
	printf("value=%d\n",c);
	
	c=a|0xe;
	printf("value=%d\n",c);
	
	return 0;
}

彙編代碼

.section .rodata
	.LC0:.string "value=%d\n"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $12,%esp
	movl $0xfffffff0,-4(%ebp);a
	movl $0xe,-8(%ebp);b
	movl -4(%ebp),%eax
	orl -8(%ebp),%eax
	movl %eax,-12(%ebp);c
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl -4(%ebp),%eax
	orl $0xe,%eax
	movl %eax,-12(%ebp)
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl $0,%eax
	leave
	ret

movl $0xfffffff0,-4(%ebp) 賦值a爲0xfffffff0,movl $0xe,-8(%ebp) 賦值b爲0xe,movl -4(%ebp),%eax 將a放入%eax中。orl -8(%ebp),%eax a與b相或,結果放入%eax中。movl %eax,-12(%ebp) 結果放入c中。
orl $0xe,%eax 將%eax與0xe相或,結果放入%eax中。
用到的指令有

指令 效果 描述
OR S,D D<-D S

異或

異或運算 0 1
0 0 1
1 1 0

可以用異或操作來翻轉某些位。

#include <stdio.h>
int main(void)
{
	int a=100;
	int b=100;
	int c=a^b;   //相當於a減去a%16的值
	printf("value=%d\n",c);
	
	c=a^100;
	printf("value=%d\n",c);
	
	return 0;
}

彙編代碼

.section .rodata
	.LC0:.string "value=%d\n"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $12,%esp
	movl $100,-4(%ebp);a
	movl $100,-8(%ebp);b
	movl -4(%ebp),%eax
	xorl -8(%ebp),%eax
	movl %eax,-12(%ebp);c
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl -4(%ebp),%eax
	xorl $100,%eax
	movl %eax,-12(%ebp)
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl $0,%eax
	leave
	ret

movl $100,-4(%ebp) 賦值a爲100,movl $100,-8(%ebp) 賦值b爲100,movl -4(%ebp),%eax 將a放入%eax中。xorl -8(%ebp),%eax a與b相異或,結果放入%eax中。movl %eax,-12(%ebp) 結果放入c中。
xorl $100,%eax 將%eax與100相異或,結果放入%eax中。
用到的指令有

指令 效果 描述
XOR S,D D<-D^S 異或

取反

取反運算 0 1
1 0

可以用取反獲取原值各位取反的結果,例如0x1的取反結果爲0xfffffffe。

#include <stdio.h>
int main(void)
{
	int a=0x55555555;
	int b=~a;   //相當於a減去a%16的值
	printf("value=%d\n",b);
	
	return 0;
}

彙編代碼

.section .rodata
	.LC0:.string "value=%d\n"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $8,%esp
	movl $0x55555555,-4(%ebp);a
	movl -4(%ebp),%eax
	notl %eax
	movl %eax,-8(%ebp);b
	
	pushl -8(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp

	movl $0,%eax
	leave
	ret

subl $8,%esp 申請了8個字節,用於存放a,b。movl $0x55555555,-4(%ebp) 將0x55555555賦值給a,movl -4(%ebp),%eax 將a的值賦值給%eax,notl %eax 取反%eax,movl %eax,-8(%ebp) 將取反的結果放入b中。
用到的指令有

指令 效果 描述
NOT D D<-~D 取反

算術左移和邏輯左移
向左移動二進制位。如 0xf << 4=0xf0。算術左移和邏輯左移的效果是相同的,可以相互替換。

#include <stdio.h>
int main(void)
{
	int a=0xf;
	int b=4;
	int c=a<<b;
	printf("value=%d\n",c);
	
	c=a<<4;
	printf("value=%d\n",c);
}

彙編代碼

.section .rodata
	.LC0:.string "value=%d\n"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $12,%esp
	movl $0xf,-4(%ebp);a
	movl $4,-8(%ebp);b
	movl -4(%ebp),%eax
	movl -8(%ebp),%ecx
	shll %lc,%eax
	movl %eax,-12(%ebp);c
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl -4(%ebp),%eax
	shll $4,%eax
	movl %eax,-12(%ebp)
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl $0,%eax
	leave
	ret

movl $0xf,-4(%ebp) 將0xf賦值給a,movl $4,-8(%ebp) 4放入b中,movl -4(%ebp),%eax a放入%eax中,movl -8(%ebp),%ecx b放入%ecx中,shll %lc,%eax左移%cl位,這裏是4位,將左移結果放入%eax中,movl %eax,-12(%ebp) 將%eax結果放入c中。
shll $4,%eax 將%eax中的值左移4位並放入%eax中。
指令有

指令 效果 描述
SAL k,D D<-D<<k 算術左移
SHL k,D D<-D<<k 邏輯左移

偏移量可以是立即數,或是放入%cl中的值。

算術右移
向右移動二進制位。右邊添加符號位。有符號數用算術右移,無符號數用邏輯右移。

#include <stdio.h>
int main(void)
{
	int a=0xf0;
	int b=4;
	int c=a>>b;
	printf("value=%d\n",c);
	
	c=a>>4;
	printf("value=%d\n",c);
}

彙編代碼

.section .rodata
	.LC0:.string "value=%d\n"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $12,%esp
	movl $0xf0,-4(%ebp);a
	movl $4,-8(%ebp);b
	movl -4(%ebp),%eax
	movl -8(%ebp),%ecx
	sarl %lc,%eax
	movl %eax,-12(%ebp);c
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl -4(%ebp),%eax
	sarl $4,%eax
	movl %eax,-12(%ebp)
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl $0,%eax
	leave
	ret

sarl %lc,%eax sarl $4,%eax 算術右移
指令有

指令 效果 描述
SAR k,D D<-D>>k 算術右移

邏輯右移
向右移動二進制位。右邊添加0。

#include <stdio.h>
int main(void)
{
	unsigned int a=0xf;
	unsigned int b=4;
	unsigned int c=a<<b;
	printf("value=%d\n",c);
	
	c=a<<4;
	printf("value=%d\n",c);
}

彙編代碼

.section .rodata
	.LC0:.string "value=%d\n"
.text
.global main

main:
	pushl %ebp
	movl %esp,%ebp
	
	subl $12,%esp
	movl $0x0,-4(%ebp);a
	movl $4,-8(%ebp);b
	movl -4(%ebp),%eax
	movl -8(%ebp),%ecx
	shrl %lc,%eax
	movl %eax,-12(%ebp);c
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl -4(%ebp),%eax
	shrl $4,%eax
	movl %eax,-12(%ebp)
	
	pushl -12(%ebp)
	pushl $.LC0
	call printf
	addl $8,%esp
	
	movl $0,%eax
	leave
	ret

shrl %lc,%eax shrl $4,%eax 算術右移
指令有

指令 效果 描述
SHR k,D D<-D>>k 邏輯右移
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章