【编程实践】黑框框里的打字小游戏,但是汇编语言(1)

简介: 开始:在学习王爽的《汇编语言》的过程中,我就真切地体会到编程实践对于理解的帮助。起初我没有安装书中的实验环境,看到100页左右就开始感觉无趣、吃力,看了后面忘前面,差点就要放弃这本书的学习。好在我后来还是装好了环境,这才开始在实际的编程练习中感受到一些乐趣。

开始:

在学习王爽的《汇编语言》的过程中,我就真切地体会到编程实践对于理解的帮助。起初我没有安装书中的实验环境,看到100页左右就开始感觉无趣、吃力,看了后面忘前面,差点就要放弃这本书的学习。好在我后来还是装好了环境,这才开始在实际的编程练习中感受到一些乐趣。


学习完《汇编语言》一书后,我又开始阅读朋友给我推荐的《x86汇编语言 从实模式到保护模式》。没错,王爽书介绍的只是实模式下编程的内容。读x86一书过程中,前面接近于复习,读起来还比较轻快,但随着渐渐深入,我每次对照书阅读代码都感觉很是吃力。到了第15章“程序的动态加载和执行”时,已经常常会将保护模式和前面实模式中的内容搞混。


于是我决定自己设计并编写一个汇编程序,以进一步理顺清晰前面所学习的内容——本文便缘起于此。需要声明的一点是,我并没有打算将这个程序做成一个教程,因为那好累,我有点懒。前面一小段内容算是我的日记,后面则是笔记。


但如果真的有人对我的程序或代码感兴趣,我也在后面提供了我的代码仓库链接,欢迎大家下载我的代码。然而你想运行它确实会有点麻烦,同样的在后面我也大致介绍了程序的运行环境。

 

介绍

1 程序简述

如果只允许用四个字来概括我的程序,那我只能对你说:打字游戏。可很遗憾今天的我有点话痨,请允许我更详细地描述一下这个小游戏:


运行程序后,首先映入你眼帘的会是一个干净的黑框框。什么?你问我怎么不做个哪怕简单点的导引界面?其实原因你猜得到:懒。那么,接着你需要任意地按下一个键,这个程序就要正式开始了。


屏幕顶部会开始在随机的位置掉下随机的大写字母,而且总会有个字母被一圈+环绕着,不要犹豫,它就是你的目标,请按下对应的字母键吧!如果你按下了正确的字母,它就会变成绿色,同时屏幕的左下角会默默地记录着你的得分。描述到这里就结束了,毕竟它本就只是一个简单的小程序。


下面是我录制的一段程序运行时的GIF:

7b94347ccdba46d5bfcc10332e1da034.gif

2 涉及知识

程序看着简单,玩起来也简单,但做起来可难了!而且最难的地方就是,我需要使用汇编语言来完成它,以至于它的源代码多达500行。关于指令的知识,我就不展开说了。除了会使用基本的指令外,想要写出本程序你还需要了解以下方面的知识:

显存操作。在汇编语言中,我们通过直接往显存写入数据,来让它显示我们想要的内容。与此同时你还需要了解ascii编码和字符的显示属性。

中断。你需要知道如何在系统中安装我们自己编写的中断例程,以及键盘扫描码相关的内容。

程序的加载。程序编译好后,首先是写入到磁盘里的,如何将它加载到内存中并运行?如果你是编写一个在Dos操作系统上运行的汇编程序,其实不需要这一步。但我将程序运行在一个没有操作系统的虚拟机裸机上,就需要了。

除了上面三点,我还使用“线性同余法”,用汇编实现了伪随机数的功能。不然,随机的字母、随机的下落位置,其中的随机从何而来呢?汇编并不像C语言那样有着丰富的库函数。


当然,BIOS中也是提供了一些中断例程以供用户调用的,我并不知道里面有没有随机数的功能。然而,自己尝试实现一个也挺有意思的,不是吗?这费不了多少功夫——如果你没有花很多时间调试bug的话。

3 运行环境

1、汇编语言

因为与计算机硬件实现的强相关性,汇编语言并不像其它高级语言那样标准统一。也就是说,存在多种不同的汇编语言,它们各自对应着不同的指令系统、体系结构。


好吧,其实没必要讨论那么多概念,我只是想说,本程序使用的是8086汇编语言。更进一步地说,我使用了Nasm编译器,该编译器是开源的,你可以在GitHub上找到它,而另一款大家常用的编译器是Masm。


主要是伪指令的不同会导致一些代码框架结构上的差异,如果你以前只用过Masm,可能还需要去单独了解一些Nasm的内容。

2、虚拟环境

最简单的环境搭建是使用DOSBox,它是一个包含Dos操作系统的虚拟机,可以运行8086的汇编代码。如果你打算用它的话,我的代码需要进行一些修改才能运行。


说实在用DOSBox学习汇编语言挺方便的,然而它并没有提供虚拟的磁盘,后来我安装了VisualBox和Bochs,《…从实模式式到保护模式》的书籍配套资料中有相关的安装教程(包括Nasm编译器):


http://www.lizhongc.com/


Bochs除了运行程序,还能debug;而VisualBox只能运行程序,效率要高一些。这两个虚拟机都没有操作系统,所以你要自己想办法将程序从磁盘加载到内存中来,这就是为什么前面“涉及的知识”中会说到程序的加载问题。


我的代码仓库中有两个.asm文件,其中程序typing_mbr.asm所做的事情就是把用户程序(也就是我的小游戏)加载到内存中,而typing.asm是真正的游戏程序代码。

- typing.asm
- typing_mbr.asm

Gitee源代码仓库:清风莫追/Typing_asm (gitee.com)

好吧,如果只是想用汇编语言编写并运行一个小游戏,这确实多走了不少弯路。也许我有空会尝试出个DOSBox中能跑的版本,但大概率会鸽,因为我懒。

最后还得吐槽一下,汇编语言的生产力太低了,这个小程序花了我整整16个小时。不过复习的效果感觉也不错,只是,我也不太确定是否划算。可是自己制作小作品时的那种投入感,是平常阅读(技术)书籍的过程中难以找到的。


接下来的部分是我编写代码过程中的一些笔记,就比较无聊了,Bug记录部分倒也可以参考一下。但我就不陪大家一起了,有缘再见!

程序结构

- 主引导程序:将用户从磁盘加载到内存中。
- 用户程序
  - 头部
    - 程序长度
    - 程序入口
    - 段重定位表
  - 代码段
  - 数据段

主引导程序包含信息:


用户程序在磁盘的位置,即起始逻辑扇区号。

用户程序被加载到内存的物理起始地址。

需要用到的例程:


显示:


显示一个字母

将屏幕一行内容左移一位

键盘中断:


获取键盘字符的扫描码

时钟中断:


控制字符移动速度

作为随机数种子(已鸽,目前采用固定种子:1)

障碍:屏幕移动与响应键盘中断是两个线程吗?


答:不需要,重写键盘中断即可。

复习知识点

1 常数定义

hello equ 100

定义一个值为100的常数hello,若继续mov ax,hello,则执行后ax寄存器的值为100。

在代码中引用常数或标号,都是在编译阶段发挥作用。但注意与标号使用时相区分,如果是hello db 100,然后mov ax,hello,则执行后ax的值为标号hello处的汇编地址

2 用户程序中段的重定位

SECTION header vstart=0                     ;定义用户程序头部段 
    program_length  dd program_end          ;程序总长度[0x00]
    ;用户程序入口点
    code_entry      dw start                      ;偏移地址[0x04]
                    dd section.code_1.start       ;段地址[0x06] 
    realloc_tbl_len dw (header_end-code_1_segment)/4  ;段重定位表项个数[0x0a]
    ;段重定位表           
    code_1_segment  dd section.code_1.start ;[0x0c]
    code_2_segment  dd section.code_2.start ;[0x10]
    data_1_segment  dd section.data_1.start ;[0x14]
    data_2_segment  dd section.data_2.start ;[0x18]
    stack_segment   dd section.stack.start  ;[0x1c]
    header_end:

如果使用主引导扇区加载用户程序,则用户程序需要描述头部信息。头部代码示例如上,记录的每个段的信息都是汇编地址,在主引导扇区程序中会转换为在物理内存中的段地址,以便之后用户程序可以通过

mov ax, [cs:data_1_segment]
mov ds, ax

这样的方式,在内存中正确地访问到对应的段。

3 关于vstart的三种情况

略了

4 显存模块

常用的是显存的文本模式,物理地址空间为0xB800~0xBFFFF。可以显示25行,每行80个字符,使用ASCII码。

5 命令行编译源代码

nasm -f bin exam.asm -o exam.bin

-f bin是要求nasm生成“纯二进制”的内容,即不包含操作系统所需要的加载和重定位信息。

6 中断向量表

对于8080PC机,中断向量表存放在0000:0000~0000:03FF的一共1024个内存单元中,每个表项占两个字,故最多可以有256个中断例程。表项中是中断处理程序的入口地址,其中高地址字存放段地址,低地址字存放偏移地址。


注:中断号从0开始。


一般0000:0200~0000:02FF这段内存是空闲的,操作系统和其他应用程序都不占用。

7 退出VBox对鼠标和键盘的独占

右边的组合键:Alt + Ctrl(按左边的这两个键没效果)。

8 发布到Gitee

如果你使用的是vscode,且以前已经配置过与Gitee的ssh公钥连接,那么发布代码到远程Gitee仓库的步骤如下:

  1. vscode进入“源代码管理”栏,初始化仓库,并提交所有更改。
  2. 登录Gitee账号,创建一个空的仓库,并复制仓库地址。
  3. 在vscode中“添加远程存储库”,然后输入仓库地址以及仓库名。
  4. 最后,发布分支。此时点开Gitee仓库,将看到你的代码已经被上传。

8036864a9bb34f5f9d1ea3a21bc00fbe.png

【编程实践】黑框框里的打字小游戏,但是汇编语言(2):https://developer.aliyun.com/article/1407231?spm=a2c6h.13148508.setting.21.79f64f0ecKMDuK

相关文章
|
15天前
汇编语言(第四版) 实验一 查看CPU和内存,用机器指令和汇编指令编程
汇编语言(第四版) 实验一 查看CPU和内存,用机器指令和汇编指令编程
|
2月前
|
算法 Python Windows
|
Windows
实验二用机器指令和汇编指令编程
实验二用机器指令和汇编指令编程
87 0
|
前端开发 rax
实验一:查看CPU和内存,用机器指令和汇编指令编程
实验一:查看CPU和内存,用机器指令和汇编指令编程
168 0
|
程序员 芯片 流计算
MOTOROLA MVME 162-01 直接用汇编语言编程的计算机程序
MOTOROLA MVME 162-01 直接用汇编语言编程的计算机程序
96 0
MOTOROLA MVME 162-01 直接用汇编语言编程的计算机程序
|
编译器
【CSAPP数据段解析】汇编语言机械级编程
【CSAPP数据段解析】汇编语言机械级编程
89 0
【CSAPP数据段解析】汇编语言机械级编程
|
人工智能 程序员 编译器
【C语言指针详解-CSAPP数据段解析】1024程序员节 | 汇编语言机械级编程|用代码,改变世界#
【C语言指针详解-CSAPP数据段解析】1024程序员节 | 汇编语言机械级编程|用代码,改变世界#
99 0
【C语言指针详解-CSAPP数据段解析】1024程序员节 | 汇编语言机械级编程|用代码,改变世界#
|
存储 C语言 内存技术
kermit配置/反汇编/c和汇编混合编程/计算机存储介质/GPIO编程
<h1>kermit配置<br> </h1> <div> <img src="http://img.blog.csdn.net/20150413142013492" alt=""><br> </div> <h1>反汇编</h1> <p></p> <div style="font-family:'Microsoft YaHei UI','Microsoft YaHei',SimSun
1439 0
|
Linux Java
linux下at&amp;t汇编下的编程编译体会
客观上,我依然使用java编写项目,但随着时间的推移,已感觉java无法带给我超越的感觉,尽管玩的是高级别的分布式高并发和架构集群方面的;因此我在前段着手研究linux内核,但发现研究linux内核,必须先吃透at&amp;t汇编,于是拿着一本美国佬(richard blum)写的资料研究at&amp;t汇编2个星期以来,觉得还是有点玩法。    第一个星期,说实话,在找方法,更多的是走马
1381 0