能力值:
( LV2,RANK:10 )
|
-
-
2 楼
相对于硬指令,伪指令完成诸如程序存储模式、主存变量、子程序、宏及段定义等一些不产生CPU动作的说明性工作,正确透彻的理解伪指令,对于理解汇编程序,程序结构,运行机制等至关重要。
一、参数、变量和标号
在源程序语句格式的4个组成部分中,参数是指令的操作对象,参数之间用逗号分隔。,汇编语言中,指令参数有数值型,它的主要形式是常数和数值表达式;还有地址型,主要形式是标号和名字(变量名、段名、过程名等)。我们知道,硬指令的参数有立即数、寄存器和存储单元,其中立即数要用数值型参数表达式,存储单元应该用地址型参数。
1、常数:表示一个固定的数值,分多种形式:
(1)十进制常数——0~9组成,以字母D或d结尾
(2)十六进制常数——0~9、A~F组成,以字母H或h结尾
(3)二进制常数——0~1组成,以字母B或b结尾
(4)八进制常数——0~7组成,以字母Q或q结尾
MASM默认不加后缀字母的是十进制,但是提供了.RADIX伪指令改变默认进制,格式如下:
.RADIX n
其中n为2~16范围内的任何数值
(5)字符串常数——利用一个标识符表达的一个数值。常数若使用有意义的符号名来表达可以提高程序的可读性,同时更具有通用性。MASM提供等价机制,用来为常量定义符号名,符号定义伪指令有等价EQU和等号=伪指令。他们的格式为:
符号名 EQU 数值表达式
符号名 EQU <字符串>
符号名 = 数值表达式
EQU用于数值等价时不能重复定义符号名,但=允许有重复值。如:
x = 7 ;同样x EQU 7是正确的
x = x + 5 ;但是x EQU x + 5是错误的
2、数值表达式
是指由运算符(MASM统称为操作符Operator)连接的各种常数所构成的表达式。汇编程序在汇编过程中计算表达式,最终得到一个数值,因为在运行前就已经计算出了,所以不影响程序的运行速度,程序的可读性却增强了。
变量定义伪指令为变量申请固定查长度的存储空间,并可以同时将相应的存储单元初始化。
一、变量定义伪指令,格式如下:
变量名 伪指令 初值表
变量名为用户自定义标识符,表示初值表首元素的逻辑地址,即用这个符号表示地址,常称为符号地址。
初值表是用逗号分隔的参数,主要由数值常数、表达式或?、DUP组成,?代表初值不确定,即未付初值,重复初值可以用DUP进行定义。DUP格式:
重复次数 DUP (重复参数)
变量定义伪指令有DB/DW/DD/DF/DQ/DT
(1)、DB——定义字节单元伪指令,用于分配一个或多个字节单元,每个数据一定是字节量(Byte),可以是0~255的无符号数或-128~+127的带符号数,也可以是字符串常数。
(2)、DW——定义字单元伪指令,用于分配一个或多个字单元,每个数据一定是字量(Word),一个字单元可用于存放任何16位数据,如一个段地址,一个偏移地址、两个字符、0~65535之间的无符号数或-32768~+32767之间的带符号数。
(3)、DD——定义双字单元伪指令,用于分配一个或多个双字单元,每个数据是一个32位的双字量(Double Word),可以是有符号数或无符号数的32位整数,也可以用来表达16位段地址(高位字)和16位的偏移地址(低位字)的远指针。
(4)、DF——定义3字伪指令,用于为一个或多个6字节变量分配空间及初始化,6字节常用在32位CPU中表示一个48位远指针(16位段选择器:32位偏移地址)。
(5)、DQ——定义4字伪指令,为一个或多个8字节变量分配空间及初始化
(6)、DT——定义10字节伪指令,为一个或多个10字节变量分配空间及初始化。
从MASM6.0开始,变量定义伪指令DB/DW/DD/DF/DQ/DT被建议是用新的表达形式,依次为:BYTE/WORD/DWORD/FWORD/QWORD/TBYTE,另外还有SBYTE/SWORD/SDWORD用于带符号数的初始化。
二、定位伪指令
用数据定义伪指令分配的数据是按顺序一个接着一个存放在数据段中的。有时我们希望能够控制数据的偏移地址,例如使数据对齐可以加快数据的存取速度,MASM提供如下伪指令:
1、ORG 参数 ;使他后面的数据或指令从参数指定的地址开始
ORG伪指令是将当前偏移地址指针指向参数表达式的偏移地址。如:
ORG 100H ;从100H处安排数据或程序
ORG $+10 ;是偏移地址加10,即跳过10个字节空间
汇编语言中$表示当前偏移地址。
2、EVEN ;使他后面的数据或指令从偶地址开始
EVEN伪指令使当前偏移地址指针指向偶数地址,即若原地址指针已指向偶地址,则不作调整;否则将地址指针加1,是地址指针偶数化。可对齐字量数据。
3、ALIGN n ;使他后面的数据或指令从n的整数倍地址开始
ALIGN伪指令是将当前偏移地址指针指向n(n是2的乘方)的整数倍的地址。
三、变量和标号的属性
标号或名字是由用户自定义的标识符,指向存储单元,分别表示其存储内容的逻辑地址。标号指示硬指令的地址,变量名指示所定义变量的开始地址,段名指示相应短的起始地址,子程序名指示相应子程序的开始地址,所以标号和名字一经定义,就具有以下三种属性:
1、段值:标号和名字对应存储单元所在的段地址。
2、偏移值:标号和名字对应存储单元所在段的段内偏移地址。
3、类型:标号、子程序名的类型可以是NEAR(近)或FAR(远),分别表示段内或段间;变量名的类型可以是BYTE(字节)、WORD(字)和DWORD(双字)等。
因为在汇编语言中,名字和标号的属性非常重要,所以MASM提供了有关的操作符:
1、地址操作符
地址操作符取得名字或标号的段地址和偏移地址两个属性。如中括号[]表示将括起来的表达式作为存储器地址指针;符号$表示当前偏移地址;段前缀的冒号:也是一种地址操作符,表示采用指定段的段地址寄存器。另外还有如下两个:
OFFSET 名字/标号 ;返回名字或标号的偏移地址
SEG 名字/标号 ;返回名字或标号的段地址
2、类型操作符
类型操作符对名字或标号的类型属性进行相关设置。
(1)类型名 PTR 名字/标号 ;使名字或标号具有指定的类型
PTR操作符中的“类型名”可以是BYTE/WORD/DWORD/FWOD/QWORD/TBYTE,或者是NEAR或FAR,还可以是由STRUCT、RECORD、UNION以及TYPEDEF定义的类型。使用PTR可以临时改变名字或标号的属性。
(2)THIS 类型名 ;创建采用当前地址,但为指定类型的操作数
如:b_var equ this byte ;按字节访问变量b_var,但与变量w_var的地址相同
w_var dw 10 dup(0) ;按字访问变量
MASM中还有一个LABEL伪指令,它的功能与EQU THIS相同
(3)SHORT 标号 ;设定标号为短转移标号
SHORT指定标号作为-128~+127字节范围内的短转移
(4)TYPE 名字/标号 ;返回一个字量数值,表明名字或标号的类型
字节、字和双字返回1、2和4,短转移、近转移(NEAR)和远转移(FAR)返回ff01h、ff02h和ff05h
(5)SIZEOF()和LENGTHOF()同TYPE类似,分别返回整个变量占用的字节数和整个变量的数据项数
程序段的定义和属性
段定义格式的伪指令
在前面我已经讲过了汇编程序的两种原程序格式即简化段格式和完整段格式。这里讲解简化段定义的伪指令
(一)简化段定义格式伪指令
1、存储模式伪指令
存储模式决定一个程序的规模,也确定进行子程序调用、指令转移和数据访问的缺省属性。使用简化段格式时,必须有存储模式.MODEL语句,格式如下:
.MODEL 存储模式 [,语言类型] [,操作系统类型] [,堆栈选项]
.MODEL语句必须位于所有段定义语句之前,共有7种不同的存储模式,分别为:
(1)TINY(微型模式)——所有的段地址寄存器都被设置为同一个值,即意味代码、数据和堆栈段都在一个段内,不大于64KB,访问操作数和指令只需要使用16位偏移地址。
(2)SMALL(小型模式)——在小模式下,一个程序至多只能有一个代码段和一个数据段,每段不大于64KB。这里数据段指数据段、堆栈段和附加段的总和。小模式下程序的最大长度为128KB。访问操作数和指令都只需要16位偏移地址,指令转移、程序调用以及数据访问都是近属性(NEAR),即小模式下的调用类型和数据指针缺省分别为近调用和近指针。
(3)COMPACT(紧凑模式)——代码段被限制在64KB的段内,数据段可以多个,超过64KB,调用类型缺省为近调用,数据指针缺省为远(FAR)指针。(数据量大代码量小程序)
(4)MEDIUM(中型模式)——代码段可以超过64KB,有多个,数据段只能有一个不大于64KB,数据指针缺省为近指针,调用类型缺省为远调用。(数据量小代码量大程序)
(5)LARGE(大型模式)——允许的代码段数据段都有多个,都可以超过64KB,但全部的静态数据(不能改变的数据)仍限制在64KB内,调用类型和数据指针缺省分别为远调用和远指针。
(6)HUGE(巨型模式)——与大型模式基本相同,只是静态数据不再局限于64KB
(7)FLAT(平展模式)——用于创建一个32位的程序,它只能运行在32位X86CPU上。该语句前要使用32位X86 CPU的处理器说明伪指令。DOS下不能使用FLAT模式,而编写32位Windows9.x或Windows NT的程序时,必须采用FLAT模式。
完整的MODEL语句还可以选择“语言类型”,如C,PASCAL等,表示采用制定语言的命名和调用规则,它将影响PUBLIC和EXTERN等伪指令。操作系统类型默认和唯一支持的就是os_dos,堆栈选项默认是NEARSTACK,表示堆栈段寄存器SS等于数据段寄存器DS;FARSTACK则表示SS不等于DS。
2、简化段定义伪指令
语句.CODE、.DATA、.STACK分别表示代码段、数据段和堆栈段的开始,一个段的开始自动结束前面的一个段。采用简化段定义指令之前,必须有存储模式语句.MODEL
(1).STACK [大小]
.STACK创建一个堆栈段,段明stack,参数制定堆栈段所占用的字节数,默认是1KB(=1024=0400H字节)
(2).DATA
.DATA?
数据段伪指令,DATA创建一个数据段,段名是:_DATA.它用于定义具有初值得变量,当然也允许定义无初值得变量。无初值的变量可以安排在另一个段中,用.DATA?伪指令创建,它建立的数据段名是:_BSS。使用.DATA?伪指令可以减小形成的EXE文件,并与其他语言保持最大的兼容性。另外.CONST伪指令用于建立只读的茶馆能量数据段(段名:CONST),.FARDATA和.FARDATA?伪指令分别建立有初值和无初值得远调用数据段。
(3).CODE [段名]
创建一个代码段,它的参数指定该代码段的段名没给出使用默认值。在TINY、SMALL、COMPACT和FLAT模式下,默认代码段名是:_TEXT,在MEDIUM、LARGE和HUGE模式下,默认段名是:模块名_TEXT。另外,在使用简化段定义中,各段名和其他用户所需要的信息可以使用MASM已定义的符号,这些符号主要有:
@CODE——表示.CODE伪指令定义的段名
@DATA——表示由.DATA和.DATA?等定义的数据段的段名
还有@CURSEG 当前段名、@STACK 堆栈段名 、@CODESIZE 代码段规模 、@DATASIZE 数据段规模等
3、程序开始伪指令
.STARTUP
按照给定的CPU类型,根据.MODEL语句选择的存储模式、操作系统和堆栈类型,产生程序开始执行的代码;同时指定程序开始执行的起始点。在DOS下,.STARTUP语句还将初始化DS值,调整SS和SP,在前面汇编(六)的li6-1.lst中可以看出,在小模式下,.STARTUP主要设置了数据段DS值,同时按照存储模式的要求使堆栈段SS=DS;为了保证堆栈区域不变,栈顶指针SP也需要相应调整,即加上数据段所占用的字节数。连接程序会根据程序的起始点正确的设置CS:IP,根据程序的大小和堆栈段的大小设置SS:SP,但没有设置DS、ES。
4、程序终止伪指令
.exit [返回数码]
此语句产生终止程序执行返回操作系统的指令代码,可选参数是一个返回的数值,通常用0表示没有错误。
5、汇编结束伪指令
END [标号]
END伪指令指示汇编程序MASM到此结束汇编过程。源程序的最后必须有一条END语句,可选标号用于指定程序开始执行点,连接程序据此设置CS:IP
完整段定义格式的伪指令
1、完整段定义伪指令
完整段定义由SEGMENT和ENDS这一对伪指令实现,格式如下:
段名 segment [定位类型] [组合类型] [段字/寻址方式] ['类别']
。。。。。
段名 ends
段定义后的4个关键字由来确定段的各种属性,堆栈段要使用stack组合类型,代码段应具有‘code’类别,其他为可选性参数。
(1)定位类型(align)——指定逻辑段在主存储器中的边界,该关键字可为:
BYTE:段开始为下一个可用的字节地址(xxxx xxxxB),属性值为1
WORD:段开始为下一个可用的偶数地址(xxxx xxx0B),属性值为2
DWORD:段开始为下一个可用的4倍数地址(xxxx xx00B),属性值为4
PARA:段开始为下一个可用的节地址(xxxx 0000B),属性值为16
PAGE:段开始为下一个可用的页地址(0000 0000B),属性值为256
完整段定义伪指令的默认定位类型为PARA,其低4位已经是0,所以默认情况下数据段的偏移地址从0开始
(2)组合类型(Combine)——指定多个逻辑段之间的关系。通常,在开发大型程序时,要分成很多模块,然后用连接程序形成一个可执行文件。在其他模块中,可以具有同名或/同类型的逻辑段,通过组合类型属性可以进行合理的合并,组合的关键字有:
PRIVATE:本段与其他段没有逻辑关系,不与其他段合并,每段都有自己的段地址。这是完整段定义伪指令的默认段组合方式。
PUBLIC:连接程序把本段与所有同名同类别的其它段相邻的连接在一起,然后为所有这些段指定一个共同的段地址,即合成一个物理段。这是简化段定义伪指令的默认值。
STACK:本段是堆栈的一部分,连接程序将所有的STACK段按照与PUBLIC段的同样方式进行合并。这是堆栈段必须具有的段组合。
COMMON:连接程序把所有同名同类别的COMMON段指向共同的段地址,因而各段相互重叠,后面的同名同类别段将覆盖前面的段,段的总长度是所有同名段中最长的段所具有的长度,主要用于数据的共享。
AT表达式:把本段定位在表达式的值指定的段地址上,它允许用户强制指定该逻辑段的物理地址,注意他不能用于定位代码段,一般用于访问系统数据(但MASM的连接程序LINK.EXE不支持这种形式)。
MEMORY:连接程序把本段定位在所有段的上面,即程序的最高地址处,如有多个MEMORY段,则遇到的第一个是MEMORY段,其余作COMMON。
(3)段字属性/寻址类型(Use)——这是为32位段设置的属性。对于16位x86CPU默认的是16位段,即USE16,而对于汇编32位x86CPU指令时,默认采用32位段,即USE32,但可以用USE16指定标准的16位段。编写运行于实地址方式(8086工作方式)的汇编语言程序,必须采用16位段。即,对于80386及以上,可以设定为USE16或USE32,代表16位寻址或32位寻址,当处理器是386级以上时,保护模式下缺省为USE32,其它模式为USE16,对于386以下的CPU,不具备32位寻址方式,只能是USE16。
(4)类别(Class)——当连接程序组织段时,将所有的同类别段相邻分配。段类别可以任意命名,但必须位于单引号中,大多数MASM程序使用‘code’、‘data’和‘stack’来分别指示代码段、数据段和堆栈段,以保持所有代码和数据的连续。
2、指定段寄存器伪指令
segment伪指令说明各逻辑段的名字、起始位置及属性,而指定段寄存器ASSUME伪指令是说明各逻辑段的种类,它的格式:
ASSUME 段寄存器:段名 [,段寄存器:段名,。。。]
ASSUME通知MASM用指定的段寄存器来寻址对应的逻辑段,即建立段寄存器与段的缺省关系,明确了程序中各段与段寄存器之间的关系后,汇编程序会根据数据所在的逻辑段,在需要时自动插入段超越前缀。ASSUME伪指令并不为段寄存器设定初值,连接程序LINK将正确的设置CS:IP和SS:SP,数据段需要在程序中自己设置。
ASSUME伪指令的段名参数,可以是:
(1)以段定义伪指令设置的段名
(2)以group伪指令设置的组名
(3)保留字NOTHING(表示取消指定的段寄存器与段名的关系)
(4)用seg操作符返回的段地址
3、段组伪指令
MASM允许程序员定义多个同类段(代码段、数据段、堆栈段),伪指令GROUP把多个同类段合并为一个64KB物理段,并用一个组名统一存取它,格式:
组名 GROUP 段名 [,段名,...]
定义段组后,段组内各段统一为一个段地址,各段定义的变量和标号的偏移地址相对于段组地址计算。OFFSET操作符取变量和标号相对于段组的偏移地址,如果没有段组则相对于段的偏移地址。OFFSET后可以跟段组中的某个段名,表示该段最后一个字节后面字节相对于段组的偏移地址。
4、段顺序伪指令
在源程序中,通常按照便于阅读的原则或个人习惯书写各个逻辑段,但段在主存中的实际顺序是可以设置的,MASM具有如下伪指令:
.SEG ;按照源程序的各段顺序
.DOSSEG ;按照其它微软的程序设计语言使用的标准DOS规定
.ALPHA ;按照段名的字母顺序
完整段定义格式中,默认按照源程序各段的书写顺序安排(即.SEG),采用.MODEL伪指令简化段定义时,则是.DOSSEG规定的标准DOS程序顺序:代码段、数据段、堆栈段。
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
温习了一下基本知识,谢谢。
|
能力值:
( LV2,RANK:10 )
|
-
-
4 楼
关于 伪指令
举例生活中的例子, 我们的语言中有很多词汇, 词汇是语言的建筑材料,由词和熟语组成。 一句话里面必须有基础词汇, 这部分就可以对应到CPU硬件指令上去,例如- "显示您的签名" "温习一下基础知识"; 有些话语中还含有熟语的,就可以对应到你说的这个,masm的伪指令上面, 例如. "掬花溪月""春涧听云雀""云阶踏雪扶梅杖";
如果要是想将例子硬套到ASM语言中去的话,可以这样说,凡是原始的语言基础词汇可以理解为指令; 凡是经过艺术加工过的语句可以理解为伪指令;
虽然这些比喻未必精准, 但是我认为还是有助于去理解 伪指令的问题吧
|
能力值:
( LV6,RANK:90 )
|
-
-
5 楼
我理解的伪指令很简单:
伪指令就是不干实事的指令,比如将
eax加1,再减一 = 什么都没敢 = 伪指令
ecx加7,减5,加1,减3 = 什么都没敢 = 伪指令
push eax,pushad,retn 24 = 什么都没敢 = 伪指令
。。。。
|
能力值:
( LV2,RANK:10 )
|
-
-
6 楼
rxzcums的理解很通俗,但不是十分准确!
对于新手来说,这样理解也算一种办法......
|
能力值:
( LV2,RANK:10 )
|
-
-
7 楼
就是cpu不动作
|
能力值:
( LV6,RANK:90 )
|
-
-
8 楼
嘿嘿,没什么基础知识,就这么理解了
----------------------------------------------
弄错了。。
楼主说的是“伪指令”,我说的应该是“花指令”,弄错弄错,汗死
|
|
|