第三章:
Tarzan版
题3.1 伪指令语句与指令语句的本质区别是什么?伪指令的主要作用是什么?
答: 伪指令语句与指令语句的本质区别是指令语句有其对应的机器指令,而伪指令没有;
伪指令的主要作用是指示汇编程序如何汇编源程序;
题3.2 汇编语言中的表达式与高级语言中的表达式有何相同点和不同点?
答: 汇编语言中的表达式与高级语言中的表达式的相同点是都采用运算符、操作符以及括号
把常数和符合连起来;
不同点是汇编语言的表达式除了数值表达式外还有地址表达式;
题3.3 汇编语言中数值表达式与地址表达式有何区别?
答: 汇编语言中数值表达式在汇编过程中由汇编程序计算出数值,而地址表达式中部分相对地址
的地方,在汇编时无法确定其确定地址;
题3.4 汇编语言中的变量和标号有何异同之处?
答: 汇编语言中的变量和标号的相同之处是都代表着一个地址;
不同之处是变量表示的地址中存放的是数据,而标号表示的地址中存放的是代码;
题3.5 请计算如下各数值表达式的值:
23H AND 45H OR 67H
1234H/16+10H
NOT(65535 XOR 1234H)
1024 MOD 7+3
LOW 1234 OR HIGH 5678H
23H SHL 4
"Eb" GE 4562H XOR -1
1234H SHR 6
'a' AND (NOT ('a'-'A')
'H' OR 00100000B
76543Q LT 32768 XOR 76543
3645H AND 0FF00H
答: 23H AND 45H OR 67H ;67H
1234H/16+10H ;133H
NOT(65535 XOR 1234H) ;1234H
1024 MOD 7+3 ;5
LOW 1234 OR HIGH 5678H ;D6H 注意1234 不是1234H
23H SHL 4 ;30H
"Eb" GE 4562H XOR -1 ;0
1234H SHR 6 ;0048H
'a' AND (NOT ('a'-'A') ;41H or 'A'
'H' OR 00100000B ;68H or 'h'
76543Q LT 32768 XOR 76543 ;题目最后的76543有错,按照76543Q处理:829CH
3645H AND 0FF00H ;3600H
题3.6 请计算如下程序片段中各地址表达式的值,设BX=1000H,SI=2000H,DI=3000H,
BP=4000H
[BX+100H]
[DI][BP]
2000H[SI]
10H[BX][SI]
[BP-128]
[BX][DI-2]
答: [BX+100H] ;[1100H]
[DI][BP] ;[7000H]
2000H[SI] ;[4000H]
10H[BX][SI] ;[3010H]
[BP-128] ;[3F80H]
[BX][DI-2] ;[3FFEH]
题3.7 设在某个程序中有如下片段,请写出每条传送指令执行后寄存器AX的内容:
ORG 100H
VARW DW 1234H,5678H
VARB DB 3,4
VARD DD 12345678H
BUFF DB 10 DUP(?)
MESS DB 'HELLO'
BEGIN: MOV AX,OFFSET VARB + OFFSET MESS
MOV AX,TYPE BUFF + TYPE MESS + TYPE VARD
MOV AX,SIZE VARW + SIZE BUFF + SIZE MESS
MOV AX,LENGTH VARW + LENGTH VARD
MOV AX,LENGTH BUFF + SIZE VARW
MOV AX,TYPE BEGIN
MOV AX,OFFSET BEGIN
答: ORG 100H
VARW DW 1234H,5678H
VARB DB 3,4
VARD DD 12345678H
BUFF DB 10 DUP(?)
MESS DB 'HELLO'
BEGIN: MOV AX,OFFSET VARB + OFFSET MESS ;AX=0218H
MOV AX,TYPE BUFF + TYPE MESS + TYPE VARD ;AX=0006H
MOV AX,SIZE VARW + SIZE BUFF + SIZE MESS ;AX=000DH
MOV AX,LENGTH VARW + LENGTH VARD ;AX=0002H
MOV AX,LENGTH BUFF + SIZE VARW ;AX=000CH
MOV AX,TYPE BEGIN ;AX=FFFFH
MOV AX,OFFSET BEGIN ;AX=0119H
题3.8 设如下两条指令中的符号ABCD是变量名,请说明这两条指令的异同。
MOV AX,OFFSET ABCD
LEA AX,ABCD
答: 两条指令都是将ABCD的偏移地址放入AX寄存器中;
不同之处是OFFSET只能取得用数据定义伪指令的变量的有效地址,而不能取得一般操作
数的有效地址;
题3.9 请指出如下指令的不明确之处,并使其明确:
MOV ES:[BP],5
ADD CS:[1000H],10H
DEC SS:[BX-8]
JMP CS:[SI+1000H]
MUL [BX+DI+2]
DIV [BP-4]
答: MOV ES:[BP],5 ;未指定存储单元属性 MOV WORD PTR ES:[BP],5
ADD CS:[1000H],10H ;同上 ADD WORD PTR CS:[1000H],10H
DEC SS:[BX-8] ;同上 DEC WORD PTR SS:[BX-8]
JMP CS:[SI+1000H] ;无法确定段间还是段内转移
JMP WORD PTR CS:[SI+1000H]
MUL [BX+DI+2] ;无法确定是8位乘法还是16位乘法
MUL WORD PTR [BX+DI+2]
DIV [BP-4] ;同上 DIV WORD PTR [BP-4]
题3.10 设在某个程序中有如下片段,请改正其中有错误的指令语句:
VARW DW 1234H,5678H
VARB DB 3,4
VARD DD 12345678H
......
MOV AX,VARB
MOV VARD,BX
MOV VARD+2,ES
MOV CL,VARW+3
LES DI,VARW
答: MOV AX,VARB ;VARB是8bit量,应该修改AX到AL or AH
MOV VARD,BX ;VARD是32bit量,要分两次传
MOV VARD+2,ES ;同上
MOV CL,VARW+3 ;同上,CL改为CX
LES DI,VARW ;VARW非32位量,应改为VARD
题3.11 请举例说明伪指令ASSUME的作用。
答: ASSUME的作用是声明现在开始CS寄存器对应于哪个段,DS对应于哪个段,SS和ES
分别对应哪个段,可以相同也可以不同;
如:
ASSUME CS:CSEG,DS:DSEG,SS:SSEG,ES:ESEG
可以根据需要重新建立对应关系;
题3.12 设在某个程序片段中有如下语句,请说明各符号的属性:
SYMB1 LABEL BYTE
SYMB2 EQU THIS BYTE
SYMB3 DW ?
SYMB4 EQU BYTE PTR SYMB3
答: SYMB1:BYTE
SYMB2:BYTE
SYMB3:WORD
SYMB4:BYTE
题3.13 为什么说汇编语言中的等价语句EQU可理解为简单的宏定义?请举例说明。
答: EQU可以用符号定义常数,表达式,指令助记符,字符串等;
而宏定义是指定一个宏指令名,宏指令可表示相对应的程序片段。
如:
HELLO EQU "How are you !"
与:
HELLO MACRO
'How are you !'
ENDM
一致;
题3.14 设在某个程序片段中有如下语句,请说明各符号所表示的值:
SYMB1 = 10
SYMB2 = SYMB1*2
SYMB1 = SYMB1 + SYMB2 + 4
SYMB3 EQU SYMB1
答: SYMB1 = 22H
SYMB2 = 14H
SYMB3 = 22H
题3.15 请改写3.3.3的程序T3-1.ASM,使其只有一个段。
答: ;程序名:T3-1.ASM
;功能 :显示信息“HELLO"
cseg segment
assume cs:cseg
mess db 'HELLO',0dh,0ah,'$'
start:
mov ax,cseg
mov ds,ax
mov dx,offset mess
mov ah,9
int 21h
mov ah,4ch
int 21h
cseg ends
end start
题3.16 请说明指令”JMP $+2“指令的机器码中的地址差值是多少?
答: 2H
题3.17 源程序是否一定要以END语句结束?程序是否一定从代码段的偏移0开始执行?
如果不是,那么如何指定?
答: 源程序可以不以END语句结束,不过END之后的内容汇编程序将忽略。
程序不一定要从代码的偏移0开始执行,一个比较简单的方法是利用END语句,
如END XXX,程序将从XXX标号处开始执行;
题3.18 利用查表的方法实现代码转换有何特点?利用查表的方法求函数值有何特点?
答: 利用查表的方法实现代码转换的特点是:
1、转换代码间不需要直接的算术或逻辑关系,只需要安排好表的组织即可;
2、对于部分代码,其转换效率比较高,主要时间用在寻址上;
利用查表的方法求函数值的特点是:
1、对于大部分的数学函数值的求值,直接计算困难较大,采用查表法可祢补
不足;
2、程序比较简单;
3、能够得到十进制或者十六进制格式的高精度函数值。
4、函数值必须事先计算好;
5、精度无法由程序控制;
题3.19 利用地址表实现多向分支有何特点?请举例说明。
答: 利用地址表实现多向分支的特点有:
1、对于实现5路以上的多向分支,使用地址表既方便又高效;
2、对于如何确定地址的位置,需要采用不同的方法实现;
例子看书。
题3.20 请举例说明如何避免条件转移超出转移范围。
答: 如果出现条件转移超出了范围,则可以利用无条件转移指令帮助跳转;
如:
cmp ax,'A'
jb out_program
如果超出范围:
cmp ax,'A'
jb out_com
...
out_com:
jmp far ptr out_program
题3.21 请写一个程序片段统计寄存器AX中置1的个数。
答: count db ?,?,0dh,0ah,'$'
... ...
call countAX
cmp bl,9
ja sub10
jmp go
sub10:
sub bl,10
mov count,31h
go:
add bl,30h
mov count+1,bl
mov dx,offset count
mov ah,9
int 21h
mov ah,4ch
int 21h
;==============================
;入口:AX
;出口:BL=AX中1的个数
countAX proc
mov cx,16
mov bl,0
count1:
shl ax,1
jnc ADDAX1
add bl,1
ADDAX1:
loop count1
ret
countAX endp
;=============================
题3.22 设一个32位有符号数存放在DX:AX中,请写一个求其补码的程序片段。
答: Invert proc
mov bx,dx
and bx,8000h
cmp bx,0
jz out_1
not dx
not ax
add ax,1
adc dx,0
or dx,8000h
out_1:
nop
ret
Invert endp
题3.23 写一个程序片段实现如下功能:依次重复寄存器AL中的每一位,得到16位的结果存
放到DX寄存器中。
答: Expand proc
mov cx,7
xor dx,dx
S0:
shl dx,1
shl dx,1
shl al,1
jnc CF0
add dx,3h
CF0:
nop
loop S0
ret
Expand endp
题3.24 写一个程序片段实现如下功能:依次重复四次寄存器AL中的每一位,得到32位的结果
存放到DX:AX寄存器中。
答: Expand proc
mov cx,3
xor dx,dx
xor bx,bx
S0:
shl al,1
jnc CF0
add dx,0Fh
CF0:
shl dx,1
shl dx,1
shl dx,1
shl dx,1
loop S0
mov cx,4
S1:
shl al,1
jnc CF0_1
add bx,0Fh
CF0_1:
shl bx,1
shl bx,1
shl bx,1
shl bx,1
loop S1
mov ax,bx
ret
Expand endp
题3.25 写一个程序片段实现如下功能:把寄存器AL和BL中的位依次交叉,得到的16位结果
存放到DX寄存器中。
答: Expand proc
mov cx,8
xor dx,dx
S0:
shl dx,1
shl al,1
jnc CF0
add dx,1h
CF0:
shl dx,1
shl bl,1
jnc CF0_1
add dx,1h
CF0_1:
loop S0
ret
Expand endp
题3.26 写一个优化的程序片段,实现把字符串中的小写子母变换为对应的大写子母。设字符串
以0结尾。
答: InvertC proc
begin:
mov al,mess[si]
cmp al,'0'
jz exit_1
cmp al,61h
jb next
cmp al,7AH
ja next
and al,11011111b
mov mess[si],al
next:
inc si
jmp begin
exit_1:
nop
ret
InvertC endp
题3.27 写一个优化的程序片段,统计字符串的长度。设字符串以0结尾。
答: count proc
mov al,mess[si]
cmp al,'0'
jz exit_2
inc si
jmp count
exit_2:
nop
ret
count endp ;si=数量
题3.28 写一个程序片段,滤去某个字符串中的空格符号(ASCII码20H),设字符串以0结尾。
答: DeleteSpace proc ;设si=0,bx=0,Mess为字符串首地址
mov al,mess[si]
cmp al,'0'
jz exit_2
cmp al,' '
jz next3
xchg al,mess[bx]
xchg al,mess[si]
inc bx
next3:
inc si
jmp DeleteSpace
exit_2:
nop
ret
DeleteSpace endp
题3.29 请写一个把两个字符串合并的示例程序。
答: dseg segment
string1 db 'Welcome to $'
string2 db 'Beijing !$'
dseg ends
cseg segment
assume cs:cseg,ds:dseg
start:
mov ax,dseg
mov ds,ax
xor bx,bx
xor si,si
keepfind:
mov al,string1[bx]
cmp al,'$'
jz combine
inc bx
jmp keepfind
combine:
mov al,string2[si]
mov string1[bx],al
cmp al,'$'
jz exit
inc si
inc bx
jmp combine
exit:
mov dx,offset string1
mov ah,09h
int 21h
mov ah,4ch
int 21h
cseg ends
end start
题3.30 请写一个可把某个字变量的值传唤为对应二进制数ASCII码串的示例程序。
答: ;Name : Show_hex_ascii
;input : ah=Hex
;output: dx='Hex'
show_hex_ascii proc
mov dh,ah
and dh,0f0h ;reserve high 4bit
shr dh,4
add dh,30h ;change 0-9 to '0-9'
cmp dh,39h
ja add_dh_7
dh_ok:
mov dl,ah
and dl,0fh ;reserve low 4bit
add dl,30h
cmp dl,39h
ja add_dl_7
dl_ok:
nop
ret
add_dl_7:
add dl,7h ;revert A-F to 'A-F'
jmp dl_ok
add_dh_7:
add dh,7h
jmp dh_ok
show_hex_ascii endp
题3.31 请写一个可把某个十进制数ASCII码串转换成对应非压缩BCD何压缩BCD的示例程序。
答: ;非压缩BCD码
;Input ah=十进制数ASCII码
;Output al=非压缩BCD码
TEST1 proc
cmp ah,'0'
jb exit
cmp ah,'9'
ja exit
sub ah,30h
mov al,ah
exit:
nop
ret
TEST1 endp
;压缩BCD码
;Input ax=两个十进制数ASCII码
;Output bl=压缩BCD码
TEST2 proc
cmp ah,'0'
jb exit
cmp ah,'9'
ja exit
sub ah,30h
mov bl,ah
shl bl,4
cmp al,'0'
jb exit
cmp al,'9'
ja exit1
sub al,30h
add bl,al
exit1:
nop
ret
TEST2 endp
题3.32 请写一个可把某个十进制数ASCII码转换为对应的二进制的示例程序。
答: table db '0000','0001','0010','0011','0100','0101','0110','0111'
db '1000','1001'
......
;Input bl=一个十进制数ASCII码
;Output dx:ax=二进制ASCII码
;程序未检验该十进制数是否在范围以内
TEST3 proc
sub bl,30h
xor bh,bh
shl bx,1
shl bx,1
mov dh,table[bx]
mov dl,table[bx+1]
mov ah,table[bx+2]
mov al,table[bx+3]
ret
TEST3 endp
题3.33 请写出一个可把某个十六进制数ASCII码转换为对应的二进制的示例程序。
答: table db '0000','0001','0010','0011','0100','0101','0110','0111'
db '1000','1001','1010','1011','1100','1101','1110','1111'
... ...
;Input bl=一个十六进制数ASCII码
;Output dx:ax=二进制ASCII码
TEST3 proc
cmp bl,30h
jb exit1 ;小于30H的不在范围内
sub bl,30h
cmp bl,0Ah ;如果在9以内,开始转换0-9
jb change1
sub bl,0Ah
cmp bl,6h ;如果在‘9’-‘A’之间,不在范围内
jb exit1
sub bl,6h ;‘A’=0
cmp bl,7h ;如果在‘A’-‘F’之间,开始转换
jb change2
cmp bl,21h ;如果大于‘F’,看是否在‘F’和‘a’之间
jb exit1 ;如果在,则不在范围内
sub bl,20h ;'a'=0
cmp bl,6h ;如果大于‘f’,则不在范围内
ja exit1
change2:
add bl,9h ;按照table表,如果A=0还需要加9才可以
change1:
xor bh,bh
shl bx,1
shl bx,1
mov dh,table[bx]
mov dl,table[bx+1]
mov ah,table[bx+2]
mov al,table[bx+3]
exit1:
ret
TEST3 endp
题3.34 请写一个实现数据块移动的示例程序。
答: data segment
data1 db 'Hello!!!.....$'
....
data2 db 128 dup(?)
data ends
....
xor ax,ax
xor bx,bx
mov1:
mov al,data1[bx]
cmp al,'$'
jz out1
mov data2[bx],al
inc bx
jmp mov1
out1:
......
题3.35 请编一个程序求从地址F000:0000H开始的64K字节内存区域的检验和,并转换为
十六进制的数的ASCII码串。
答: ;F000:0000H 字检验和
;Output: BX=字检验和
TEST5 proc
mov ax,0F000H
mov es,ax
mov cx,0ffffh
xor si,si
xor bx,bx
ADD0:
add bx,es:[si]
inc si
inc si
loop add0
ret
TEST5 endp
table1 db '0','1','2','3','4','5','6','7','8','9'
db 'A','B','C','D','E','F'
;Input bx=字检验和
;Output dx:ax=字检验和ASCII码
TEST4 proc
push cx
mov cx,bx
push cx
mov cl,12
shr bx,cl
pop cx
mov dh,table1[bx]
mov bx,cx
and bx,0F00h
push cx
mov cl,8
shr bx,cl
pop cx
mov dl,table1[bx]
mov bx,cx
and bx,00f0h
push cx
mov cl,4
shr bx,cl
pop cx
mov ah,table1[bx]
mov bx,cx
and bx,000fh
mov al,table1[bx]
mov bx,cx
pop cx
ret
TEST4 endp
题3.36 设已在地址F000:0000H开始的内存区域安排了100个字节的无符号8位二进制数。
请编写一个程序求它们的和,并转换为对应十进制数的ASCII码串。
答: ;从 F000:0000H开始100个byte无符号数相加
;output BX=Sum
TEST6 proc
push cx
push ax
push si
mov ax,0f000h
mov es,ax
xor bx,bx
xor si,si
xor ax,ax
mov cx,100
ADD2:
mov al,es:[si]
add bx,ax
inc si
loop ADD2
pop si
pop ax
pop cx
ret
TEST6 endp
... ...
Dec_ASC db ' $' ;在数据区
... ...
;Name:Convert1
;function: Hex convert to Dec
;Input: BX=a word of Hex
;Output: DS:Dec_ASC
Convert1 proc
push ax
push cx
push dx
mov ax,bx
xor dx,dx
mov cx,2710h ;2710H=10000
div cx
add ax,30h
mov dec_asc[0],al ;[0]=万位
mov ax,dx
xor dx,dx
mov cx,3E8h ;3E8H=1000
div cx
add ax,30h
mov dec_asc[1],al ;[1]=千位
mov ax,dx
mov cl,64h ;64H=100
div cl
add al,30h
mov dec_asc[2],al ;[2]=百位
mov al,ah
mov ah,0
mov cl,0ah ;0A=10
div cl
add ax,3030h
mov dec_asc[3],al ;[3]=十位
mov dec_asc[4],ah ;[4]=个位
pop dx
pop cx
pop ax
ret
Convert1 endp
题3.37 设已在地址F000:0000H开始的内存区域安排了1024个16位有符号数。请编写一个程序
统计其中的正数、负数和零的个数,并分别转换为对应的十进制数的ASCII码串。
答: ;从 F000:0000H开始1024个Word有符号数统计
;output Di=0的个数
; Bx=正数的个数
; DX=负数的个数
TEST7 proc
push cx
push ax
push si
mov ax,0f000h
mov es,ax
xor bx,bx
xor si,si
xor ax,ax
xor di,di
xor dx,dx
mov cx,1024
Next1:
mov ax,es:[si]
cmp ax,0
jnz check_P
inc di
jmp next2
check_p:
shl ax,1
jnc ADD_P
inc dx
jmp next2
ADD_P:
inc bx
next2:
inc si
inc si
loop Next1
pop si
pop ax
pop cx
ret
TEST7 endp
分别call convert1, 并保存到不同的地方即可;
题3.38 设从地址F000:0000H开始的内存区域是缓冲区,存放了一组单字节的正数或负数,
以0结尾。请编写一个程序确定其中最大的正数和最小的负数。
答: ;从 F000:0000H开始以0结尾的单字节正数负数统计
;output bh=最大的正数
; bl=最小的负数
TEST8 proc
xor bx,bx
xor si,si
mov ax,0F000h
mov es,ax
next9:
mov al,es:[si]
cmp al,0
jz exit9
test al,80h
jnz Neg_1
cmp al,bh
jb next7
xchg al,bh
next7:
inc si
jmp next9
Neg_1:
cmp al,bl
jg next8
xchg al,bl
next8:
inc si
jmp next9
exit9:
ret
TEST8 endp
题3.39 设从地址F000:0000H开始的1K字节内存区域是缓冲区。请写一个可收集该区域内
所有子串“OK”开始地址的程序
答: ;从 F000:0000H开始1K字节内存区域,统计子串“OK”开始地址
;output 开始地址=ADDRESS
TEST9 proc
xor bx,bx
xor si,si
mov ax,0F000h
mov es,ax
mov cx,1024
next5:
mov ax,es:[si]
cmp ax,'OK'
jnz next6
mov ADDRESS[BX],si
inc bx
inc bx
next6:
inc si
inc si
loop next5
ret
TEST8 endp
题3.40 请优化3.6.2节例7所示排序程序。
答: 自己优化下;