MVS TOOLS AND TRICKS OF THE TRADE NOVEMBER 2002 Sam Golob MVS Systems Programmer P.O. Box 906 Tallman, New York 10982 Sam Golob is a Senior Systems Programmer. He also participates in library tours and book signings with his wife, author Courtney Taylor. Sam can be contacted at sbgolob@cbttape.org. Information about the CBT MVS Tapes can be found on the web, at http://www.cbttape.org. THOUGHTS ABOUT ASSEMBLER MACROS Assembler macros are normally a good way to shorten your coding steps. You code one macro instruction instead of a bunch of normal instructions. And usually a macro is made to stand for a concept or a complete operation, where one normal instruction is not available to get that particular job done. When you code one macro instruction, the Assembler uses the macro definition (which is either inline in the source code, or it has been stored in a pds) to create a sequence of several (or many) instructions that will execute the complete concept, or the complete operation. But in your coding, it is only one "instruction". Therefore, having a macro definition available makes the coding clearer, in a way that follows your thought processes. Instead of having to code a complicated sequence of instructions, whenever you want to get a certain single job done, you just have to code one macro instruction, and possibly a few parameters along with it. This is the CONCEPT of why you might want to have "macro instructions" in the Assembler language. But the actual implementation of how a macro instruction is interpreted, and how it is expanded by the Assembler, makes it possible for macro instructions to do far more than just this. Today, we're going to talk about things like how macros can actually be used to simulate real Assembler language instructions, using other Assembler language instructions. In other words, we'll talk about how macros can be used to "enlarge" the Assembler's instruction set. Why would one want to simulate an assembler instruction by using a macro? One reason, is that a person didn't get the newer version of the Assembler, which supports "new instructions". This happened in the early days of MVS/XA, when the old IFOX00 Assembler wouldn't assemble the new "XA instructions". Another place where this could happen, is when you're running ancient (circa 1975) MVS 3.8 on a Hercules emulator, on your PC. If you can't run a modern assembler (HLASM or ASMH, which has to be licensed from IBM) and you're restricted to using IFOX00 (the old free XL assembler), and you want to assemble more recently written code, you'd be stuck. But if you use macros to simulate the more recent assembler instructions, then you can also assemble some more recent code, using the old system as a base. I knew of a software house which couldn't afford (for a while) to buy Assembler H Version 2, which you needed to assemble code for XA (and they supported code for XA). What did they do? They wrote a set of macros, to run under the older IFOX00 Assembler, which produced the same effect as if the new instructions were assembled using IEV90. IEV90 was Assembler H version 2, the precursor of HLASM, IBM's most current "High Level Assembler" product. You can see this company's macro collection in File 177 of the CBT Tape collection, as member OPCODES. File 177 also contains a far larger collection of instruction simulating macros, which comes from Jan Jaeger, and which is the result of the Hercules effort. Jan Jaeger's macro collection, which expands into a large macro library called SYS1.MNEMAC, allows the IFOX00 assembler to correctly assemble very modern instructions, including most (or all) of the 64-bit instructions which are available as of the time of this writing. IBM has always provided several large collections of macros, for the purpose of allowing you (as a coder), and them (internally), to access many system services in a relatively simple way. IBM's two main macro libraries are (nowadays) called SYS1.MACLIB and SYS1.MODGEN. (In earlier systems, you sometimes had to use SYS1.AMODGEN instead of SYS1.MODGEN.) You use SYS1.MACLIB and SYS1.MODGEN in a source code assembly by allocating them to the assembler, coding the SYSLIB DD card in the assembly JCL. And of course, you can add your own macro libraries to the assembly, by concatenating them with SYS1.MACLIB and SYS1.MODGEN in the SYSLIB DD statement of the assembly JCL. I've observed one more thing about the use of macros, and you might find it useful to make a mental note of this. Vendors of commercial software tend to use many more macros than other coders. Of course, a programmer's use of a macro, instead of coding the instructions in "longhand", is often a matter of personal preference and taste. But I've gotten a lot of exposure to seeing free code (largely from the CBT Tape software collection), and I've also worked as a coder for software vendors. My observation is that a software vendor, who doesn't let the user see the source code of their product, has a great tendency to use a very large collection of their "homegrown" macros in their coding. The folks who write free code, tend not to bother coding too many macro definitions of their own, unless they really need them. I think the difference comes because the software vendor coders have created their own coding environment, which tends not to change too much, and which they keep "in-house". All of their assemblies include their own macro library, as a matter of course. And they don't show these macros, or their other source code, to outside people. So the macros stay with the software house--they aren't meant to be moved from place to place. Therefore there's no burden of having to carry a big macro library around, just in order to be able to assemble your software. The big proprietary macro library stays put, and doesn't have to be moved. The "free coders", on the contrary, tend to write programs in a more isolated and "ad hoc" fashion, so they don't have so much of a "proprietary environment" of their own, and they also want to make their programs more portable. After all, if they move from shop to shop, they want to take their programs with them. So they don't want to burden their code with a huge set of macros that they'll have to take from place to place. Therefore they tend not to use anywhere nearly as many "personal macros" in their coding as the vendors will. BASICS In order for an assembler macro, which isn't an assembler instruction, to be available when assembling a source program, its code, which is called a "macro definition", must reside in either of two places. One place is called a "macro library", a pds that is accessed via the SYSLIB DD card in the assembler JCL. The other place is for the macro to be "inline" with the program source. In that case, the macro definition must be preceded by a MACRO assembler instruction, and ended by a MEND assembler instruction. (Macros included in a "copy member" are, of course, copied inline into the source code, so they become inline macros, and they don't belong to a separate category.) A very simple macro definition can be seen in Figure 1. The name of the macro is REGS, and it can be stored in a macro library, as pds member name REGS. If this macro is made available to an assembly of source code, and if you code REGS in the assembler source, then the assembler will generate the following 16 lines of code, starting with R0 EQU 0, and so forth. Therefore, if you code the REGS macro, your code has been shortened by 15 lines. Macros (of course) are not all this simple. The assembler macro language, which relies very heavily on "conditional assembly language", is an extremely rich and capable facility that allows macros to accept parms and defaults. The "official" place to learn about all these matters, is in IBM's HLASM Programmer's Guide (SC26-4941), and the HLASM Language Reference (SC26-4940), which are available from IBM on their cd-rom manual collections, either in Bookmanager or PDF format. However, just because macros CAN be complicated, they don't have to be. If you want to code some simple macros for yourself, just to shorten your coding work, that's not a bad idea, and it'll give you a good start, so that you can get more ambitious later. USING MACROS TO SIMULATE INSTRUCTIONS An interesting application of the macro language, as we said before, is to simulate machine instructions that an older version of the Assembler doesn't know about yet. One example where the Assembler now would "know" about more instructions, is in the jump between HLASM Release 3, and HLASM Release 4. HLASM Release 3 was pre-OS390 2.10. HLASM Release 3 did not incorporate "knowledge" of the 64-bit machine instruction subset. But HLASM Release 4 "knows" about the many new instructions, which are incorporated in the 64-bit instruction subset. At the time of this writing, there are still many installations whose default Assembler is not yet HLASM Release 4. Please look at Figure 2. There, we see two ways to use a macro to generate the same result as is produced by the BASSM instruction. Even if an old Assembler was used for the assembly, the result produced is equivalent to what gets generated by a new version of the Assembler. And the assembled program can be run on a new machine, which is able to understand the new instruction set and execute it. You'll notice the difference between the two macros illustrated in Figure 2. Both of them generate the exact same machine code. But the first macro uses another instruction (BALR) as a model for getting the BASSM machine code to be generated. The second macro uses the Assembler's own ability to calculate different types of constants, to generate the exact same result, as if a newer Assembler were assembling the BASSM instruction. It's obvious that in order to assemble the first macro, the old Assembler program has to "know" how to assemble the BALR instruction. But to assemble the second macro, the Assembler doesn't have to "know" about the BALR instruction at all. There is no dependency, in the second macro, on the Assembler "knowing" about any other instruction. Another advantage of the second macro, is that in doing things the first macro's way, you have to be absolutely sure that the "model" instruction works exactly like the newly simulated instruction. Of course, if the "Principles of Operation" manual says that the two instructions are physically constructed the same way, that's pretty safe, but maybe there might be some small, hidden margin for error. But with the second macro, you just have to be sure you know how the new instruction works. There is no dependency at all, on how another, different instruction actually works. These two examples came from File 177 of the CBT Tape. The first example was written by the software house (mentioned above) in the early MVS/XA days (circa 1983). That's the example which was dependent on the Assembler knowing how another instruction works. The first example can be found as part of the OPCODES member in File 177 of the CBT Tape. The second example was created by the Hercules effort. Hercules is a program, written mostly in C, which simulates S/390 instructions on a PC. Users of Hercules usually run MVS 3.8 (OS/VS2), which only contains the IFOX00 Assembler program. So to give someone running OS/VS2 the ability to assemble "new code" using IFOX00, an entire macro library that simulates new instructions, called SYS1.MNEMAC, was created. SYS1.MNEMAC can be constructed from the MNEMAC member of the CBT Tape File 177 pds. FURTHER THOUGHTS I don't have space in the remainder of this column, to delve deeply into other aspects of the macro language, and to talk about the conditional assembly language, which is so important in the construction of most macro definitions. For the details of that knowledge, you have to see IBM's HLASM manuals, which can be downloaded from IBM's web sites, reachable from www.ibm.com, and which are fairly easy to obtain nowadays. My aim today was to show you something clever, and to stimulate your ability to think. Original thinking has always been part of the systems programmer's job. Systems programmers are continually called upon to overcome problems that they may have never seen before, and a big part of a systems programmer's training consists of how to think originally, and to invent new ways of doing something, using old tools. To do that on a consistent basis, requires a constant stimulation of "the creative juices" of the mind. In other words, it is helpful for us to gain exposure to other people's inventive and original ways of solving tough problems. I've always been fascinated by the ability to make macros "pretend" that they were simple machine instructions. This is a mechanism which systems programmers have long used, to overcome the limitations of an older Assembler. Or, they have attempted to "invent" their own "instruction set" using macro definitions, and they have thus expanded their ability to write code, not being restricted AT ALL by the limitations of the instruction set IBM has provided them. Their saying is: "If you want a new instruction, go invent your own!" So I hope that this has opened up a new direction for your thinking, and I wish you all the best of luck. I'm personally looking forward to seeing you here again, next month. * * * * * * * * * * * * * * * * * * * * * * Figure 1. The very simple REGS macro definition. When you code REGS in an assembler program, and this macro definition is available, you will get all the general register equates, so instead of having to code 1 for Register 1, you can code R1, and so forth. MACRO REGS 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 MEND * * * * * * * * * * * * * * * * * * * * * * Figure 2. Two ways of simulating a new instruction with a macro. Suppose our Assembler does not "know" about the BASSM instruction: A. Use another instruction which works the same way, and substitute the generation of a different opcode. In other words, let the other instruction do the work, and then overlay the operation code that is produced by the assembler. MACRO &LABEL BASSM &R1,&R2 &LABEL BALR &R1,&R2 BRANCH AND SAVE AND SET MODE (RR) ORG *-2 DC X'0C' REPLACE OPERATION CODE FIELD ORG *+1 MEXIT MEND B. Use the macro to generate the entire machine instruction from scratch, employing the Assembler's ability to calculate the values of different types of constants. In this case, we use the Assembler's ability to calculate the value of "address constants". MACRO &LABEL BASSM &R1,&R2 DS 0H &LABEL. DC 0XL2'00',X'0C',AL.4(&R1.,&R2.) MEND