|Using the METAL option in the XL C compiler
Assembly language is powerful. It is close to the underlying hardware architecture; it allows you to access low-level system features, interacting closely with the operating system; and it has no runtime dependency. In short, it allows you to do almost anything you want.
But assembly language forces you to spell out all the minor details in the code. You need to focus on the leaves and trees, not the forest and the landscape. You need to spend time on the low-level details and not the high level logic. You need to hand hold the underlying machine every step of the way. It is tedious. An assembly program can take time to write and debug. The resulting code can be difficult to maintain.
Wouldn’t it be nice if you could use a high level language to do low-level programming ?
The METAL option of the XL C compiler is designed with this in mind. The concept of metal is such that the code generated can inter-operate with code written in assembler and therefore is close to the hardware – the metal. With the METAL option you can now use C language features to express low-level programming logic, for example writing user exits. You are freed from the tedious tasks such as managing the registers and developing the correct instruction sequences. Let us take a few moments to look at what the METAL option can do.
Close to the metal
The XL C compiler generated code requires the Language Environment to establish an overall execution context. The C library functions also require the Language Environment in order to provide their services; most noticeably the functions to manage the heap storage and dynamic storage area, to do file input-output, and to handle exception conditions. If your C program needs to get close to the metal, it needs the means to acquire these services directly from the operating system. Since you can only acquire these using assembler macros, the compiler needs to incorporate your assembler statements in the C program. The compiler also needs to make the C program to follow conventions expected in the operating system environment.
As a first step to achieving the above, the METAL option generates code in assembly source program format. You can then feed the assembly source through the High Level Assembler, like any other assembly programs. The resulting code is independent of the Language Environment. You can write a statement like if (x + y * z > 0) x = -x, and the XL C compiler will turn it into assembly instructions. You work on the high level logic, and the compiler generates assembly code. The code is close to the metal.
Keep things local
One reason why a normal C program requires support from the Language Environment is the requirement of a stack, on which local variables reside. Normal C code relies on the runtime to manage this stack. When doing low-level programming, this could be a roadblock as you might have your own storage management scheme.
METAL C gives you control of stack allocation by letting you customize the function prolog and epilog code. This is code generated by the compiler at the beginning and end of a function to acquire sufficient storage for local variables. METAL C provides a default code sequence; but you can override it by providing you own. You can allocate the stack according to your own scheme.
Protect your investment
But what about the existing library of high level assembly code? These are often the result of years of cumulative work, encapsulating the knowledge and experience of many skilled programmers. You don’t have to throw them away. METAL C allows you to tap into these treasures.
Function calls and argument passing in METAL C follow the MVS linkage convention. For example, when you call a function from C, the compiler will set up the arguments so that register 1 points to the parameter list, like you would when calling an assembly routine. When coding the C call statement, you just treat the assembly routine like any other C functions -- the C programs and your assembly programs are interoperable. You are now poised to enhance your collection of assembly programs with new additions written in C.
Well, you might say, all these are fine, but it is not just assembly routines which we need to worry about. It is assembler macros that contain the pearls of low-level services. There is a large body of system services which are available only as assembler macros; and you may have a few of your own. These are good stuff, and can be accessed only through assembly code. We need a way to open the clamshell and get the pearl.
No problem; METAL C has a clamshell opener -- you can embed a short sequence of assembly instructions inside a C function, in between other C statements. Further more, you can reference the values in C variables from these assembly instructions. For example, within a C function, you can set up the parameter values for the STORAGE macro, call the STORAGE macro, and then return the obtained storage address in a C variable. All these can be done within a C function. You can even develop a C library to get at the system services, and design a high level application interface tailoring for your purpose.
The key is in the register
Sometimes an application written in assembly code may put aside a certain register for a special purpose throughout the application, using it to hold the address of a key data block, for example. This is done for efficiency. Of course, you can use embedded assembly instructions as described above to access the data block. But METAL C provides an even easier way – you can tie a register to a pointer variable. The address value in the C pointer is the address stored in the register. You can declare a C structure representing the layout of the data block, and then access the data through a pointer variable in C expressions. No assembly code is needed.
And reaching far …
Speaking of pointers and data blocks, what if you need to manipulate a very large table of data and you are not ready for AMODE 64? An application written in assembly code may use data spaces to do it. METAL C allows you to access data spaces through far pointers. These are C pointer variables but wider – the lower half is an address within the data space; the upper half is the ALET. You can use a far pointer like a normal pointer; you can deference it, increment/decrement it, compare it with other far pointers to the same data space, etc. You can write a sort routine in C, for example, to sort the data, and then call this C routine from existing assembly code. You can now exploit the advantage of data spaces using a high-level language.
But what about printf() ?
Well, printf() needs the Language Environment, as do other C library functions. Since we want the code to be independent of the Language Environment, we don’t have the full C library. But all is not lost; we still provide a useful subset of these functions in the METAL C library. Please refer to the companion article for more details. We cannot provide normal input-output functionality, but we can still provide functions like sprintf(). Not printf(), but sprintf(), which is equally useful. You can still enjoy the convenience of %-substitution in the format string; and you can emit the resulting string in a buffer. You can print this buffer using, for example, WTO.
Putting it all together
The above represents some significant additions to the XL C compiler, and they are available in the z/OS V1R9 release. You can use these features in a number of ways. As indicated in the above, METAL C does not require you to rewrite your existing assembly code. METAL C code is meant to inter-operate with existing assembly routines, and work without the Language Environment. You can use it when adding new features to your existing application written in assembly language. Your investment in existing code is protected, and you can leverage them using a programming tool that can better express the high-level logic. You can rewrite selected routines in C, if you like. You might want to do this for the code that requires frequent maintenance. And, of course, you can write user exists in C. You have a power tool to work close to the iron. To top off all these, you can enjoy the capabilities exist in the XL C compiler to optimize your programs tailored to the latest hardware you have.
For further information on the METAL compiler option and related features, see z/OS V1R9.0 Metal C Programming Guide and Reference (SA23-2225-00) and z/OS XL C/C++ User's Guide (SC09-4767-06).