目录
问题1:编写汇编语言源程序,实现从键盘键入单个小写字母,转换成对应的大写字母输出。
问题2:已知X,Y,Z为十六位带符号数,编写汇编语言源程序实现公式计算
问题4:自编程序,从键盘输入一个用$结尾的字符串,在屏幕上输出该字符串(不包括$)
问题5:自编程序:完成双字数据(如:87654321H)算术右移一个二进制位。
问题1:编写汇编语言源程序,实现从键盘键入单个小写字母,转换成对应的大写字母输出
实验代码如下所示:
;使用简化的段定义
.model small ;定义存储模型时的段默认情况
.stack ;指定堆栈段的大小,如果不指定,默认值为1kb
.data ;定义数据段
string db 'Please input a Lowercase letter:',0dh,0ah,'$'
.code ;定义代码段
start:
mov ax,@data
mov ds,ax
lea dx,string
mov ah,9
int 21h
mov ah, 1
int 21h
sub al, 20h
mov dl, al
mov ah, 2
int 21h
mov ah,4ch
int 21h
end start
运行程序,测试结果如下所示:
问题2:已知X,Y,Z为十六位带符号数,编写汇编语言源程序实现下列公式计算,并将除后的结果不仅存入Z中,也存入自定义的堆栈段中。
实现代码如下所示:
;已知XYZ为十六位带符号数,求((X+Y)*8-X)/2,将得到的结果存入Z和自定义的堆栈段
assume cs:code,ds:data,ss:stack
data segment
array dw 1234H,4321H,? ;分别为X,Y,Z的位置0000 0001,0002 0003,0004,0005
data ends
stack segment
answer db 20 dup(?)
stack ends
code segment
start:
mov ax,data
mov ds,ax
mov bx,stack
mov ss ,bx
mov bx,offset answer
add bx,4
mov sp,bx
lea si,array
mov ax,[si]
mov bx,[si+2]
mov di,si
add di,4 ;di存放Z的位置
call calc
push dx
push ax ;将结果保存到自定义的堆栈段中
mov ax,4c00h
int 21h
calc:
push ax ;进入程序时ax = X, bx = Y
add ax,bx
mov bx,8H
imul bx ;(X+Y)*8,此时高字节在dx,低字节在ax
mov cx,ax
mov bx,dx ;将(X+Y)*8保存到bx,cx中
pop ax
cwd ;将X转换为双字,放在dx,ax中
sub cx,ax
sbb bx,dx ;减去进位
mov ax,cx
mov dx,bx ;(X+Y)*8-X
sar dx,1 ;dx除以2,余数放入CF中,算术右移适合用来处理无符号运算
rcr ax,1 ;ax除以2,CF进ax中,余数进CF
adc ax,0 ;加上ax余数
mov [di],ax
mov [di+2],dx ;小端存储,低字节放低地址,高字节放高地址,结果位4c3a
ret
code ends
end start
使用debug观察运行结果如下所示:
问题3:段定义及段组定义伪指令的使用
实现代码如下所示:
data1 segment word 'data'
const1 dw 100
const2 db -12H
data1 ends
data2 segment word 'data'
var1 dw ?
data2 ends
datagroup group data1,data2
code segment
assume cs:code, ds:datagroup
start:
mov ax, datagroup
mov ds, ax
mov al, byte ptr const1+1 ;101
mov var1, ax
mov ax, 4c00h
int 21h
code ends
end start
(1)、编辑,编译,连接,生成LST文件,运行该程序获得如下结果:
(2)、使用type命令查看生成的.LST文件内容,如下所示:
可以观察到各个变量const1,const2,var1,标号start,文件名filename:4-3其中:
const1的type类型为word,偏移地址为0000,属于数据段data1
const2的类型为byte,偏移地址为0002,属于数据段data1
var1的类型为word,偏移地址为0000,属于数据段data2
start的类型为near,说明该标号是在本段内部引用的,偏移地址为0000,属于代码段code,使用debug追踪调试,可以观察到便变量const1和const2以及var1修改之后的值
const1上的值为100,即0064,const2上的值为-12(byte类型)即为EE,mov ax,const1+1,const1+1即0001,而ax为字单元,所以从0002-0001取一个字数据即EE00赋值给ax寄存器所以(ax)= 00EE,再将ax中的内容赋值给变量var1,所以var1中的值为00EE。
(3)、data1段和data2段的起始字节的物理地址显然是不相同的,两个段使用段组定义伪操作,共用同一个数据段段,其偏移地址必然不相同,添加指令,获取两端首字节的段地址和偏移地址。添加指令如下:
mov ax,seg const1
mov bx,seg var1
mov dx,offset const1
mov cx,offset var1
Debug追踪调试,可以观察到data1和var1的段地址相同,均为076C,而偏移地址不同,分别为0000和0004,与上一题的分析符合一致,两者的物理地址不相同,并且两个数据段的存储位置存在一个字节的间隔,而代码段CS的段地址为076D,显然与两个数据段之间的存储位置是有间隔的。
(4)、之前的程序中(ax)的值修改为EE00,al中的值为00
将ax修改为al后,由于const1是字数据,而al是字节类型,显然会报错.修改该指令的源操作数
的类型为字节型数据即可,修改指令如下所示:
mov al, byte ptr const1+1
得到al的正确结果00
问题4:自编程序,从键盘输入一个用$结尾的字符串,在屏幕上输出该字符串(不包括$)
assume cs:code,ds:data
data segment
output db 'Enter your string: $'
input db 0dh,0ah,'Your input is'
string db 30 DUP('1')
data ends
code segment
start:
mov ax,data
mov ds,ax
lea dx,output
mov ah,9h
int 21h
lea dx,string
mov ah,0ah
int 21h
mov ax, 203AH
mov word ptr string,ax ;将dx和dx+1中的值覆盖
lea dx,input
mov ah,9
int 21h
mov ax,4c00h
int 21h
code ends
end start
运行结果如下所示:
题目五:自编程序:完成双字数据(如:87654321H)算术右移一个二进制位。
对一个双字数据进行算术右移,最低位进入CF标志寄存器,最高位保持不变
因此我们将该数据分别存放在dx(高16位)和ax(低16位),然后对dx进行算术右移一位,再对ax进行带进位循环右移一位即可,高16位的最低一位进入CF,CF再进入低十六位的最高位,低十六位的最低一位进入CF寄存器即可完成双字数据的算术右移,实验程序如下所示:
assume cs:code,ds:data
data segment
num dd 87654321H
data ends
code segment
start:
mov ax,data
mov ds,ax
lea si,num
mov ax,[si]
mov dx,[si+2]
sar dx,1
rcr ax,1
mov ax,4c00h
int 21h
code ends
end start
借用计算机求得算术右移的结果应当为87654321/2+10000000 = C3B2 A190
调试源程序得到如下结果:
右移之前(dx)= 8765,(ax)= 4321.CF = 0
右移之后,(dx)= C3B2 ,(ax) = A190,CF = 1
即双字右移后的结果位C3B2 A190,与预期结果一致