0%

第三章_汇编语言程序格式_1

完整段定义的伪操作

8086/8088在管理内存时,需要按照逻辑段进行划分,不同的逻辑段可以用来存放不同目的的数据。在程序中使用四个段寄存器CS,DS,ES和SS来访问它们。

段定义伪指令

一般格式:

1
2
3
4
5
段名   SEGMENT   [定位类型] [组合类型] [‘类别名']
…...
... ... 本段语句序列
… ...
段名 END

定位类型

定位类型用于决定段的起始边界,即第一个可存放数据的位置(不是段基址)

PAGE

表示该段从一个页面的边界开始

由于一个页面为256个字节,并且页面编号从0开始,因此,PAGE定位类型的段起始地址的最后8位二进制数一定为0,即以00H结尾的地址。

PARA

表示该段从一个小节的边界开始

如果用户未选定位类型,则缺省为PARA。

WORD

表示该段从一个偶数字节地址开始,即段起始单元地址的最后一位二进制数一定是0。

BYTE

表示该段起始单元地址可以是任一地址值。

注意:定位类型为PAGE和PARA时,段起始地址与段基址相同。定位类型为WORD和BYTE时,段起始地址与段基址可能不同。

组合类型

用来指定段与段之间的连接关系和定位

NONE

若未指定组合类型,表示本段与其它段无连接关系。在装入内存时,本段有自己的物理段,因此有自己的段基址。

PUBLIC

在满足定位类型的前提下,将不同模块的同名段邻接在一起,形成一个新的逻辑段,共用一个段基址。段内的所有偏移量调整为相对于新逻辑段段基址的偏移量

COMMON

产生一个覆盖段。在多个模块连接时,把该段与其它也用COMMON说明的同名段置成相同的段基址,这样就达到了共享同一存储区。共享存储区的长度由同名段中最大的段确定。

STACK

把所有同名段连接成一个连续段,且系统自动对SS段寄存器初始化为该连续段的段基址。并初始化堆栈指针SP。

用户程序中应至少有一个段用STACK说明,否则需要用户程序自己初始化SS和SP。

AT表达式

表示本段可定位在表达式所指示的小节边界上。表达式的值也就是段基值。

MEMORY

表示本段在存储器中应定位在所有其它段这之后的最高地址上。如果有多个用MEMORY说明的段,则只处理第一个用MEMORY说明的段。其余的被视为COMMON

类别名

类别名为某一个段或几个相同类型段设定的类型名称。系统在进行连接处理时,把类别名相同的段存放在相邻的存储区,但段的划分与使用仍按原来的设定。

在定义一个段时,段名是必须有的项,而定位类型、组合类型和类别名三个参数是可选项。各个参数之间用空格分隔。各参数之间的顺序不能改变。


举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
STACK1   SEGMENT PARA STACK 'STACK0'
.....
STACK1 ENDS

DATA1 SEGMENT PARA 'DATA'
......
DATA1 ENDS

STACK2 SEGMENT PARA 'STACK0'
......
STACK2 ENDS

CODE SEGMENT PARA MEMORY
ASSUME CS:CODE, DS:DATA1, SS:STACK1
MAIN:
......
......
CODE ENDS

END MAIN

DATA2 SEGMENT BYTE 'DATA'
......
DATA2 ENDS

视频讲解


段寻址伪指令

段寻址伪指令ASSUME的作用是告诉汇编程序,在处理源程序时,定义的段与哪个寄存器关联。并不设置各个段寄存器的具体内容,段寄存器的值是在程序运行时设定的。

问题:这个怎么在emu8086中看?

注:可以使用关键字NOTHING将前面的设置删除。

ASSUME ES:NOTHING ;删除前面对ES与某个定义段的关联 ASSUME NOTHING ;删除全部4个段寄存器的设置

段寄存器的装入

DS和ES的装入

没有声明就无法装入

为了改正上述程序中的错误,可以在变量DBYTE2前加一个段前缀说明即可。即:
MOV  ES:DBYTE2[2],  AL

视频讲解

初步小结:貌似既需要用ASSMUE指定段分配到哪个段寄存器里面,也要将段的首地址分配到段寄存器里面?

SS的装入

视频讲解

法一:

1. 组合类型使用STACK参数

2. ASSUME语句与SS关联

3. 栈顶指针SP初始化为最大值(根据声明的堆栈段大小决定)


举例:


法二

类似前面数据段装入,需要额外定义一个变量top

堆栈操作都是按字操作

当前位置计数器$与定位伪指令ORG(Origin)

当前位置计数器$

$表示当前指针地址

定位伪指令ORG

格式

ORG 数值表达式

作用

将数值表达式的值赋给当前位置计数器。ORG相当于移动当前位置指针赋给它的值必须是正值


举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DATA1    SEGMENT
ORG 30H
DB1 DB 12H,34H ; DB1在DATA1段内的偏移量为30H
ORG $+20H ; 保留20H个字节单元,其后再存放'ABCD....
STRING DB ‘ABCDEFGHI’
COUT EQU $-STRING ; 计算STRING的长度
DB2 DW $ ; 取$的偏移量,类似变量的用法
; DB3 DB $ ; 此语句错误!
DATA1 ENDS

CODE SEGMENT
ASSUME CS:CODE
ORG 10H
START:
MOV AX, DATA
MOV DS, AX
; ...
CODE ENDS

END START

视频讲解


从程序返回操作系统的方法

使用DOS系统功能调用实现返回

1
2
MOV  AH,4CH
INT 21H

程序基本结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
【例3-11】求字存储单元中两个数之差,结果存入下一个相邻的字单元中。
NAME EXAMPLE
DATA SEGMENT
BUF DW 3483H,4596H
RES DW ?
DATA ENDS
STACK SEGMENT STACK ‘STACK’
STA DW 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE.DS:DATA
START:MOV AX,DATA
MOV DS,AX
MOV AX,BUF
SUB AX,BUF+2
MOV RES,AX
MOV AH,4CH
INT 21H
CODE ENDS
END START

视频讲解

一个段的名字就是一个段的标号,就是这个段的首地址。是个常亮

取变量,变量名字出现在指令中,表示取变量中内容

DOS 功能子程序调用

带显示的键盘输入(1号功能)

视频讲解

将字符的ASCII码送入AL寄存器,并在屏幕上显示该字符

1
2
MOV  AH,01H
INT 21H

不带显示的键盘输入(8号功能)

除了不显示字符其他和1号功能一样

1
2
MOV  AH,8
INT 21H

字符显示(2号功能)

打印单个字符

1
2
3
MOV DL, 'A'
MOV AH, 02H
INT 21H

打印单个字符还好,什么叫数字转ASCII码值?还有2位数需要转字符串循环输出

数字转ASCII码方法:数字+‘0’即可

字符串输入(0AH号功能)

缓冲区第一个字节是可输入的最大字符数+1

第二个字节是系统在调用该功能时,自动填入的本次调用时实际输入的字符个数,实际应用时初始化时常设置为0

从第三个字节开始存放输入字符的ASCII码,当用户输入回车键时,结束输入,并将回车键的ASCII码(0DH)作为最后一个字符送入缓冲区。但它不计入实际输入字符个数

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
DATA SEGMENT
CHAR_BUF DB 31H, DB 0, DB 31H DUP('$')
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX

; 显示字符串
MOV DX, OFFSET CHAR_BUF
MOV AH, 0AH
INT 21H

; 退出程序
MOV AH, 4CH
INT 21H
CODE ENDS

END START

视频讲解

字符串显示(9号功能)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DATA SEGMENT
CHAR_BUF DB 'This is a test', 0AH, 0DH, '$'
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX


MOV DX, OFFSET CHAR_BUF
MOV AH, 9H
INT 21H
; 退出程序
MOV AH, 4CH ; 功能号:退出程序
INT 21H ; 调用 DOS 中断 21H
CODE ENDS

END START

解释:

  • 0AH表示换行,将光标移到下一行开头。
  • 0DH表示回车,将光标移到当前行开头。