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

《汇编语言:基于X86处理器》第10章 编程练习

本篇记录《汇编语言:基于X86处理器》第9章 编程练习的学习笔记。

10.8 编程练习

*1.宏 mReadkey

编写一个宏,等待一次按键操作并返回被按下的键。宏参数要包括ASCII码和键盘扫描码提示:调用本书链接库的ReadChar。编写程序对宏进行测试。比如,下面的代码等待一次按键当它返回时,两个实参分别为按键的ASCI码和扫描码:

.data
ascii BYTE ?
scan BYTE?
.code
mReadkey ascii, scan

完整代码测试笔记

;10.8_1.asm    10.8 编程练习           *1.宏 mReadkeyINCLUDE Irvine32.incmReadkey MACRO asciiVal, scanValcall ReadCharmov asciiVal, almov scanVal, ah
ENDM.data
ascii BYTE ?
scan BYTE ?
prompt BYTE "Press any key... (ESC to exit)", 0Dh, 0Ah, 0.code 
main PROCmov esi, OFFSET ascii;显示提示信息mov edx, OFFSET promptcall WriteString			;如果按下的是字符键,ascii保存在al中,扫描码保存在ah中,如果用户按下的是扩展键,;如功能键、方向键、Ins键或Del键,则过程就把AL清零,而AH包含的是键盘扫描码;call ReadChar
L1:mReadkey ascii, scan;检查是否是ESC键(ASCII码1Bh)cmp ascii, 1Bhje quitmov bx, axmovzx eax, alcall WriteDec		;显示ASCII码mov al, 9			;tab符call WriteChar		;显示tab符mov al, bh			;把扫描码赋给alcall WriteChar		;显示扫描码call Crlfjmp L1quit:call CrlfINVOKE ExitProcess, 0
main ENDP 
END main

运行调试:

*2.宏mWritestring

(需提前阅读 11.1.11节。)编写一个宏,用指定文本颜色向控制台写一个空字节结束的字符串。宏参数需包括字符串的名称和颜色。提示:调用本书链接库的 SetTextColor。编写程序,用不同的颜色和字符串测试该宏。示例调用如下:

.data
myString db "Here is my string", 0
.code
mWritestring myString, white

完整代码测试笔记

;10.8_2.asm    10.8 编程练习           *2.宏mWritestring
;black=0	red=4		gray=8			lightRed=12
;blue=1		magenta=5	lightBlue=9		lightMagenta=13
;green=2	brown=6		lightGreen=10	yellow=14
;cyan=3		lightGray=7	lightCyan=11	white=15INCLUDE Irvine32.incmWritestring MACRO name, colorpush edxpush eaxmov edx, OFFSET namemov eax, colorcall SetTextColorcall WriteStringcall Crlfpop eaxpop edx
ENDM.data
buffer BYTE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
myString db "Here is my string", 0
color BYTE ?.code 
main PROCmov esi, OFFSET buffer;获取控制台窗口当前的前景色和背景色,它没有输入参数,;返回时,AL中的高四位是背景色,低四位是前景色call GetTextColormov color, AL;设置输出广西的前景色和背景色,调用SetTextColor时,给EAX分配一个颜色属性;mov eax, white + (blue * 16)		;白底黄字;call SetTextColormov ecx, LENGTHOF buffer
L1:mWritestring myString, [esi]inc esiloop L1;恢复颜色call SetTextColorINVOKE ExitProcess, 0
main ENDP 
END main

运行调试:

*3.宏mMove32

编写宏 mMove32,接收两个32 位的内存操作数,并将源操作数传送到目的操作数。编写程序对宏进行测试。

;10.8_3.asm    10.8 编程练习           *3.宏mMove32
;编写宏 mMove32,接收两个32 位的内存操作数,
;并将源操作数传送到目的操作数。编写程序对宏进行测试。INCLUDE Irvine32.incmMove32 MACRO src, dstpush eaxmov eax, srcmov dst, eaxpop eax
ENDM.data
source DWORD 1111h, 2222h, 3333h, 4444h
target DWORD 4 DUP(?).code 
main PROCmov esi, OFFSET sourcemov edi, OFFSET targetmov ecx, LENGTHOF source
L1:mMove32 [esi], [edi]add esi, 4add edi, 4loop L1call CrlfINVOKE ExitProcess, 0
main ENDP 
END main

运行调试:

调用宏之后

*4.宏 mMult32

创建宏 mMult32,将两个32 位内存操作数相乘,生成一个32 位的乘积。编写程序对宏进行测试。

;10.8_4.asm    10.8 编程练习          *4.宏 mMult32INCLUDE Irvine32.incmMult32 MACRO val1, val2mov eax, val1mul val2
ENDM.data
value1 DWORD 12h
value2 DWORD 13h.code 
main PROCmMult32 value1, value2call CrlfINVOKE ExitProcess, 0
main ENDP 
END main

运行调试:

**5.宏 mReadInt

创建宏 mReadInt,从标准输入读取一个16 位或 32 位的有符号整数,并用实参返回该值。用条件运算符使得宏能适应预期结果的大小。编写程序,向宏传递不同大小的操作数以对其进行测试。

;10.8_5.asm    10.8 编程练习          **5.宏 mReadIntINCLUDE Irvine32.incmReadInt MACRO val, valW, valD, eltTypemov eax, valIFIDNI <eltType>, <WORD>		;;不区分大小写mov valW, axELSEmov valD, eaxENDIFENDM.data
resW WORD ?
resD DWORD 0.code 
main PROCmReadInt 12345678h, resW, resD, dwordmReadInt 1234h, resW, resD, wordcall CrlfINVOKE ExitProcess, 0
main ENDP 
END main

运行调试:

**6.宏 mWriteInt

创建宏 mWritelnt,通过调用 Writelnt 库过程向标准输出写一个有符号整数。向宏传递的参数可以是字节、字或双字。在宏内使用条件运算符,使之能适应实参的大小。编写程序,向宏传递不同大小的实参以对其进行测试。

;10.8_6.asm    10.8 编程练习          **6.宏 mWriteIntINCLUDE Irvine32.incmWriteInt MACRO val1, val2, val3
LOCAL prompt, prompt1, prompt2		;;解决重入的问题
LOCAL LB, LW, LD, PRINT, quit
.data
prompt byte "Please enter an integer: ", 0
prompt1 byte "Please enter integer's type (0 for BYTE, 1 for WORD, 2 for DWORD): ", 0
prompt2 byte "Data type input error! ", 0.codemov edx, OFFSET promptcall WriteString		;;输入提示call ReadInt			;;从键盘读入一个整数mov ebx, eax			;;保存到ebx中call Crlf				;;换行mov edx, OFFSET prompt1call WriteString		;;输入提示call ReadInt			;;从键盘读入整数类型call Crlf				;;换行cmp eax, 0je LBcmp eax, 1je LWcmp eax, 2je LDmov edx, OFFSET prompt2call WriteString		;;错误提示jmp quit
LB:movzx eax, blmov val1, bljmp PRINT
LW:mov ax, bxmov val2, bxjmp PRINT
LD:mov eax, ebxmov val3, ebxPRINT:call WriteDecquit:call Crlf
ENDM.data
resB BYTE ?
resW WORD ?
resD DWORD ?.code
main PROCmov esi, OFFSET resBmWriteInt resB, resW, resDmWriteInt resB, resW, resDmWriteInt resB, resW, resDmWriteInt resB, resW, resDinvoke ExitProcess, 0
main ENDP
END main

运行调试:

***7.教授丢失的手机

当10.1.6节的醉酒教授在校园里绕圈子时,我们发现他在路上的某个地方丢失了手机。在对醉酒路线进行模拟时,程序必须在教授停留随机时长的任何地方丢掉手机。每次运行程序,都必须在不同的时间间隔(和位置)丢失手机。

;10.8_7.asm    10.8 编程练习          ***7.教授丢失的手机INCLUDE Irvine32.inc
WalkMax = 50
StartX = 25
StartY = 25DrunkardWalk STRUCTpath COORD WalkMax DUP(<0, 0>)pathsUsed WORD 0
DrunkardWalk ENDS
DisplayPosition PROTO currX:WORD, currY:WORD
DropPhonePosition PROTO position:DWORD, currX:WORD, currY:WORD.data
aWalk DrunkardWalk <>.code 
main PROCmov esi, OFFSET aWalkcall TakeDrunkenWalkINVOKE ExitProcess, 0
main ENDP
;---------------------------------------------
;向随机方向行走(北、南、东、西)
;接收:ESI为Drunkardwalk结构的指针
;返回:结构初始化为随机数
;---------------------------------------------
TakeDrunkenWalk PROCLOCAL currX:WORD, currY:WORDpushad;用OFFSET运算符获取path--COORD对象数组--的地址,并将其复制到EDImov edi, esiadd edi, OFFSET DrunkardWalk.pathmov ecx, WalkMax							;循环计数器mov currX, StartX							;当前X的位置mov currY, StartY							;当前Y的位置;生成随机丢手机的位置mov eax, WalkMaxcall RandomRangemov ebx, eax								;把位置保存在ebx中mov edx, 0									;比对位置
Again:;把当前位置插入数组mov ax, currXmov (COORD PTR [edi]).X, axmov ax, currYmov (COORD PTR [edi]).Y, axcmp edx, ebxjne nextINVOKE DropPhonePosition, ebx, currX, currYnext:INVOKE DisplayPosition, currX, currYmov eax, 4									;选择一个方向(0-3)call RandomRange.IF eax == 0								;北dec currY.ELSEIF eax == 1							;南inc currY.ELSEIF eax == 2							;西dec currX.ELSE										;东(EAX=3)inc currX.ENDIF										;指向下一个COORDadd edi, TYPE COORDinc edxloop Again
Finish:mov (DrunkardWalk PTR [esi]).pathsUsed, WalkMaxpopadret
TakeDrunkenWalk ENDP
;-----------------------------------------------
;显示当前x和Y的位置。
;------------------------------------------------
DisplayPosition PROC currX:WORD, currY:WORD
.data
commaStr BYTE ",",0
.codepushadmovzx eax, currX							;当前X的位置call WriteDecmov edx, OFFSET commaStr					;“,”字符串call WriteStringmovzx eax, currY							;当前Y的位置call WriteDeccall Crlfpopadret
DisplayPosition ENDP
;-----------------------------------------------
;显示丢手机的位置。
;------------------------------------------------
DropPhonePosition PROC position:DWORD, currX:WORD, currY:WORD
.data
commaString BYTE ",",0
msg BYTE "Phone droped at pos: ",0
.codepushadmov edx, OFFSET msg						call WriteString							;显示丢手机的位置mov eax, positioncall WriteDecmov al, 9									;TAB空位call WriteCharmovzx eax, currX							;当前X的位置call WriteDecmov edx, OFFSET commaString					;“,”字符串call WriteStringmovzx eax, currY							;当前Y的位置call WriteDeccall Crlfpopadret
DropPhonePosition ENDP
END main

运行调试:

***8.带概率的醉汉行走问题

在测试 DrunkardWalk 程序时,你可能已经注意到教授徘徊的位置距离起点不会太远。这种情况毫无疑问是由教授在各方向移动的等概率造成的。因此按照如下条件来修改程序:教授有 50%的概率沿着与上一步相同的方向行走;有 10% 的概率选择相反的方向;有20%的概率会向右或向左转。循环开始前指定一个默认的起步方向。

;10.8_8.asm    10.8 编程练习         ***8.带概率的醉汉行走问题INCLUDE Irvine32.inc
WalkMax = 30
StartX = 25
StartY = 25DrunkardWalk STRUCTpath COORD WalkMax DUP(<0, 0>)pathsUsed WORD 0
DrunkardWalk ENDS
DisplayPosition PROTO currX:WORD, currY:WORD
DropPhonePosition PROTO position:DWORD, currX:WORD, currY:WORD
GetNextDirection PROTO position:DWORD.data
aWalk DrunkardWalk <>.code 
main PROCmov esi, OFFSET aWalkcall TakeDrunkenWalkINVOKE ExitProcess, 0
main ENDP
;---------------------------------------------
;向随机方向行走(北、南、东、西)
;接收:ESI为Drunkardwalk结构的指针
;返回:结构初始化为随机数
;---------------------------------------------
TakeDrunkenWalk PROCLOCAL currX:WORD, currY:WORD, lastDirection:DWORDpushad;用OFFSET运算符获取path--COORD对象数组--的地址,并将其复制到EDImov edi, esiadd edi, OFFSET DrunkardWalk.pathmov ecx, WalkMax							;循环计数器mov currX, StartX							;当前X的位置mov currY, StartY							;当前Y的位置;生成随机丢手机的位置mov eax, WalkMaxcall RandomRangemov ebx, eax								;把位置保存在ebx中mov edx, 0									;比对位置mov lastDirection, 0						;默认位置Again:;把当前位置插入数组mov ax, currXmov (COORD PTR [edi]).X, axmov ax, currYmov (COORD PTR [edi]).Y, axcmp edx, ebxjne nextINVOKE DropPhonePosition, ebx, currX, currYnext:INVOKE DisplayPosition, currX, currY;mov eax, 4									;选择一个方向(0-3);call RandomRange;调用概率方向INVOKE GetNextDirection, lastDirection.IF eax == 0								;北dec currY.ELSEIF eax == 1							;南inc currY.ELSEIF eax == 2							;西dec currX.ELSE										;东(EAX=3)inc currX.ENDIF										;指向下一个COORDmov lastDirection, eax						;保存上一次的方向add edi, TYPE COORDinc edxloop Again
Finish:mov (DrunkardWalk PTR [esi]).pathsUsed, WalkMaxpopadret
TakeDrunkenWalk ENDP
;-----------------------------------------------
;获取概率方向。50%概率同上一步, 10%概率相反
;20%概率左,  20%概率右
;------------------------------------------------
GetNextDirection PROC direction:DWORDmov eax, 10					;按对应的比例,分成4个方向(0~3)call RandomRange			;生成随机数0——9.IF (eax >=0) && (eax < 5)	;50%的概率同上一步mov eax, direction.ELSEIF eax == 5			;10%概率相反方向.IF direction == 0mov eax, 1.ELSEIF direction == 1mov eax, 0.ELSEIF direction == 2mov eax, 3.ELSEIF direction == 3mov eax, 2.ENDIF.ELSEIF (eax == 6) || (eax == 7)	;20%概率向左mov eax, 2.ELSEIF (eax == 6) || (eax == 7)	;20%概率向右mov eax, 3.ENDIFret
GetNextDirection ENDP
;-----------------------------------------------
;显示当前x和Y的位置。
;------------------------------------------------
DisplayPosition PROC currX:WORD, currY:WORD
.data
commaStr BYTE ",",0
.codepushadmovzx eax, currX							;当前X的位置call WriteDecmov edx, OFFSET commaStr					;“,”字符串call WriteStringmovzx eax, currY							;当前Y的位置call WriteDeccall Crlfpopadret
DisplayPosition ENDP
;-----------------------------------------------
;显示丢手机的位置。
;------------------------------------------------
DropPhonePosition PROC position:DWORD, currX:WORD, currY:WORD
.data
commaString BYTE ",",0
msg BYTE "Phone droped at pos: ",0
.codepushadmov edx, OFFSET msg						call WriteString							;显示丢手机的位置mov eax, positioncall WriteDecmov al, 9									;TAB空位call WriteCharmovzx eax, currX							;当前X的位置call WriteDecmov edx, OFFSET commaString					;“,”字符串call WriteStringmovzx eax, currY							;当前Y的位置call WriteDeccall Crlfpopadret
DropPhonePosition ENDP
END main

运行调试:

****9.移位多个双字创

建一个宏,使用 SHRD 和SHLD 指令,将一个32位整数数组向任意方向移动可变的位数。编写程序对宏进行测试,把同一个数组向两个方向移动并显示结果。可以假设数组为小端顺序。宏声明示例如下:

mShiftDoublewords MACRO arrayName, direction, numberOfBits
Parameters:arrayName			Name of the arraydirection			Right (R) or Left (L)numberOfBits	Number of bit positions to shift

***10.三操作数指令

有些计算机指令集允许算术运算指令有三个操作数。这种操作有时出现在用于向学生介绍汇编语言概念的简单虚拟汇编器中,或是在编译器中使用中间语言的时候。在下面的宏中,假设EAX 被保留用于宏操作,但是还未保存。其他会被宏修改的寄存器必须保存。所有的参数都是有符号的内存双字。编写宏模拟下述操作;

例如,下面的宏调用实现的是表达式x=(w+y)*z;

编写程序测试宏,要求实现 4个算术表达式,每个表达式都要包含多个操作

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

相关文章:

  • SFT最佳实践教程 —— 基于方舟直接进行模型精调
  • stm32中优先使用原子操作的具体实现方式
  • leecode611 有效三角形的个数
  • 基于N32G45x+RTT驱动框架的定时器外部计数
  • WebMvcConfigurer配置接口详解
  • ClickHouse vs PostgreSQL:数据分析领域的王者之争,谁更胜一筹?
  • 模型优化——在MacOS 上使用 Python 脚本批量大幅度精简 GLB 模型(通过 Blender 处理)
  • 【linux驱动开发】Vscode + Remote SSH + clangd + bear=内核源码阅读环境搭建
  • Visual Studio Code (VSCode) 的常用快捷键
  • 33.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--财务服务--记账
  • Shader开发(五)什么是渲染管线
  • 【大模型理论篇】混合思考之自适应思维链
  • day28_2025-07-31
  • 基于京东评论的文本挖掘与分析,使用LSTM情感分析算法以及网络语义分析
  • 【数据结构】算法代码
  • 前端框架Vue3(三)——路由和pinia
  • 分布内侧内嗅皮层的层Ⅱ或层Ⅲ的网格细胞(grid cells)对NLP中的深层语义分析的积极影响和启示
  • vue3.0 +TypeScript 项目中pinia基础语法和使用
  • 【大数据】open_metadata 开源元数据管理平台建设与数据血缘实践
  • 「源力觉醒 创作者计划」开源大模型重构数智文明新范式
  • AI任务相关解决方案12-NLP的15项任务大融合系统:传统NLP与Qwen大模型的深度结合
  • NTLDR源代码分析之从GetSector函数到blread函数
  • 解决 IntelliJ IDEA Build时 Lombok 不生效问题
  • 商旅平台怎么选?如何规避商旅流程中的违规风险?
  • 【未解决】STM32无刷电机驱动电路问题记录
  • .NET Core部署服务器
  • 智慧收银系统开发进销存库存统计,便利店、水果店、建材与家居行业的库存汇总管理—仙盟创梦IDE
  • Spring Boot 异常处理:从全局捕获到优化用户体验!
  • PostgreSQL面试题及详细答案120道(01-20)
  • 解放双手!Report Distro 实现报表自动化分发