《汇编语言:基于X86处理器》第4章 复习题和练习,编程练习
本篇记录《汇编语言:基于X86处理器》第4章的复习题和练习,编程练习的学习。
4.9 复习题和练习
4.9.1 简答题
1.执行下列标记为(a)和(b)的指令后,EDX 的值分别为多少?
.data
one WORD 8002h
two WORD 4321h
.code
mov edx,21348041h
movsx edx,one ;(a) EDX = 00008002h
movsx edx,two ;(b) EDX = 00004321h
答:(a) EDX = 00008002h,(b) EDX = 00004321h
2.执行下列指令后,EAX 的值是多少?
mov eax,1002FFFFh
inc ax
答:EAX=10020000h。
3.执行下列指令后,EAX 的值是多少?
mov eax, 30020000h
dec ax
答:EAX=3002FFFFh。
4.执行下列指令后,EAX的值是多少?
mov eax,1002FFFFh
neg ax
答:EAX=10020001h。
5.执行下列指令后,奇偶标志位的值是多少?
mov al, 1
add al, 3
答:al = 4, 二进制为 0100b 奇偶标志位PF=0,即显示PE = 0。
6.执行下列指令后,EAX和符号标志位的值分别是多少?
mov eax, 5
sub eax, 6
答:EAX=-1,标志位的值,符号标志PL=1,进位标志CY=1,奇偶标志PL=1
7.下面的代码中,AL 为一字节有符号数。说明,在判断 AL 最终结果是否在有符号数的有效范围内时,溢出标志位是否有用,若有用,是如何起作用的?
mov al, -1
add al, 130
答:al=129=81h,不在-128~127的有符号范围内,130不在有符号范围内,所以此处进行的是无符号计算,溢出标志位不起作用。再看最高位为1,因此,有进位标记。
8.执行下列指令后,RAX 的值是多少?
mov rax, 44445555h
答:RAX=0000000044445555h。
9.执行下列指令后,RAX 的值是多少?
.data
dwordVal DWORD 84326732h
.code
mov rax, 0FFFFFFFF00000000h
mov eax, dwordval
答:RAX=0000000084326732h。
10.执行下列指令后,EAX 的值是多少?
.data
dVal DWORD 12345678h ;在内存中是这样存放的78 56 34 12
.code
mov ax, 3
mov WORD PTR dVal+2, ax ;赋值给dVal的高16位,此时dVal = 0003 5678h
mov eax, dVal
答:EAX=0x00035678h。
11.执行下列指令后,EAX 的值是多少?
.data
dVal DWORD ?
.code
mov dVal,12345678h ;dVal = 12345678h
mov ax,WORD PTR dVal+2 ;ax=1234h
add ax,3 ;ax=1237h
mov WORD PTR dVal,ax ;dVal = 1234 1237h
mov eax,dVal ;eax = 1234 1237h
答:EAX=1234 1237h。
12.(是/否):正数与负数相加时,是否可能使溢出标志位置1?
答:否
13.(是/否):两负数相加,结果为正数,溢出标志位是否置1?
答:是
14.(是/否):执行NEG指令是否能将溢出标志位置1?
答:是,NEG
指令可以将 OF
置 1,但仅当操作数是当前位数的最小负数时(如 -128
对于 8 位,-32768
对于 16 位)。其他情况下,OF
保持 0。
15.(是/否):符号标志位和零标志位是否能同时置1?
答:否
问题16~问题19使用如下变量定义:
.data
var1 SBYTE -4, -2, 3, 1
var2 WORD 1000h, 2000h, 3000h, 4000h
var3 SWORD -16, -42
var4 DWORD 1, 2, 3, 4, 5
16.判断下述每条指令是否为有效指令:
a. mov ax, varl?
b. mov ax, var2
c. mov eax,var3
d. mov var2, var3
e. movzx ax, var2
f. movzx var2,al
g. mov ds, ax
h. mov ds,1000h
答:a.无效 b.有效 c.无效 d.无效 e.无效 f.无效 g.有效 h.无效
17.顺序执行下列指令,则每条指令目标操作数的十六进制值是多少?
mov al, var1 ;a.
mov ah, [var1+3] ;b.
答:a. al = -4 补码 0FCh, b. ah = 1= 01h
18.顺序执行下列指令,则每条指令目标操作数的值是多少?
mov ax, var2 ;a.
mov ax, [var2+4] ;b.
mov ax, var3 ;c.
mov ax, [var3-2] ;d.
答:a. ax = 1000h, b. ax = 3000h, c. ax = -16 补码为0FFF0h, c. ax = 4000h
19.顺序执行下列指令,则每条指令目标操作数的值是多少?
mov edx, var4 ;a.
movzx edx, var2 ;b.
mov edx, [var4+4] ;c.
mov edx, var1 ;d.
答:a. edx = 1, b. edx = 0000 1000h, c. edx = 2 (占4个字节), c. edx = 0FFFCh
4.9.2 算法基础
1.有一变量名为 three 的双字变量,编写一组 MOV指令来交换该变量的高位字和低位字。
;4.9.2_1.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
three DWORD 12345678h.code
main PROC;方法1;mov esi, OFFSET three;mov eax,[esi];shl eax,16;mov ax,WORD PTR [esi+2];mov [esi],eax;方法2mov esi, OFFSET threemov edx,[esi] ;这两行查看地址数据测试用mov ax,WORD PTR [three+2]mov bx,WORD PTR [three]xchg ax, WORD PTR [three]xchg bx, WORD PTR [three+2];方法3;mov eax,three;ror eax,16 ;循环右移16位;mov DWORD PTR [three], eax ;mov three, eax 这样写也可以INVOKE ExitProcess,0
main endp
end main
运行调试:
交换后:
2.用不超过 3 条的 XCHG 指令对 4 个 8 位寄存器的值进行重排序,将其顺序从 A、B、C、D 调整为 B、C、D、A。
;4.9.2_2.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
arrayB BYTE 0Ah,0Bh,0Ch,0Dh.code
main PROCmovzx eax, BYTE PTR [arrayB]movzx ebx, BYTE PTR [arrayB+1]movzx ecx, BYTE PTR [arrayB+2]movzx edx, BYTE PTR [arrayB+3];原始顺序 A->B->C->Dxchg al,bl ;B->A->C->Dxchg bl,cl ;B->C->A->Dxchg cl,dl ;B->C->D->AINVOKE ExitProcess,0
main endp
end main
3.被传输的信息通常包含有一个奇偶位,其值与数据字节结合在一起,使得 1 的位数为偶数。设 AL寄存器中信息字节的值为01110101,如何用一条算术运算指令和奇偶标志位判断该信息字节是偶校验还是奇校验?
答:用TEST指令和PE标志位的值来判断,如果PE=1是偶校验,如果PE=0是奇校验。
4.编写代码,用字节操作数实现两个负整数相加,并使溢出标志位置 1。
答:两个负数相加,只要超过-128就会产生溢出。例如:-64 + (-65) = -129
;4.9.2_4.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.code
main PROCmov al,-64add al,-65INVOKE ExitProcess,0
main endp
end main
运行调试:
5.编写连续的两条指令,用加法使零标志位和进位标志位同时置1。
答:使用字节操作数,相加结果等于256即可。
;4.9.2_5.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.code
main PROCmov al,0FFhadd al,1INVOKE ExitProcess,0
main endp
end main
运行调试:
6.编写连续的两条指令,用减法使进位标志位置1。
;4.9.2_6.asm .386
.model flat,stdcall
.stack 4096ExitProcess PROTO,dwExitCode:DWORD.code
main PROCmov al,0sub al,1INVOKE ExitProcess,0
main endp
end main
运行调试:
7.用汇编语言实现算术表达式:EAX=-val2+7-val3+vall。假设vall、val2 和 val3 都是32位整数变量。
答:这里以val1=55, val2=30,val3=13为例,eax=30+7-13+55=79
;4.9.2_7.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
val1 DWORD 55
val2 DWORD 30
val3 DWORD 13.code
main PROCmov eax, val2add eax, 7mov ebx, val3sub eax, ebxmov edx, val1add eax, edxINVOKE ExitProcess,0
main endp
end main
运行调试:
8.编写循环代码,在一个双字数组中进行迭代。用带比例因子的变址寻址,计算该数组元素的总和。
;4.9.2_8.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
arrayD DWORD 1000h,2000h,3000h,4000h.code
main PROCmov eax, 0 ;初始化为0mov esi, 0 ;下标mov ecx, LENGTHOF arrayD ;元素的个数
L1: add eax, arrayD[esi*4]inc esiloop L1INVOKE ExitProcess,0
main endp
end main
运行调试:
9.用汇编语言实现算术表达式:AX=(val2+BX)-val4。假设val2 和val4都是16位整数变量。
答:这里以val2=22,bx=33,val4=44为例,AX=22+33-44=11。
;4.9.2_9.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
val2 WORD 22
val4 WORD 44.code
main PROCmov ax, val2mov bx, 33add ax, bxmov bx, val4sub ax, bxINVOKE ExitProcess,0
main endp
end main
运行调试:
10.编写连续的两条指令,使进位标志位和溢出标志位同时置1。
答:两条指令mov al,0F0h, add al,88h
;4.9.2_10.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.code
main PROCmov al,0F0hadd al,88hINVOKE ExitProcess,0
main endp
end main
运行调试:
11.编写指令序列,说明在执行INC和DEC指令后,如何用零标志位来判断无符号溢出情况
;4.9.2_1.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.code
main PROCmov al, 0FFhinc al jz inc_ov ;加1等于,说明有溢出mov bl, 0dec bl cmp bl, 0FFh ;减1等于0FFh,说明有借位溢出je dec_ovinc_ov: mov edx,0jmp exit
dec_ov:mov edx,0FFFFFFFFhjmp exitexit:nopINVOKE ExitProcess,0
main endp
end main
运行调试:
问题12~问题18使用如下数据定义:
.data
myBytes BYTE 10h, 20h, 30h, 40h
myWords WORD 3 DUP(?), 2000h
myString BYTE "ABCDE"
12.在给定数据中插人一条伪指令,将myBytes 对齐到偶地址.
;4.9.2_12.asm 4.9.2 算法题 12.在给定数据中插人一条伪指令,将myBytes 对齐到偶地址..386
.model flat,stdcall
.stack 4095
ExitProcess PROTO,dwExitCode:DWORD.data
ALIGN 2 ;插入2字节对齐
myBytes BYTE 10h, 20h, 30h, 40h
myWords WORD 3 DUP(?), 2000h
myString BYTE "ABCDE".code
main PROCmov eax, DWORD PTR myBytesmov al, BYTE PTR myBytesmov bl, BYTE PTR myBytes+1mov esi, offset myWordsINVOKE ExitProcess,0
main endp
end main
13.下列每条
指令执行后,EAX的值分别是多少?
;4.9.2_1.asm 4.9.2 算法题 .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
myBytes BYTE 10h, 20h, 30h, 40h
myWords WORD 3 DUP(?), 2000h
myString BYTE "ABCDE".code
main PROCmov eax, TYPE myBytes ;a. eax=1mov eax, LENGTHOF myBytes ;b. eax=4mov eax, SIZEOF myBytes ;c. eax=4mov eax, TYPE myWords ;d. eax=2mov eax, LENGTHOF myWords ;e. eax=4mov eax, SIZEOF myWords ;f. eax=8mov eax, SIZEOF myString ;g. eax=5INVOKE ExitProcess,0
main endp
end main
14.编写一条指令将myBytes 的前两个字节送入 DX 寄存器,使寄存器的值为 2010h。
答:mov dx, WORD PTR myBytes
完整测试代码:
;4.9.2_14.asm
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
myBytes BYTE 10h, 20h, 30h, 40h
myWords WORD 3 DUP(?), 2000h
myString BYTE "ABCDE".code
main PROCmov dx, WORD PTR myBytesINVOKE ExitProcess,0
main endp
end main
运行调试:
15.编写一条指令将myWords 的第二个字节送人 AL 寄存器。
答:mov AL, BYTE PTR myWords
完整测试代码:
;4.9.2_15.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
myBytes BYTE 10h, 20h, 30h, 40h
myWords WORD 3 DUP(?), 2000h
myString BYTE "ABCDE".code
main PROCmov AL, BYTE PTR myBytes+1INVOKE ExitProcess,0
main endp
end main
运行调试:
16.编写一条指令将myBytes 的全部四个字节送人 EAX寄存器。
答:mov eax, DWORD PTR myBytes
完整测试代码:
;4.9.2_16.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
myBytes BYTE 10h, 20h, 30h, 40h
myWords WORD 3 DUP(?), 2000h
myString BYTE "ABCDE".code
main PROCmov EAX, DWORD PTR myBytesINVOKE ExitProcess,0
main endp
end main
运行调试:
17.在给定数据中插人一条LABEL 伪指令,使得myWords 能直接送入 32 位寄存器。
答:var32 LABEL DWORD ;定义var32为4个字节
完整测试代码:
;4.9.2_17.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
myBytes BYTE 10h, 20h, 30h, 40h
var32 LABEL DWORD
myWords WORD 3 DUP(?), 2000h
myString BYTE "ABCDE".code
main PROCmov EAX, var32INVOKE ExitProcess,0
main endp
end main
运行调试:
18.在给定数据中插人一条LABEL伪指令,使得myBytes能直接送人16位寄存器。
答:var16 LABEL WORD ;定义var16为两个字节
完整测试代码:
;4.9.2_18.asm .386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
var16 LABEL WORD ;定义var16为两个字节
myBytes BYTE 10h, 20h, 30h, 40h
myWords WORD 3 DUP(?), 2000h
myString BYTE "ABCDE".code
main PROCmov AX, var16INVOKE ExitProcess,0
main endp
end main
运行调试:
4.10 编程练习
下面的练习可以在32 位模式或 64 位模式下完成。
*1.将大端顺序转换为小端顺序
使用下面的变量和MOV 指令编写程序,将数值从大端顺序复制为小端顺序,颠倒字节的顺序。32 位数的十六进制值为12345678。
.data
bigEndian BYTE 12h, 34h, 56h, 78h
littleEndian DWORD ?
完整的代码:
;4.10_1.asm 4.10 编程练习 *1.将大端顺序转换为小端顺序.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
bigEndian BYTE 12h, 34h, 56h, 78h
littleEndian DWORD ?.code
main PROCmov esi, offset bigEndian ;这行查看地址测试用mov ax, WORD PTR bigEndian ;ax=3412hxchg ah,al ;ax=1234hshl eax, 16 ;eax=12340000hmov ax, WORD PTR bigEndian+2 ;eax=12347856hxchg ah,al ;eax=12345678hmov littleEndian, eaxINVOKE ExitProcess,0
main endp
end main
运行调试:
**2.交换数组元素对
编写循环程序,用变址寻址交换数组中的数值对,每对中包含偶数个元素。即,元素i与元素i+1 交换,元素i+2 与元素i+3 交换,以此类推。
完整的代码:
;4.10_2.asm 4.10 编程练习 **2.交换数组元素对.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
arrayB BYTE 10h,20h,30h,40h,50h,60h.code
main PROCmov edi, offset arrayB ;测试查看地址用mov esi, 0mov ecx, LENGTHOF arrayB ;元素个数
L1:mov AL, BYTE PTR arrayB[esi] ;AL = 10hmov BL, BYTE PTR arrayB[esi+1] ;BL = 20hxchg BYTE PTR arrayB[esi], BLmov BYTE PTR arrayB[esi+1], ALDEC ecx ;这里减一次1,下面loop还会减1,交换次数为元素个数/2ADD esi,2loop L1INVOKE ExitProcess,0
main endp
end main
运行调试:
**3.数组元素间隔之和
;4.10_3.asm 4.10 编程练习 **3.数组元素间隔之和.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
arrayD DWORD 0,2,5,9,10.code
main PROCmov esi, 0 ;数据位置mov edx, 0 ;存放间隔数之和mov ecx, LENGTHOF arrayD - 1 ;元素个数
L1:mov eax, arrayD[esi] ;相邻的第1个元素mov ebx, arrayD[esi+4] ;相邻的第2个元素sub ebx, eax ;元素间隔add edx, ebx ;把间隔数相加存放到edx中add esi, 4 ;下一个元素loop L1INVOKE ExitProcess,0
main endp
end main
运行调试:
**4将字数组复制到双字数组
编写循环程序,把一个无符号字(16位)数组的所有元素复制到无符号双字(32位)数组。
完整的代码:
;4.10_4.asm 4.10 编程练习 **4将字数组复制到双字数组.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
arrayW WORD 1111h,2222h,3333h,4444h,5555h,6666h,7777h,8888h
arrayD DWORD 8 DUP(?).code
main PROCmov esi, OFFSET arrayW mov edi, 0 ;下标mov ecx, LENGTHOF arrayW ;元素个数
L1:movzx eax, WORD PTR arrayW[edi*2]mov DWORD PTR arrayD[edi*4], eaxinc ediloop L1INVOKE ExitProcess,0
main endp
end main
运行调试:
**5.斐波那契数列
编写循环程序,计算斐波那契(Fibonacci)数列前七个数值之和,算式如下:
Fib(1)=1,Fib(2)=1,Fib(n)=Fib(n-1)+Fib(n-2)
完整的代码:
;4.10_5.asm 4.10 编程练习 **5.斐波那契数列.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data.code
main PROCmov eax, 1 ;f1=1mov ebx, 1 ;f2=1mov edx, 1 ;f3=1 edx存放数值之和mov ecx, 7 ;数列个数
L1:mov edx, eaxadd edx, ebx ;f3 = f2+f1mov eax, ebx ;f2 = f1mov ebx, edx ;f2 = f3cmp ecx,1 ;当ecx等1时,edx要减1,因为前面加了一次1je exitloop L1exit: dec edxINVOKE ExitProcess,0
main endp
end main
运行调试:
***6.数组反向
编写循环程序,用间接或变址寻址实现整数数组元素的位置颠倒。不能将元素复制到其他数组。考虑到数值大小和类型在将来可能发生变化,用 SIZEOF、TYPE 和 LENGTHOF运算符尽可能增加程序的灵活性。
完整的代码:
;4.10_6.asm 4.10 编程练习 ***6.数组反向.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
arrayW WORD 11h,22h,33h,44h,55h.code
main PROCmov ebx, offset arrayW ;查看内存数据测试用mov esi, 0 ;正向下标mov ecx, LENGTHOF arrayW ;元素个数mov edi, ecxdec edi ;下标是从0开始的,所以这里要减1
L1:mov ax, WORD PTR arrayW[esi * TYPE arrayW]xchg ax, WORD PTR arrayW[edi* TYPE arrayW]mov WORD PTR arrayW[esi * TYPE arrayW], axinc esi ;正向下标dec edi ;反向下标cmp ecx,1 ;如果ecx等于1,结束循环je exitdec ecx ;循环次数为元素个数/2loop L1exit: mov ecx, 0INVOKE ExitProcess,0
main endp
end main
运行调试:
反向:
***7.将字符串复制为相反顺序
编写循环程序,用变址寻址将一个字符串从源复制到目的,并实现字符的反向排序。变量定义如下:
source BYTE "This is the source string, 0
target BYTE SIZEOF source DUP('#')
完整的代码:
;4.10_7.asm 4.10 编程练习 ***7.将字符串复制为相反顺序.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
source BYTE "This is the source string", 0
target BYTE SIZEOF source DUP('#').code
main PROCmov edx, offset source ;测试查看内存数据用mov ecx, LENGTHOF source ;元素个数mov esi, 0 ;下标mov edi, ecxdec edi ;防止下标越界
L1: mov AL, BYTE PTR source[esi]mov BYTE PTR target[edi], ALinc esidec ediloop L1INVOKE ExitProcess,0
main endp
end main
运行调试:
反向排序
***8.数组元素移位
编写循环程序,用变址寻址把一个32位整数数组中的元素向前(向右)循环移动一个位置数组最后一个元素的值移动到第一个位置上。比如,数组[10,20,30,40]移位后转换为[40,10,20,30]。
完整的代码:
;4.10_8.asm 4.10 编程练习 ***8.数组元素移位.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
arrayB BYTE 10h,20h,30h,40h.code
main PROCmov esi, OFFSET arrayB ;测试查看内存数据用mov ecx, LENGTHOF arrayBdec ecxmov edi, ecx
L1:mov AL, arrayB[edi]xchg BYTE PTR arrayB[edi-1], ALmov BYTE PTR arrayB[edi], ALdec ediloop L1INVOKE ExitProcess,0
main endp
end main
运行调试:
向右循环移动后: