1. 以第一个汇编源程序为例说明:
assume cs:codesg
codesg segment
mov ax, 0123H
mov bx, 0456H
add ax, bx
add ax, ax
mov ax, 4C00H
int 21H
codesg ends
end
1) 汇编指令和伪指令的区别:首先这里要讲两个概念,即汇编语言包含什么,其总共包含两个部分,一部分就是汇编指令,就是指那些和01机器码具有一一对应关系的指令,这种指令可以直接利用简单的对应关系直接翻译成相应的机器指令01码,还有一种是伪指令,这部分指令没有直接的01机器码相对应,无法经过一步就翻译成机器指令,这类指令往往具有一定复杂的功能,也就是汇编编译器专有的功能,比如定义变量,定义符号等,这类指令比普通的汇编指令复杂,可能一条伪指令是若干条(多条)汇编指令的复合,即可以理解为编译器的命令,例如上面代码中的assume伪指令等,还有end指令,这些都是伪指令,它们不像mov指令等直接由一条机器指令与之对应;
总的来说就是汇编指令是让机器识别的,而伪指令是让编译器识别的;
2) assume 段寄存器:用户定义的段名:将某个段寄存器和用户定义的段相关联,在这里就相当于mov cs, codesg所代表的地址了,这就完成了对cs寄存器的初始化;
!注意:这里并没有人为指定cs的值,那是因为为了保证安全由系统自动查找一段空闲的空间分配给当前程序,因此这个codesg是系统自动检索出来的值,在程序中codesg可以被当成一个符号地址使用,即可以把它理解成一个C语言的宏,宏的值就是一个地址;
3) XXX segment:表示一个段的定义的开始,XXX是该段的名字(即assume中定义的),至于这个段里面放什么东西完全由用户决定,在此程序中,该段明显存放的是程序代码,因此逻辑上是一个代码段,而XXX ends必须和XXX segment成对出现,表示XXX段的结束,ends是指end segment的意思,千万不要错写成end了!
4) end:表示整个汇编源程序结束,编译器碰到end时将会停止编译;
!!!注意:再次重申,cs并不是由用户初始化的,而是由编译器自动完成初始化的(即值是由编译器决定的,编译器会挑选一个空闲的段地址赋给cs),这完全是为了保护系统,因此用户不能对cs随便乱修改!
**只有cs能通过assume伪指令进行初始化(只有cs能被assume修改),如果同时定义了其他的段,比如assume ds:datasg, es:extrasg等都不会将datasg和extrasg的值赋给两个寄存器,assume只有对cs寄存器真正有效!一定要记住这点,因此在程序中要将extrasg和datasg赋给ds还必须通过ax等寄存器进行一遍中转才行,因此在assume中定义ds、ss、es等只是一种形式上或者说是逻辑上的一种行为,只是为了让程序的逻辑更加清晰而已!
***小结:assume语句最重要的作用就是对cs寄存器进行初始化,其余没有产生任何实际作用!
5) 程序返回:汇编语言里并没有像C语言那样的return语句,汇编程序的返回是通过中断实现的,通过中断去执行一个中断程序,在这里int 21H就是一个中断语句,表示产生一个内部中断(即在会变成程序中显示执行中断语句,还有一种是外部中断,即I/O设备像CPU请求中断,这种中断当前汇编程序无法预测),然后让系统提供某种中断服务,但是系统提供的中断服务有很多种,具体是那种由中断号决定,中断号要放在ax寄存器中,这里4C00H中断号代表一个终结当前程序的服务,因此在这里的最后两句话就是请求一个终结当前程序的中断服务,通过系统中断终结当前程序;
!注意:在源程序中忘记写程序返回语句并不会报错,但是会由于程序永远无法退出而产生运行时错误!
2. 编译链接源程序:
1) 编译和链接分步进行:
最终就形成了a.exe可执行文件;
所有工具:文本编辑器、masm、link都是在操作系统上运行的;
2) 也可以直接使用ml命令将编译和连接合并在一起执行,但不过生成的文件的名字都使用默认名(即源文件名);
3. DOS的命令解释器简介:
1) 命令解释器是DOS操作系统的一个模块,即DOS的shell;
2) 其全称是COMMAND.COM,用来作为人和操作系统交互的一个介质,分析用户输入的命令并执行;
3) 当用户执行一个命令或者一个程序时,先将CS:IP指向命令或者程序的代码段首地址(即发生了中断),然后将CPU的控制权交给命令或程序,待执行完成后,在将CPU控制权交还给命令解释器(程序返回);
4. 使用Debug命令调试汇编程序.exe:
1) 使用Debug命令将汇编程序打开并调试,加载顺序为:DOS系统加载Debug程序,在Debug程序加载test.exe程序
2) DOS加载程序的过程(以上图为例):
i. 首先CX中存放的是程序的长度,即多少个字节,这里是000FH个字节,即15个字节;
ii. 加载程序时操作系统会在内存中随机找一段空闲空间作为作为程序的加载区,并且规定该段空间的首地址必为10H的倍数,并且将该空间的段地址存入寄存器DS中,偏移地址存入DX中,即图中的DS:DX即为程序内存的首地址,这里是075A:0000
iii. 而所有程序都需要在开头处留256个字节空间的内容用于和DOS通信,而之后的空间才是真正的程序代码(即CS:IP的指向),也就是说开始时CS:IP - DS:DX = 100H,从图中可以但出来075A:0000 - 076A:0000 = 100H,而这段和DOS通信的区域就称为PSP(Program Segment Prefix即段前缀的意思),如图所示:
3) 使用T命令一直单步执行到到int 21H时停止使用T命令,要退出程序并回到Debug中必须使用P命令,否则(继续使用T)会不停往下执行后面为止的代码而无法退出当前程序回到Debug:
P即Proceed的缩写,是指继续,这里是指终结后继续运行加载它的程序:
!注意:可以直接使用U指令,查看CS:IP当前指向处的反汇编指令!!!