这几天一直在玩,要抓紧学完,去学别的东西哦
直接定址表
学习如何有效的组织数据,以及相关的编程技术
描述了单元长度的标号
我们先以一个程序为例
1 | assume cs:code |
这里的 a
b
start
s
code
都是标号。这些标号仅仅表示了内存单元的地址
但是我们还有一种标号,这种标号不仅表示内存单元的地址,同时还表示了内存单元的长度
上面的程序可以写成下面的形式
1 | assume cs:code |
在code段中使用的标号a,b后面没有
:
,他们是同时描述内存地址和长度的标号,例如:
- 标号a,描述了地址code:0,和从这个地址开始,以后的内存单元都是字节单元
- 标号b,描述了地址code:8,和从这个地址开始,以后的内存单元都是字单元
可见,使用这种包含单元长度的标号,可以使我们以简洁的形式访问内存中的数据。我们将这种标号称为 数据标号
在其他段中使用数据标号
指定段寄存器
在其他段中,也可以使用数据标号来描述存储数据的单元的地址和长度
不过要注意,在后面加有”:“的地址标号,只能在代码段中使用,不能在其他段中使用
比如我们以一个累加程序为例:
1 | assume cs:code,ds:data |
注意,如果想在代码段中直接用数据标号访问数据,需要用都安寄存器和标号所在的段进行关联,否则编译器无法却确定标号的段地址在哪一个寄存器里。
这里并不是说,如果用assume指令将段寄存器和某个段相联系,段寄存器中就真的回存放该段的地址。我们在程序中,仍然需要指令对段寄存器进行设置
将标号当作数据定义
可以将标号当作数据来定义,此时,编译器将标号所表示的地址当作数据的值。比如:
1 | data segment |
数据标号c存储的两个字型数据为标号a,b的偏移地址。相当于:
c dw offset a, offset b
再比如:
1 | data segment |
数据标号c处存储的两个双字型为标号a的偏移地址和段地址,标号b的偏移地址和段地址。相当于:
c dw offset a,seg a,offset b,seg b
这里的seg操作符,功能为取得某一标号的段地址
直接定址表
我们注意到数值015和字符”0”“F”之间并没有直接的映射关系,所以我们需要再他们之间建立新的映射关系
数值09和字符”0”“9”之间的映射关系最明显,有
数值 + 30H = 对应字符的ASCII值
数值1015和字符”A”“F”之间的映射关系则是,
数值 + 37H = 对应字符的ASCII值
具体的做法是,建立一张表,表中依次存储字符”0”“F”,我们可以通过数值015直接查找到对应的字符
1 | assume cs:code |
这张表定义后可以实现映射操作,当我们向ax中传输一个数值时,它会返回这个数值到显示器上
这种映射关系一般用作以下几种用途:
- 为了算法的清晰和简洁
- 为了加快运算速度
- 为了使程序易于填充
接下来编写一个子程序sin (x), x ∈ {0∘, 30∘, 60∘, 90∘, 120∘, 150∘, 180∘}并在屏幕中央显示结果,我们可以用麦克劳林公式进行计算sin(x),不过为了加快运算速度,在这里我们使用映射来加快这个过程。我们可以写出以下程序:
1 | assume cs:code |
上面这种可以通过依据数据,直接计算出所要找的元素的位置的表,我们称之为直接定址表
程序入口的直接定址表
我们可以在直接定址表中存储子程序的地址,从而方便的实现不同子程序的调用。
我们编写以下程序

得知需求之后,分析一下功能的实现:
- 清屏:讲显存中当前屏幕中的字符设置为空格符
- 设置前景色:设置显存中当前屏幕中处于奇地址的属性字节的第0,1,2位
- 设置背景色:设置显存中当前屏幕中处于奇地址的属性字节的第4,5,6位
- 向上滚动一行:依次将第n+1行的内容复制到第n行;最后一行为空
我们可以写出以下程序:
1 | assume cs:code |
根据上面的程序需求即可修改对应的参数
最后的挑战
字符串打印

程序如下,利用栈和int 16h
模拟了键盘的输入和撤回:
1 | assume cs:code |