1、第17章 大型机汇编语言扩展第17章 大型机汇编语言扩展当前COBOL语言主要是应用于大型机上的,而大型机上的汇编语言则更加贴近其内部结构。因此,学习汇编语言,对于更加深入地理解COBOL语言是有必要的。同时,汇编语言能够从更加底层的角度上,反映大型机程序的工作原理。因此,若要从事大型机上更为高级的应用开发或系统管理工作,也是必须要掌握汇编语言的。17.1 基本概念首先需要明确的是,汇编语言是针对不同的机型而言的。例如,PC机上的80x86汇编语言和大型机上的S/390汇编语言就是两个不同的概念。本章只讲解大型机上的汇编语言。关于大型机的汇编语言,主要需要理解以下几个方面的概念,下面分别予以讲
2、解。17.1.1 主存组织计算机中最小的存储单位是一个位(bit)。位是用0和1这两个二进制数表示的,其中8个位形成一个字节(Byte)。存储空间通常是以字节为基本单位的,由字节组成字。字所占的存储空间大小称为字长。字节在任何机器上都是由8位组成的,但字在不同的机器上则有着不同的字长。关于字及其相关概念,在大型机的主存中有以下3种组织形式: 半字(HALF WORD):由2个字节组成,占16位存储空间。 全字(FULL WORD):由4个字节组成,占32位存储空间。其中全字也就是所谓的字。 双字(DOUBLE WORD):由8个字节组成,占64位存储空间。此外,在表示大型机的主存地址空间时,除
3、了二进制数外,通常还会应用到十六进制数。十六进制数中的数字09分别表示十进制数中的09。而十六进制数中的数字AF则分别表示十进制数中的1015。例如,以下为一组十进制数:021045100则以上数列对应的二进制数如下:01010101011011100100以上数列对应的十六进制数如下:02A2D64实际上,引入十六进制数的概念也是为了更方便地表示二进制数。可以看到,24正好等于16,因此一个十六进制数正好可以表示4个二进制数。由于一个字节是由8个位组成的,而每个位又由一个二进制数表示。因此,一个字节也可以通过两个十六进制数来表示。大型机主存中的普通地址空间(Common Area)和私有地址
4、空间(Private Area)一共是16MB。由于1MB=220,因此16MB大小的地址空间可以用24个bits表示,同时也可以使用6个十六进制数表示。图17.1反映了使用十六进制数表示的一段主存空间。图17.1 主存空间示例图上图中每一行为4个字节,表示一个全字空间。这4个字节只在最下面一行划分了出来,以上各行相同。根据该示例图,需要理解以下两个重要概念: 半字空间的边界为偶数地址。 全字空间的起始地址应该能被4整除。17.1.2 数码表示同其他汇编语言一样,在大型机的汇编语言中通常也涉及到以下3个关于数码表示的概念。这3个概念分别如下所示。 原码:即该数据自身。例如,以下分别为不同进制中
5、示例数据与原码的关系:十进制数中:10的原码为10二进制数中:1010的原码为1010十六进制数中:A的原码为A 反码:通过将数据在二进制的表示中各位取反得到。以下为不同进制中示例数据与反码的关系:十进制数中:10的反码为5二进制数中:1010的反码为0101十六进制数中:A的反码为5 补码:通过将数据在二进制的表示中各位取反后加1得到。以下为各示例数据与反码的关系:十进制数中:10的补码为6二进制数中:1010的补码为0110十六进制数中:A的补码为6在大型机中,以上所说的反码通常也叫做1的补码,而以上所说的补码则通常叫做2的补码。实际上,所谓n的补码,也就是在n-1的补码基础上再加1得到的
6、。对于大型机中的整数数据,是以32位全字空间作为存储单元的。其中最左边的1位表示符号位,正号用0表示,负号用1表示。以下为大型机上两组不同整数的表示方式: 0231-1之间的整数:直接使用该整数的原码表示。 -1-231+1之间的整数:使用该整数绝对值编码形式的2的补码表示。例如,对于整数-2,在大型机中的表示方法如下:11111111 11111111 11111111 11111110此外,关于大型机中的数码,还有以下几点需要注意: 负数的2的补码就是该数绝对值的原码,该绝对值的原码的2的补码为负数本身。 系统内部进行减法运算的过程是先得到减数的2的补码,再与被减数相加。17.1.3 寄存
7、器与程序状态字在汇编语言中,寄存器可以看作是一块单独的存储空间。该存储空间通常用于存储汇编语言中的操作数。在S/390大型机上,有以下几种类型的寄存器: General Purpose Registers(GPRs):通用寄存器。用于在程序中作为存储地址、工作空间或者计数器。 Floating Point Registers(FPRs):浮点寄存器。用于进行浮点运算。 Control Registers:控制寄存器。用于操作系统。 Access Registers:通道(访问)寄存器。用于操作系统。 Vector Registers:向量寄存器。用于向量运算。其中通用寄存器(GPRs)在汇编语
8、言程序中经常要用到。大型机汇编语言中共有16个通用寄存器,分别用R0R15表示。每个通用存储器的大小为一个全字空间。在汇编语言程序中,使用015这16个数字分别表示以上16个通用寄存器。如果在源程序最后通过EQU特别指定,也可使用字符R0R15来表示以上寄存器。使用EQU指定的方式如下:R0 EQU 0R1 EQU 1R2 EQU 2 R15 EQU 15程序状态字(Program Status Word)简称为PSW。PSW位于硬件上的一块特定区域,用于保存中央处理器(CPU)当前的状态。实际上,PSW也是一个寄存器,并且常用于程序开发之中。扩展模式下的PSW共有64位,首位地址从0开始。其
9、中以下几位表示的内容经常会用到: 31位:表示程序是否产生异常。 3435位:表示条件码(Condition Code)当前的值。 4063位:表示下一条指令的地址。关于条件码,也可将其简称为CC。CC常用于程序流程控制中。通常条件运算的结果和CC的对应关系如下: 运算结果等于0时,CC为0,对应的二进制数为00。 运算结果小于0时,CC为1,对应的二进制数为01。 运算结果大于0时,CC为2,对应的二进制数为10。 运算结果溢出时,CC为3,对应的二进制数为11。程序在执行过程中必然要用到PSW。实际上,程序的每步执行都是根据PSW中的内容而来的。关于程序的具体执行步骤如下:(1)程序第一条
10、指令的绝对地址被装入PSW,实现程序执行的初始化。其中具体取多少字节装入是由指令的类型决定的。(2)机器从PSW指向的存储地址中检查出程序指令以执行。(3)机器更新PSW的内容,使其指向下一条指令地址。并且,如果上条指令是转移分支,则PSW中的相应内容将指向跳转地址。17.1.4 操作数的主存地址表示方式与COBOL不同,汇编语言程序并不是按照语句执行的,而是按照指令来执行的。COBOL中的一条语句往往对应汇编语言中的多条指令。例如,以下为一条在COBOL中实现算术加运算的语句:ADD A TO B.该条COBOL语句对应的汇编指令如下:PACK X,APACK Y,BAP X,YUNPK B
11、,X汇编中的一条指令通常是由操作符和操作数共同组成的。其中操作符一般在指令的左边,操作数一般在指令的右边。例如,对于以上第一条指令,PACK就为操作符,而X和A则分别为两个操作数。以上指令中的操作数是直接用变量表示的。实际上,操作数也可直接通过其地址表示,并且变量最终也会转换为操作数的地址形式。操作数的地址通常有以下两种表示方式。为观察方便,此处不妨假设已通过EQU将R0R15指定为015,直接通过R0R15表示寄存器。(1)基址+偏移地址表示方式以上表示方式的格式如下:D(B)其中B代表基址,D代表相对于该基址的偏移地址。基址也就是一个基准地址,是通过基址寄存器表示的。偏移地址表示相对基址的
12、偏移量,是通过十进制数表示的。该十进制数的范围从0217-1。例如,以下为一个使用基址+偏移地址表示的操作数:20(R13)以上是将通用寄存器R13作为基址寄存器,并将十进制数20作为相对于基址的偏移量。如果R13中的内容如下:(R13) = 010000A0则以上操作数的地址是将偏移量20加上R13中右边24位表示的基址得到的。因此,该操作数的地址如下:20(R13) = 0000B4(2)基址+偏移地址+索引地址表示方式以上表示方式的格式如下:D(X, B)其中X为索引地址,通过索引寄存器表示。基址和偏移地址的要求和上一种表示方法相同。例如,以下为使用基址+偏移地址+索引地址表示的操作数:
13、10(R1, R15)以上操作数是将通用寄存器R15作为基址寄存器,而将R1作为索引寄存器,10作为偏移量。如果R1和R15中的内容分别如下:(R1) = 00000100(R15) = 10A051A1则以上操作数的地址如下:10(R1, R15) = A052AB此外需要注意的是,在汇编语言程序中操作数地址表示中的寄存器是可以省略不写的。例如,以下这几种表示方式都是正确的:2525( , R15)25(R15, )以上操作数地址中,第一个使用的是D(B)表示方式,后两个使用的则是D(X, B)表示方式。当寄存器省略不写时,可以认为省略处的寄存器内容为0。另外,在16个通用寄存器中,R15通
14、常作为基址寄存器。而R0则既可作为基址寄存器,也可作为索引寄存器。并且,当在操作数地址中使用R0时,将直接用0进行计算,而不理会R0寄存器中的实际内容。以下例子充分说明了这一点:(R0) = 0010010126(R0) = 1A由此可见,虽然此时R0中的内容为00100101,但26(R0)所表示的地址并不理会R0中的内容。此时是将R0看作0,直接通过计算十进制数26加上0后所对应的十六进制数得到的最终地址。最后,关于指令中操作数地址的表示方法,还有以下两点需要注意: 地址都是为正值的,即使其首位为1。 地址的表示不能超出相应的范围。17.1.5 程序基本结构在汇编语言源程序中,通常是以CS
15、ECT标志符表示程序的开始。其中程序名写在CSECT的左边,代码写在CSECT的下面。当涉及到子程序调用时,子程序使用DSECT替代CSECT。当程序编写完成后,使用END加上程序名表示结束。在汇编语言程序主体代码中,通常分为两块内容。其中一块为程序逻辑部分,另一块为数据定义部分。同COBOL类似,当程序代码中某行首列为星号时,表示该行是注释行。例如,下面为一段汇编语言程序的基本结构:TEST CSECT /*程序模块化代码,只在z/OS环境下使用*/* BEGIN LOGIC * /*此行为注释,下同*/ /*此处为程序逻辑部分代码*/* END LOGIC * /*程序模块化代码,只在z/
16、OS环境下使用*/* DATA AREA * /*此处为数据定义部分代码,若在z/OS环境下,还包括DCB参数的定义*/ END TEST 大型机汇编语言通常可以在两种环境下运行。其中一种是在ASSIST软件下运行,另一种是直接在z/OS大型机操作系统上运行。例如,以下是一段运行于ASSIST软件下的程序代码:TRANS1 CSECT* BEGIN LOGIC * USING TRANS1, 15 XREAD CARD1, 80 BC B 0100, EXIT XPRNT FIELD1, 81 XREAD CARD2, 80LOOP BC B 0100, EXIT XPRNT FIELD2,
17、80 BC B 1111, LOOPEXIT BCR B 1111, 14* END LOGIC * DATA AREA *FIELD1 DC C1CARD1 DS CL80FIELD2 DC C0CARD2 DS CL80 END TRANS1以上程序实现的功能是依此读取CARD指向的每条记录,并将其显示输出,直至全部读完。在z/OS系统上具有与之类似功能的程序代码(包括相关JCL语句)如下: /*相关JCL语句,根据不同的系统配置而有所不同*/TRANS2 CSECT STM R14, R12, 12(R13) BALR R12, R0 USING *, R12 LR R11, R13 L
18、A R13, SAVEAREA ST R11, 4(, R13) ST R13, 8(, R11)* BEGIN LOGIC * OPEN (INFILE, (INPUT), OUTFILE, (OUTPUT) LOOP EQU * GET INFILE, INAREA MVC OUTREC, INAREA PUT OUTFILE, OUTAREA B LOOP ENDDATA EQU * CLOSE (INFILE , , OUTFILE)* END LOGIC * RETURN EQU * L R13, SAVEAREA+4 RETURN (14,12), RC=0* DATA AREA
19、* INAREA DS CL80 OUTAREA DS 0CL133 OUTASA DC C0 OUTREC DS CL80 DC CL52 INFILE DCB DDNAME = SYSIN, RECFM = FB, LRECL = 80, DSORG = PS, MACRF = GM, EODAD = ENDDATAOUTFILE DCB DDNAME = SYSPRINT, RECFM = FBA, LRECL = 133, DSORG = PS, MACRF = PM, BLKSIZE = 6650SAVEAREA DC 18F0 PRINT GEN YREGS LTORG END T
20、RANS2/G.SYSIN DD DSN = ADCDA.ASM.DATA, DISP = SHR /G.SYSPRINT DD SYSOUT = *以上程序实现的功能是读取z/OS系统上数据集ADCDA.ASM.DATA中的每条记录并将其输出。对于以上两段程序,只需了解其大体框架结构,对汇编语言程序建立一个感性认识。至于其中的具体内容,此处不必深究。17.2 指令类型与机器码COBOL语言属于高级语言,而汇编语言属于低级语言。二者编写的程序分别需要经过编译或汇编转换为机器语言后,计算机才能理解和执行。汇编语言更加贴近于机器语言,因此其执行效率也更高。汇编语言的指令根据其转换后的机器码类型可以
21、分为不同的格式,下面分别予以介绍。17.2.1 RR指令类型及其机器码当某一指令中的两个操作数都为寄存器时,则该指令属于RR类型的指令。例如,以下这几条指令都为RR类型的指令。AR 12, 0SR 3, 1LR 4, 5CR 2, 3RR指令类型的格式及其对应的机器码分别为:OP r1, r2 /*RR指令格式*/h0h0hr1hr2 /*RR指令机器码*/关于以上机器码中的内容,分别介绍如下: h0h0:该指令的操作符OP,通过两位十六进制数表示。 hr1:该指令的第一个操作数r1,为一个寄存器,通过一位十六进制数表示。 hr2:该指令的第二个操作数r2,为一个寄存器,通过一位十六进制数表示
22、。由此可见,RR指令所占存储空间为1个半字空间。其中操作符占1个字节,第一个操作数和第二个操作数各占0.5个字节。对于以上第一条指令,由于其操作符AR的机器码为1A。因此,可写出该条指令对应的机器码如下:1AC0对于该类型中的其余各条指令,只要知道了指令中操作符的机器码,便可写出整条指令的机器码。这点对于以下各类型的指令也是适用的。17.2.2 RX指令类型及其机器码当某一指令的第一个操作数为寄存器,第二个操作数为主存地址时,该指令属于RX类型的指令。例如,以下这几条指令都为RX类型的指令:L 2, 10(1, 15)ST 1, 4(8)A 2, 14( , 14)S 3, 10(2, )C
23、2, 8(0, 13)LA 2, 5(3, 5)STC 3, 0(6)RX指令类型的格式及其对应的机器码分别为:OP r, D(X, B)h0h0hrhX hBhDhDhD关于以上机器码中的内容,分别介绍如下: h0h0:该指令的操作符OP,通过两位十六进制数表示。 hr:该指令的第一个操作数r,为一个寄存器,通过一位十六进制数表示。 hX:该指令第二个操作数D(X, B)中的索引寄存器X,通过一位十六进制数表示。 hB:该指令第二个操作数D(X, B)中的基址寄存器B,通过一位十六进制数表示。 hDhDhD:该指令第二个操作数D(X, B)中的偏移量D,通过三位十六进制数表示。由此可见,RX
24、指令所占存储空间为2个半字空间。其中操作符占1个字节,第一个操作数占0.5个字节,第二个操作数占2.5个字节。对于以上第一条指令,由于其操作符L的机器码为58。因此,可写出该条指令对应的机器码如下:5821F00A需要注意的是,当索引寄存器省略未写或使用D(B)方式表示地址时,hX位为0。这点对于其他类型的指令也是相同的。17.2.3 RS指令类型及其机器码当某一指令的前两个操作数为寄存器,第三个操作数为主存地址时,该指令属于RS类型的指令。例如,以下这几条指令都为RS类型的指令:LM 0, 15, 300(3)STM 14, 1, 24(5)BXLE 1, 2, 10(4)RS指令类型的格式
25、及其对应的机器码分别为:OP r1, r2, D(B)h0h0hr1hr2 hBhDhDhD关于以上机器码中的内容,分别介绍如下: h0h0:该指令的操作符OP,通过两位十六进制数表示。 hr1:该指令的第一个操作数r1,为一个寄存器,通过一位十六进制数表示。 hr2:该指令的第二个操作数r2,为一个寄存器,通过一位十六进制数表示。 hB:该指令第三个操作数D(B)中的基址寄存器B,通过一位十六进制数表示。 hDhDhD:该指令第三个操作数D(B)中的偏移量D,通过三位十六进制数表示。由此可见,RS指令所占存储空间为2个半字空间。其中操作符占1个字节,第一个操作数和第二个操作数各占0.5个字节
26、,第三个操作数占2个字节。对于以上第一条指令,其操作符LM的机器码为98。因此,可写出该条指令对应的机器码如下:980F312C需要注意的是,该指令中使用主存地址表示的第三个操作数只能使用D(B)方式。也就是说,此处不能含有索引寄存器。17.2.4 SI指令类型及其机器码当某一指令的第一个操作数为主存地址,第二个操作数为直接数时,该指令属于SI类型的指令。其中有的地方也将直接数称作立即数。以下这条指令为SI类型的指令:MVI 10(1), C*RS指令类型的格式及其对应的机器码分别如下所示。OP D(B), Ih0h0hIhI hBhDhDhD关于以上机器码中的内容,分别介绍如下: h0h0:
27、该指令的操作符OP,通过两位十六进制数表示。 hIhI:该指令的第二个操作数I,为一个直接数,通过两位十六进制数表示。 hB:该指令第一个操作数D(X, B)中的基址寄存器B,通过一位十六进制数表示。 hDhDhD:该指令第一个操作数D(X, B)中的偏移量D,通过三位十六进制数表示。由此可见,SI指令所占存储空间为2个半字空间。其中操作符占1个字节,前两个个操作数共占1个字节,第三个操作数占2个字节。对于以上第一条指令,其操作符MVI的机器码为92,并且立即数“*”的机器码为5C。因此,可写出该条指令对应的机器码如下:925C100A需要注意的是,该条指令中第一个操作数为主存地址,第二个操作
28、数为直接数。然而在该指令对应的机器码中,则将第二个操作数的机器码写在前面,而将第一个操作数的写在后面。17.2.5 SS指令类型及其机器码当某一指令的两个操作数都为主存地址时,该指令属于SI类型的指令。例如,以下这几条指令都为SS类型的指令:MVC 24(5),12(6)SP 0(4), 12(3)AP 12(3), 0(4)PACK 10(1), 20(2)UNPK 20(1), 10(2)SS指令类型的格式如下:OP D1(B1), D2(B2)SS指令类型的格式实际上共分为两种情况。第一种情况是两操作数的长度相等,第二种情况是两操作数的长度不等。这两种情况对应的机器码分别为:h0h0hL
29、hLhB1hD1hD1hD1 hB2hD2hD2hD2h0h0hL1hL2 hB1hD1hD1hD1 hB2hD2hD2hD2可以看到,SS指令所占存储空间为3个半字空间。其中以上机器码中关于操作符和操作数部分的内容和其他类型指令的机器码类似。此处仅重点介绍以下两点不同的地方: hLhL:对应于指令中两操作数长度相等的情况,表示两者共同的长度大小。该长度通过两位十六进制数表示,因此对应的十进制数数值大小为0255。 hL1hL2:对应于指令中两操作数长度不等的情况。其中hL1表示第一个操作数的长度大小,hL2表示第二个操作数的长度大小。每个操作数的长度通过一位十六进制数表示,因此对应的十进制数
30、数值大小为015。需要注意的是,由于长度为0的操作数是没有意义的。因此,在机器语言中操作数长度的显示数值都要比其真实数值小1。例如,机器语言中长度显示为0时,表示的真实长度是1;长度显示为1时,表示的真实长度为2等等。以上第一条指令属于SS指令类型的第一种情况,即两操作数长度是相等的。不妨设该条指令中两操作数的长度均为100个字节,则反映到机器码中的数值应为99。将99转换为十六进制数,为63。此外,由于操作符MVC的机器码为D2,因此可以写出第一条指令的机器码如下:D2635018600C以上第二条指令属于SS指令类型的第二种情况,即两操作数长度是不等的。不妨设第一个操作数的长度为5个字节,第二个操作数的长度为1个字节。则二者在相应的机器码中将分别为4和0。由于操作符SP的机器码为5B,因此可以写出第二条指令的机器码如下:5B404000300C17.3 数据的定义在汇编语言程序中,各数据都是在程序末尾的数据定义部分通过DC和DS进行定义的。其中DC用于定义程序中的常量,DS用于定义一段存储空间。下面分别予以讲解。17.3.1 使用DC定义常量通过前面的例子可以看出,在程序的数据定义部分经常会使
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1