汇编16位部分学习总结!

来源:互联网 发布:淘宝卖家买家秀怎么弄 编辑:程序博客网 时间:2024/04/28 08:36

    今天把汇编16位部分学完了,随着学习的深入,似乎找到了我学习汇编想知道的答案,但还并不完整.

    基础的指令,DOS调用,BIOS中断就不多说了,我的BLOG中有一篇响应的中断一览表,大家有需要可以去参考.

    PSP 驻留程序也不多说了,高级汇编语言技术也并不难接受,只要大家有一点高级语言的基础,看明白还是不难的,我想说说模块化程序设计部分的段的定义,简单的说一下供C调用的过程(汇编编写)!

    段的定义分为完整定义和简化定义,完整定义通过你定义段时指定的参数来实现

    段名 SEGMENT [对齐类型] [组合类型] [类别] … 段名 ENDS

程序中的段名可以是唯一的,也可以与其它段同名。在同一模块中,如果有二个段同名,则后者被认为是前段的后续,这样,它们就属同一段。

 

段对齐类型PARA是一个适用于所有段类型的对齐类型,它也是缺省的对齐类型。对齐类型BYTEWORD通常用于数据段的定位,对齐类型DWORD通常用于80386及其以后CPU代码段的定位。

表6.1 段对齐类型与段起始地址之间的对应关系

对齐类型 起始地址(二进制) 功能说明 最多的空闲字节数 BYTE xxxx xxxx xxxx xxxx xxxx

下一个字节地址

0 WORD xxxx xxxx xxxx xxxx xxx0

下一个字地址

1 DWORD xxxx xxxx xxxx xxxx xx00

下一个双字地址

3 PARA xxxx xxxx xxxx xxxx 0000

下一个节地址

15 PAGE xxxx xxxx xxxx 0000 0000

下一个页地址

127

 

 

 

组合类型(COMBINE)

组合类型是告诉连接程序如何把不同模块中段名相同的段合并在一起。具体的组合类型如下:

  NONE

表示当前段在逻辑上独立于其它模块,并有其自己的基地址。NONE是缺省的组合类型。

PUBLIC 表示当前段与其它模块中同段名的PUBLIC类型段组合成一个段。组合的先后次序取决于LINK程序中目标模块排列的次序。在组合时,后续段的起始地址要按其对齐类型进行定位,所以,同名段之间可能有间隔。 COMMON 表示当前段与其它模块中同名段重叠,也就是说,它们的起始地址相同。最终段的长度是同名段的最大长度。由于段覆盖,所以,前一同名段中的初始化数据被后续段的初始数据覆盖掉。 STACK 组合类型STACK表示当前段是堆栈栈,其组合情况与PUBLIC相同。 AT 数值表达式 该数值表达式是当前段所指定的绝对起始地址的段地址。

 

类别(CLASS)

类别是一个由程序员指定的用单引号括起来的字符串。如果一个段没有给出类别,那么,这个段的类别就为空。类别是用于段的分类,连接程序利用该类别来调整同名、同类别的段,并使它们相邻。典型的类别是"Data"和"Code"。如果指定某段的类别是"Code",那么,该段最好是代码段,这样,有的调试程序(如:CodeView)就可以顺序工作。

例如:

  DATA1 SEGMENT  WORD  PUBLIC  "Data" … DATA1 ENDS

上述段定义说明了该段的起始地址是下一个字地址、组合类型为PUBLIC、段类别是"Data"。

 

 

段组(GROUP)

段组伪指令GROUP是用于把源程序模块中若干个段结合成一个组,并对该段组定义一个段组名。段组伪指令的格式如下:

段组名  GROUP  段名[, 段名, ……]

其中:段名之间要用逗号间隔,段名也可以用表达式“SEG 变量”或“SEG 标号”。

下面举例说明段组伪指令的使用方法和作用。

例6.12 段组的作用

方法1:用一个段寄存器对应二个数据段

  DATA1 SEGMENT ;第一个数据段 b1 DB 10h DATA1 ENDS DATA2 SEGMENT ;第二个数据段 b2 DB 23h DATA2 ENDS CODE1 SEGMENT ASSUME CS:CODE1, DS:DATA1 ;(1) START: MOV AX, DATA1 MOV DS, AX  ;(2)把数据段DATA1的段值赋给段寄存器DS … MOV BL, b1 ;(3)引用DS来访问DATA1中的变量b1 … ASSUME DS:DATA2 ;(4) MOV AX, DATA2 MOV DS, AX ;(5)把数据段DATA2的段值赋给段寄存器DS … MOV AL, b2 ;(6)引用DS来访问DATA2中的变量b2 … CODE1 ENDS END START

在上例中,语句(1)说明DS与DATA1建立联系,语句(2)对DS赋值,语句(3)用DS来访问DATA1段的变量名。语句(4)说明DS与DATA2建立联系,语句(5)对DS赋值,语句(6)用DS来访问DATA2段的变量名。

在该例子中,因为只使用一个段寄存器DS来对应二个数据段,所以,需要切换DS的对应关系(如:语句(4))。但我们也可以用段寄存器DS和ES来分别对应段DATA1和DATA2,这样,方法1就可变成方法2。

方法2:用二个段寄存器对应二个数据段

  DATA1 SEGMENT b1 DB 10h DATA1 ENDS DATA2 SEGMENT b2 DB 23h DATA2 ENDS CODE1 SEGMENT ASSUME CS:CODE1, DS:DATA1, ES:DATA2 START: MOV AX, DATA1 MOV DS, AX  ;把数据段DATA1的段值赋给段寄存器DS MOV AX, DATA2 MOV ES, AX ;把数据段DATA2的段值赋给段寄存器ES … MOV BL, b1 ;引用DS来访问DATA1中的变量b1 … MOV AL, b2 ;引用ES来访问DATA2中的变量b2 … CODE1 ENDS END START

我们还可以用段组来简化段寄存器的使用,把段DATA1和DATA2组成一个数据段。所以,把方法2再改写成方法3的形式。

方法3:用一个段组组成二个数据段

  GSEG GROUP DATA1, DATA2 ;把段DATA1和DATA2定义成一个段组 DATA1 SEGMENT   b1 DB 10h DATA1 ENDS DATA2 SEGMENT b2 DB 23h DATA2 ENDS CODE1 SEGMENT ASSUME CS:CODE1, DS:GSEG START: MOV AX, GSEG MOV DS, AX  ;把段组GSEG的段值赋给段寄存器DS … MOV BL, b1 ;引用DS来访问DATA1中的变量b1 … MOV AL, b2 ;引用DS来访问DATA2中的变量b2 … CODE1 ENDS END START

定义段组后,段组内各段所定义的标号和变量,除了与定义它们的段起始点相关外,还与段组的起始点相关。规定如下:

如果在ASSUME伪指令中说明段组与段寄存器相对应,那么,有关标号或变量的偏移量就相对于段组起点计算;

如果在ASSUME伪指令中说明段组内的某各段与段寄存器相对应,那么,有关标号或变量的偏移量就相对于该段的起点。

 

简化的段定义

在使用简化的段定义方式之前,必须使用存储模式说明伪指令来描述源程序所采用的存储模式。该伪指令说程序所使用的存储模式,汇编程序将用该存储模式生成相应的ASSUME和GROUP语句,同时也为其它的简化段创建等价的预定义。

程序存储模式说明伪指令的格式如下:

.MODEL  存储模式[,语言类型] [,操作系统类型] [,堆栈类型]

隐含的动作还有

DEGROUP GROUP DATA,CONST,BSS,STACK

ASSUME CS:_TEXT,DS:DGROUP,SS:DGROUP   

这样所有除代码的段都在DEGROUP段组里,同过同一寄存器来实现存取

、SMALL

所有的数据变量必须在一个数据段之内,所有的代码也必须在一个代码段之内。在这种模型下,数据段寄存器的内容保持不变,所有转移也都是段内转移。

该存储类型是独立汇编语言源程序常用的存储模型。

、MEDIUM

所有的数据变量必须在一个数据段之内,但代码段可以有多个。在这种模型下,数据段寄存器的内容保持不变,转移可以是段间转移。

、COMPACT

数据段可以有多个,但代码段只能有一。

、LARGE

数据段和代码段都可以有多个,但一个数组的字节数不能超过64KB。

、HUGE

数据段和代码段都可以有多个,一个数组的字节数也可以超过64KB。

 

简化段定义伪指令

简化段定义伪指令在说明一个新段即将开始的同时,也说明了上一个段的结束。在本段定义结束时,也不必用伪指令“ENDS”来标识。

具体的伪指令说明形式及其功能描述如下:

1、代码段定义

.CODE

作用:说明其下面的内容是代码段中内容。

2、堆栈段定义

.STACK  [堆栈字节数]

其中,“堆栈字节数”可以不写,其缺省值为1024B。

3、数据段定义

.DATA / .DATA? / .CONST

作用:说明其下面的内容是数据段中的变量定义。

在一个源程序中,可以有多个伪指令.DATA定义的数据段,这就好象在源程序中定义多个同段名的数据段一样。

伪指令.DATA?说明下面是一个未初始化数据段的开始,伪指令.CONST说明下面是一个常数数据段的开始。这二条伪指令很少使用,除非在与高级语言编写的程序相结合时,为了遵守高级语言的某些约定,而需要特殊说明时才使用。

汇编程序在处理简化的堆栈段和数据段定义时,它会自动地把伪指令.STACK、.DATA、.DATA?和.CONST所定义的段组合成一个段组。如果想定义一个独立的、不与其它段组合在一起的数据段的话,那么,就可选用下面的数据段定义方式。

4、远程数据段定义

.FARDATA  [段名] / .FARDATA?  [段名]

其中:“段名”是可选项,如果不指定的话,则该段名就取其缺省段名。

作用:说明一个独立的数据段。

伪指令.FARDATA?说明下面是一个未初始化的、独立数据段的开始。通常情况下,很少使用该伪指令。

 

 

简化段段名的引用

当使用简化的段定义时,一般情况下,程序员可以不知道这些段的段名、段地址堆齐类型和组合类型等。但当把简化定义的段和标准定义的段混合使用时,就需要知道简化定义段的基本属性。表6.3是在小模式下段的基本属性对应表。

表6.3 小模式下简化段定义的缺省属性表

伪指令

缺省段名

对齐类型

组合类型

类别

段组名

.CODE

_TEXT

WORD

PUBLIC

'CODE'

 

.FARDATA

FAR_DATA

PARA

NONE

'FAR_DATA'

 

.FARDATA?

FAR_BSS

PARA

NONE

'FAR_BSS'

 

.STACK

STACK

PARA

STACK

'STACK'

DGROUP

.DATA

DATA

WORD

PUBLIC

'DATA'

DGROUP

.DATA?

BSS

WORD

PUBLIC

'BSS'

DGROUP

.CONST

CONST

WORD

PUBLIC

'CONST'

DGROUP

在其它存储模型下,由伪指令".CODE"说明的代码段段名在"_TEXT"之前还要加上其模块名(源程序名)。假设,某模块名为ABC,则其缺省的代码段段名就为ABC_TEXT。因此,在这种情况下,程序的模块名或源程序名不要以数字开头。

 

 

供C调用的过程:主要大家记住几个要点,C语言把函数和外部变量和静态变量在生成的汇编代码中以_开头,内存模式要匹配,通过堆栈,BP压栈,BP=SP,返回要看C的汇编,一般为累加AX,记得保护积存器

原创粉丝点击