Navigating through control block, error



High Level Assembler(HLASM) for MVS & VM & VSE

Navigating through control block, error

Postby eaglei22 » Tue Feb 21, 2012 8:13 am

Hi,

I'm working on an assignment for class, so I'm still not very literate with assembly language, and we are working on Control Blocks. I'm a grad student, and before this class I've taken a regular Assembly language class about 3 yrs ago. This is a class on the Z/Os. So my Assembly skills are pretty rusty.

On to the question, we are to navigate through a set of task related control blocks, I'm getting stuck when moving the Jobname from the TIOT to JOBNAME in the GETTIOT Routine.. I keep getting an ABEND when I do MVC JOBNAME(8),TIOCNJOB. Well actually when I print it.. is when I get the actual error.

Here is the output from the run.
http://ideone.com/PtapO

//........ JOB ,'JC',MSGCLASS=H,REGION=2048K 
//STEP1 EXEC ASMACLG
//C.SYSLIB DD DSN=SYS1.MACLIB,DISP=SHR
//         DD DSN=KC02.SYS2.MACLIB,DISP=SHR
//         DD DSN=KC02.CSCI464.MACLIB,DISP=SHR
//SYSPRINT DD  SYSOUT=*
//SYSIN   DD *
         COPY ASMMSP
         PRINT NOGEN
         EQUREGS
MAIN CSECT
         STM   14,12,12(13)     SAVES ALL CALLING REGS EXCEPT R13
         LR    12,15            LOADS ADDRESS OF MAIN INTO R12
         USING MAIN,12          SETS R12 AS BASE REGISTER
         LA    14,MAINSAVE      WHERE REGISTERS ARE STORED WHEN CALL
         ST    13,4(,14)        BACKWARD POINTER STORED
         ST    14,8(,13)        FORWARD POINTER STORED
         LR    13,14            R13 POINTED TO MAIN'S SAVE AREA
         PGMDUMP
*
* Csect main processing logic goes here.
*
         BAL   R10,GETPSA       GETS PSA
         BAL   R10,GETTCB       GETS TCB
         BAL   R10,GETTIOT      GETS TIOT
         XPRNT JOBNAME,8

*
         L     13,4(,13)        LOADS ADDRESS OF CALLING ROUTINE REGS
         LM    14,12,12(13)     RELOADS CALLING ROUTINE'S REGISTERS
         BR    14               RETURN CONTROL       
***********************************************************************
*        STORAGE FOR MAIN                                             *
***********************************************************************
         LTORG
MAINSAVE DS    18F
*
*
*---------------------------------------------------------------------*
*        GETPSA Routine - get the PSA ADDR                            *
*---------------------------------------------------------------------*
GETPSA   DS    0H                   Routine entry point.
         STM   R0,R15,PSAVE         SAVES ALL REGS
*
         LA    R5,0                 GET THE ADDR OF PSA
         USING PSA,R5               SET ADDRESSABILITY TO PSA
*
         LM    R6,R4,PSAVE          RESTORES ALL REGISTERS BUT 5
         BR    R10                  RETURN TO MAIN
***********************************************************************
*        STORAGE FOR GETPSA                                           *
***********************************************************************
PSAVE    DS    16F       REGISTERS SAVED HERE
*
*
*---------------------------------------------------------------------*
*        GETTCB Routine - get the TCB ADDR                            *
*---------------------------------------------------------------------*
GETTCB   DS    0H                   Routine entry point.
         STM   R0,R15,TSAVE         SAVES ALL REGS
*
         L     R5,PSATOLD           GET THE ADDR OF TCB FROM PSA
         USING TCB,R5               SET ADDRESSABILITY TO TCB
*
         LM    R6,R4,TSAVE          RESTORES ALL REGISTERS BUT 5
         BR    R10                  RETURN TO MAIN
***********************************************************************
*        STORAGE FOR GETTCB                                           *
***********************************************************************
TSAVE    DS    16F       REGISTERS SAVED HERE
*
*
*---------------------------------------------------------------------*
* GETTIOT Routine - get the TIOT ADDR AND STORE JOB AND STEP NAME     *
*---------------------------------------------------------------------*
GETTIOT  DS    0H                   Routine entry point.
         STM   R0,R15,TIOSAVE       SAVES ALL REGS
*
         L     R6,TCBTIO            GET THE ADDR OF TIOT FROM TCB
         USING TIOT1,R6             SET ADDRESSABILITY TO TIOT
         MVC   JOBNAME(8),TIOCNJOB  STORE JOBNAME
         MVC   STEPNAME(8),TIOCPSTN STORE STEP NAME
*
         LM    R7,R5,TIOSAVE        RESTORES ALL REGISTERS BUT 6
         BR    R10                  RETURN TO MAIN
***********************************************************************
*        STORAGE FOR GETTIOT                                          *
***********************************************************************
TIOSAVE  DS    16F       REGISTERS SAVED HERE
*
JOBNAME  DS    CL8'A'    STORE JOB NAME
STEPNAME DS    CL8       STORE STEP NAME FOR NON-PROCS
*
*
*
***********************************************************************
***           DSECTS FOR SYSTEM CONTROL BLOCKS                      ***
***********************************************************************
*---------------------------------------------------------------------*
*        TIOT Dsect.                                                  *
*---------------------------------------------------------------------*
TIOT     DSECT
         IEFTIOT1
*---------------------------------------------------------------------*
*        PSA Dsect.                                                   *
*---------------------------------------------------------------------*
         IHAPSA
*---------------------------------------------------------------------*
*        TCB Dsect.                                                   *
*---------------------------------------------------------------------*
         IKJTCB
         IHAEPIE
/*
//L.SYSLIB   DD DSN=KC02293.SYS2.CALLIB,DISP=SHR
//G.STEPLIB  DD DSN=KC02293.CSCI464.LOADLIB,DISP=SHR
//G.SPX$DUMP DD SYSOUT=*
//G.XPRNT DD SYSOUT=*
//G.XSNAPOUT DD SYSOUT=*
eaglei22
 
Posts: 8
Joined: Sat Jan 28, 2012 2:30 am
Has thanked: 0 time
Been thanked: 0 time

Re: Navigating through control block, error

Postby steve-myers » Tue Feb 21, 2012 11:39 am

You have two additional, non-standard macro libraries, and you have a COPY of some unknown member. You also use a non-standard macro, XPRNT, presumably from one of the non-standard macro libraries. How can we help you with all this non-standard junk in your program?

The PSA always starts at location 0 from the point of view of a normal, problem state program. Why do you have this GETPSA routine? The following shows 3 methods to get the jobname from the TIOT.
SHOWJOB  CSECT
         IHAPSA ,
         CVT   DSECT=YES
         IKJTCB ,
TIOT     DSECT
         IEFTIOT1 ,
SHOWJOB  CSECT
         USING *,12
         SAVE  (14,12),,*
         LR    12,15
         LA    15,SAVEAREA
         ST    15,8(,13)
         ST    13,4(,15)
         LR    13,15
* "TRADITIONAL" METHOD TO GET THE TIOT
         L     15,CVTPTR
         L     15,CVTTCBP-CVTMAP(,15)
         L     15,4(,15)
         L     2,TCBTIO-TCB(,15)
* MVS VARIANT OF THE "TRADITIONAL" METHOD,
* WILL NOT WORK IN SOME OS/360 SYSTEMS
         L     15,PSATOLD-PSA
         L     2,TCBTIO-TCB(,15)
* "OFFICIAL" METHOD TO GET THE TIOT
         EXTRACT RESULTS,FIELDS=TIOT
         L     2,RESULTS
         USING TIOT,2
         MVC   JOBNAME,TIOCNJOB
         ...
SAVEAREA DC    18F'0'
JOBNAME  DC    CL8' '
RESULTS  DC    A(*-*)
CVTPTR is defined in the CVT macro and specifies the offset of the CVT pointer in the PSA. CVTTCBP points to PSATNEW; PSATOLD is always 4 bytes after PSATNEW. Printing the jobname is an exercise for you.
steve-myers
Global moderator
 
Posts: 2105
Joined: Thu Jun 03, 2010 6:21 pm
Has thanked: 4 times
Been thanked: 243 times

Re: Navigating through control block, error

Postby steve-myers » Tue Feb 21, 2012 12:04 pm

Going back to your original code
  • Why are you defining register save areas for your GETxxx routines? You have a save area that register 13 points to, provided that non-standard junk does a normal save area setup like my code does.
  • I didn't trace through your GETxxx routines, but I suspect your register restore is wiping out your result registers. The usual convention for this type of routine is to return the result address in reg 1, not in registers 2 through 12. Using these rules, your GETPSA becomes
    GETPSA   SR    1,1
             BR    10
    I didn't save any registers because the only altered register is the register with the returned address.
  • Your program exit code does not set a return code in register 15 before you exit.
steve-myers
Global moderator
 
Posts: 2105
Joined: Thu Jun 03, 2010 6:21 pm
Has thanked: 4 times
Been thanked: 243 times

Re: Navigating through control block, error

Postby eaglei22 » Tue Feb 21, 2012 12:25 pm

Thanks for the response, I'm not a 100% on the JCL, the professor gave us that. I know the macro library is our schools, but the copy ASMMSP, according to the assembled job states this:

THIS PROCEDURE RUNS THE HIGH LEVEL ASSEMBLER, LINK-EDITS THE
NEWLY ASSEMBLED PROGRAM AND RUNS THE PROGRAM AFTER
THE LINK-EDIT IS ACCOMPLISHED.

I found my error, it was in my LM coming back out of the subroutine, I was STM all registers, but then only Loading all but R5.. I did this because I don't 100% understand the macro. When I do lets say,

*---------------------------------------------------------------------*
*        GETPSA Routine - get the PSA ADDR                            *
*---------------------------------------------------------------------*
GETPSA   DS    0H                   Routine entry point.
          STM   R6,R4,PSAVE         SAVES ALL REGS
*
          LA    R5,0                      GET THE ADDR OF PSA
          USING PSA,R5                SET ADDRESSABILITY TO PSA
*
         LM    R6,R4,PSAVE          RESTORES ALL REGISTERS BUT 5
         BR    R10                       RETURN TO MAIN


And then branch back to main and then call the Gettcb routine which gets the address of the TCB from PSATOLD

*---------------------------------------------------------------------*
*        GETTCB Routine - get the TCB ADDR                            *
*---------------------------------------------------------------------*
GETTCB   DS    0H                   Routine entry point.
         STM   R6,R4,TSAVE         SAVES ALL REGS
*
         L     R5,PSATOLD           GET THE ADDR OF TCB FROM PSA
         USING TCB,R5               SET ADDRESSABILITY TO TCB
*
         LM    R6,R4,TSAVE          RESTORES ALL REGISTERS BUT 5
         BR    R10                  RETURN TO MAIN


PSATOLD will hold the value regardless if I return R5 right? Sorry if that question seems dumb, but as stated it's been 3 yrs since I touched assembly.. So I'm relearning a lot.

Thanks for the Example that helps a lot as well..
Here is my working code which actually prints out the job name.

//K........ JOB ,'JC',MSGCLASS=H,REGION=2048K 
//STEP1 EXEC ASMACLG
//C.SYSLIB DD DSN=SYS1.MACLIB,DISP=SHR
//         DD DSN=KC02293.SYS2.MACLIB,DISP=SHR
//         DD DSN=KC02293.CSCI464.MACLIB,DISP=SHR
//SYSPRINT DD  SYSOUT=*
//SYSIN   DD *
         COPY ASMMSP
         PRINT NOGEN
         EQUREGS
MAIN CSECT
         STM   14,12,12(13)     SAVES ALL CALLING REGS EXCEPT R13
         LR    12,15            LOADS ADDRESS OF MAIN INTO R12
         USING MAIN,12          SETS R12 AS BASE REGISTER
         LA    14,MAINSAVE      WHERE REGISTERS ARE STORED WHEN CALL
         ST    13,4(,14)        BACKWARD POINTER STORED
         ST    14,8(,13)        FORWARD POINTER STORED
         LR    13,14            R13 POINTED TO MAIN'S SAVE AREA
         PGMDUMP
*
* Csect main processing logic goes here.
*
*
         BAL   R10,GETPSA       GETS PSA
         BAL   R10,GETTCB       GETS TCB
         BAL   R10,GETTIOT      GETS TIOT
         XPRNT JOBNAME,8
         L     13,4(,13)        LOADS ADDRESS OF CALLING ROUTINE REGS
         LM    14,12,12(13)     RELOADS CALLING ROUTINE'S REGISTERS
         BR    14               RETURN CONTROL       
***********************************************************************
*        STORAGE FOR MAIN                                             *
***********************************************************************
         LTORG
MAINSAVE DS    18F
*
*
*---------------------------------------------------------------------*
*        GETPSA Routine - get the PSA ADDR                            *
*---------------------------------------------------------------------*
GETPSA   DS    0H                   Routine entry point.
          STM   R6,R4,PSAVE         SAVES ALL REGS
*
          LA    R5,0                 GET THE ADDR OF PSA
          USING PSA,R5               SET ADDRESSABILITY TO PSA
*
         LM    R6,R4,PSAVE          RESTORES ALL REGISTERS BUT 5
         BR    R10                  RETURN TO MAIN
***********************************************************************
*        STORAGE FOR GETPSA                                           *
***********************************************************************
PSAVE    DS    15F       REGISTERS SAVED HERE
*
*
*---------------------------------------------------------------------*
*        GETTCB Routine - get the TCB ADDR                            *
*---------------------------------------------------------------------*
GETTCB   DS    0H                   Routine entry point.
         STM   R6,R4,TSAVE         SAVES ALL REGS
*
         L     R5,PSATOLD           GET THE ADDR OF TCB FROM PSA
         USING TCB,R5               SET ADDRESSABILITY TO TCB
*
         LM    R6,R4,TSAVE          RESTORES ALL REGISTERS BUT 5
         BR    R10                  RETURN TO MAIN
***********************************************************************
*        STORAGE FOR GETTCB                                           *
***********************************************************************
TSAVE    DS    15F       REGISTERS SAVED HERE
*
*
*
*---------------------------------------------------------------------*
* GETTIOT Routine - get the TIOT ADDR AND STORE JOB AND STEP NAME     *
*---------------------------------------------------------------------*
GETTIOT  DS    0H                   Routine entry point.
         STM   R7,R5,TIOSAVE        SAVES ALL REGS
*
         L     R6,TCBTIO            GET THE ADDR OF TIOT FROM TCB
         USING TIOT1,R6             SET ADDRESSABILITY TO TIOT
         MVC   JOBNAME(8),TIOCNJOB  STORE JOBNAME
*         MVC   STEPNAME(8),TIOCPSTN STORE STEP NAME
*
         LM    R7,R5,TIOSAVE        RESTORES ALL REGISTERS BUT 6
         BR    R10                  RETURN TO MAIN
***********************************************************************
*        STORAGE FOR GETTIOT                                          *
***********************************************************************
TIOSAVE  DS    15F       REGISTERS SAVED HERE
*
JOBNAME  DC    CL8'A'    STORE JOB NAME
STEPNAME DS    CL8       STORE STEP NAME FOR NON-PROCS
*
*
*
*
***********************************************************************
***           DSECTS FOR SYSTEM CONTROL BLOCKS                      ***
***********************************************************************
*---------------------------------------------------------------------*
*        TIOT Dsect.                                                  *
*---------------------------------------------------------------------*
TIOT     DSECT
         IEFTIOT1
*---------------------------------------------------------------------*
*        PSA Dsect.                                                   *
*---------------------------------------------------------------------*
         IHAPSA
*---------------------------------------------------------------------*
*        TCB Dsect.                                                   *
*---------------------------------------------------------------------*
         IKJTCB
         IHAEPIE
/*
//L.SYSLIB   DD DSN=KC02293.SYS2.CALLIB,DISP=SHR
//G.STEPLIB  DD DSN=KC02293.CSCI464.LOADLIB,DISP=SHR
//G.SPX$DUMP DD SYSOUT=*
//G.XPRNT DD SYSOUT=*
//G.XSNAPOUT DD SYSOUT=*


and thanks for the return code reminder. I'm gonna set that as well.

As for the logic of my subroutines.. I'm not sure, that is how I was taught it looked like from going over my old programs in my first Assembly class. I'm always up for constructive criticism though to do things the better way. :)

I made a bunch of subroutines, I guess to keep track of things better I guess. Maybe it's not the best way?
eaglei22
 
Posts: 8
Joined: Sat Jan 28, 2012 2:30 am
Has thanked: 0 time
Been thanked: 0 time

Re: Navigating through control block, error

Postby steve-myers » Tue Feb 21, 2012 1:23 pm

eaglei22 wrote:... I made a bunch of subroutines, I guess to keep track of things better I guess. Maybe it's not the best way?
Actually that's an issue with no real stock answer. In a way you have three options:
  • Simple in-line. This is best for something like your GETPSA. Actually, since the PSA is always less than 4K (and you can't look between 512 and 4K anyway), you don't need it; you reference the storage directly using reg 0 as a base register. That is the effect of PSATOLD-PSA.
  • In-line, but implemented using a macro. I have been developing a program that reads through a VB dataset. Part of the program logic tests for a fixed character string at a known offset in the record. However, before the compare you must verify the record is long enough that the string can exist in the record. Since there are several of these strings, a macro was the best solution. I had a stock macro for this, which I copied into the program. Then I went and improved the macro, and I have replaced my stock macro with the new macro.
  • A subroutine. Now here we get complicated. If the code can be used for many programs, a subroutine can be useful. If the code is complex, and is used more than once, then a subroutine is a best solution. Again, going back to my program, there is code to convert a date expressed as ddmmmyy (e.g., 20FEB12) to the "usual" MVS "Julian" date. This code is done twice, so a subroutine was the logical choice. On the other hand there are some small subroutines called once. In this case in-line code would have been the "better" choice, but doing it as a subroutine, which I can do entirely by memory, probably made more sense, at least to me. On the other hand, there is one place where I goofed in this program. I had code I originally thought I would use once. It turned out I did it twice. Not a huge amount of code, but a little tricky, so a subroutine would have been the better solution.
steve-myers
Global moderator
 
Posts: 2105
Joined: Thu Jun 03, 2010 6:21 pm
Has thanked: 4 times
Been thanked: 243 times

Re: Navigating through control block, error

Postby eaglei22 » Tue Feb 21, 2012 2:07 pm

Thanks Steve, that sheds more light on to better structure my next program :)
eaglei22
 
Posts: 8
Joined: Sat Jan 28, 2012 2:30 am
Has thanked: 0 time
Been thanked: 0 time

Re: Navigating through control block, error

Postby steve-myers » Tue Feb 21, 2012 10:05 pm

One more comment about subroutines.

Saving and restoring registers is often a major cost in using subroutines, especially small routines like your GETxxx routines. Indeed, reducing the cost of using a subroutine was a major reason for the addition of XPLINK in the IBM C++ product.

If you look at the cost drivers in traditional "standard" linkage, you'll find STM 14,12,12(13) sucks up most of the CPU time, especially if the save area is not in the storage cache. The fundamental problem is that more often than not, way too many registers are being saved. Not saving registers is often the major justification for doing some code inline.

Again, going back to the program I've been developing. Twenty years ago I started writing C programs. One thing I developed a liking for was the qsort library function, so I wanted something like it for my Assembler programs. One feature of the qsort library function is its use of a compare function. A few years later when I wrote a qsort for use in my Assembler programs I kept this concept; my qsort calls a compare function using standard linkage, like so -

CALL COMPARE,(DATA1,DATA2)

Right away you can see a concept problem; the CALL is building a parameter list in storage, which is not real fast. As I'm sure you can imagine, calling a compare function, as well as the compare function itself, represent a major consumer of CPU time in a sort. Now, I do not want to mess with my qsort subroutine, but I can try to be creative with my compare functions, and minimizing standard linkage costs is one thing I absolutely can do.

When I first started doing these functions they were running on a 3090, which did not have the relative branch instructions. This meant I needed a base register for the branches in the compare. My early compare functions looked like this -
COMPARE  SAVE  (14,2)
         BALR  2,0
         USING *,2
         LM    14,0(,1)
         L     1,4(,1)
         LA    15,1
* Do the actual compare here
         BH    EXIT
         BL    LOW
         SR    15,15
         B     EXIT
LOW      LNR   15,15
EXIT     RETURN (14,2),RC=(15)
I used the same return convention as the C library compare function, less than 0 for data1 less than data2, 0 if they are equal, and greater than 0 if data1 is greater than data2. Now, I am saving 5 registers here, and using 4, though register 0 is often used in the compare. The RETURN is bad: it takes 2 instruction since the return code is in register 15, so LM 14,2,12(13) can't be used; the RETURN macro has to use -

L 14,12(,13)
LM 0,2,20(13)

The great advantage of relative branch instructions in these compare functions is you don't need a base register, so you don't have to save and restore it. The compare function becomes -
COMPARE  SAVE  (14,1)
         LM    14,0(,1)
         L     1,4(,1)
         LA    15,1
* Do the actual compare here
         JH    EXIT
         JL    LOW
         SR    15,15
         J     EXIT
LOW      LNR   15,15
EXIT     RETURN (14,1),RC=(15)
But wait a minute! An often unmentioned "feature" of standard linkage is you don't really need to restore registers 0 and 1 since the CALL macro uses them to prepare the parameter list. Since you don't have to restore them, you don't have to save them! Now the compare function becomes
COMPARE  SAVE  14
         L     14,0(,1)
         L     1,4(,1)
         LA    15,1
* Do the actual compare here
         JH    EXIT
         JL    LOW
         SR    15,15
         J     EXIT
LOW      LNR   15,15
EXIT     RETURN 14,RC=(15)
And, the RETURN macro just generates one instruction rather than 2, to restore just 1 register.
steve-myers
Global moderator
 
Posts: 2105
Joined: Thu Jun 03, 2010 6:21 pm
Has thanked: 4 times
Been thanked: 243 times

Re: Navigating through control block, error

Postby steve-myers » Wed Feb 22, 2012 6:09 am

Oops. Loking through my previous post, I realized

LM 14,0(,1)

in a couple of examples is wrong. It should be

L 14,0(,1)
steve-myers
Global moderator
 
Posts: 2105
Joined: Thu Jun 03, 2010 6:21 pm
Has thanked: 4 times
Been thanked: 243 times

Re: Navigating through control block, error

Postby steve-myers » Wed Feb 22, 2012 11:35 pm

Another issue is my qsort function calls the compare function using a reenterable CALL linkage, which is slower than the CALL I showed. The macro call is something like

L 15,compare-routine-address
CALL (15),((data1-reg),(data2-reg)),MF=(E,parmlist)

and the macro expands to

LA 1,parmlist
ST data1-reg,0(,1)
ST data2-reg,4(,1)
BALR 14,15
steve-myers
Global moderator
 
Posts: 2105
Joined: Thu Jun 03, 2010 6:21 pm
Has thanked: 4 times
Been thanked: 243 times

Re: Navigating through control block, error

Postby xboss » Thu Feb 23, 2012 11:51 pm

Eaglei22,
What school are you attending to take assembler class? Even I am looking forward to take some assembler class work.

Thanks.
xboss
 
Posts: 79
Joined: Mon Nov 29, 2010 10:55 am
Has thanked: 0 time
Been thanked: 0 time

Next

Return to Assembler

 


  • Related topics
    Replies
    Views
    Last post