Page 1 of 2

Advice for writing and executing Assembler on the Mainframe

PostPosted: Fri May 27, 2016 1:52 pm
by deucalion0
Hey guys!

So I may be asking a lot here but I feel the advice I get here often saves me a lot of time and is often very helpful I have to ask.

I am trying in my spare time to learn Assembler on the Mainframe.

I can list the huge amount of resources I use if I need to.

I have some questions which I am finding it difficult to find answers.

I have written a lot of code in C#, Java and many web languages but getting my head around assembler is tricky.

The reason I want to learn Assembler is because I work with Mainframes and I am becoming more and more interested in z/OS and the architecture.

My head is spinning with the amount of information I have read with regards to Assembler.

What is the smallest Assembler program I can write that covers all or most of the fundamentals of a Mainframe Assembler program?

Once I have this code, is it going to be in a dataset and then I run some JCL using HLASM to link edit the code into a load module?

Once I have the load module how can I execute it and see it do something in order to see the code has run?

I want to learn how CSECTS come together and how I can zap code to make it abend and then read the dump to track down where it abended.

I want to do a lot more than this but if I could have any advice on how to do the things above that would be much appreciated.

Thank you!

Re: Advice for writing and executing Assembler on the Mainfr

PostPosted: Fri May 27, 2016 2:34 pm
by enrico-sorichetti
...
What is the smallest Assembler program I can write that covers all or most of the fundamentals of a Mainframe Assembler program?
...


such programs does not exist.
ANY arbitrary/illogic sequence of instruction is a <valid> assembler program ( as far as compilation is concerned )
if the addressing rules are satisfied

IMNSHO ;) from a general point of view ( let's not nitpick - please )
Assembler in se is not a real language ( with a formal definition like ALGOL,PL/1,REXX,...,)
it is a set of pretty basic rules and a few directives
that lets programmers interface the quirks
of the binary format of the MACHINE instruction set
of the general structure of a <machine instruction> program related to the register utilization for addressing instructions and data

You should notice that the macros normally used ( CALL for example ) are not described in the assembler manuals
but in the reference manuals of the host operating system.


the general environment is similar to COBOL/PL/1,C

a Source Program,
some include files ( COPY, <macro> )
an object deck ( output of the assembly)

some library subroutines ( only the one EXPLICITLY called )
pay attention, no language provide subroutines like in COBOL,PL/1,C
a load module

How to build and run the whole shebang
like a COBOL one

just start reading the Assembler reference .

more to come!

Re: Advice for writing and executing Assembler on the Mainfr

PostPosted: Fri May 27, 2016 6:05 pm
by steve-myers
deucalion0 wrote: ... What is the smallest Assembler program I can write that covers all or most of the fundamentals of a Mainframe Assembler program? ...

You can always replicate IEFBR14:
IEFBR14  CSECT
         SR    15,15
         BR    14
         END   IEFBR14
IEFBR14 has quite a lot of assumptions.
  • Register 14 specifies the address of the next instruction to execute when the program completes.
  • When the program is finished, register 15 has the binary return code for the program.
... Once I have this code, is it going to be in a dataset and then I run some JCL using HLASM to link edit the code into a load module?...
You've been around long enough to know this. By definition your program must be in a data set, because all Assembler programs I know about require their source to be in a data set. In this JCL, the data set is included in the JCL.
//A       EXEC HLASMC
//SYSIN    DD  *
IEFBR14  CSECT
         SR    15,15
         BR    14
         END   IEFBR14
You can also store your program text in a regular data set, depending on what you are comfortable doing. Back when I started we used punched cards, so more often than not the program text was in the JCL. These days punched cards are rather rare and, at least for me, program text is in a regular data set.
...then I run some JCL using HLASM to link edit the code into a load module?
Sigh. HLASM just assembles a program. It does not then prepare a load module. This is exactly like C++ on the mainframe. After the assembler completes, the object output for the program is then processed by a program now called the Binder to prepare a load module, just like C++ on the mainframe. For example -
//A       EXEC HLASMCL
//SYSIN    DD  *
IEFBR14  CSECT
         SR    15,15
         BR    14
         END   IEFBR14
//L.SYSLMOD DD -- data set where you want to store the load module for your program --
HLASM V1R6 Programmer's Guide will discuss this in more detail. The Binder is discussed in MVS Program Management User's Guide and Reference for your z/OS release.
... Once I have the load module how can I execute it and see it do something in order to see the code has run? ...
Since we have no idea what your program is doing, how can we help you with that??? z/OS does not have an IDE like toy machines; attempts to devise a checkout environment for mainframes, such as the PL/I checkout compiler in the 1970s, did not work out very well.

I use TSO TEST as described in TSO/E Command Reference for your z/OS release quite a lot, despite its many flaws. TEST, at least is available everywhere. Another popular tool is DBC, which I have never used because it, too, has many flaws.
... I want to learn how CSECTS come together and how I can zap code to make it abend and then read the dump to track down where it abended. ...
The Linkage Conventions chapter in MVS Assembler Services Guide for your z/OS release discusses this better than we could here.

We rarely "zap" code on a mainframe to make it ABEND. It usually ABENDs all by itself. Of course, you can easily insert

DC H'0'

into your program to make it ABEND at a location of your choosing. Another option is to use the ABEND macro, but this is rarely done for testing.

Dump analysis is too complex and difficult for this forum.

Re: Advice for writing and executing Assembler on the Mainfr

PostPosted: Sat May 28, 2016 4:37 pm
by willy jensen
Unfortunately there is no 'zOS Assembler for beginners' nor a free self-study as already mentioned. There are still some people offering courses, but not for free. And neither will I. So I suggest that you try to find a mentor in your organization.
This small sample only demonstrates one method for starting and ending a program, plus a bit of I/O thrown in. By the way, this is a assemble-link-go, so the module is not stored permanently.
But there is of course much more to assembler than that. First you must decide in which environment the program will run.
Search the internet for 'ibm assembler language tutorial' and similar and see what pops up.

//ASMMINI  JOB (WJ),'small asm pgm',CLASS=A,MSGCLASS=T,COND=(0,LT)
//*                                                                
//   EXEC HLASMCLG,PARM.C='TERM',PARM.L='RMODE(24),AMODE(31)'      
//C.SYSLIB  DD DISP=SHR,DSN=SYS1.MACLIB                            
//          DD DISP=SHR,DSN=SYS1.MODGEN                            
//C.SYSTERM DD SYSOUT=*                                            
//C.SYSIN   DD *                                                  
*PROCESS COMPAT(NOCASE,MACROCASE)                                  
         sysstate archlvl=2                                        
*                                                                  
* equate registers                                                
*                                                                  
r0       equ   0                                                  
r1       equ   1                                                  
r2       equ   2                                                  
r3       equ   3                                                  
r4       equ   4                                                  
r5       equ   5                                                  
r6       equ   6                                                  
r7       equ   7                                                  
r8       equ   8                                                  
r9       equ   9                                                  
r10      equ   10                                                  
r11      equ   11                                                  
r12      equ   12                                                  
r13      equ   13                                                  
r14      equ   14                                                  
r15      equ   15                                                  
*                                                                  
* Macro for clearing area                                          
*                                                                  
         Macro                                                    
         CLEAR &area                                              
         mvi   &area,c' '              clear                      
         mvc   &area+1(l'&area-1),&area    target                  
         Mend                                                      
*                                                                  
* Program prolog                                                  
*                                                                  
         using ASMMINI,r12                                        
ASMMINI  amode 31                                                  
ASMMINI  rmode any                                                
ASMMINI  csect                                                    
         save  (14,12)                                            
         larl  r12,ASMMINI                                        
         sam31                                                    
* get dynamic storage                                              
         getmain R,lv=workln                                      
         lr    r10,r1                                              
         using work,r10                                            
* chain saveareas re linkage conventions                          
         la    r14,sa1                                            
         st    r13,4(,r14)                                        
         st    r14,8(,r13)                                        
         lr    r13,r14                                                  
*                                                                      
* open files                                                            
*                                                                      
         Open  (infile,(input))                                        
         Open  (prtfile,(output))                                      
*                                                                      
         clear prtrec                                                  
         mvc   prtrec(20),=cl20'
*Starting program'                      
         put   prtfile,prtrec                                          
*                                                                      
* read and list                                                        
*                                                                      
Readit   equ   *                                                        
         get   infile,inrec                                            
         clear prtrec                                                  
         mvc   prtrec,inrec                                            
         put   prtfile,prtrec                                          
         j     readit                                                  
Readend  equ   *                                                        
         clear prtrec                                                  
         mvc   prtrec(25),=cl25'*End of file reached'                  
         put   prtfile,prtrec                                          
* remove the asterix in the next statement to get a S0C1 abend          
*        dc    h'0'                                                    
         clear prtrec                                                  
         mvc   prtrec(15),=cl25'*End of program'                        
         put   prtfile,prtrec                                          
*                                                                      
* close files                                                          
*                                                                      
         close  infile                                                  
         close  prtfile                                                
*                                                                      
* Program epilog                                                        
*                                                                      
         l     r13,4(,r13)         unchain savearea                    
* release dynamic storage                                              
         Freemain R,lv=workln,a=(10)                                    
*        wto 'freemain done'                                            
* set rc and get back                                                  
         xr    r15,r15                                                  
         l     r14,12(,r13)                                            
         return (2,12)                                                  
*                                                                      
* static work area                                                      
*                                                                      
blank    dc    cl150' '                                                
         print nogen                                                    
infile   dcb   ddname=INDATA,dsorg=ps,macrf=gm,recfm=fb,eodad=readend  
prtfile  dcb   ddname=SYSPRINT,                                        c
               dsorg=ps,macrf=pm,recfm=fb,lrecl=l'prtrec,blksize=0      
         print gen                                                      
         ltorg                                                          
*                                                                      
* dynamic work area      
*                        
work     Dsect          
sa1      ds    18f      
         ds    0d        
inrec    ds    cl200    
prtrec   ds    cl133    
         ds    0d        
workln   equ   *-work    
                         
         End            
//G.SYSPRINT DD SYSOUT=*
//G.INDATA   DD *        
kilroy                  
 was                    
  here                  

Re: Advice for writing and executing Assembler on the Mainfr

PostPosted: Sun May 29, 2016 5:20 am
by steve-myers
This is a simpler example of Mr. Jensen's sample.
//A       EXEC HLASMCLG
//C.SYSIN  DD  *
LIST8080 CSECT                     Define program csect
* "Standard" program entry -
* Reg 13 - Address of a 72-byte register save area
* Reg 14 - Address of next instruction to execute when the program
*          is finished
* Reg 15 - Address of the program
* Reg  1 - Address of a parameter list
         SAVE  (14,12),,*          Save registers
         BALR  12,0                Store address of the next          ->
                                    instruction in reg 12
         USING *,12                Establish program addressability
* Register 12 is commonly used as a program base register.  Register 0
* cannot be used, registers 1, 13, 14 and 15 should not be used as they
* are used for other purposes.
         LA    15,SAVEAREA         Compute address of the new save area
         ST    13,4(,15)           Add new save area to the
         ST    15,8(,13)            save area chain
         LR    13,15               Prepare new save area pointer
         OPEN  (INPUT,INPUT,OUTPUT,OUTPUT)  Open the data sets
LOOP     GET   INPUT,IOBUF         Read an input record into the      ->
                                    area known as IOBUF
         PUT   OUTPUT,IOBUF        Write the input record to the      ->
                                    output data set
         B     LOOP                Do it again
EOF      CLOSE (INPUT,,OUTPUT)     Close the data sets
         L     13,4(,13)           Load address of the higher save area
         RETURN (14,12),T,RC=0     Restore registers and return
SAVEAREA DC    9D'0'               72 byte register save area
         PUSH  PRINT
         PRINT NOGEN
INPUT    DCB   DSORG=PS,MACRF=GM,DDNAME=INPUT,EODAD=EOF
OUTPUT   DCB   DSORG=PS,MACRF=PM,DDNAME=OUTPUT,                       ->
               RECFM=F,LRECL=80,BLKSIZE=80
         POP   PRINT
IOBUF    DC    CL80' '
         END   LIST8080
//G.OUTPUT DD  SYSOUT=*
//G.INPUT  DD  *
Kilroy
 was
  here

Just a few thoughts -
  • HLASM *PROCESS statement and obscure HLASM options. The *PROCESS statement is only understood by HLASM, and there are issues about the options you can use with it and it location in the input. HLASM has many obscure options, too, like the NOCASE and MACROCASE options Mr. Jensen uses.
  • Register equates - This was a useful idea for many years because the symbols appear in the symbol XREF listing. I quit using them after the register XREF table was added in HLASM. This table is far superior to using the old symbol XREF table.
  • Mr. Jensen's CLEAR macro. The actual code it generates has been used for more than 40 years. It's so common the microcode on most machines optimizes its execution. However, there are serious flaws in the macro.
    • No label. If it is coded in your program, any label on the macro call is lost. In other words, if your code is
      NEWREC   CLEAR xxx
      you cannot use the NEWREC symbol elsewhere in your program.
    • Area length. The macro depends on the length attribute of the area being known and correct. This is not always the case.
    • Area length limitation. The macro can clear up to 256 bytes. No more.
  • Obscure and "new" instructions. Mr. Jenson uses the SAM31 and LARL instructions. From 2000 through 2008 I worked for a well known ISV. One of our products (fortunately not the one I supported) used the LARL instruction, which was not in the original z/Architecture instruction set. It ran OK in test (the ISV usually had the latest machines) but when it was run on a z/900 machine (the original z/Architectire system) the product got an S0C1 ABEND.

    The SAM31 instruction is entirely unnecessary.
    • The module is declared as being AMODE 31, so it should be entered in the 31-bit addressing mode. The SAM31 instruction is an expensive NOP instruction.
    • There is no particularly good reason for it to run AMODE 31 anyway.
  • Use of a dynamically acquired work area in a non-reenterable module. Reenterable code uses a work area obtained by the GETMAIN macro. However, this module is not reenterable, so there is little point in obtaining a work area.

    <Personal opinion>I seldom bother writing reenterable code. It adds to module complexity, it rarely provides any real benefit, and until z/OS 1.10, there was no practical way to validate that the module was really reenterable. In the early 1980s, this bit my ass when a module I thought was reenterable turned out to not be reenterable. There was a long thread about this over on our sister site several years ago when the topic starter had a module declared to be reenterable was not reenterable.

Re: Advice for writing and executing Assembler on the Mainfr

PostPosted: Sun May 29, 2016 3:02 pm
by willy jensen
I never claimed it to be perfect, just a starting point to get him going. I included the getmain / freemain to demonstrate dynamic storage. And I object to calling it a serious flaw that the 'clear' macro do not have a label - it's an inline macro so all down to how it is being used. Allowing for a label is good practice but the absence is not necessarily a flaw. I don't want to start a discussion about coding techniques, just get him started.

Re: Advice for writing and executing Assembler on the Mainfr

PostPosted: Sun May 29, 2016 3:05 pm
by willy jensen
Oh, one more point re 'Use of a dynamically acquired work area in a non-reenterable module'. If I need a large work area then I prefer to allocate it dynamically rather than having it part of the load module. But each to his own.

Re: Advice for writing and executing Assembler on the Mainfr

PostPosted: Sun May 29, 2016 3:48 pm
by steve-myers
willy jensen wrote:Oh, one more point re 'Use of a dynamically acquired work area in a non-reenterable module'. If I need a large work area then I prefer to allocate it dynamically rather than having it part of the load module. But each to his own.
Agreed, though I have to admit, in my dotage this is a rule I don't always follow!

Re: Advice for writing and executing Assembler on the Mainfr

PostPosted: Mon May 30, 2016 7:49 pm
by deucalion0
enrico-sorichetti wrote:
...
What is the smallest Assembler program I can write that covers all or most of the fundamentals of a Mainframe Assembler program?
...


such programs does not exist.
ANY arbitrary/illogic sequence of instruction is a <valid> assembler program ( as far as compilation is concerned )
if the addressing rules are satisfied

IMNSHO ;) from a general point of view ( let's not nitpick - please )
Assembler in se is not a real language ( with a formal definition like ALGOL,PL/1,REXX,...,)
it is a set of pretty basic rules and a few directives
that lets programmers interface the quirks
of the binary format of the MACHINE instruction set
of the general structure of a <machine instruction> program related to the register utilization for addressing instructions and data

You should notice that the macros normally used ( CALL for example ) are not described in the assembler manuals
but in the reference manuals of the host operating system.


the general environment is similar to COBOL/PL/1,C

a Source Program,
some include files ( COPY, <macro> )
an object deck ( output of the assembly)

some library subroutines ( only the one EXPLICITLY called )
pay attention, no language provide subroutines like in COBOL,PL/1,C
a load module

How to build and run the whole shebang
like a COBOL one

just start reading the Assembler reference .

more to come!



Hi Enrico.

Thank you very much for your input.

It is interesting that you say Assembler is not really a language, I think I know where you are coming from.

I will definitely make time for the Assembler Reference!!

Cheers for your time!

Re: Advice for writing and executing Assembler on the Mainfr

PostPosted: Mon May 30, 2016 8:00 pm
by deucalion0
steve-myers wrote:
deucalion0 wrote: ... What is the smallest Assembler program I can write that covers all or most of the fundamentals of a Mainframe Assembler program? ...

You can always replicate IEFBR14:
IEFBR14  CSECT
         SR    15,15
         BR    14
         END   IEFBR14
IEFBR14 has quite a lot of assumptions.
  • Register 14 specifies the address of the next instruction to execute when the program completes.
  • When the program is finished, register 15 has the binary return code for the program.
... Once I have this code, is it going to be in a dataset and then I run some JCL using HLASM to link edit the code into a load module?...
You've been around long enough to know this. By definition your program must be in a data set, because all Assembler programs I know about require their source to be in a data set. In this JCL, the data set is included in the JCL.
//A       EXEC HLASMC
//SYSIN    DD  *
IEFBR14  CSECT
         SR    15,15
         BR    14
         END   IEFBR14
You can also store your program text in a regular data set, depending on what you are comfortable doing. Back when I started we used punched cards, so more often than not the program text was in the JCL. These days punched cards are rather rare and, at least for me, program text is in a regular data set.
...then I run some JCL using HLASM to link edit the code into a load module?
Sigh. HLASM just assembles a program. It does not then prepare a load module. This is exactly like C++ on the mainframe. After the assembler completes, the object output for the program is then processed by a program now called the Binder to prepare a load module, just like C++ on the mainframe. For example -
//A       EXEC HLASMCL
//SYSIN    DD  *
IEFBR14  CSECT
         SR    15,15
         BR    14
         END   IEFBR14
//L.SYSLMOD DD -- data set where you want to store the load module for your program --
HLASM V1R6 Programmer's Guide will discuss this in more detail. The Binder is discussed in MVS Program Management User's Guide and Reference for your z/OS release.
... Once I have the load module how can I execute it and see it do something in order to see the code has run? ...
Since we have no idea what your program is doing, how can we help you with that??? z/OS does not have an IDE like toy machines; attempts to devise a checkout environment for mainframes, such as the PL/I checkout compiler in the 1970s, did not work out very well.

I use TSO TEST as described in TSO/E Command Reference for your z/OS release quite a lot, despite its many flaws. TEST, at least is available everywhere. Another popular tool is DBC, which I have never used because it, too, has many flaws.
... I want to learn how CSECTS come together and how I can zap code to make it abend and then read the dump to track down where it abended. ...
The Linkage Conventions chapter in MVS Assembler Services Guide for your z/OS release discusses this better than we could here.

We rarely "zap" code on a mainframe to make it ABEND. It usually ABENDs all by itself. Of course, you can easily insert

DC H'0'

into your program to make it ABEND at a location of your choosing. Another option is to use the ABEND macro, but this is rarely done for testing.

Dump analysis is too complex and difficult for this forum.


Superb feedback as always Steve, thanks a lot for your detailed answers and explanations.

I will take the time to go through all of this bit by bit until I understand what it all means.

Your explanations make a lot of sense in correspondence to what I have read and learnt so far.

I will do exactly that, I will try and recreate IEFBR14.

I appreciate that you broke down Willy Jensen's example, I think it make more sense to see it that example as Assembler as opposed to what I think that is, is a Macro?

I guess I need to get out of the frame of mind of a non Mainframe programmer and see Assembler for what it is and not what I expect it to be.

I am looking forward to trying this, thanks again for the advice and examples!