资源描述
第4章 程序结构
4.1 简答题
(1)CPUID指令返回识别字符串的首字符“G”在哪个寄存器中?
EBX的高8位
(2)数据的直接寻址和指令的直接寻址有什么区别?
数据的直接寻址给出数据所在的存储器地址,指令的直接寻址给出指令所在的存储器地址。
(3)是什么特点决定了目标地址的相对寻址方式应用最多?
指令代码中提供目标地址相对于当前指令指针寄存器EIP的位移量,使得同一个程序被操作系统安排在不同的存储区时,指令间的位移并没有变化的特点。
(4)Jcc指令能跳转到代码段之外吗?
不能,Jcc指令采用段内相对寻址方式
(5)什么是奇偶校验?
数据通信时,数据的某一位用做传输数据的奇偶校验位,数据中包括校验位在内的“1”的个数恒为奇数,就是奇校验;恒为偶数,就是偶校验
(6)助记符JZ和JE为什么表达同一条指令?
两个数相减,差值为0(JZ)与两个数相等(JE)是一个含义
(7)为什么判断无符号数大小和有符号大小的条件转移指令不同?
判断两个无符号数的大小和判断两个有符号数大小关系要利用不同的标志组合。
判断有符号数的大小需要组合SF和OF标志,并利用ZF标志确定相等与否。
判断无符号数的高低利用CF标志,利用ZF标志确定相等。
(8)双分支结构中两个分支体之间的JMP指令有什么作用?
用于跳过分支体2,避免进入分支体2而出现错误。
(9)如果循环体的代码量远超过128个字节,还能用LOOP指令实现计数控制循环吗?
不能,因为LOOP指令的目标地址采用相对短转移,只能在-128~+127字节之间循环
(10)什么是“先循环、后判断”循环结构?
指先执行循环体,然后判断是否继续循环的结构,这种结构通常至少执行一次循环体
4.2 判断题
(1)指令指针或者号包括代码段寄存器值的改变将引起程序流程的改变。
对
(2)指令的相对寻址都是近转移。
对
(3)采用指令的寄存器间接寻址,目标地址来自存储单元。
错,
(4)JMP指令对应高级语言的GOTO语句,所以不能使用
错,需要使用
(5)因为条件转移指令Jcc要利用标志作为条件, 所以也影响标志。
错
(6)JA和JG指令的条件都是“大于”,所以是同一个指令的两个助记符。
错,JA针对无符号数,JG针对有符号数
(7)JC和JB的条件都是CF=1,所以是同一条指令。
对。无符号小于(JB)必然借位(JC)
(8)控制循环是否结束只能在一次循环结束之后进行
错
(9)介绍loop指令时,常说它相当于dec ecx和jnz两条指令。但是考虑对状态标志的影响,它们有差别。Loop指令不影响标志,而dec指令却影响除cf之外的其他状态标志。
对
(10)若ECX=0,则LOOP指令和JECX指令都发生转移。
对
4.3 填空题
(1)JMP指令根据目标地址的转移范围和寻址方式,可以分成4种类型:段内转移、
( ),段内转移、( )以及段间转移、( ),段间转移、( )。
相对寻址,间接寻址,直接寻址,间接寻址
(2)MASM给短转移、近转移和远转移定义的类型名依次是___、___和___。
SHORT,NEAR,FAR
(3)假设在平展存储模型下,EBX=1256H,双字变量TABLE的偏移地址是20A1H,线性地址32F7H处存放3280H,执行指令“JMP EBX” 后EIP=_______,执行指令“JMP TABLE[EBX]”后EIP=_______。
1256H,3280H
(4)“CMP EAX,3721H”指令之后是JZ指令,发生转移的条件是EAX=________,此时ZF=_______。
3721H,1
(5)执行“SHR EBX,4”指令后,JNC发生转移,说明EBX的D3=_____。
0
(6)在EDX等于0时转移,可以使用指令“CMP EDX,____”、也可以使用“TEST EDX,_____”构成条件,然后使用JE指令实现转移。
0,EDX
(7)循环结构程序一般由三个部分组成,它们是( )、循环体和 ( )部分。
循环初始,循环控制
(8)JECXZ指令发生转移的条件是( ),loop指令不发生转移的条件是( )。
Ecx=0, ecx 不等于0
(9)loop指令进行减1计数,实际应用中也常进行加1计数。针对例4-14程序,如果删除其中的loop指令,则可以使用指令“cmp( ),ecx”和“jb ( ) ”替代。
Ebx, jb again
(10)小写字母“e”是英文当中出现频率最高的字母。如果某个英文文档利用例4-16的异或方法进行简单加密, 统计发现密文中字节数据“8FH”最多, 则高程序采用的字节密码可能是( )
0EAh
习题4.4
已知var1、var2、var3和var4是32位无符号整数,用汇编语言程序片段实现如下C++语句:
var4=(var1*6)/( var2-7)+var3
解答:
mov eax,var1
mov ebx,6
mul ebx ;var1*6
mov ebx,var2
sub ebx,7 ;var2-7
div ebx ;(var1*6)/( var2-7)
add eax,var3 ;(var1*6)/( var2-7)+var3
mov var4,eax
习题4.5
已知var1、var2、var3和var4是32位有符号整数,用汇编语言程序片段实现如下C++语句:
Var1=(var2*var3)/( var4+8)-47
解答:
Mov eax,var2
Imul var3
Mov ebx,var4
Add ebx,8
Idiv ebx
Sub eax,47
Mov var1,eax
习题4.6
参看例4-1,假设N小于90000,这时求和结果只需要eax保存,edx为0。修改例4-1使其可以从键盘输入一个数值N(用readuid子程序),最后显示累加和(用dispuid子程序)。
解答:
.data
Msg byte ‘Input a number(0~90000):’,0
.code
Start:
Mov eax,offset msg
Call readuid
Call dispcrlf
Mov ebx,eax
Add ebx,1
Imul ebx
Shr edx,1
Rcr eax,1
Call dispuid
习题4.7
定义COUNT(假设为10)个元素的32位数组,输入元素编号(0~COUNT-1),利用DISPHD子程序输出其地址、利用DISPSID子程序输出其值。
解答:
;数据段
count = 10
array dword 0,1,2,3,4,5,6,7,8,9
;代码段
call readuid ;输入N,小于10
lea eax,array[eax*4] ;EAX=地址
call disphd ;显示地址
mov eax,array[eax*4] ;EAX=变量值
call dispsid ;显示数值
习题4.10
判断下列程序段跳转的条件
(1)xor ax,1e1eh
Je equal
(2)test al,10000001b
Jnz here
(3)cmp cx,64h
Jb there
答:
(1) zf= 1 (2) zf= 0 (3) cf =1
习题4.11
假设EBX和ESI存放的是有符号数,EDX和EDI存放的是无符号数,请用比较指令和条件转移指令实现以下判断:
(1)若EDX > EDI ,转到above执行
(2)若EBX > ESI ,转到greater执行
(3)若EBX = 0 ,转到zero执行
(4)若EBX - ESI产生溢出 ,转到overflow执行
(5)若ESI <= EBX ,转到less_eq执行
(6)若EDI<= EDX ,转到below_eq执行
答:
(1) cmp ebx,edi
Ja above
(2) cmp ebx,esi
Jg greater
(3) cmp ebx ,0
Je zero
(4) cmp ebx,esi
Jo overflow
(5) cmp esi,ebx
Jle less_eq
(6) cmp edi,edx
Jbe below_eq
习题4.12
使用“shr eax,2”将eax中的D1位移入CF标志,然后用JC /JNC指令替换JZ /JNZ指令完成例4-6程序的功能。
答:
mov eax,56h
Shr eax,2
jnc nom
mov eax,offset yes_msg
jmp done
nom: mov eax,offset no_msg
done: call dispmsg
或
mov eax,58h
Shr eax,2
jc yesm
mov eax,offset no_msg
jmp done
yesm: mov eax,offset yes_msg
done: call dispmsg
习题4.13
将例4-7程序修改为实现偶校验,并进一步增加显示有关提示信息的功能,使得程序具有更加良好的交互性.
答:
.data
Msg1 byte ‘Please input a char:”,0
Msg2 byte ‘Ascii is :’,0
Msg3 byte ‘Party is :’,0
.code
start:
mov eax,offset msg1
call dispmsg
call readc
call dispcrlf
lea eax,msg2
call dispmsg
call dispbb
call dispcrlf
and al,7fh
jp next
or al,80h
next:
push eax
lea eax,msg3
call dispmsg3
pop eax
call dispbb
exit 0
end start
习题4.14
在采用奇偶校验传输数据的接收端应该验证数据传输的正确性.例如,如果采用偶校验,那么在接受到的数据中,其包含“1”的个数应该为0或偶数个, 否则说明出现传输错误。现在,在接收端编写一个的程序,如果偶校验不正确显示错误信息,传输正确则继续。假设传送字节数据、最高位作为校验位,接收到的数据已经保存在Rdata变量中。
答:
.data
Rdata byte ‘a’
Errmsg byte ‘Data Error!’,0
.code
Start:
Test rdata,0
Jnp err
…
Err:
Lea eax,errmsg
Call dispmsg
习题4.15
IA-32处理器的指令CDQ将EAX符号扩展到EDX。假若没有该指令,编程实现该指令功能。
(1)按照符号扩展的含义编程,即:EAX最高为0,则EDX=0;EAX最高为1,则EDX=FFFFFFFFH。
编程实现指令CDQ,将EAX符号扩展到EDX
(2)使用移位等指令进行优化编程。
答: (1)
test eax,8000h ;测试最高位
jz next1 ;最高位为0,转移
mov edx,0ffffffffh
;最高位为1,设置EDX=FFFFFFFFH
jmp done ;跳过另一个分支
next1: mov dx,0 ;设置EDX=0
done:
(2)
方法1:
mov edx,eax
sar edx,31
方法2:
rol eax,1
rcr edx,1
sar edx,31
ror eax,1
习题4.16
编写一个成旭,首先测试双字变量DVAR的最高位,如果为1,则显示字母“L”;如果最高位不为1,则继续测试最低位,如果最低位为1则显示字母“R”,如果最低位也不为1,则显示字母“M”。
答:
.data
Dvar dword 80000000h
.code
…
Test dvar,80000000h
Jnz dispL
Test dvar,1
Jz dispM
Mov al,’R’
Jmp disp
dispL:
mov al,’L’
jmp disp
dispM:
mov al,’M’
disp:
call dispc
习题4.17
编写一个程序,先提示输入数字“Input Number:0~9”,然后在下一行显示输入的数字,结束;如果不是键入了0~9数字,就提示错误“Error!”,继续等待输入数字。
方法1:使用字符输入输出子程序
;数据段
inmsg byte 'Input number(0~9): ',0
ermsg byte 0dh,0ah,'Error! Input again: ',0
;代码段
mov eax,offset inmsg ;提示输入数字
call dispmsg
方法1:使用字符输入输出子程序
again: call readc ;等待按键
cmp al,'0' ;数字 < 0?
jb erdisp
cmp al,'9' ;数字 > 9?
ja erdisp
call dispcrlf
call dispc
jmp done
erdisp: mov eax,offset ermsg
call dispmsg
jmp again
done:
方法2:使用数字输入输出子程序
again: call readuid ;call readsid
cmp eax,0 ;数字 < 0?
jb erdisp ;jl erdisp
cmp eax,9 ;数字 > 9?
ja erdisp ;jg erdisp
call dispuid ;call dispsid
jmp done
erdisp: mov eax,offset ermsg
call dispmsg
jmp again
习题4.18
有一个首地址为Array 的20个双字的数据,说明下列程序段的功能。
Mov ecx,20
Mov eax,0
Mov esi,eax
Sum1p:
Add eax,array[esi]
Add esi,4
Loop sum1p
Mov total,eax
答:
累加Array数组,并将结果存入total变量
习题4.19
说明如下程序段的功能:
Mov ecx,16
Mov bx,ax
Next:
Shr ax,1
Rcr edx,1
Shr bx,1
Rcr edx,1
Loop next
Mov eax,edx
答:
习题4.20
编程将一个64位数据逻辑左移3位,假设这个数据已经保存在EDX.EAX寄存器对中。
答:
Mov ecx,3
Next: shr edx,1
Rcr eax,1
Loop next
习题4.21
编程中经常要记录某个字符出现的次数。现编程记录某个字符串中空格出现的次数,结果保存在space单元。
答:
space dword 0
string byte 'this is a test string !'
.code
start:
; 主程序
mov eax,0
mov ebx,eax
mov ecx,lengthof string
nextchar:
cmp string[ebx],20h
jnz nospace
inc eax
nospace:
inc ebx
loop nextchar
mov space,eax
call dispuid
exit 0
; 子程序
end start
习题4.22
将一个已经按升序排列的数组(地1个元素最小,后面的逐个增大)改为按照降序排列。编程实现该功能。
答:
.data
; 数据定义
ArrayUp dword -1,0,2,3,20,23,36,100,2048
.code
start:
; 主程序
mov ecx,lengthof ArrayUp
add ecx,1
rcr ecx,1
xor esi,esi
mov edi,(lengthof ArrayUp) -1
exchange:
mov eax,ArrayUp[esi* Type ArrayUp]
xchg eax,ArrayUp[edi* Type ArrayUp]
xchg eax,ArrayUp[esi* type ArrayUp]
inc esi
dec edi
loop exchange
exit 0
; 子程序
end start
习题4.23
编写计算100个16位正整数之和的程序。如果和不超过16位字的范围,则保存其和到wordsum,如果超过则显示“overflow !”.
答:
.data
count = 100
num word count dup(90)
wordsum word 0
errmsg byte 'Overflow!'
; 数据定义
.code
start:
; 主程序
xor eax,eax
mov ebx,eax
mov ecx,count
sum:
add ax,num[ebx]
jc over
inc ebx
inc ebx
loop sum
mov wordsum,ax
call dispuiw
jmp quit
over:
mov eax,offset errmsg
call dispmsg
quit:
exit 0
; 子程序
end start
习题4.27
在屏幕上显示ASCII表,现仅在数据段设置表格缓冲区,编程将ASCII代码值填入留出位置的表格,然后调用显示功能实现(需要利用双重循环)。
答:
table byte ' |0 1 2 3 4 5 6 7 8 9 A B C D E F',13,10
byte '---+-------------------------------',13,10
tab1 byte 6 dup(36 dup(?),13,10)
byte 0
mov ebx,offset tab1
mov edx,'| 02'
mov ax,2020h
mov esi,6
again0: mov [ebx],edx
add ebx,4
mov ecx,16
again1: mov word ptr [ebx],ax
add ebx,2
inc al
loop again1
add ebx,2
add edx,1
dec esi
jnz again0
mov eax,offset table
call dispmsg
习题4.29 素数判断程序
(1)采用直接简单的算法:假设输入N,将其逐个除以2~N-1,只要能整除(余数为0)说明不是素数,只有都不能整除才是素数。
(2)采用只对奇数整除的算法:1、2和3是素数,所有大于3的偶数不是素数,从5开始的数字只要除以从3开始的奇数,只有都不能整除才是素数。
提示:
排除4的情况,从3开始除,每次循环加2
答:
(1)核心程序片段如下:
cmp eax,3
jbe doney ;小于等于3的都是素数
cdq
mov esi,eax ;EDI.ESI=N>3
mov edi,edx
mov ebx,2 ;EBX从2开始
again: div ebx
test edx,edx
jz donen
;余数为0,能整除,不是素数
inc ebx
cmp ebx,esi ;EBX到N-1结束
mov eax,esi
mov edx,edi
jb again
(2)
mov ebx,3
……
add ebx,2
展开阅读全文