OK -I'm sure I'm doing something stupid, but I can't see it.
I have a small sample assembler program which I'm going to provide to a colleague who wants to learn assembler, but it has a weird bug I need to iron out first. .
When the output file (DDNAME SYSUT2) is a temporary 80-byte file, it works fine. Change SYSUT2 to SYSOUT=* and it loops from the 'Closing file' WTO.
So here's the program:
//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
and JCL to execute it:
//JOBLIB DD DISP=SHR,DSN=<your.load.library>
//*
//STEP EXEC PGM=SYMBOLIC,PARM='THIS IS MY PARAMETER'
//SYSUT2 DD SYSOUT=*
Submit this and the job loops and you have to cancel it. You get 'THIS IS MY PARAMETER' written to SYSUT2 but the WTOs show:
+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
forever.
Change SYSUT2 to :
//SYSUT2 DD DISP=(MOD,PASS),
// DSN=&AMSCNTL,
// UNIT=SYSDA,
// SPACE=(TRK,1)
works (I know as I had another step to GENER the temp file to Sysout).
So having FILE1 (SYSUT2) being SYSOUT causes a corruption such that it appears R14 gets restored only to point back to the WTO for the SIMSG004.
This is an old program so it should work. I haven't done much assembler of the last 4 years but have some code using the linkage stack and relative addressing but want to stick with some simple base-displacement code first for teaching this colleague.
Any idea where this is going wrong?
You don't establish a new register save area after saving the registers. So, R13 still points to the same area and the next one saving registers will overwrite, and destroy the the initial return address (and more).
The PUT macro will call different code for real data sets, and for SYSOUT (JESx) data sets. The difference must be there: If the PUT routine for sysout stores registers at the address in R13, the return address (R14) in the save area will now be the instruction after the PUT. Thus the loop.
For non-reentrant code this should look like this at entry:
...
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
And before retuning, get back addressability to caller's 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
Finally, you need to define your own save area:
...
*****************************************************************
OUTREC DC 80C' ' .OUTPUT CARD IMAGE
*****************************************************************
...
SAVEAREA DS 18F
...