当前位置: 首页 > news >正文

《汇编语言:基于X86处理器》第7章 复习题和练习,编程练习

本篇记录《汇编语言:基于X86处理器》第7章 复习题和练习,编程练习的学习笔记

7.9 复习题和练习

7.9.1 简答题

1.有如下代码序列,请写出每条移位或循环移位指令执行后AL的值:

mov al, 0D4h
shr al, 1					;a. AL=06Ah
mov al, 0D4h
sar al, 1					;b. AL=0EAh
mov al, 0D4h
sar al, 4					;c. AL=0FDh
mov al, 0D4h
rol al, 1					;d. AL=0A9h

2.有如下代码序列,请写出每条移位或循环移位指令执行后AL的值:

mov al, 0D4h
ror al, 3						;a. AL=9Ah
mov al, 0D4h
rol al, 7						;b. AL=6Ah
stc
mov al, 0D4h				
rcl al, 1						;c. AL=0A9h
stc
mov al, 0D4h
rcr al, 3						;d. AL=3Ah

3.执行如下操作后,AX与DX的内容是什么?

mov dx, 0
mov ax, 222h
mov cx, 100h
mul cx

答:AX为 2200h,DX为0002h

4.执行如下操作后,AX的内容是什么?

mov ax, 63h
mov bl, 10h
div bl

答:AX为0306h ,

5.执行如下操作后,EAX和 EDX的内容是什么?

mov eax, 123400h
mov edx, 0
mov ebx, 10h
div ebx

答:EAX为12340h ,EDX为0

6.执行如下操作后,AX和 DX的内容是什么?

mov ax, 4000h
mov dx, 500h
mov bx, 10h
div bx

答:溢出了,执行16位除法时DX:AX=05004000h ,除bx时,商为504000h超出了AX的范围

7.执行如下操作后,BX的内容是什么?

mov bx, 5
stc
mov ax, 60h
adc bx, ax

答:BX为60h+5+1 = 66h

8.在64位模式下执行下述代码并描述其输出:

.data
dividend_hi QWORD 00000103h
dividend_lo QWORD 33300020h
divisor		QWORD 00000100h
.code
mov rdx, dividend_hi
mov rax, dividend_lo
div divisor

答:溢出,64位除法时被除数为rdx:rax = 00000103 0000000033300020h / 100h = 1 0000000000333000h超过64的寄存器范围

9.下面的程序执行的是 val1 减去 val2,找出并纠正其中所有的逻辑错误(CLC清除进位标志位):

.data
val1 QWORD 20403004362047A1h
val2 QWORD 055210304A2630B2h
result QWORD 0
.codemov cx, 8				;循环计数器mov esi, val1			;设置开始索引mov edi, val2clc						;清除进位标志位
top:mov al, BYTE PTR[esi]	;取第一个数sbb al, BYTE PTR[edi]	;减去第二个数mov BYTE PTR[esi], al	;保存结果dec esidec ediloop top

答:修改后:

;7.9.1_9.asm     7.9.1   简答题
;9.下面的程序执行的是 val1 减去 val2,找出并纠正其中所有的逻辑错误(CLC清除进位标志位):.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
val1 QWORD 20403004362047A1h
val2 QWORD 055210304A2630B2h
result QWORD 0.code
main PROCmov ecx, 8						;循环计数器(修正)mov esi, offset val1			;(修正)mov edi, offset val2            ;(修正)clc								;清除进位标志位
top:mov al, BYTE PTR[esi]	        ;取第一个数sbb al, BYTE PTR[edi]	        ;减去第二个数mov BYTE PTR[esi], al       	;保存结果inc esi                         ;(修正) inc edi                         ;(修正)loop topINVOKE ExitProcess,0
main ENDP
END main

10.在64位模式下执行下述指令后,RAX中的十六进制内容是什么?

.data
multiplicand QWORD 0001020304050000h
.code
imul rax, multiplicand, 4

答:RAX中的十六进制内容为04080C10140000h

7.9.2 算法基础

1.编写一个移位指令序列,使得AX符号扩展到EAX。也就是说,把AX的符号位复制到EAX的高16位。不要使用CWD指令。

答:方法1:

;7.9.2_1.asm     7.9.2 算法基础
;1.编写一个移位指令序列,使得AX符号扩展到EAX。也就是说,把AX的符号位复制到EAX的高16位。不要使用CWD指令。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
var1 SWORD -1024.code
main PROCmov ax, var1; 方法1: 最简洁的移位序列movsx eax, ax			; 最简单的方法,但使用了movsx而不是移位; 方法2: 使用移位和算术运算movzx eax, ax			; 首先将AX零扩展到EAXmov ebx, eax			; 保存原始值到EBXshl eax, 16				; 将AX左移到EAX的高16位sar eax, 16				; 算术右移16位,将符号位扩展到高16位INVOKE ExitProcess,0
main ENDP
END main

测试:初始值 AX = -1024

2.假设指令集没有循环移位指令,请说明如何用SHR和条件判断指令将AL循环右移一位.

答:原理:把最低位移到进位标志位,判断进位标志位是否置1,如果置1,右移1位后再把AL的最高位置1。

;7.9.2_2.asm     7.9.2 算法基础
;2.假设指令集没有循环移位指令,请说明如何用SHR和条件判断指令将AL循环右移一位..386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.code
main PROCmov al, 01011101b		;AL = 5Dhshr al, 1jnc no_carray			;CF=0, 没有进位跳转or al, 80h				;CF=1表示最低位为1,把最高位设置为1,实现循环右移1位
no_carray:nopINVOKE ExitProcess,0
main ENDP
END main

3.编写一条逻辑移位指令,实现EAX乘以16。

答:shl eax, 4

;7.9.2_3.asm     7.9.2 算法基础
;3.编写一条逻辑移位指令,实现EAX乘以16。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.code
main PROCmov eax, 7shl eax, 4INVOKE ExitProcess,0
main ENDP
END main

运行调试:

4.编写一条逻辑移位指令、实现EBX除以4。

答:shr eax, 2

;7.9.2_4.asm     7.9.2 算法基础
;4.编写一条逻辑移位指令、实现EBX除以4。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.code
main PROCmov eax, 1Dhshr eax, 2		;右移2位,相当于除4INVOKE ExitProcess,0
main ENDP
END main

运行调试:

5.编写一条循环移位指令,交换DL寄存器的高4位和低4位。

答:ror DL, 4

;7.9.2_5.asm     7.9.2 算法基础
;5.编写一条循环移位指令,交换DL寄存器的高4位和低4位。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.code
main PROCmov dl, 07hror dl, 4INVOKE ExitProcess,0
main ENDP
END main

运行调试:

6.编写一条SHLD指令,把AX寄存器的最高位移入DX的最低位,并把DX左移一位。

答:shld dx, ax, 1

;7.9.2_6.asm     7.9.2 算法基础
;6.编写一条SHLD指令,把AX寄存器的最高位移入DX的最低位,并把DX左移一位。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.code
main PROCmov ax, 8080hmov dx, 8080hshld dx, ax, 1INVOKE ExitProcess,0
main ENDP
END main

运行调试:

7.编写指令序列,把三个内存字节右移一位,使用数据如下:

byteArray BYTE 8lh, 20h, 33h

答:内存字节右移后结果为 40h, 90h, 19h

;7.9.2_7.asm     7.9.2 算法基础
;7.编写指令序列,把三个内存字节右移一位,使用数据如下:
;byteArray BYTE 8lh, 20h, 33h.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
byteArray BYTE 81h, 20h, 33h.code
main PROC			mov ecx, LENGTHOF byteArraymov esi, OFFSET byteArrayclc				            ;清除进位标志位
L1:mov al, BYTE PTR [esi]rcr al, 1					;带进位循环右移mov BYTE PTR [esi], alinc esiloop L1INVOKE ExitProcess,0
main ENDP
END main

运行调试

8.编写指令序列,把三个内存字节左移一位,使用数据如下:

wordArray WORD 810Dh, 0C064h, 93ABh

答:数据整体向左移一位,最后一个数据最低位用0填充。

;7.9.2_8.asm     7.9.2 算法基础
;8.编写指令序列,把三个内存字节左移一位,使用数据如下:
;wordArray WORD 810Dh, 0C064h, 93ABh.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
wordArray WORD 810Dh, 0C064h, 93ABh.code
main PROC	mov esi, offset wordArraymov ax, WORD PTR wordArray[2]shld WORD PTR wordArray[0], ax, 1	;左移1位用第2个字的最高位填充第1个字的最低位mov ax, WORD PTR wordArray[4]shld WORD PTR wordArray[2], ax, 1	;左移1位用第3个字的最高位填充第2个字的最低位shl WORD PTR wordArray[4], 1		;最后一个字左移1位INVOKE ExitProcess,0
main ENDP
END main

运行调试:

9.编写指令,实现-5乘以3,并把结果存人一个16 位变量 val1。

答:val1 = FFF1h,为-15的补码

;7.9.2_9.asm     7.9.2 算法基础
;9.编写指令,实现-5乘以3,并把结果存人一个16 位变量 val1。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
var1 SWORD 0.code
main PROCmov ah, 0mov al, -5mov bl, 3imul blmov var1, axINVOKE ExitProcess,0
main ENDP
END main

运行调试:

10.编写指令,实现-276除以10,并把结果存入一个16 位变量 val1。

答:8位除法,商放在AL中,余数放在AH中。

;7.9.2_10.asm     7.9.2 算法基础
;10.编写指令,实现-276除以10,并把结果存入一个16 位变量 val1。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
var1 SWORD 0.code
main PROCmov ax, -276mov bl, 10idiv bl				;商在AL中, 余数在AH中mov var1, ax	    ;结果存入val1中INVOKE ExitProcess,0
main ENDP
END main

11.使用32位无符号操作数,用汇编语言实现下述C++表达式:

vall=(val2*va13)/(val4-3)

答:32位乘法,高32位存在EDX中,低32位存在EAX中,32位除数,被除数为EDX:EAX,除数为32位,结果:商存放在EAX中,余数存放在EDX中。

;7.9.2_11.asm     7.9.2 算法基础
;11.使用32位无符号操作数,用汇编语言实现下述C++表达式:
;vall=(val2*va13)/(val4-3).386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
val1 DWORD 0
val2 DWORD 20h
val3 DWORD 30h
val4 DWORD 13h.code
main PROCmov eax, val2mul val3			;结果:高32位存在edx中,低32位存放在eax中mov ebx, val4sub ebx, 3div ebx				;结果:商在EAX中,余数在EDX中INVOKE ExitProcess,0
main ENDP
END main

12.使用32位有符号操作数,用汇编语言实现下述C++表达式:

vall=(va12/va13)*(val1 + va12)

答:

;7.9.2_12.asm     7.9.2 算法基础
;12.使用32位有符号操作数,用汇编语言实现下述C++表达式:
;vall=(va12/va13)*(val1 + va12).386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
val1 DWORD 20h
val2 DWORD 600h
val3 DWORD 60h.code
main PROCmov ebx, val1add ebx, val2		;val1+val2mov edx, 0			;高位清0mov eax, val2div val3			;val2/val3mul ebx				;(va12/va13)*(val1 + va12)mov val1, eaxINVOKE ExitProcess,0
main ENDP
END main

运行调试:

13.编写一个过程,把8位无符号二进制数值显示为十进制形式。用AL接收二进制数值,其取值范围为十进制的0~99。你能从本书链接库中调用的只有WriteChar。过程应包含约8条指令。调用示例如下:

mov al,65 ;取值范围0~99

call showDecimal8

;7.9.2_13.asm     7.9.2 算法基础
;13.编写一个过程,把8位无符号二进制数值显示为十进制形式。用AL接收二进制数值,
;其取值范围为十进制的0~99。你能从本书链接库中调用的只有WriteChar。过程应包含约8条指令。调用示例如下:
;mov al,65	;取值范围0~99
;call showDecimal8INCLUDE Irvine32.inc.code
main PROCmov al, 65call showDecimal8INVOKE ExitProcess,0
main ENDP
; 输入:AL = 无符号二进制数值(0~99)
showDecimal8 PROCmov  ah, 0          ; 清除 AH,为除法准备mov  bl, 10         ; 除数 BL = 10div  bl             ; AL = 商(十位),AH = 余数(个位)or   al, '0'        ; 转换为 ASCII 码call WriteChar      ; 显示十位数字mov  al, ah         ; 将个位移到 ALor   al, '0'        ; 转换为 ASCII 码call WriteChar      ; 显示个位数字ret
showDecimal8 ENDP
END main

运行结果:

14.挑战:假设两个未知的ASCII 十进制数字相加,其结果为AX的值是0072h,辅助进位标志位置1。用Intel64和IA-32指令集参考手册来判断AAA指令会产生怎样的输出,并解释其原因。

答:执行AAA指令后:AX=0108h, AF=1, CF=1

;7.9.2_14.asm     7.9.2 算法基础
;14.挑战:假设两个未知的ASCII 十进制数字相加,其结果为AX的值是0072h,辅助进位标志位置1。
;用Intel64和IA-32指令集参考手册来判断AAA指令会产生怎样的输出,并解释其原因。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.code
main PROCmov ah, 0;mov al,42h;add al,30h		;这个相加没有辅助进位标志,所以别然AL都等于72h,同样执行aaa指令,结果不一样;mov al, '9';add al, '9'	;这个相加有辅助进位标志mov al, 34hadd al, 3Eh		;AL=72h, 有辅助进位标志aaaINVOKE ExitProcess,0
main ENDP
END main

运行调试:

原因解释

虽然AL的低4位(2)不大于9,但由于辅助进位标志AF=1,表示在之前的加法操作中低4位向高4位产生了进位(即发生了十进制调整所需的"加6"操作)。因此AAA指令仍然会进行调整:

  1. 加6修正:因为两个ASCII数字相加时,如果和超过9,需要加6来得到正确的BCD结果
  2. AH递增:表示十位上的进位
  3. 高4位清零:因为我们要的是纯数字值,不是ASCII码

15.挑战:假设给定ny的值,若只能使用SUB、MOV和AND指令,如何计算x=n mod y。其中n为任意32位无符号整数,y为2的幂。

答: 当y是2的幂时,计算n mod y有一个非常高效的位操作技巧:n mod y = n AND (y-1)

原理:

对于任何2的幂的数y,可以表示为y=2^k。那么y-1的二进制表示就是k个1后面跟着(32-k)个0。例如:

  • 如果y=8 (2^3),则y-1=7=0b0111
  • 如果y=16 (2^4),则y-1=15=0b1111

n mod y实际上就是取n的最低k位,这正好可以通过n AND (y-1)来实现。

;7.9.2_15.asm     7.9.2 算法基础
;15.挑战:假设给定n和y的值,若只能使用SUB、MOV和AND指令,如何计算x=n mod y。其中n为任意32位无符号整数,y为2的幂。
;当y是2的幂时,计算n mod y有一个非常高效的位操作技巧:n mod y = n AND (y-1)。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
n DWORD 27
y DWORD 8		;2的3次方.code
main PROCmov eax, nmov ebx, ysub ebx, 1and eax, ebxINVOKE ExitProcess,0
main ENDP
END main

运行调试:

16.挑战:编写代码计算EAX寄存器中有符号整数的绝对值,要求只能使用SAR、ADD和XOR指令(不能使用有条件跳转)。提示:一个数加-1可取反,然后形成其反码。同时,如果一个数与全1进行 XOR运算,则其为1的位取反。也就是说,如果与全0进行XOR运算,则该数不变。

;7.9.2_16.asm     7.9.2 算法基础
;16.挑战:编写代码计算EAX寄存器中有符号整数的绝对值,要求只能使用SAR、ADD和XOR指令(不能使用有条件跳转)。
;提示:一个数加-1可取反,然后形成其反码。同时,如果一个数与全1进行 XOR运算,则其为1的位取反。
;也就是说,如果与全0进行XOR运算,则该数不变。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
var1 SWORD -1024.code
main PROCmov eax, 25h        ;可以用-25验证     mov edx, eax        ;保存原始值到EDXsar edx, 31         ;将EDX算术右移31位,得到符号掩码(全0或全1)xor eax, edx        ;如果原数为负,这将得到反码, 如果是正数,eax的值不变xor edx, 0FFFFFFFFh ;如果为负数, e 8 dx = 0, 如果为正数,edx = 1add edx, 1          ;取反加1的效果add eax, edx        ;如果是正数值不变,如果是负数+1;方式2mov ebx, 111mov eax, ebxsar eax, 31         ;符号位填充最左边xor eax, 0ffffffffh ;负数结果是0,否则全是1add eax, 1          ;负数结果是1,正数结果是0mov  ecx, eaxLOOP _finaladd ebx, -1         ;-1的补码是全1,add运算时,符号位不变, 数据运算:1+原来的1=0,进位,1+原来的0=1,所以是反码xor ebx, 0ffffffffh ;反码xor全1,符号位全部变为0,数据位,1变0,0变1,数据位恢复为原值,最终结果为其绝对值_final: mov eax, ebx ;返回值;方式3mov eax, 9          ;可以用-9验证     mov edx, eax        ;保存原始值到EDXsar edx, 31         ;将EDX算术右移31位,得到符号掩码(全0或全1)xor eax, edx        ;如果原数为负,这将得到反码, 如果是正数,eax的值不变sub eax, edx        ;原理等同 EAX = EAX - (-1),也就是 EAX = EAX + 1;方式4mov eax, 6          ;可以用-6验证     mov edx, eax        ;保存原始值到EDXsar edx, 31         ;将EDX算术右移31位,得到符号掩码(全0或全1)xor eax, edx        ;如果原数为负,这将得到反码, 如果是正数,eax的值不变shr edx, 31add eax, edx        ;加上符号位 (下面两条指令也可以实现同样的功能)INVOKE ExitProcess,0
main ENDP
END main

7.10 编程练习

*1.显示 ASCII十进制数

编写名为WriteScaled的过程,输出有隐含十进制小数点的ASCII十进制数。假设数据定义如下,其中DECIMAL_OFFSET 表示的是十进制小数点必须在数据右起第5位上:

DECIMAL_OFFSET = 5
.data
decimal_one BYTE = "100123456789765"

WriteSclaed输出数据如下所示:

1001234567.89765

调用WriteSclaed 时,EDX为数的偏移量,ECX为数的长度,EBX为小数点偏移量。编写测试程序,向 WriteSclaed 过程传递三个不同大小的数。

;7.10_1.asm     7.10 编程练习  *1.显示 ASCII十进制数
;编写名为WriteScaled的过程,输出有隐含十进制小数点的ASCII十进制数。INCLUDE Irvine32.incDECIMAL_OFFSET = 5.data
decimal_one BYTE "100123456789765"
decimal_two BYTE "3456776510012"
decimal_three BYTE "523546568083453345342".code
main PROCmov edx, OFFSET decimal_one		;数的偏移量mov ecx, LENGTHOF decimal_one	;数的长度call WriteSclaedcall Crlfmov edx, OFFSET decimal_two		;数的偏移量mov ecx, LENGTHOF decimal_two	;数的长度call WriteSclaedcall Crlfmov edx, OFFSET decimal_three	;数的偏移量mov ecx, LENGTHOF decimal_three	;数的长度call WriteSclaedcall CrlfINVOKE ExitProcess,0
main ENDPWriteSclaed PROCmov ebx, DECIMAL_OFFSET			;EBX为小数点偏移量
L1:cmp ecx, ebxjne	outputmov al, 46						;点的ASCII值call WriteChar					;输出小数点
output:mov al, BYTE PTR [edx]call WriteChar					;输出字符inc edx							;下一个字符loop L1ret
WriteSclaed ENDP
END main

运行调试:

测试数据:"100123456789765","3456776510012","523546568083453345342"

*2.扩展减法过程

编写名为Extended_Sub的过程,实现任意大小的两个二进制数减法。这两个数需要有同样大小的存储空间,且其大小应为32位的倍数。编写测试程序向该过程传递不同的整数对,每个数至少长10个字节。

;7.10_2.asm     7.10 编程练习 *2.扩展减法过程
;编写名为Extended_Sub的过程,实现任意大小的两个二进制数减法。
;这两个数需要有同样大小的存储空间,且其大小应为32位的倍数。
;编写测试程序向该过程传递不同的整数对,每个数至少长10个字节。INCLUDE Irvine32.inc.data		;32个字节, 
num1    BYTE 12h,34h,56h,78h, 23h,45h,67h,89h, 34h,56h,78h,9Ah, 45h,67h,89h,0ABh ;被减数
num2    BYTE 22h,34h,56h,78h, 23h,45h,67h,89h, 34h,56h,78h,9Ah, 45h,67h,89h,0ABh ;减数
num3    BYTE 23h,45h,67h,89h, 45h,67h,89h,0ABh                                   ;被减数
num4    BYTE 22h,34h,56h,78h, 23h,45h,67h,89h                                    ;减数
result  BYTE 32 DUP(0)                                                           ;存储结果.code
main PROCstc		                ;设置进位标志mov esi, OFFSET num1mov ebx, OFFSET num2mov edi, OFFSET resultmov ecx, LENGTHOF num1	;数的长度call Extended_Sub;第2次调用 mov esi, OFFSET num3mov ebx, OFFSET num4mov edi, OFFSET resultmov ecx, LENGTHOF num3	;数的长度call Extended_SubINVOKE ExitProcess,0
main ENDPExtended_Sub PROCclc		                ;清除进位标志
L1:mov al, BYTE PTR [esi]	;读取第一个操作数sbb al, BYTE PTR [ebx]	;带进位减法, 减第2个操作数mov BYTE PTR [edi], al	;把差存入result中inc esiinc ebxinc ediloop L1ret
Extended_Sub ENDP
END main

运行调试:

第1次调用 :

第2次调用 :

**3.压缩十进制转换

编写名为PackedToAsc的过程,将4字节的压缩十进制整数转换为 ASCII 十进制数字串。向过程传递压缩整数和存放ASCII数字的缓冲区地址。编写一个简短的程序测试该过程,至少使用5个压缩十进制整数作为测试数据

;7.10_3.asm     7.10 编程练习  **3.压缩十进制转换
;编写名为PackedToAsc的过程,将4字节的压缩十进制整数转换为 ASCII 十进制数字串。
;向过程传递压缩整数和存放ASCII数字的缓冲区地址。
;编写一个简短的程序测试该过程,至少使用5个压缩十进制整数作为测试数据INCLUDE Irvine32.inc.data
;5个32位测试数据
packedNumbers DWORD 12345678h,00240001h,99999987h,10090700h,01234567h  
;每个字符串需要 9 字节(8 位 + '\0')
asciiBuffers  BYTE 9 DUP(?), 9 DUP(?), 9 DUP(?), 9 DUP(?), 9 DUP(?)
;每个字符串占13个字节
testResults   BYTE "Test Case 1:", 0BYTE "Test Case 2:", 0BYTE "Test Case 3:", 0BYTE "Test Case 4:", 0BYTE "Test Case 5:", 0.code
main PROCmov esi, OFFSET packedNumbersmov edi, OFFSET asciiBuffersmov ecx, LENGTHOF packedNumbers  ;数据个数mov ebx, 0
L1:mov eax, [esi]		             ;取数据call PackedToAscadd esi, 4add edi, 9add ebx, 13loop L1INVOKE ExitProcess,0
main ENDPPackedToAsc PROCpushad			                ;保存寄存器的值mov edx, OFFSET testResultsadd edx, ebxcall WriteStringcall Crlfmov ecx, 8add edi, ecxjmp L2L1:	;输出到屏幕的是87654321   低位存放在低地址mov BYTE PTR [edi], aland BYTE PTR [edi], 00001111b	;清空高4位or BYTE PTR [edi], 110000b		;转成ASCII码shr eax, 4						;右移4位inc ediloop L1jmp showL2:	;输出到屏幕的是12345678    与定义的顺序一致dec edimov BYTE PTR [edi], aland BYTE PTR [edi], 00001111b	;清空高4位or BYTE PTR [edi], 110000b		;转成ASCII码shr eax, 4						;右移4位loop L2show:popad;mov edx, OFFSET asciiBuffersmov edx, edicall WriteStringcall Crlfret
PackedToAsc ENDP
END main

运行结果:

**4.用循环移位操作进行加密

编写一个过程,通过将明文的每个字节向不同方向循环移动不同的位数来对其进行简单加密例如,下面的数组就表示一个密钥,负数代表循环左移,正数代表循环右移。其中的每个整数表示的是循环移动的位数:

key BYTE -2,4,1,0,-3,5,2,-4,4,6

该过程应将消息明文进行循环,把密钥分配给消息的前10个字节。明文的每个字节循环移动的位数由其对应的密钥值来决定。然后再把密钥分配给消息的下一组10个字节,并重复前述过程。编写测试程序,用两组不同的数据集调用加密过程两次,以对其进行测试。

;7.10_4.asm     7.10 编程练习 **4.用循环移位操作进行加密   参考6.11.2编程练习的第8题
;编写一个过程,通过将明文的每个字节向不同方向循环移动不同的位数来对其进行简单加密例如,
;下面的数组就表示一个密钥,负数代表循环左移,正数代表循环右移。其中的每个整数表示的是循环移动的位数:
;key BYTE -2, 4, 1, 0, -3, 5, 2, -4, 4, 6INCLUDE Irvine32.incBUFMAX = 128								;缓冲区的最大容量.data
sPrompt  BYTE "Enter the plain text: ", 0
sEncrypt BYTE "Cipher text:   ", 0 
sDecrypt BYTE "Decrypted:    ",0
buffer   BYTE BUFMAX+1 DUP(0)
key BYTE -2, 4, 1, 0, -3, 5, 2, -4, 4, 6
bufSize DWORD ?
buffer1 BYTE "Stray birds of summer come to my window to sing and fly away.",0
buffer2 BYTE "see the following details.",0.code
main PROC;第1次调用加密mov bufSize, LENGTHOF buffer1mov esi, OFFSET buffer1call EncryptBuffer						;加密缓冲区mov edx, OFFSET sEncrypt				;显示加密消息call WriteStringcall Crlfmov edx, OFFSET buffer1					;显示缓冲区call WriteStringcall Crlf;显示解密消息call DecryptBuffer						mov edx, OFFSET sDecrypt				;显示解密消息call WriteStringcall Crlfmov edx, OFFSET buffer1					;显示缓冲区call WriteStringcall Crlf;第2次调用加密mov bufSize, LENGTHOF buffer2mov esi, OFFSET buffer2call EncryptBuffer						;加密缓冲区mov edx, OFFSET sEncrypt				;显示加密消息call WriteStringcall Crlfmov edx, OFFSET buffer2					;显示缓冲区call WriteStringcall Crlf;显示解密消息call DecryptBuffer						mov edx, OFFSET sDecrypt				;显示解密消息call WriteStringcall Crlfmov edx, OFFSET buffer2					;显示缓冲区call WriteStringcall Crlfquit:;exitINVOKE ExitProcess,0
main ENDP;---------------------------------------------------------------
;字符串的每个字节都与密钥字节进行移位加密
;实现转换, 负数代表循环左移,正数代表循环右移
;接收:无
;返回:无
;----------------------------------------------------------------
EncryptBuffer PROCpushadmov ecx, bufSize							;循环计数器mov edi,0									;密钥的索引,循环使用
L1:push ecxmovzx eax, BYTE PTR key[edi]cmp al, 0									;判断是否大于0jns rorMove									;无符号跳转,大于0表示正数循环右移js rolMove									;有符号跳转,小于0表示负数循环左移je nextchar									;等于0不作处理rorMove:mov cl, alror BYTE PTR [esi], cl						;循环位数要放在cl中jmp nextcharrolMove:neg eaxmov cl, alrol BYTE PTR [esi], clnextchar:inc esi										;指向下一个明文inc edi										;指向下一个密钥cmp edi, LENGTHOF key						;比较密钥是否越界je correct									;密钥是否已经用完一次jne next
correct:mov edi, 0									;修改edi,继续从0开始
next:pop ecxloop L1popadret
EncryptBuffer ENDP;---------------------------------------------------------------
;字符串的每个字节都与密钥字节进行移位解密
;与加密相反, 负数代表循环右移,正数代表循环左移
;接收:无
;返回:无
;----------------------------------------------------------------
DecryptBuffer PROCpushadmov ecx, bufSize							;循环计数器mov edi,0									;密钥的索引,循环使用
L1:push ecxmovzx eax, BYTE PTR key[edi]cmp al, 0									;判断是否大于0jns rolMove									;无符号跳转,大于0表示正数循环左移js 	rorMove									;有符号跳转,小于0表示负数循环右移je nextchar									;等于0不作处理rorMove:neg eaxmov cl, alror BYTE PTR [esi], cl						;循环位数要放在cl中jmp nextcharrolMove:mov cl, alrol BYTE PTR [esi], clnextchar:inc esi										;指向下一个明文inc edi										;指向下一个密钥cmp edi, LENGTHOF key						;比较密钥是否越界je correct									;密钥是否已经用完一次jne next
correct:mov edi, 0									;修改edi,继续从0开始
next:pop ecxloop L1popadret
DecryptBuffer ENDPEND main

运行调试:

***5.素数

编写程序,使用厄拉多塞过滤算法(SieveofEratosthenes)生成2~1000之间的全部素数。互联网上可以发现很多文章描述了使用该算法寻找素数的方法。要求显示所有的素数。

;7.10_5.asm     7.10 编程练习  ***5.素数
;编写程序,使用厄拉多塞过滤算法(SieveofEratosthenes)生成2~1000之间的全部素数。
;互联网上可以发现很多文章描述了使用该算法寻找素数的方法。要求显示所有的素数。INCLUDE Irvine32.inc.code
main PROCmov ecx, 999mov esi, 2L1:mov ebx, 2		;从2开始判断是否有被整除的
L2:cmp ebx, esije prime		;相等说明前面都没有被整除,该数是素数mov edx, 0		;高位清0mov eax, esi	;被除数放在eax中div ebx			;商在eax中,余数在edx中cmp edx, 0je next			;等于0, 有被整除,不是素数,检查下一个数cmp ebx, esijl next2		;ebx比esi小,再除下一个数jmp nextnext2:inc ebxjmp L2prime:mov eax, esi	;打印素数call WriteDeccall Crlfnext:inc esiloop L1call CrlfINVOKE ExitProcess,0
main ENDPEND main

运行结果:

2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
101
103
107
109
113
127
131
137
139
149
151
157
163
167
173
179
181
191
193
197
199
211
223
227
229
233
239
241
251
257
263
269
271
277
281
283
293
307
311
313
317
331
337
347
349
353
359
367
373
379
383
389
397
401
409
419
421
431
433
439
443
449
457
461
463
467
479
487
491
499
503
509
521
523
541
547
557
563
569
571
577
587
593
599
601
607
613
617
619
631
641
643
647
653
659
661
673
677
683
691
701
709
719
727
733
739
743
751
757
761
769
773
787
797
809
811
821
823
827
829
839
853
857
859
863
877
881
883
887
907
911
919
929
937
941
947
953
967
971
977
983
991
997

***6.最大公约数(GCD)

两个数的最大公约数(GCD)是指能整除这两个数的最大整数。下述伪代码描述的是循环整数

除法的 GCD 算法:

int GCD(int x, int y)
{x = abs(x)y = abs(y)do {int n = x % yx = y y = n}while (y > 0)return x
}

用汇编语言实现该函数,并编写测试程序,通过向该函数传递不同的数值对其进行多次调用。

在屏幕上显示全部结果。

;7.10_6.asm     7.10 编程练习  ***6.最大公约数(GCD)
;两个数的最大公约数(GCD)是指能整除这两个数的最大整数。INCLUDE Irvine32.inc
;测试数据
.data
x DWORD -75
y DWORD 50.code
main PROCmov eax, -75mov ebx, 50call GCDcall WriteDeccall Crlfmov eax, 96mov ebx, -64call GCDcall WriteDeccall CrlfINVOKE ExitProcess,0
main ENDP;两个数的最大公约数(GCD)
;接收:eax为第1个参数, ebx为第2个参数
;返回:eax返回的最大公绝数
GCD PROC;取eax的绝对值call ABSpush eax        ;保存绝对值;取ebx的绝对值mov eax, ebxcall ABSmov ebx, eax    ;把返回的绝对值赋给ebxpop eax         ;还原eax的绝对值L1:mov edx, 0      ;高位清0div ebx         ;商在eax中, 余数在edx中  int n = x % ymov eax, ebx    ;x = y mov ebx, edx    ;y = ncmp edx, 0      ;while (y > 0)ja L1           ;大于0跳转到L1ret
GCD ENDP;取绝对值
;接收:eax为输入值
;返回:eax返回的绝对值
ABS PROC;mov eax, 25h       ;可以用-25验证     mov edx, eax        ;保存原始值到EDXsar edx, 31         ;将EDX算术右移31位,得到符号掩码(全0或全1)xor eax, edx        ;如果原数为负,这将得到反码, 如果是正数,eax的值不变xor edx, 0FFFFFFFFh ;如果为负数, edx = 0, 如果为正数,edx = 1add edx, 1          ;取反加1的效果add eax, edx        ;如果是正数值不变,如果是负数+1ret
ABS ENDPEND main

运行调试:

***7.位元乘法

编写名为 BitwiseMultiply的过程,仅使用移位和加法,实现任意 32位无符号数与 EAX相乘过程用 EBX寄存器传递乘数,用EAX寄存器传递返回值。编写简单的测试程序,调用过程并显示乘积。(假设乘积不会超过32位。)编写该程序具有相当的挑战性。一种可能的方法是用循环结构右移乘数,记录在进位标志位被置1之前移动的位数。然后把这个位数用到SHL指令中,被乘数作为该指令的目的操作数。重复该过程,直到乘数最后一个为1的位。

***8.压缩整数加法

扩展 7.6.1节的 AddPacked过程,使其实现两个任意大小(但其长度必须相同)的压缩十进制数加法。编写测试程序,向AddPacked传送几组整数:4字节的、8字节的和16字节的。假设该过程使用如下寄存器传递参数:

ESI--第一个数的指针

EDI--第二个数的指针

EDX--和数指针

ECX--相加的字节数

http://www.dtcms.com/a/279540.html

相关文章:

  • RAG索引流程中的文档解析:工业级实践方案与最佳实践
  • SMTPman,发送邮件服务器smtp怎么填才行?
  • 鹧鸪云:别墅光储项目方案设计的最终选择
  • 面试150 二叉树中的最大路径和
  • 水务工程中自动化应用:EtherNet/IP转PROFIBUS DP连接超声波流量计
  • 9.服务容错:构建高可用微服务的核心防御
  • Go泛型完全指南:从基础到实战应用
  • 【深度学习笔记】2 浅层神经网络
  • 【Golang】GORM - GEN工具 快速开始
  • Go迭代器完全指南:从基础到实战
  • MYOJ_8512:CSP初赛题单1:计算机常识
  • Unsloth 实战:DeepSeek-R1 模型高效微调指南(下篇)
  • ECUs、ZCUs、CCUs:产生的软件栈(SW stack)也有所不同
  • C++-linux 7.文件IO(三)文件元数据与 C 标准库文件操作
  • 七彩喜平台:养老行业的 “智慧革命”,老年人的 “幸福驿站”
  • 网络安全|网络准入控制系统有哪些?网络准入控制系统十大解决方案详解
  • winfom自定义一个椭圆按钮
  • Codex,Copilot 是什么
  • 艺术总监的构图“再造术”:用PS生成式AI,重塑照片叙事框架
  • Vim库函数
  • NE综合实验2:RIP 与 OSPF 动态路由精细配置及ACL访问控制列表
  • pycharm连接远程终端的Anaconda安装与bug记录
  • 洛谷【数学 1】基础数学问题:最小公倍数的计算与应用
  • ELK、Loki、Kafka 三种日志告警联动方案全解析(附实战 Demo)
  • mysql 与redis缓存一致性,延时双删 和先更新数据库,再删除缓存,哪个方案好
  • 系统思考:跨境跨界团队学习
  • 安装Keycloak并启动服务(macOS)
  • SpringMVC4
  • 用基础模型构建应用(第九章)AI Engineering: Building Applications with Foundation Models学习笔记
  • mac安装nvm执行命令报错-解决方案