z/OS 如果输出文件属性改变,汇编程序会奇怪地循环
z/OS Assembler program looping weirdly if output file attributes changed
好的 - 我确定我在做一些愚蠢的事情,但我看不到它。
我有一个小的示例汇编程序,我将提供给想学习汇编程序的同事,但它有一个奇怪的错误,我需要先解决。 .
当输出文件 (DDNAME SYSUT2) 是一个 80 字节的临时文件时,它工作正常。将 SYSUT2 更改为 SYSOUT=* 并从 'Closing file' WTO 循环。
程序如下:
//C.SYSLIB DD DISP=SHR,DSN=SYS1.MACLIB
// DD DISP=SHR,DSN=SYS1.MODGEN
// DD DISP=SHR,DSN=SYS1.ASM.SASMMAC2
//* DD DISP=SHR,DSN=JOCS065.STEVE.SOURCE
- - - - - - - - - - - - - - - - 4 Line(s) not Displayed
TITLE 'TEST PROGRAM'
SYMBOLIC CSECT
ASMDREG .Register equates
SAVE (14,12),,'SYMBOLIC PARM SUB &SYSDATE &SYSTIME'
LR R12,R15 .R12 -> entry point
USING SYMBOLIC,R12 .Establish addressability
* Get the parm passed
L R1,0(R1) .R1 -> parm
LTR R1,R1 .Is there one?
BZ RETURN .No - return
* We have a parm
LH R2,0(R1) .R2 = PARM LENGTH
LTR R2,R2 .parm length = 0?
BZ RETURN . Yes - return
* And the parm has length
BCTR R2,0 .Decrement length for move
EX R2,SETOUT .Move parm to output
* Open output file and write parm to output
LA R4,FILE1 .R4 -> DCB for output file.
USING IHADCB,R4 .Establish addressability
OPEN (FILE1,OUTPUT) .Open log file
TM DCBOFLGS,DCBOFOPN .Open successful ?
BZ BADOPEN .No - go to error routine
WTO 'SIMSG001 OPEN successful.'
DROP R4
WTO 'SIMSG003 writing to file'
PUT FILE1,OUTREC .PUT output record
WTO 'SIMSG004 Closing file...'
CLOSE (FILE1) .close files
WTO 'SIMSG005 Returning to caller...'
B RETURN .Return
* EXecute instructions
SETOUT MVC OUTREC(0),2(R1)
*****************************************************************
* PROGRAM TERMINATION
*****************************************************************
RETURN DS 0H
WTO 'SIMSG006 RESTORING REGISTERS AND RETURNING'
XR R15,R15 .Clear R15 (RC=0)
RETURN (14,12),RC=(15) .Restore caller's regs and return
BADOPEN DS 0H
WTO 'SIMSG002 OPEN failed.'
B RETURN
*****************************************************************
* STORAGE AREAS
*****************************************************************
OUTREC DC 80C' ' .OUTPUT CARD IMAGE
*****************************************************************
* MACROS AND LITERALS
*****************************************************************
PRINT NOGEN
FILE1 DCB RECFM=F,LRECL=80,BLKSIZE=80, X
DSORG=PS,DDNAME=SYSUT2,MACRF=PM
DCBD
PRINT GEN
*
LTORG LITERAL STORAGE
END
//L.SYSLMOD DD DISP=SHR,DSN=<your.load.library>(SYMBOLIC)
//L.SYSPRINT DD SYSOUT=*
//L.SYSIN DD DUMMY
和 JCL 来执行它:
//JOBLIB DD DISP=SHR,DSN=<your.load.library>
//*
//STEP EXEC PGM=SYMBOLIC,PARM='THIS IS MY PARAMETER'
//SYSUT2 DD SYSOUT=*
提交这个和作业循环,你必须取消它。您将 'THIS IS MY PARAMETER' 写入 SYSUT2,但 WTO 显示:
+SIMSG001 OPEN successful.
+SIMSG003 writing to file
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
永远。
将 SYSUT2 更改为:
//SYSUT2 DD DISP=(MOD,PASS),
// DSN=&AMSCNTL,
// UNIT=SYSDA,
// SPACE=(TRK,1)
有效(我知道我还有一个步骤可以将临时文件生成到 Sysout)。
因此,将 FILE1 (SYSUT2) 设置为 SYSOUT 会导致损坏,因此 R14 似乎得到恢复只是为了指向 SIMSG004 的 WTO。
这是一个旧程序,所以它应该可以工作。在过去的 4 年里,我没有做过多少汇编程序,但有一些使用链接堆栈和相对寻址的代码,但我想首先坚持使用一些简单的基本位移代码来教这位同事。
知道哪里出了问题吗?
保存寄存器后没有建立新的寄存器保存区。因此,R13 仍然指向同一区域,下一个保存寄存器将覆盖并破坏初始 return 地址(以及更多)。
PUT 宏将为实际数据集和 SYSOUT (JESx) 数据集调用不同的代码。区别肯定在那里:如果 sysout 的 PUT 例程将寄存器存储在 R13 中的地址,则保存区域中的 return 地址 (R14) 现在将成为 PUT 之后的指令。因此循环。
对于不可重入代码,在入口处应如下所示:
...
LR R12,R15 .R12 -> entry point
USING SYMBOLIC,R12 .Establish addressability
* Establish addressability to new save area and chain the save areas
ST R13,SAVEAREA+4 Set backward chain pointer
LR R15,R13
LA R13,SAVEAREA Let R13 point to new SA
ST R13,8(,R15) Set forward chain pointer
并且在重新调整之前,取回调用方 SA 的可寻址性:
RETURN DS 0H
...
* Establish addressability to caller's SA
L R13,4(,R13)
XR R15,R15 .Clear R15 (RC=0)
RETURN (14,12),RC=(15) .Restore caller's regs and return
最后,您需要定义自己的保存区域:
...
*****************************************************************
OUTREC DC 80C' ' .OUTPUT CARD IMAGE
*****************************************************************
...
SAVEAREA DS 18F
...
与@phunsoft 相同的答案,但更多的是为什么。 WTO
和 OPEN
执行 SVC,因此不需要保存区域; CLOSE
也是。但是,PUT
是 branch and set register
。您需要分配一个 72 字节的 SAVEAREA
,或 GETMAIN
,一个或任何您想要的。如果您将它放在现有的 CSECT
中,则它不可重入,但那是另一天的事了。这意味着,当您 return 时,它会尝试重新加载您未分配的 SAVEAREA
和 return 到 PUT
之后,这是您的循环即将到来的地方来自.
在我的系统上是
.PUT output record
000000A6 4110 C1D0 000001D0 78+ LA 1,FILE1 LOAD PARAMETER REG 1 02-IHBINNRA
000000AA 4100 C180 00000180 79+ LA 0,OUTREC LOAD PARAMETER REG 0 02-IHBINNRA
000000AE 1FFF 80+ SLR 15,15 CLEAR REGISTER FOR ICM @L1A 01-PUT
000000B0 BFF7 1031 00000031 81+ ICM 15,7,49(1) LOAD PUT ROUTINE ADDRESS @L1C 01-PUT
000000B4 0DEF 82+ BASR 14,15 LINK TO PUT ROUTINE @L3C 01-PUT
因此 PUT
保存在原始保存区域,当发出 return 时,您跳回到 PUT returned.
之后
好吧,我忍不住了。这是一个更好的序言
TITLE 'TEST PROGRAM'
SYMBOLIC CSECT
ASMDREG .Register equates
SAVE (14,12),,'SYMBOLIC PARM SUB &SYSDATE &SYSTIME'
LR R12,R15 .R12 -> entry point
USING SYMBOLIC,R12 .Establish addressability
在序言中添加这些
GETMAIN LV=72
ST R13,4(R1)
LR R13,R1
然后,在尾声
LR R2,R13
FREEMAIN LV=72,LA=(R2)
L R13,4(R13)
LM R14,R12,12(R13)
LA R15,0
BR R14
SR
与 XR
与 LA
但辩论所消耗的时间远远超过任何时钟周期所花费的时间。
所以,这就是为什么您需要一个 SAVEAREA。但由于这是一个 OG 24 位汇编程序,您不必担心。以前16MB就够了。看起来 JES2 拦截了 SYSOUT 并做了一些魔术,但无论您的 DD 偏好如何,以上内容都会起作用。
我希望 JES 不相信任何人会正确地执行 SAVEAREA,而这正是我会做的
好的 - 我确定我在做一些愚蠢的事情,但我看不到它。
我有一个小的示例汇编程序,我将提供给想学习汇编程序的同事,但它有一个奇怪的错误,我需要先解决。 .
当输出文件 (DDNAME SYSUT2) 是一个 80 字节的临时文件时,它工作正常。将 SYSUT2 更改为 SYSOUT=* 并从 'Closing file' WTO 循环。
程序如下:
//C.SYSLIB DD DISP=SHR,DSN=SYS1.MACLIB
// DD DISP=SHR,DSN=SYS1.MODGEN
// DD DISP=SHR,DSN=SYS1.ASM.SASMMAC2
//* DD DISP=SHR,DSN=JOCS065.STEVE.SOURCE
- - - - - - - - - - - - - - - - 4 Line(s) not Displayed
TITLE 'TEST PROGRAM'
SYMBOLIC CSECT
ASMDREG .Register equates
SAVE (14,12),,'SYMBOLIC PARM SUB &SYSDATE &SYSTIME'
LR R12,R15 .R12 -> entry point
USING SYMBOLIC,R12 .Establish addressability
* Get the parm passed
L R1,0(R1) .R1 -> parm
LTR R1,R1 .Is there one?
BZ RETURN .No - return
* We have a parm
LH R2,0(R1) .R2 = PARM LENGTH
LTR R2,R2 .parm length = 0?
BZ RETURN . Yes - return
* And the parm has length
BCTR R2,0 .Decrement length for move
EX R2,SETOUT .Move parm to output
* Open output file and write parm to output
LA R4,FILE1 .R4 -> DCB for output file.
USING IHADCB,R4 .Establish addressability
OPEN (FILE1,OUTPUT) .Open log file
TM DCBOFLGS,DCBOFOPN .Open successful ?
BZ BADOPEN .No - go to error routine
WTO 'SIMSG001 OPEN successful.'
DROP R4
WTO 'SIMSG003 writing to file'
PUT FILE1,OUTREC .PUT output record
WTO 'SIMSG004 Closing file...'
CLOSE (FILE1) .close files
WTO 'SIMSG005 Returning to caller...'
B RETURN .Return
* EXecute instructions
SETOUT MVC OUTREC(0),2(R1)
*****************************************************************
* PROGRAM TERMINATION
*****************************************************************
RETURN DS 0H
WTO 'SIMSG006 RESTORING REGISTERS AND RETURNING'
XR R15,R15 .Clear R15 (RC=0)
RETURN (14,12),RC=(15) .Restore caller's regs and return
BADOPEN DS 0H
WTO 'SIMSG002 OPEN failed.'
B RETURN
*****************************************************************
* STORAGE AREAS
*****************************************************************
OUTREC DC 80C' ' .OUTPUT CARD IMAGE
*****************************************************************
* MACROS AND LITERALS
*****************************************************************
PRINT NOGEN
FILE1 DCB RECFM=F,LRECL=80,BLKSIZE=80, X
DSORG=PS,DDNAME=SYSUT2,MACRF=PM
DCBD
PRINT GEN
*
LTORG LITERAL STORAGE
END
//L.SYSLMOD DD DISP=SHR,DSN=<your.load.library>(SYMBOLIC)
//L.SYSPRINT DD SYSOUT=*
//L.SYSIN DD DUMMY
和 JCL 来执行它:
//JOBLIB DD DISP=SHR,DSN=<your.load.library>
//*
//STEP EXEC PGM=SYMBOLIC,PARM='THIS IS MY PARAMETER'
//SYSUT2 DD SYSOUT=*
提交这个和作业循环,你必须取消它。您将 'THIS IS MY PARAMETER' 写入 SYSUT2,但 WTO 显示:
+SIMSG001 OPEN successful.
+SIMSG003 writing to file
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
+SIMSG004 Closing file...
+SIMSG005 Returning to caller...
+SIMSG006 RESTORING REGISTERS AND RETURNING
永远。
将 SYSUT2 更改为:
//SYSUT2 DD DISP=(MOD,PASS),
// DSN=&AMSCNTL,
// UNIT=SYSDA,
// SPACE=(TRK,1)
有效(我知道我还有一个步骤可以将临时文件生成到 Sysout)。
因此,将 FILE1 (SYSUT2) 设置为 SYSOUT 会导致损坏,因此 R14 似乎得到恢复只是为了指向 SIMSG004 的 WTO。
这是一个旧程序,所以它应该可以工作。在过去的 4 年里,我没有做过多少汇编程序,但有一些使用链接堆栈和相对寻址的代码,但我想首先坚持使用一些简单的基本位移代码来教这位同事。
知道哪里出了问题吗?
保存寄存器后没有建立新的寄存器保存区。因此,R13 仍然指向同一区域,下一个保存寄存器将覆盖并破坏初始 return 地址(以及更多)。
PUT 宏将为实际数据集和 SYSOUT (JESx) 数据集调用不同的代码。区别肯定在那里:如果 sysout 的 PUT 例程将寄存器存储在 R13 中的地址,则保存区域中的 return 地址 (R14) 现在将成为 PUT 之后的指令。因此循环。
对于不可重入代码,在入口处应如下所示:
...
LR R12,R15 .R12 -> entry point
USING SYMBOLIC,R12 .Establish addressability
* Establish addressability to new save area and chain the save areas
ST R13,SAVEAREA+4 Set backward chain pointer
LR R15,R13
LA R13,SAVEAREA Let R13 point to new SA
ST R13,8(,R15) Set forward chain pointer
并且在重新调整之前,取回调用方 SA 的可寻址性:
RETURN DS 0H
...
* Establish addressability to caller's SA
L R13,4(,R13)
XR R15,R15 .Clear R15 (RC=0)
RETURN (14,12),RC=(15) .Restore caller's regs and return
最后,您需要定义自己的保存区域:
...
*****************************************************************
OUTREC DC 80C' ' .OUTPUT CARD IMAGE
*****************************************************************
...
SAVEAREA DS 18F
...
与@phunsoft 相同的答案,但更多的是为什么。 WTO
和 OPEN
执行 SVC,因此不需要保存区域; CLOSE
也是。但是,PUT
是 branch and set register
。您需要分配一个 72 字节的 SAVEAREA
,或 GETMAIN
,一个或任何您想要的。如果您将它放在现有的 CSECT
中,则它不可重入,但那是另一天的事了。这意味着,当您 return 时,它会尝试重新加载您未分配的 SAVEAREA
和 return 到 PUT
之后,这是您的循环即将到来的地方来自.
在我的系统上是
.PUT output record
000000A6 4110 C1D0 000001D0 78+ LA 1,FILE1 LOAD PARAMETER REG 1 02-IHBINNRA
000000AA 4100 C180 00000180 79+ LA 0,OUTREC LOAD PARAMETER REG 0 02-IHBINNRA
000000AE 1FFF 80+ SLR 15,15 CLEAR REGISTER FOR ICM @L1A 01-PUT
000000B0 BFF7 1031 00000031 81+ ICM 15,7,49(1) LOAD PUT ROUTINE ADDRESS @L1C 01-PUT
000000B4 0DEF 82+ BASR 14,15 LINK TO PUT ROUTINE @L3C 01-PUT
因此 PUT
保存在原始保存区域,当发出 return 时,您跳回到 PUT returned.
好吧,我忍不住了。这是一个更好的序言
TITLE 'TEST PROGRAM'
SYMBOLIC CSECT
ASMDREG .Register equates
SAVE (14,12),,'SYMBOLIC PARM SUB &SYSDATE &SYSTIME'
LR R12,R15 .R12 -> entry point
USING SYMBOLIC,R12 .Establish addressability
在序言中添加这些
GETMAIN LV=72
ST R13,4(R1)
LR R13,R1
然后,在尾声
LR R2,R13
FREEMAIN LV=72,LA=(R2)
L R13,4(R13)
LM R14,R12,12(R13)
LA R15,0
BR R14
SR
与 XR
与 LA
但辩论所消耗的时间远远超过任何时钟周期所花费的时间。
所以,这就是为什么您需要一个 SAVEAREA。但由于这是一个 OG 24 位汇编程序,您不必担心。以前16MB就够了。看起来 JES2 拦截了 SYSOUT 并做了一些魔术,但无论您的 DD 偏好如何,以上内容都会起作用。
我希望 JES 不相信任何人会正确地执行 SAVEAREA,而这正是我会做的