1.第一个程序
1.1 用汇编语言编写的源程序
4.1-4.2
在汇编语言源程序中,包含两种指令,一种是汇编指令,一种是伪指令。
汇编指令是有对应的机器码的指令,可以被编译为机器指令,最终为 CPU所执行。
伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作。
assume cs:codesg ;假定段寄存器cs与段codesg关联
;定义段codesg,以segment开始,以ends结束
codesg segment
mov ax,0123H
mov bx,0456H
add ax, bx
add ax,ax
;下面这两句表示程序返回,将CPU交给另一个程序
;程序结束运行后,将CPU的控制权交还给使它得以运行的程序(常为DOS系统)
mov ax, 4c00H
int 21H
codesg ends ;段结束
;表示程序结束
end
程序中可能出现的错误:
语法错误:程序在编译时被编译器发现的错误;
逻辑错误:程序在编译时不能表现出来的、在运行时发生的错误;
1.2 由源程序到程序执行
4.3-4.8
masm 1; ;编译
link 1; ;连接
1 ;执行
操作系统是由多个功能模块组成的庞大、复杂的软件系统。任何通用的操作系统,都要提供一个称为shell(外壳)的程序,用户(操作人员)使用这个程序来操作计算机系统进行工作。
DOS中有一个程序command.com,这个程序在 DOS中称为命令解释器,也就是DOS系统的shell。
如果用户要执行一个程序,则输入该程序的可执行文件的名称,command首先根据文件名找到可执行文件,然后将这个可执行文件中的程序加载入内存,设置CS:IP 指向程序的入口。此后,command暂停运行,CPU运行程序。程序运行结束后,返回到 command中,command再次显示由当前盘符和当前路径组成的提示符,等待用户的输入。
1.3 用Debug跟踪程序的执行
4.9
debug 1.exe ;command先调用debug,debug再调用1.exe
继续命令P(Proceed):类似T命令,逐条执行指令、显示结果。但遇子程序、中断等时,直接执行,然后显示结果。
p ;p可以一次性执行完循环
运行命令G(Go)∶从指定地址处开始运行程序直到遇到断点或者程序正常结束。
g
g 偏移地址 ;从CS:IP执行至CS:偏移地址 处
(1)程序加载后,ds中存放着程序所在内存区的段地址,这个内存区的偏移地址为0,则程序所在的内存区的地址为ds:0;
(2)这个内存区的前256个字节中存放的是 PSP,DOS用来和程序进行通信。从256字节处向后的空间存放的是程序。
所以,从 ds 中可以得到PSP的段地址SA,PSP的偏移地址为0,则物理地址为SA×16+0。
CS:IP=SA+10H:0
2.[BX]和loop指令
2.1 […]的规定和(…)的约定
第五章序言部分+5.1
[…]:(汇编语法规定)表示一个内存单元
(…):(为学习方便做出的约定,非汇编语法)表示一个内存单元或寄存器中的内容
符号idata表示常量
2.2 Loop指令
5.2
mov cx,idata ;idata为循环次数
s: add ax,ax ;要循环执行的代码
loop s
CPU 执行loop s 的时候,要进行两步操作:
1.(cx)=(cx)-1;
2.判断 cx 中的值,不为0则转至标号s所标识的地址处执行(这里的指令是add ax,ax),如果为零则执行下一条指令(下一条指令是mov ax,4c00h)。
2.3 Loop指令使用再例
5.3
在汇编源程序中,数字不能以字母开头,如A000h应写为0A000h。
p:一次性执行完循环
g 偏移地址:将程序从CS:IP执行至CS:偏移地址
2.4 段前缀的使用
5.4-5.8
在Debug中将[idata]解释为一个内存单元;
masm编译器将源程序中的[idata]解释为idata。
在汇编源程序中,可以用ds:[idata](即显式地加上段地址)的方式访问内存。
inc [bx] ;bx+=1
“ds:”,“cs:”,“ss:”,“es:”称为段前缀。
在一般的PC机中,DOS方式下,DOS和其他合法的程序一般都不会使用0:200-0:2ff (00200h-002ffh)的256个字节的空间。所以,我们使用这段空间是安全的。不过为了谨慎起见,在进入DOS后,我们可以先用Debug 查看一下,如果0:200-0:2ff单元的内容都是0的话,则证明DOS和其他合法的程序没有使用这里。
随便的向任意地址的内存单元写入数据是很危险的。
3.包含多个段的程序
3.1 在代码段中使用数据
6.1
可以将数据、代码、栈放入同一个段,也可以放入不同段。
assume cs:code
code segment
:
数据
:
start:
:
代码
:
code ends
end start
start指明程序的入口。程序载入CPU时CS:IP指向start后的指令。
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
“dw”的含义是定义字型数据。dw即“define word”。在这里,使用dw定义了8个字型数据(数据之间以逗号分隔),它们所占的内存空间的大小为16个字节。
3.2 在代码段中使用栈
6.2
可以在程序中通过定义数据来取得一段空间,然后将这段空间当作栈空间来用。
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;定义了16个字型数据,开辟出了32个字节的空间
3.3 将数据、代码、栈放入不同段
6.3
assume cs:code,ds:data,ss:stack
data segment
dw 0h,1h,2h,3h,4h,5h,6h,7h
data ends
stack segment
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,20h ;设置栈顶ss:sp指向stack:20
mov ax,data
mov ds,ax ;ds指向data段
mov bx,0 ;ds:bx指向data段中的第一个单元
mov cx,8
s: push [bx]
add bx,2
loop s ;入栈
mov bx,0
mov cx,8
s0: pop [bx]
add bx,2
loop s0 ;出栈
mov ax,4c00h
int 21h
code ends
end start
程序中对段名的引用,如指令“mov ds,data”中的“data”,将被编译器处理为一个表示段地址的数值。数值是不能直接送入段寄存器的。