当前仓库属于暂停状态,部分功能使用受限,详情请查阅 仓库状态说明
1 Star 2 Fork 0

Kaz / prolearn
暂停

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
format.md 17.47 KB
一键复制 编辑 原始数据 按行查看 历史
Kaz 提交于 2021-01-03 21:21 . 汇编

一.汇编源程序格式

1.概述

  1. 编写一个汇编源程序,需要做以下几件事:
    • 编写数据段
    • 编写代码段,指定代码入口
    • 使用 ASSUME 指定各段与寄存器的关系
    • 将各段装入相应的寄存器
    • 编写程序主代码
    • 结束程序
    • 汇编结束,并指定程序执行的起点
; 数据段定义
DATAS SEGMENT
	TESTDATA  DB 1,2,3,4
	TESTDATA1 DB 5,6,7,8
DATAS ENDS

CODES SEGMENT
	      ASSUME CS:CODES,DS:DATAS
START:								; 程序开始	
	      MOV    AX,DATAS			; 装填寄存器
	      MOV    DS,AX            	

		  ; 程序代码

	      MOV    AH,4CH           	; 程序退出
	      INT    21H
CODES ENDS							; 代码段结束
END START							; 汇编结束,并指定程序执行的起点

2.数据分段

  1. 代码段:
    • 概念:代码段用来存放程序的指令序列
    • 段寄存器:$CS$
    • 寻址:$CS:IP$
  2. 堆栈段:
    • 概念:堆栈段确定堆栈所在的主存区域
    • 段寄存器:$SS$
    • 寻址:$SS:SP$
  3. 数据段:
    • 概念:数据段存放当前运行程序所用的数据
    • 段寄存器:$DS$
    • 寻址:$DS:EA$,$EA$ 为数据的偏移地址
  4. 附加段:
    • 概念:附加的数据段,也用于数据的保存
    • 段寄存器:$ES$
    • 寻址:$ES:EA$ ,$EA$ 为数据的偏移地址

3.表达式

表达式可以作为各指令的操作数。其值可以在汇编的时候确定。

  1. 标号/变量:存储的是地址,拥有段值、偏移量、类型三种属性

    • 标号、子程序名的类型可以是NEAR(近)和FAR(远),分别表示段内或段间
    • 变量名的类型可以是BYTE(字节)、WORD(字)和DWORD(双字)等
  2. 表达式:数字表达式 地址表达式

  3. 算术操作符: + 、- 、*、/、mod

  4. 逻辑和移位运算符:AND、OR、XOR、NOT、SHL(左移位)、SHR(右移位)

  5. 关系运算符:EQ(相等)、NE(不相等)、LT(小于)、LE(小于等于)、GT(大于)、GE(大于等于)

    • 真的结果为 0FFFFH
    • 假的结果为 0000H
  6. 数值回送运算符:

运算符 说明
SEG expression 分离出其后变量或标号所在段的段地址
OFFSET expression 分离出其后变量或标号所在段的偏移地址
TYPE expression 如果是变量,将返回该变量的类型对应字节数;
如果是标号,则返回代表标号类型的数值(NEAR=-1,FAR=-2)。
LENGTH expression 取出变量所含的数据存储单元个数。
对于DUP 定义的变量,返回重复的次数,否则返回1
SIZE expression 等于 LENGTH 变量 * TYPE 变量

示例

DATA	SEGMENT
   A	 DB ABCDEF, 5 DUP( 0 )
   B	 DW   10  DUP(12  DUP( 2 ) )
   C	 DB   320	DUP0
   D   DB   3  DUP( 5 ), 0,10  DUP( ? )
DATA	ENDS
MOV	AXLENGTH	A	; AX=1
MOV	BXLENGTH	B	; BX=10
MOV	CXLENGTH	C	; CX=1
MOV	DXLENGTH	D	; DX=3

  1. 属性操作符
    • PTR:type PTR expression 用于指定表达式的类型,type 有 byteword
    • 段操作符:段名:表达式 用于指定一个变量或标号的段地址
    • SHORT:用于指定转移地址的属性
    • THIS:类似PTR ,可以建立指定类型或指定距离的地址操作数,其段地址和偏移地址和下一个存储地址相同
    • HIGH、LOW、HIGHWORD、LOWWORD:用于分离高字节、低字节、高字、低字

4.类型

  1. 数据类型
    • 汇编的数据类型只按照其大小进行区分,不区分有无符号、字符和整数
数据类型 大小LENGTH 变量
BYTE 1
WORD 2
DWORD 3
FWORD 4
QWORD 8
TWORD 10
  1. 标号和子程序的类型
    • 标号 标号:,表示一行代码的起始地址
    • 标号和子程序的类型只区分要跳转的代码距离当前正在执行的代码的远近
数据类型 大小LENGTH 变量 说明
NEAR PTR -1 近地址类型
FAR PTR -2 远地址类型

二.伪操作

1.概述

伪操作是汇编程序对源程序进行汇编时处理的操作,完成处理器选择、存储模式定义、数据定义、存储器分配、指示程序开始结束等功能。

  • 处理器选择伪操作
  • 段定义伪操作
  • 存储模式伪操作
  • 程序开始和结束伪操作
  • 数据定义及存储器分配伪操作
  • 表达式赋值伪操作
  • 地址计数器与对准伪操作
  • 基数控制伪操作

2.处理器选择

指令 说明
.8086 (默认)选择8086指令系统
.286 选择80286指令系统
.286P 选择保护模式下的80286指令系统
.386 选择80386指令系统
.386P 选择保护模式下的80386指令系统
.486 选择80486指令系统
.486P 选择保护模式下的80486指令系统
.586 选择Pentium指令系统
.586P 选择保护模式下的Pentium指令系统

3.段定义

段名	segment	定位  组合  段字  '类别'
		...	;语句序列
段名	ends
  1. 定位:指定逻辑段在主存储器中的边界
说明
PARA (默认) 表示本段必须从能被16整除的地址处开始存放,即段起始地址最低四位必须是0
WORD 表示本段要从一个偶数地址处开始存放,即段起始地址的最低一位必须是0
BYTE 表示本段起始地址可以从任一地址处开始存放
PAGE 表示本段要从能被256整除的地址处开始存放,即起始地址的最低八位必须是0
  1. 组合:指定多个逻辑段之间的关系
说明 注意
PRIVATE (默认) 本段与其他段没有逻辑关系,不与其他段合并,每段都有自己的段地址
PUBLIC 连接程序把本段与所有同名同类型的其他段相邻地连接在一起,然后为所有这些段指定一个共同的段地址,也就是合成一个物理段
STACK 本段是堆栈的一部分,连接程序将所有STACK段按照与PUBLIC段的同样方式进行合并。 堆栈段必须具有该段组合
COMMON 把该段和与该段名称相同的其他段重叠在一起形成一个重叠段(多个逻辑段拥有相同的段基值),重叠段的长度取决于其中最长逻辑段的长度。类似C的共用体。
MEMORY 表示该段的起始地址位于其他所有段的后面(在程序中位于最高内存地址一端)。 只有第一个被解释的MEMORY段作为MEMORY组合类型,后面的MEMORY段全部被解释为COMMON段
AT 表达式 使用这种类型可以自己定义段的起始地址 表达式的取值只能是16位二进制数,且低四位必须为0
  1. 类别:

    • 当连接程序组织段时,将所有的同类别段相邻分配
    • 段类别可以是任意名称,但必须位于单引号中
  2. ASSUME伪指令:指定各段和寄存器的关系,建立段寄存器与段的缺省关系。

    • 汇编程序会根据数据所在的逻辑段,在需要时自动插入段超越前缀。
    • ASSUME伪指令并不为段寄存器设定初值,仅指定对应关系
    • ASSUME 伪指令可以重复使用,影响声明后的代码。
ASSUME register_name:segment_name,...

例子

假设有ASSUME伪指令:

ASSUME DS:DATAS

则它告诉编译器,在以后使用 DATAS 段中定义的符号时,默认使用 DS 寄存器作为段地址。


  1. 段寄存器的装填:在程序开始执行时,需要对寄存器进行装填。
    • CS 由系统自动装填
    • DS、ES、SS(未使用STACK作为组合类型的堆栈段)则由用户自行装填。
MOV AX,逻辑段名
MOV 寄存器名,AX
  1. 段组伪指令:把多个同类段合并为一个64KB物理段
    • 定义段组后,段组内各段就统一为一个段地址,各段定义的变量和标号的偏移地址就相对于段组基地址计算。
    • offset 操作符取变量和标号相对于段组的偏移地址,如果没有段组则取得相对于段的偏移地址。
    • 每个段的偏移地址是按照段组中段顺序来的
    • offset 后可以跟段组中的某个段名,表示该段最后一个字节后面字节相对于段组的偏移地址。
group_name GROUP segment1,segment2,...

例子

data1  segment  word  
           const1    dw     100
data1  ends
 
data2  segment  word  
           var1        dw     ?
data2  ends

datagroup  group  data1,data2

ASSUME DS:datagroup 则:

  • MOV BX,offset data1 时,$BX=2$
  • MOV BX,offset const1 时,$BX=0$
  • MOV BX,offset data2 时,$BX=4$
  • MOV BX,offset var1 时,$BX=2$

4.程序的开始

  1. NAME 作为模块名称
  2. TITLE 作为列表文件每一页上打印的标题,最大长度为60个字符
  3. 两种定义的关系:
    • 如果没有指定 NAME,则text 前六个字符作为模块名
    • 如果没有指定 TITLE,则使用文件名作为模块名
NAME module_name
TITLE text
  1. .STARTUP 伪操作:产生程序开始执行的代码
    • 按照CPU类型、存储模式、操作系统和堆栈类型,产生程序开始执行的代码
    • 同时还指定程序开始执行的起始点
    • 使用了 .STARTUP 则源程序结束时不需要指定程序运行起点

5.程序的结束

结束汇编(源程序结束)

  1. 格式:
    • [LABEL] 用于指定程序运行的起点
END [LABEL]

结束运行

  1. 通过 RET 进行结束
code  segment
main  proc  far
      assume ……
start:
      push  ds
      mov   ax, 0
      push  ax
      ……
      ret			; CS=DS,IP=0,此时会执行20H 中断指令
main  endp
code  ends
      end   start
  1. 通过中断进行结束
code  segment
      assume ……
start:
      ……
      ……
      mov  ax,4c00h
      int  21h
code  ends
      end  start
  1. 产生结束的代码:可选参数是一个返回的数码,通常用0表示没有错误
    • 此伪指令会自动产生结束运行的代码
.EXIT [返回参数]

6.数据定义

[ 变量名 ]   大小标识  操作数项 [ ,操作数项,…   ]
  1. 大小标识
大小标识 大小
DB 1B
DW 2B(字)
DF 3B
DD 4B(双字)
DQ 8B(四字)
DT 10B
  1. 操作数项
类型 解释 示例
数字 为一个或连续的存储单元设置数值初值 INT_VAR DB 13H
字符串 必须用引号引起来,将字符串中的各字符均以ASCⅡ码形式存放在相应的存储单元 STR_VAR DB 'HELLO WORLD$'
带标识符的表达式 适用于 DW 和 DD
对于 DW,则存储偏移地址
对于 DD,则高位存储段地址,低位存储偏移地址
ADDR_VAR DW INT_VAR+2
INT_VAR 的偏移地址加2,赋值给 ADDR_VAR
? 不赋初始值 ADDR_VAR DW ?
N DUP(初值,...) 为连续的存储单元提供重复数据
N为重复次数
BUF DB 100 DUP (0)
定义一个大小为100个字节,初值为0的数据存储单元

例子

对于 数据 'AB'

若按照字节存储(数组):

MESSAGE DB 'AB'

其为数组类型,A存入低字节,B存入高字节。

其存储格式为:

高字节 低字节
$42H$ $41H$

若按照字存储:

MESSAGE DW 'AB'

其不为数组类型,则认为它是一个整体(同普通数字的存储),A存入高字节,B存入低字节。

其存储格式为:

高字节 低字节
$41H$ $42H$

  1. 多行变量的赋值
    • 前一行尾不可加逗号
    • 后续行不可丢伪操作符

例子

array	db	12345
		db	6789
		db	0ah0bh

  1. LABEL 伪操作:定义别名
    • label 操作后面跟的数据定义即为其别名
    • 等价操作:EQU THIS
标识符 label 大小标识
标识符 EQU THIS 大小标识

例子

my_array label dw
array	db	01H,02H,03H,04H

arraymy_array 代表了同一片存储空间,但 array 是字节,my_array 是字。


7.表达式赋值

EQU 伪操作

expression_name EQU expression
  1. 先定义后使用,且不能重复定义
  2. 表达式可以为常数、数值表达式、地址表达式、变量名、标号、寄存器名称、指令助记符等
  3. 源程序中的所有符号名都会被替换为它代表的内容,类似C语言的宏常量

例子

a	equ	var4
mov	axa

mov ax,a 汇编时变成 mov ax,var+4


= 伪操作

符号名  =  表达式
  1. 等号语句的作用和等值语句完全一致,区别是已经用等号定义过的符号可以再次使用等号修改其定义。
  2. EQU伪操作和等号伪操作不能同时使用

8.地址计数与地址对齐

地址计数器 $

  1. 保存当前正在汇编的指令的偏移地址
  2. 同一个数据定义中,$ 的值不变

例子

DATAS SEGMENT
A_VAR DB 1
B_VAR DW $,$+1,$+2
DATAS ENDS

B_VAR 开始的3个DW值为 1,2,3


ORG 对齐

  1. 使紧跟其后的单元偏移地址为常数表达式计算出的值
  2. ORG 会修改地址计数器的值
  3. 特殊别名:
    • EVEN:使下一地址从偶地址开始
    • ALIGN boundary:从boundary的整数倍地址开始

例子

DATAS SEGMENT
A_VAR DB 1
ORG 20H
B_VAR DW $,$+1,$+2
DATAS ENDS

A_VAR 的偏移地址为 0B_VAR的偏移地址为 20HB_VAR开始的3个DW值为 20H,21H,22H


9.基数控制

.RADIX EXPRESSION
  1. 规定源程序中无标记数的基数( 2、8、10、16 选一)

三.宏汇编和重复汇编

1.宏汇编

宏定义和宏调用

  1. 宏定义
    • params1,params2,... 是哑元,可省
macro_name MACRO params1,params2,...
;code
ENDM
  1. 宏调用
    • params1,params2,... 是实元
macro_name params1,params2,...
  1. 宏必须先定义后调用

哑元和实元

  1. 哑元:相当于函数的形参
  2. 实元:相当于函数的实参
  3. 参数和操作码的连接:&

示例

; 宏定义
JUMP_MACRO MACRO CONDITION,FUNC
	J&CONDITION FUNC
ENDM

; 宏调用
		MOV AX,0
		SUB AX, 0
	      JUMP_MACRO Z,TEST_FUNC
TEST_FUNC:
		; some code

; 展开结果
		MOV AX,0
		SUB AX, 0
		JZ TEST_FUNC
TEST_FUNC:

  1. 在宏调用中,% 用于将表达式的值转换成当前基数下的数,而不是直接把表达式代入哑元

示例

; 宏定义
TEST_MACRO MACRO NUM
	MOV AX, NUM
ENDM

; 宏调用
CNTR = 0
		TEST_MACRO % CNTR
CNTR = CNTR + 1		
		TEST_MACRO CNTR
CNTR = CNTR + 1
		TEST_MACRO % CNTR
CNTR = CNTR + 1

; 宏展开结果
CNTR = 0
		MOV AX, 0
CNTR = CNTR + 1		
		MOV AX, CNTR
CNTR = CNTR + 1
		MOV AX, 2
CNTR = CNTR + 1

宏定义中的标号

LOCAL SIGN1,SIGN2,...
  1. LOCAL操作符:宏展开时,LOCAL操作符中出现的标号会变成全局唯一的符号。从而避免宏展开时,重名标号导致的报错。
LOCAL_MACRO MACRO CONDITION,FUNC
	LOCAL MAR
MAR:
	MOV AX, 0
ENDM

; 宏调用
		LOCAL_MACRO
		LOCAL_MACRO
		LOCAL_MACRO

; 宏展开结果
??0000:
		MOV AX, 0
??0001:
		MOV AX, 0
??0002:
		MOV AX, 0

宏定义中的注释

  1. 指示在 .lst 中,宏如何展开的伪操作:
伪操作 说明
.XALL (默认) 只展开代码,不展开单双分号注释
.SALL 不列出任何展开信息
.LALL 只展开代码,不展开双分号注释
  1. 双分号注释: ;; 在任何时候都不展开
  2. 单分号注释 :;.XALL 模式下展开

宏库

  1. 概念:把常用的宏建立成独立的文件
  2. 定义宏库:以 .mac.inc 结尾
  3. 使用宏库: INCLUDE 路径
    • 必须放在宏调用之前

删除宏

  1. PURGE 指令:
PURGE MACRO1,MACRO2,...

2.重复汇编

REPT

  1. 语法
REPT expression
; CODE
ENDM
  1. expression 的值将作为重复次数

IRP

  1. 用于把重复的代码按照参数进行重复。
  2. 重复时,每个参数都会赋值给 dummy(哑元,同宏里面的哑元)
IRP dummy,<argument1,argument2,argument3,...>
; CODE
ENDM

示例

; 重复定义
IRP X,<1,2,3,4,5,6>
	MOV AX, X
ENDM

; 展开
	MOV AX, 1
	MOV AX, 2
	MOV AX, 3
	MOV AX, 4
	MOV AX, 5
	MOV AX, 6

IRPC

  1. 用于把重复的代码按照参数进行重复。
  2. 参数是一个字符串,重复时,会按照字符赋值给dummy(哑元,同宏里面的哑元)
IRPC dummy,string
; CODE
ENDM

示例

; 重复定义
IRPC K,ABCD
	MOV K&X, 0
ENDM

; 展开
	MOV AX, 0
	MOV BX, 0	
	MOV CX, 0
	MOV DX, 0

1
https://gitee.com/pikoyo/prolearn.git
git@gitee.com:pikoyo/prolearn.git
pikoyo
prolearn
prolearn
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891