汇编语言学习笔记-ch5-6
·88 words·1 min
Table of Contents
隐式指定需要操作的数据长度 #
- 例如:
MOV AX,[BX]
和MOV AL,[BX]
中,BX的地址的意义分别是字地址和字节地址。 - 因此,具体这个地址是字地址还是字节地址,实际上是由其操作
隐式决定
的。
idata #
- 可以指代任意常量。可以出现在任意需要常量的位置并替换它。
- 例如
MOV AX,[idata]
符号描述:() #
- 括号用于符号描述,不允许出现在汇编语言中,而是只能作为
伪代码
出现。 - 括号内的元素可以是
寄存器或内存单元物理地址
,即一切可以存放数据的地方
。 - 主要用于使用伪代码描述一个过程。常用于解释一个汇编指令的具体功能。
- 例如解释push ax的功能:
(sp)=(sp)-2
((ss)*16+(sp))=(ax)
- (注意,只要是段寄存器就会使用左移4位的机制,不管是
什么
段。)
- 例如解释push ax的功能:
在汇编源程序中,数据不能以字母开头。 #
- 因此,如果写
fffffh
,只能写成0fffffh
。
标号 #
- 标号是地址的标识符。当进行汇编时,此标识符会被原封替换为对应的地址,写入机器指令。
debug和masm对汇编指令的不同解释 #
- 如果在debug中,通过a指令一条一条地输入汇编指令,其中输入了
mov al,[0]
,此外还新建了一个asm文件,编写程序,其中包括了mov al,[0]
,然后放在debug里运行。 - 那么区别是,一个被解释为内存单元,一个被解释成了立即数。debug中直接输入上述汇编指令,则[idata]会被解释为以ds为段地址,idata为偏移量的
内存单元
,但是后者的汇编程序中,会被debug解释为idata本身,是一个立即数
。 - 在masm中,如何显式指定内存单元地址,而不被当做立即数?
- 可以把idata放到一个
寄存器
中,例如bx中,然后再通过[bx]
访问。则masm就默认是以ds为段地址,以bx为偏移量的内存单元了。 - 可以显式地写成
ds:[idata]
的形式,则masm就默认是以ds为段地址,以bx为偏移量的内存单元了。 - 当然,如果上述两者结合,即通过
ds:[bx]
的方式显然也是可以的。 - 总之,不能直接写
[idata]
。
- 可以把idata放到一个
每次循环时,采用相同方式改变要访问的内存单元的地址(使用inc 指令) #
- 例如,可以使用变量,例如bx寄存器来代表偏移量。
- 这样,每次循环体的末尾使用
inc bx
即可。这样每次bx都会增1.
使用中间寄存器 #
- 考虑将一个字节类型数据一直累加。每次累加新的字节数据,它们分别从连续的字节型地址单元中读出。
- 存在问题:如果将字节型寄存器作为累加寄存器,那么
有可能溢出
。但是如果将字型寄存器作为累加寄存器,那么字节型数据不能给字型数据之间做运算,因为类型不匹配
。 - 解决上述问题的方法就是添加一个中间寄存器,例如
dx
。这样,每次把从内存读取到的数据放到al
中,然后把ah
确保清零,那么字型寄存器ax
的值就是读出的字节型数据的值了。之后,执行ADD dx,ax
,即可完成运算,且dx
中存放的结果就不可能是溢出的。
段前缀 #
- 你可以
任意显式地指定
一个段寄存器来作为你要访问的内存单元地址的段地址。 - 例如,你用
cs:[idata]
来访问某个内存单元都是没问题的。只是区别是:我们不使用ds
作为段地址了,而是非常神奇地指定cs
。 - 好处:如果需要同时遍历两个数组,那么处理预先设置
ds
作为其中一个数组的起始地址外,还可以设置例如es
作为另一个数组的起始地址,并显式指出。这样,即便两个数组所在的内存空间相差64kB以上,仍然可以不需要每次都通过修改ds
的值来同时遍历两个数组。
尝试破坏操作系统 #
- 在DOS下, 由于所有的地址空间和硬件都不能被DOS严格地管理,所以把手伸进别人的口袋里是轻而易举的。
- 但是在Unix、Windows等下,由于在有CPU保护下的操作系统能够完全、严格地管理所有的地址空间和硬件,所以把手伸进别人的口袋里是不可能的。也就更不可能去修改OS的地址空间了。
end的新作用 #
- 如果在end后,不加东西,那就是通知编译器程序结束了。但是如果end后跟着一个标号,那么就告诉编译器,程序从这个地址才正式开始,即程序的入口是这个地址,你把CS:IP指向这个地址就可以正确运行了。
- 编译器知道了这一点后,会把该程序入口放在可执行文件开头的描述信息中。OS读取此描述信息,就能根据此信息正确地拿到程序入口的地址,从而设置CS:IP的值,以使得程序正确执行。
dw指令 #
- 如果在代码段刚开始,把
dw
作为第一个指令,那就相当于在代码段的开头若干字定义了若干字的数据,其中,多个数据之间可以用逗号间隔。 - 如果要直接访问它们,那么就直接
CS:0h
,CS:2h
,CS:4h
以此类推了。需要注意的是,汇编指令不允许字母开头的地址出现,因此需要写成类似于CS:0fh
这样的地址。 dw
指令的好处- 类比C++中的变量声明。我们想要定义一些数据,存到内存中,便于程序运行中访问,但是我们除非等到OS给我们分配地址,否则我们也不知道该存在哪里。同时,有时为了数组,我们需要存放它们到连续的单元。
dw
定义字长度的数据。可以用它实现数据的预先定义,且如果连续定义,用逗号间隔,那么实际运行时,它们也是连续出现在内存空间中的。dw
的位置非常重要:因为dw也是一条机器指令,但是机器指令实际上就是顺序存放在内存空间中的。dw
的作用实际上就是:**汇编到他了,那就不编译机器指令了,而是直接把它后面的数据放到这条机器指令对应的内存单元中。**因此,如果上述例子中,不是在代码段的一开始使用dw
,而是在中间使用,那可就不好找了,而且如果正常顺序执行,那么执行到这些数据就会错误地执行这些数据代表的机器指令。要知道,机器只是根据CS:IP
判断当前是指令还是数据的!