Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!shelby!portia.stanford.edu!lindy.stanford.edu!ralerche From: ralerche@lindy.stanford.edu (Robert A. Lerche) Newsgroups: comp.lang.asm370 Subject: Re: help for new assembly'er Message-ID: Date: 27 Feb 91 17:37:11 GMT References: <9102261052.AA16278@ucbvax.Berkeley.EDU> <1991Feb27.043234.23995@chinet.chi.il.us> Sender: news@portia.Stanford.EDU (Mr News) Distribution: inet Organization: AIR, Stanford University Lines: 83 laird@chinet.chi.il.us (Laird J. Heal) writes: ... >Always observe register saving and save area chaining scrupulously. >That is, use the SAVE and RETURN macros or write code yourself to >put R14-R12 at 12(R13), then save the address of your area in the >caller's area and save hers in yours. Note: a calling process is >generally called the `mother' process. In OS the common entry sequence is... MODULE CSECT SAVE (14,12),,* LR R12,R15 (OS PROVIDES MY ENTRY POINT IN R15) USING MODULE,R12 LR R2,R1 PRESERVE PARM POINTER ACROSS GETMAIN GETMAIN R,LV=SVLENGTH MINIMUM LENGTH IS 72 FOR A SAVE AREA ST R13,4(,R1) BACK-CHAIN NEW TO OLD SAVE AREA ST R1,8(,R13) FWD-CHAIN OLD TO NEW SAVE AREA XC 8(4,R1),8(R1) CLEAR FWD CHAIN OF NEW SAVE AREA LR R13,R1 OK -- SAVE AREA ALL SET UP >All other registers [besides 0, 1, 2, 13, 14 and 15] >can be used for base or scratch as you like. >Writing reentrant code (use RU-type GETMAIN for all data areas) >is good practice but not much good otherwise. Actually R2 is not used by any usual operating system functions, so it's safe too (though the TRT instruction does use it as an implicit operand). Reentrant code is not that hard to do, and besides being good practice it is critical if you ever use multiple tasks. An easy way to arrange the data areas is to make your save area (gotten above via GETMAIN) include them after the register save area. E. g., USING R13,SAVEAREA ... SAVEAREA DSECT DS 18F STANDARD OS SAVE AREA SVLENGTH EQU *-SAVEAREA TOTAL LENGTH OF GETMAIN'ED AREA You also need to learn about the MF=E forms of the MACROs -- what it amounts to is that the standard forms of some MACROs don't generate reentrant code because they have to create some kind of parameter list, so they put it directly in the code and branch around it. Those MACROs all provide an MF=L form to generate the parameter list (as a constant) and an MF=E form to fill it in and execute the operation. You copy the MF=L list into your work storage (again, in the GETMAIN'ed area) and use MF=(E,) to point to it. >... Never write self-modifying code - there is >always a better way to accomplish the same thing, generally with >a table of things to pick up and EXECUTE with, if your program is >so constituted. Amen! ----- (other points) Note the use of symbolic names R for the registers. This helps because it causes register references to appear in the cross-reference listing generated by the assembler. In a complex piece of code it can be difficult to follow the register usage; having a listing can help this. A related point: pick a convention for your use of the registers, document it in comments in the beginning of the routine, and STICK TO IT! There is nothing more difficult than keeping track in one's mind of the meaning of all the registers. LOTS of bugs come from failing to notice some subtlety in this area. Finally, remember that no matter how well you write assembler code it is almost always easier to write (and debug!) in a high-level language. If what you are doing requires the use of assembler (e.g., because you need to access some system interface that is only available from assembler), a good approach is to write a small, well-defined subroutine in assembler that can be called from a high-level language.