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
2. 汇编程序: 包含汇编指令和伪指令的文本
-
伪指令: 没有对应的机器码的指令, 最终不被cpu 所执行, 第1, 2, 9, 10 行代码
- 伪指令是由编译器来执行的指令, 编译器根据伪指令来进行相关的编译工作
汇编指令, 对应有机器码的指令, 可以被编译为机器指令, 最终被cpu 执行, 3~8 行
程序返回: 程序运行结束后, 将cpu 的控制权交还给使它得以运行的程序, 常为dos 系统
3. 三种伪指令
- 段定义:
- 一个汇编程序是由多个段组成的, 这些段被用来存放代码, 数据或当做栈空间来使用
- 一个有意义的汇编程序中至少有一个段, 这个段用来存放代码
- 定义程序中的段: 每个段都需要有段名,
segment
段开始,end
段结束
- end: 汇编程序的结束标记, 若程序结尾处不是end, 编译器在编译程序时, 无法知道程序在何处结束
- assume: 含义是假设某一段寄存器和程序中的某一个用segment...ends 定义的段相关联. assume cs:codesg 指cs 寄存器与codesg 关联, 将定义的codesg 当做程序的代码段使用
源程序经编译连接后变为机器码
适合编写大程序, ;注释符号
为注释
4. 编写程序的步骤
- 定义一个段
- 实现处理任务
- 支出程序在何处结束
- 段与寄存器关联
- 加上程序返回的代码
assume cs:abc
abc segment
mov ax,2
add ax,ax
add ax,ax
mov ax,4c00h
int 21h
abc ends
end
程序中可能出现的错误
-
语法错误
在编译时被编译器发现的错误
-
逻辑错误
在编译时不能表现出来, 在运行时发生的错误
5. 源程序到程序运行
assume cs:codesg
codesg segment
mov ax,0123H
mov bx,0456H
add ax,ax
add ax,ax
mov ax,4c00h
int 21h
codesg ends
end
- 目标文件(*.obj) 是我们对一个源程序进行编译得到的最终结果
- 列表文件(*.lst) 是编译器将源程序编译为目标文件过程中产生的中间结果
- 交叉引用文件(*.crf) 同列表文件一样, 是编译器将源程序编译为目标文件过程中产生的中间结果
- 对源程序的编译结束, 编译器输出的最后两行告诉我们这个源程序没有警告错误和必须要改正的错误
- 命令后加上
;
可以简化流程
- 可执行文件(.exe) 是我们对一个重新进行连接得到的最终结果
- 印象文件(.map) 是连接程序将目标文件连接为可执行文件过程中产生的中间结果
- 库文件(.lib) 里包含了一些可以调用的子程序, 如果我们的程序中调用了某一个库文件中的子程序, 就需要在连接的时候, 将这个库文件和我们的目标文件连接到一起, 生成可执行的文件
- no stack segment, 一个"没有栈段" 的警告错误, 可以不用理会
执行过程, 源文件.asm -> 目标文件.obj -> 可执行文件.exe
使用debug 装载程序
- ds 中存放程序所在区的段地址, 这个内存的偏移地址为0, 则乘车所在的内存区的地址为
ds:0
- 这个内存区的前256 字节存PSP, dos 用来和程序进行通信
- 从256 字节后的空间存放的是程序, cs 的值为ds+10h
- 程序加载后, cx 中存放代码长度
6. [...] 的规定与(...) 的约定
- [...] 汇编语法的规定, 表示一个内存单元
指令 | 段地址 | 偏移地址 | 操作单位 |
---|---|---|---|
mov ax,[0] | DS 中 | 在[0] 中 | 字 |
mov al,[0] | DS 中 | 在[0] 中 | 字节 |
mov ax,[bx] | DS 中 | 在[bx] 中 | 字 |
mov al,[bx] | DS 中 | 在[bx] 中 | 字节 |
- (...) 方便学习做出的约定, 表示一个内存单元或寄存器中的内容
描述对象 | 描述方法 | 描述对象 | 描述方法 |
---|---|---|---|
ax中的内容为0010h | (ax)=0010h | 2000:1000处的内容为0010h | (21000h)=0010h |
mov ax,[2]的功能 | (ax)=((ds)*16+2) | mov [2],ax的功能 | ((ds)*16+2)=(ax) |
add ax,2 的功能 | (ax)=(ax)+2 | add ax,bx 的功能 | (ax)=(ax)+(bx) |
push ax 的功能 | (sp)=(sp)-2; ((ss)*16 + (sp))=(ax) | pop ax 的功能 | (ax)=((ss*16)+(sp)); (sp)=(sp)+2 |
符号idata 表示常量
mov ax,[idata] 表示, mov ax,[1]
mov bx,idata 表示, mov bx,2
7. Loop 指令
功能: 实现循环, 计数型循环
指令格式loop 标号
cpu 执行loop 指令时要进行的操作
- (cx)=(cx)-1
- 判断cx 中的值, 不为0 则跳转至标号处执行, 为0 则向下执行
注意点:
- cx 存放循环次数
- 定义一个标号, 在标号和loop 指令中间写循环执行的代码段
实现
; loop 指令程序
assume cs:code
code segment
mov ax,2
mov cx,3
s: add ax,ax
loop s
mov ax,4c00h
int 21h
code ends
end
8. 段前缀的使用
现象
assume cs:code
code segment
mov ax,2000h
mov ds,ax
mov al,[0]
mov bl,[1]
mov cl,[2]
mov dl,[3]
mov ax,4c00h
int 21h
code ends
end
对策
在[idata] 前显示写上段寄存器
mov al,ds:[bx]
mov al,ds:[0]
这些出现在访问内存单元的指令中, 用于显示的指明内存单元段地址的"ds:", "cs:", "ss:", "es", 在汇编语言中称为段前缀
; 使用附加段寄存器
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,12
s: mov dl,[bx]
mov es:[bx],dl
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
但是以上代码有问题, 是危险的
不可以直接写地址, 这段地址中可能存放其他代码或者数据
应该为:
- 在程序的段中存放数据, 运行时由操作系统分配空间
- 段的类别, 数据段, 代码段, 栈段
- 各种段中均可以有数据
- 可以在单个段中安置, 也可以将数据, 代码, 栈放入不同的段中
assume cs:code
code segment
dw 0123H,0456h,0789h,0abch
mov bx,0
mov ax,0
mov cx,4
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end
执行debug 查看
代码混乱, ip 是从0000 开始执行, 但是, 段中开始存放的为数据, 因此需要从0008 开始
改进代码
assume cs:code
code segment
dw 0123H,0456h,0789h,0abch
start: mov bx,0
mov ax,0
mov cx,4
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
9. 代码中使用栈
方案一
问题, 将定义的数据逆序存放
思路:
- 定义的数据存在cs:0~cs:f 单元总, 共8 个字单元
- 一次将这8 个字单元中的数据入栈, 然后再一次出栈到8 个字单元中, 从而实现数据的逆序存放
- 栈需要的内存空间, 在程序中通过定义空数据来取得
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
start: mov ax,cs
mov ss,ax
mov sp,30h
mov bx,0 ; 入栈
mov cx,8
s: push cs:[bx]
add bx,2
loop s
mov bx,0 ; 出栈
mov cx,8
s0: pop cs:[bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
code ends
end start
这种方案数据段, 栈, 代码都在同一个段中
- 程序显得混乱, 编程和阅读时都要注意何处是数据, 何处是栈, 何处是代码
- 只应用于处理数据很少, 用到的栈空间小, 没多少代码的情况
我们应该将数据, 栈, 代码放在不同段中
方案二
修改为:
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
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
mov ax,data
mov ds,ax
mov bx,0
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