微机原理常用代码
选择结构(简单分支程序设计)
1.编写程序,计算下面函数的值并输出。
? 
include io32.inc
? .data
? .code
start:
? call readuid
? cmp eax,0
? jge xge0
? imul eax,2
? jmp display
xge0:
? cmp eax,10
? jg xg10
? imul eax,3
? jmp display
xg10:
? imul eax,4
display:
? call dispuid
? exit 0
? end start
2.输入一个年份(可调用readuid子程序,读入年份),判断是否是闰年.
提示:采用伪代码描述如下:
include io32.inc
.data
msg1 byte 'is leap year', 13, 10, 0
msg2 byte 'is not leap year', 13, 10, 0
.code
start :
call readuid
mov edx,0
mov ecx,4
div ecx
cmp edx,0
je s1
jmp s2
exit 0
s1:
mov edx,0
mov ecx,100
div ecx
jne leap
jmp s2
s2:
mov edx,0
mov ecx,400
div ecx
je leap
jmp noleap
leap:
mov eax,offset msg1
call dispmsg
exit 0
noleap:
mov eax,offset msg2
call dispmsg
exit 0
end start
3. 输入三个无符号整数(可调用rebulid子程序),判断并输出这三个数能否构成一个三角形的三条边
include vcio.inc
.data ;setdata segment
yes byte '可以构成',0
no byte '不能构成', 0
dengbian byte '等边三角形',0
dengyao byte '等腰三角形',0
x dword ?
y dword ?
z dword ?
fmt byte '%d %d %d',0
fmts byte '%s',0
.code
main proc
invoke scanf,offset fmt,offset x,offset y,offset z
mov eax,x
add eax,y
mov ebx,x
add eax,z
mov ecx,y
add ecx,z
mov esi,x; 做运算时不能两个同为memory变量 所以esi
mov edi,y
.if(eax>z)&&(ebx>y)&&(ecx>x)
invoke printf,offset fmts,offset yes; //如果是字符串一定要加offset
.if(esi==y)&&(esi==z)
invoke printf,offset fmts,offset dengbian
.else if(esi==y||esi==z||edi==z)
invoke printf,offset fmts,offset dengyao
.endif
.else
invoke printf,offset fmts,offset no
.endif
ret
main endp
end main
4. 采用无条件和有条件转移指令构造while和do while 循环结构,完成下面的求和任务并输出sum(sum为双字)。
inclued vcio.inc
.data
fmt bate 'sum=%d',0
.code
start:
mov eax,0
mov ecx,1
.while ecx<101
add eax,ecx
inc ecx
.endw
invoke printf,offset fmt,eax
ret
end start
//**思考题:假设双字为无符号整数,sum=1+2+...n,在和不溢出的情况下求出n的最大值;q求出sum和n的值。
include vcio.inc
.data
fmt byte 'sum=%u n=%d',0
.code
start:
mov eax,0
mov ecx,1
again:
add eax,ecx
jc next
inc ecx
jmp again
next:
sub eax,ecx //加上ecx数超线
dec ecx// ecx减
invoke printf,offset fmt,eax,ecx
ret
end start
5. 编写一个程序,先提示输入数字“input number:09”,然后再下一行显示输入的数字,结束;如果不是键入了09数字,就提示错误“Error”,继续等待输入数字。
include vcio.inc
.data
inmsg byte 'input number(0~9):',10,0
ermsg byte 'ERROR!',10,0
fmt byte '%c',0
fmtin byte '%s',0
fmeter byte '%s',0
chd byte ?
tt bytr ?
.code
start:
L1: invoke printf,offset fmtin,offset inmsg
invoke scanf,offset fmt,offset chd
.if chd>='0'&&chd<='9'
invoke printf,offset fmt,chd
.else
invoke printf,offset fmter,offset ermsg
invoke scanf,offset fmt,offset tt//tt吸收无效字符
jmp L1
.endif
ret
end start
循环结构
1. 有一个首地址为array的10个有符号的双字数组,编程分别求出偶数和与奇数和并输出。思考:改求最大值,最小值,正数和,负数和。
include vcio.inc
.data
array dword 1,2,3,6
fmt byte 'evensum=%d oddsum=%d',0
.code
start:
mov ecx,lengthof array
xor eax,eax//oushu
xor ebx,ebx//奇数
mov esi,0 ;数组下标-0开始
.while ecx>0
test array[esi*4],1//奇数 结果为0 zf为1
.if zero?
add eax,array[esi*4];偶数和
.else
add ebx,array[esi*4];
.endif
inc esi 下标增加
dec ecx
endw
invoke printf,offset fmt,eax,ebx
ret
end start
最大最小
include vcio.inv
.data
array dword 11,3,4,6,55,9
fmt byte 'max = %d min=%d',0
.code
mov esi,0
mov eax,array[esi*4]
mov ebx,eax
mov ecx,lebgthof array
.while esi
正数和负数
include vcio.inv
.data
array dword 11,3,4,6,55,9
fmt byte 'Positive = %d Negetive=%d',0
.code
mov esi,0
mov eax,0
mov ebx,0
mov ecx,lebgthof array
.while esi
2. 有一个首地址为array的10个有符号的双字数组,编程逆置数组并输出。
;逆置一个一维数组
;算法描述
;left,right分别指向数组的第一个和最后一个元素,采用首尾交换。
; 1.left=0,right=n-1;
; 2.while left
3. Fibonacci 给出前30项,思考:在不产生溢出的情况下n的最大值
1. print 1,1
2. esi=esi+edi
2.1 if cy=1 then goto done
2.2print esi
2.3exchange esi,edi
2.4goto 2
4. 编程写一个完整的程序,求出2012年~2099年中的所有闰年年份,存入Lyear数组中
include vcio.inc
.data
array dword 100,dup(?)
fmt byte '%d',0
fmto byte '%d' ,0
.code
start:
mov esi,0
again:
mov ecx,2020
.while ecx<=2020
mov eax,ecx
xor edx,edx
mov ebx,400
div ebx
cmp edx,0
jz yes
mov eax,ecx
xoe edx,edx
mov ebx 4
div ebx
cmp edx,0
jnz no
mov eax,ecx
xoe edx,edx
mov ebx 100
div ebx
cmp edx,0
jz no
yes:
mov array[esi*4],ecx
inc esi
no:
inc ecx
.endw
mov ebx,0
.while ebx
5. 有一个首地址为string的字符串 ,分别统计string中空格、英文字母、数字和其它字符的个数并输出。
include vcio.inc
.data
msg byte '12 ahi'
space dword ?
letter dword ?
digit dword ?
other dword ?
fmt byte 'space = %d digit=%d other=%d',0
.code
main proc
mov edi,lengthof msg-1 为了不判断0
xor eax,eax ;space=eax=0
mov ebx,eax ;letter=ebx=0
mov ecx,eax ;digit=ecx=0
mov edx,eax ;other=edx=0
mov esi,0
.while esi='a'&&msg[esi]<='z')||(msg[esi]>='A'&&msg[esi]<='Z')
inc ebx;
letter++
.elaseif(msg[esi]>='1'&&msg[esi]<='9')
inc edx;
digit++
.else
inc edx
other ++
.endif
inc esi
.endw
invoke printf,offset fmt,eax,ebx,ecx,edx
ret
main endp
end start
6. palindrome(回文)是指正读和反读都一样的数或文本。例如:11、121、12321等,编写程序,求10到10000之间所有回文数并输出。要求每行输出10个数。
include vcio.inc
.data
fmt byte '%4d',0
.code
start:
mov ecx,10
mov ebx,ecx //ecx=10除数
.while ecx<=100
xor edz,edx //edx被除数的高32位
div ebx
imul esi 10
add esi,edx//逆序生成新数,esi=esi*10+edx
.endw
.if esi==ecx
pushad
invoke pritf,offset fmt,ecx
popad
.endif
inc ecx
.endw
ret
end start
子程序
1..编写一个求n!的子程序,利用它求1!+2! +3! +4! +5! +6! +7! +8! 的和并输出。要求参数的传递分别采用寄存器传递,全局变量传递,堆栈传递。
;寄存器传参
include vcio.inc
.data
fmt byte 'result =%d',10,0
.code
main proc
mov edx,1
.while ebx<=8
call jcc;阶层子程序
inoke printf,offset fmt,eax ;;eax传回来的值
inc ebx
.endw
ret
main endp
jcc proc
mov ecx,1
mov eax,1
.while ecx<=ebx ;ebx是主程序传参进来的 寄存器传递
imul eax,ecx ;阶层的和在eax
inc ecx
.endw
ret
jcc endp
end main
;堆栈传参
;ebp+4断点地址,ebp+8 call 植爱玲前的入栈就是参数 子程序里找ebp
include vcio.inc
.data
fmt byte 'result=%d',10,0
.code
main proc
.while mov ebx<=8
push ebx
call jcc
invoke printf,offset fmt,eax
inc ebx
.endw
ret
main endp
jcc proc
;ret 1*4是平衡ebx call
push ebp
mov ebp,esp
mov ecx,1
mov eax,1
mov ebx,[ebp+8]
.while ecx<=ebx
imul eax,ecx
inc ecx
.endw
pop ebp
ret 1*4
jcc endp
end main
;全局变量传递
2. 编写一个判断闰年的子程序,利用它求出2010到2060之间所有的闰年并输出。
3. 编程写一个名为Prime的子程序,用于测试一个整数是否是素数,主子程序间的参数传递通过堆栈完成。调用Prime子程序求出2~100之间的所有素数,并将它们存入Parray数组中,素数的个数存入变量Pcounter中
#include
void main()
{
int j,i,k;
for(i=2;i<=100;i++)
{
k=1/2;
for(j=k;j>=2;j--)
if(i%i==0)
break;
if(j<2)
printf("%5d",i);
}
}
;换一个思路设置标记位
#include
voide main()
{
int j,i,k,flag;
for(i=2;i<=100;i++)
{
k=i/2;
for(j=k;j>=2;j--)
if(i%j==0)
flag=0;
else
flag==1;
if(flag==1)
printf("%5d",i);
}
}
;汇编
include vcio.inc
.data
Prime dword 100 dup(?)
flag byte 1
fmt byte '%3d',0
fmtn byte 'Pcounter=%d',0
.code
main proc
xor esi,esi;下标
mov ecx,2; 2~10
.while(ecx<=10)
call prime
.if flag==1
mov Prime[esi*4],ecx
.else
jmp L1
.endif
pushad
invoke printf,offset fmt,Prime[esi*4]
popad
inc esi
L1:
inc ecx
.endw
invoke printf,offset fmtn,esi
ret
main endp
prime proc
push ecx
push esi
mov eax,ecx ;x
mov ebx,ecx ;x
shr ecx,1 ;ecx=x/2
.while(ecx>=2)
mov eax,ebx
div ecx
.if edx==0
mov flag,0
.else
mov flag,1
.endif
dec ecx
.endw
pop esi
pop ecx
ret
prime endp
end main
4. 编程写一个名为Gcd的求两个数最大公约数子程序,主子程序间的参数传递通过堆栈完成。调用Gcd子程序求出三个双自变量:dvar1、dvar2与dvar3的最大公约数并输出。(欧几里得算法 辗转相除法)
;算法思想:gcd(a,o)=a; gcd(a,b)=gcd(b,a mod b)
;in c
int gcdx(int m,int n)
{
int r;
while(n!=0)
{
r=m%n;
m=n;
n=r;
}
return m;
}
;汇编
include vcio.inc
.data
m dword ?
n dword ?
r dword ?
dgcd dword ? ;2个数的最大公约数
fmtout byte 'gcd($d,%d,%d)=%d',10,0
fmtin byte '%d %d %d',0
.code
main proc
invoke scanf,offset fmtin,offset m,offset n,offset r
mov eax,m
mov ebx,n
mov ecx,r
call Gcd ;求a,b的最大公约数
mov eax,dgcd
mov ebx,ecx
call Gcd ;(a,b)和c的最大公约数
ret
main endp
;全局寄存器变量
Gcd proc;求两个数的最大公约数
.while(ebx!=0)
xor edx,edx
div ebx
mov eax,ebx;m=n
mov ebx,edx;n=r edx=余数
.endw
mov dgcd,eax ;dgcd最大公约数
ret
Gcd endp
end main
//多次强调输出
5. 编写一子程序,将一个32位二进制数用8位十六进制形式在屏幕上显示出来。采用堆栈方法传递这个32位二进制数,并写主程序验证它。
include vcio.inc
.data
dvar dword 1234abcd
table byte '0123456789abcdef' ;查表法
fmt byte '%c',0
.code
main proc
call btoh
ret
main endp
btoh proc
mov eax,dvar
mov ecx,1
.while ecx<=8
rol eax,4 ;eax的最高四位移动到最低4位
mov ebx,eax
and eax,0fh ;保留eax的最低的四位
mov al,table[eax]
pushad
invoke printf,offset fmt,al
popad
mov eax,ebx
inc ecx
.endw
ret
btoh endp
6. 编程写一个名为Bubble的冒泡排序子程序,主子程序间的参数传递通过堆栈完成;并写主程序验证它。显示一个无符号数的子程序为:dispuid,入口参数:EAX=要显示无符号数的值。
include vcio.inc
.data
array dword 2,3,1
num dword lengthof array-1
fmt byte '%3d',0
.code
main proc
call Bubble
mov esi,0
.while(esi<=num)
invoke printf,offset fmt,array[esi*4]
inc esi
.endw
ret
main endp
Bubble proc
mov esi,0 ;i
mov edi,1 ;j
mov ecx,1 ;pass
.while ecx<=num
mov esi,0 ;i
mov edi,0 ;j
.while esiarray[edi*4]
mov edx,array[esi*4]
xchg edx,array[edi*4]
mov array[esi*4],edx
.endif
inc esi
inc edi
.endw
inc ecx
.endw
ret
Bubble endp
end main
;if a[i]>a[i+1] i+1用j表示
上课汇编程序
1. 数据比较程序
; 数据段
in_msg1 byte 'Enter a number: ',0
in_msg2 byte 'Enter another number: ',0
out_msg1 byte 'Two numbers are equal: ',0
out_msg2 byte 'The less number is: ',0
out_msg3 byte 13,10,'The greater number is: ',0
; 代码段
mov eax,offset in_msg1 ; 提示输入
call dispmsg
call readsid ; 输入第一个数据
mov ebx,eax ; 保存到EBX
mov eax,offset in_msg2 ; 提示输入
call dispmsg
call readsid ; 输入第二个数据
mov ecx,eax ; 保存到ECX
cmp ebx,ecx ; 二个数据进行比较
jne nequal ; 两数不相等,转移
mov eax,offset out_msg1
call dispmsg ; 显示两数相等
mov eax,ebx
call dispsid ; 显示相等的数据
jmp done ; 转移到结束
nequal: jl first
; EBX较小,不需要交换,转移
xchg ebx,ecx
; EBX保存较小数,ECX保存较大数
first: mov eax,offset out_msg2
; 显示较小数
call dispmsg
mov eax,ebx ; 较小数在EBX中
call dispsid
mov eax,offset out_msg3
; 显示较大数
call dispmsg
mov eax,ecx ; 较大数在ECX中
call dispsid
done:
2. 显示符号最高位程序
; 数据段
dvar dword 0bd630422h ; 假设一个数据
; 代码段
mov ebx,dvar
shl ebx,1 ; EBX最高位移入CF标志
jc one
; CF=1,即最高位为1,转移
mov al,'0'
; CF=0,即最高位为0:AL←'0'
jmp two ; 一定要跳过另一个分支
one: mov al,'1' ; AL←'1'
two: call dispc ; 显示
mov ebx,dvar
mov al,'0'
; 假设最高位为0:AL←'0'
shl ebx,1 ; EBX最高位移入CF标志
jnc two
; CF=0,即最高位为0,转移
mov al,'1'
; CF=1,即最高位为1,AL←'1'
two: call dispc ; 显示
3. 有符号位运算溢出程序
; 数据段
dvar1 dword 1234567890 ; 假设两个数据
dvar2 dword -999999999
dvar3 dword ?
okmsg byte 'Correct!',0 ; 正确信息
errmsg byte 'ERROR ! Overflow!',0 ; 错误信息
; 代码段
mov eax,dvar1
sub eax,dvar2 ; 求差
jo error ; 有溢出,转移
mov dvar3,eax ; 无溢出,保存差值
mov eax,offset okmsg ; 显示正确
jmp disp
error: mov eax,offset errmsg ; 显示错误
disp: call dispmsg
4. 简单加密解密程序
; 数据段
key byte 234
bufnum = 255
buffer byte bufnum+1 dup(0)
; 定义键盘输入需要的缓冲区
msg1 byte 'Enter messge: ',0
msg2 byte 'Encrypted message: ',0
msg3 byte 13,10,'Original messge: ',0
; 代码段
mov eax,offset msg1 ; 提示输入字符串
call dispmsg
mov eax,offset buffer ; 设置入口参数EAX
call readmsg ; 调用输入字符串子程序
push eax ; 字符个数保存进入堆栈
mov ecx,eax
; ECX=实际输入的字符个数,作为循环的次数
xor ebx,ebx ; EBX指向输入字符
mov al,key ; AL=加密关键字
encrypt: xor buffer[ebx],al ; 异或加密
inc ebx
dec ecx ; 等同于指令:loop encrypt
jnz encrypt ; 处理下一个字符
mov eax,offset msg2
call dispmsg
mov eax,offset buffer ; 显示密文
call dispmsg
pop ecx
; 从堆栈弹出字符个数,作为循环的次数
xor ebx,ebx ; EBX指向输入字符
mov al,key ; AL=解密关键字
decrypt: xor buffer[ebx],al ; 异或解密
inc ebx
dec ecx
jnz decrypt ; 处理下一个字符
mov eax,offset msg3
call dispmsg
mov eax,offset buffer ; 显示明文
call dispmsg
5.字符个数统计程序
; 数据段
string byte ‘Do you have fun with Assembly?’,0
; 以0结尾的字符串
; 代码段
xor ebx,ebx
; EBX用于记录字符个数,也用于指向字符的指针
again: mov al,string[ebx]
cmp al,0
; 用指令“test al,al”更好
jz done
inc ebx ; 个数加1
jmp again ; 继续循环
done: mov eax,ebx ; 显示个数
call dispuid
6.字符剔除程序
mov eax,offset string
; 显示处理前字符串
call dispmsg
mov esi,offset string
outlp: cmp byte ptr [esi],0
; 外循环,先判断后循环
jz done ; 为0结束
again: cmp byte ptr [esi],' ' ; 是否是空格
jnz next ; 不是空格继续循环
mov edi,esi ; 是空格,剔除空格分支
inlp: inc edi ; 该分支是循环程序
mov al,[edi] ; 前移一个位置
mov [edi-1],al
cmp byte ptr [edi],0
; 内循环,先循环后判断
jnz inlp ; 内循环结束处
jmp again
; 再次判断是否为空格(处理连续空格)
next: inc esi
; 继续对后续字符进行判断处理
jmp outlp ; 外循环结束处
done: mov eax,offset string
; 显示处理后字符串
call dispmsg
7. 计算有符号数平均值
; 数据段
array dword 675,354,-34, ...
; 代码段
push lengthof array ; 压入数据个数
push offset array ; 压数组的偏移地址
call mean
; 调用求平均值子程序
;出口参数:EAX=平均值(整数部分)
add esp,8
; 平衡堆栈(压入了8个字节数据)
call dispsid ; 显示
; 计算32位有符号数平均值子程序
mean proc
; 入口参数:顺序压入数据个数和数组偏移地址
push ebp ;出口参数:EAX=平均值
mov ebp,esp
push ebx ; 保护寄存器
push ecx
push edx
mov ebx,[ebp+8] ; EBX=取出的偏移地址
mov ecx,[ebp+12] ; ECX=取出的数据个数
xor eax,eax ; EAX保存和值
xor edx,edx ; EDX=指向数组元素
mean1: add eax,[ebx+edx*4] ; 求和
add edx,1 ; 指向下一个数据
cmp edx,ecx ; 比较个数
jb mean1 ; 循环
cdq ; 将累加和EAX符号扩展到EDX
idiv ecx ; 有符号数除法,EAX=平均值
pop edx ; 恢复寄存器
pop ecx
pop ebx
pop ebp
ret
mean endp