M.S.G. Inc LOGO FREE HLASM Source Code - #STACK #UNSTACK

McColley Systems Software Inc.
If it's assembler, WE CAN HELP!
"Elegant Solutions for Your Processing Needs"


Home   Shared Spool Mods   ESSM!   Tip of the Month   Articles   Free Source   LINKS   ASSEMBLER SURVIVAL GUIDE   ABOUT US  


#STACK / #UNSTACK - my macros used to enter an exit subroutines using a stack area to save the linkage register in.

For many years I started most programs, like many programmers did by documenting what I would use each of the general purpose register for. This of course changed as I went along, but there were a few things that I did every time - I reserved a register (r13) for the save area pointer, - I reserved a base register or two, I reserved registers for use with dsects that I knew I would work with. I would always reserve at least one register for use with BAL or BAS instructions for sub-routine linkage - sometimes I would reserve two of them, one for normal BAS linkage, and one to be used for linkage from within other routines - a second level linkage. There are a number of problems that creep into your code when you start using more than one linkage level - more than one register for sub-routine calls, so I have begun using a linkage stack lately. It is a bit more overhead than simple BAS or BAL based sub-routine linkage, but the advantages outweigh the additional overhead in my opinion. A linkage stack works very simply. You pick a single register you can leave alone (don't use R0, R1, R13, R14, or R15) to point to the current location in the stack area - let's assume we will be using r9 for now. The stack area is simply a Software of fullwords used to save return addresses. Usually I find that four or five words is plenty of room to use with a stack area. Initially the register you pick to point to the current location in the stack (the stack register - remember we chose R9) simply points to the first word in the list.
When you need to call a sub-routine, you use a           BAS           R14,SUBRTN1
Instead of the expected BAS using your sub-routine linkage register. It should be safe to use R14, as it should be left alone for normal macro and service call linkages and we only need it to hold our return address for a couple of instructions. Then to use the linkage stack within SUBRTN1 your first few instructions should be -

DATA LABEL OP OPERANDS COMMENTS
  SUBRTN1 ST R14,0(,R9) SAVE RTN ADDR IN STACK
    LA R9,4(,R9) BUMP POINTER INTO STACK (FOR NEXT SUB-RTN)

Then the sub-routine should go ahead and do whatever it does, and when it it time to return you code something like the following;

DATA LABEL OP OPERANDS COMMENTS
    AHI R9,-4 BACK STACK POINTER UP TO OUR RTN ADDR
    L R14,0(,R9) LOAD OUR RTN ADDR IN R14
    BR R14 Return to Caller via R14

Now, all of that will work fine, and it's so simple there is no real need for a macro to help us out - unless we just want one. But this would all work a bit 'better' if the entry logic (#stack) and the exit or return logic (#unstack) were a bit more flexible. The entry code should check for 'stack overflow' meaning we have nested our sub-routines one level too deep, or more likely we are in a loop. It can do this if we prefill the last word in the stack with high values x'FFFFFFFF'. Further the #UNSTACK or return logic should be able to set a return code in R15, either a fixed value, or a value in another register. Of course we shouldn't be locked into using R9 for our stack register, so that should be variable. By using multiple linkage stack registers (each pointing to a seperate stack area) it is possible (although a bit to complicated for me to keep track of) to use more than one stack area at a time.

This is all done in the #STACK AND #UNSTACK macros that I have coded.

The #STACK macro accepts two variables - STK= specifies the stack register (the stack pointer) which defaults to R9 ( STK=R9 ). The other variable is specified with the RTN= keyword, which defaults to RTN=R14, which is probably good for most people.
The #UNSTACK macro accepts the same two STK and RTN variables which must match the #STACK variables which you are #UNSTACKing from. In addition it accepts an RC= keyword that sets the return code in R15. RC= can specify either a fixed value i.e. RC=16 or RC=0, or you may specify a register that contains the return code i.e. RC=(R4).

Finally, I offer up an example of actually using the #STACK and #UNSTACK macros and how they handle multiple levels of sub-routines.

DATA LABEL OP OPERANDS COMMENTS
  TWOLVLS CSECT    
    COPY REGEQU NORMAL REGISTER EQUATES
    USING TWOLVLS,12 SET ADDRESSABILITY
    BAKR 14,0 SAVE ALL REGS PSW ETC.
    LR R12,R15 SET OUR BASE REG
    LA R9,STCKAREA REQUIRED - INIT STACK POINTER
    MVS STCKEND,=X'FFFFFFFF' SET HIGH VALUES (END OF STACK)
  MAINLINE BAS R14,RTNLVL1 GO DO LEVEL 1 ROUTINE
  RETURNRF PR   RETURN TO CALLER- DONE!
         
  OVERFLOW WTO 'STACK OVERFLOW' REQUIRED ROUTINE - CALLED BY #STACK
    LA R15,64(0,0) SET REALLY HIGH RETURN CODE
    J RETURNRF RETURN RC IS IN R15
         
  RTNLVL1 #STACK   SAVE RTN ADDR ON STACK
    XR R0,R0 DO WHATEVER WORK WE DO...
    BAS R14,RTNLVL2 GO DO 2ND LEVEL ROUTINE. (COME BACK HERE)
    XR R15,R15 SET R15 = ZERO
    BAS R14,RTNLVL2 CALL 2ND LEVEL ROUTINE... AGAIN.
    #UNSTACK RC=(R15) END RTN1 ... RC IS IN R15
         
  RTNLVL2 #STACK   SAVE RTN ADDR ON STACK
    LHI R15,16 SET RC = 16...
    BAS R14,RTNLVL3 GO DO 3RD LEVEL ROUTINE. (COME BACK HERE)
    #UNSTACK RC=(R15) END RTN2 ... RC IS IN R15
         
  RTNLVL3 #STACK   SAVE RTN ADDR ON STACK
    LHI R2,32 PUT 32 IN R2...
    #UNSTACK RC=(R2) END RTN3 ... RC IS IN R2 ... IT'S 32
         
  SAVEAREA DS 18F SAVE AREA (JUST GOOD FORM)
  STCKAREA DS 3F ROOM FOR 3 LEVELS OF CALLS
  STCKEND DS F INDICATES END OF TABLE WHEN HIGH VALUES
    LT0RG    
    END TWOLVLS  

Click HERE to get a copy of the sample you can cut and paste into your 3270 session.

Click HERE to return to the free source main page.

" Remember - If It's Assembler - We can HELP!"

Feel free to Contact Us.

Last updated August 2011 - copyright © 2011 McColley Systems Software Inc.
Return to top of Page.