joachim@iraul1.ira.uka.de (Joachim Lindenberg) (07/30/88)
Apple, while writing some small patches to toolbox traps, I noticed that Multifinder doesn't conform to the register saving conventions stated in Inside Macintosh. Some routines apparently assume, that registers are not changed by the trap. The traps I patched are GetResource and DrawMenuBar. Both of them work only if I save registers D0-D2/A0-A1. I know that you did a great job implementing MultiFinder, but fixing problems like that will ease the life of your developers. Joachim Lindenberg, Dept. of Computer Science, University of Karlsruhe Sommerstrasse 4, 7500 Karlsruhe 1, Federal Republic of Germany
bob@eecs.nwu.edu (Bob Hablutzel) (08/01/88)
>while writing some small patches to toolbox traps, I noticed that >Multifinder doesn't conform to the register saving conventions stated >in Inside Macintosh. Some routines apparently assume, that registers >are not changed by the trap. The traps I patched are GetResource and >DrawMenuBar. Both of them work only if I save registers D0-D2/A0-A1. Are you attempting to make tail patches? (A tail patch is one which processes AFTER the ROM code). MultiFinder is making tail patches very hard to impliment, as the MultiFinder code often checks to see where it comes from, or it can depend on the ROM code leaving certain registers in specific states. I think Apple is quietly saying that tail patches are no longer valid, although I have not heard this verbatum from Apple. Isn't programming a moving target fun?? (severe sarcasm) Bob Hablutzel BOB@NUACC.ACNS.NWU.EDU AppleLink: A0173 CompuServe: 76474,154
dee@cca.CCA.COM (Donald Eastlake) (08/01/88)
Don't know about DrawMenuBar but as I recall Inside Macintosh specifically says that GetResource saves ALL registers. -- +1 617-969-9570 Donald E. Eastlake, III ARPA: dee@CCA.CCA.COM usenet: {cbosg,decvax,linus}!cca!dee P. O. Box N, MIT Branch P. O., Cambridge, MA 02139-0903 USA
mkg@lzsc.ATT.COM (Marsh Gosnell) (08/02/88)
When I patch traps I make it a point to save/restore everything (D0-D7/A0-A4). No telling what assumptions the ROM makes or, worse yet, what assumptions some other programmer who patches the same trap as you made (or forgot to). Marsh Gosnell
darin@Apple.COM (Darin Adler) (08/02/88)
In article <664@iraun1.ira.uka.de> joachim@iraul1.ira.uka.de (Joachim Lindenberg) writes: > While writing some small patches to toolbox traps, I noticed that > MultiFinder doesn't conform to the register saving conventions stated > in Inside Macintosh. Some routines apparently assume, that registers > are not changed by the trap. The traps I patched are GetResource and > DrawMenuBar. Both of them work only if I save registers D0-D2/A0-A1. If you read page I-113 of Inside Macintosh, you will see the following note: "Assembly-language note: Except for LoadResource, all Resource Manager routine preserve all registers except A0 and D0. LoadResource preserves A0 and D0 as well." Thus, the Resource Manager is an exception to the normal rules for Toolbox register saving. If you patch a Resource Manager trap, you have to keep this in mind. I don't think that this is clear enough in Inside Macintosh, but it is definitely a documentation problem rather than a MultiFinder problem. -- Darin Adler AppleLink: Adler4 UUCP: {sun,voder,nsc,mtxinu,dual}!apple!darin CSNET: darin@Apple.com
t-benw@microsoft.UUCP (Benjamin Waldmin) (08/03/88)
In article <10050005@eecs.nwu.edu> bob@eecs.nwu.edu (Bob Hablutzel) writes: >Are you attempting to make tail patches? (A tail patch is one which >processes AFTER the ROM code). MultiFinder is making tail patches very >hard to impliment, as the MultiFinder code often checks to see where >it comes from, or it can depend on the ROM code leaving certain registers >in specific states. I think Apple is quietly saying that tail patches >are no longer valid, although I have not heard this verbatum from Apple. > In the Macintosh supplement in the August Byte, there's an article by Phil Goldman, one of the authors of MultiFinder. Goldman writes "... it's illegal for an application to have a patch that does post- processing--that is, that has code after the call to the old routine." Ben Waldman Software Design Engineer, Microsoft Corp. uw-beaver!microsoft!t-benw Disclaimer 1: No, I usually don't read Byte; I find it useless. But when I saw the words Macintosh Supplement on the cover I though I'd give it a try. Unfortunately, there's a disgusting article on animation, where the author directly calls the Color Manager rather than working through the Palette Manager. Shame !!! Disclaimer 2: My thoughts, opinions, and writings are purely my own and are no related in any way to those of my employer.
lsr@Apple.COM (Larry Rosenstein) (08/03/88)
In article <10050005@eecs.nwu.edu> bob@eecs.nwu.edu (Bob Hablutzel) writes: >processes AFTER the ROM code). MultiFinder is making tail patches very >hard to impliment, as the MultiFinder code often checks to see where >it comes from, or it can depend on the ROM code leaving certain registers >in specific states. I think Apple is quietly saying that tail patches >are no longer valid, although I have not heard this verbatum from Apple. Tail patches have always been questionable, even before MultiFinder. Bugs in the ROM are often fixed using the technique of looking at return addresses (known as "come-from patches"). Instead of replacing the entire buggy routine (which might be large), a patch is made at a trap called just before the bug. The patch looks at the return address to see if it really is just before the bug. If so, it fixes the bug and jumps back into ROM. The recommended way to patch a trap is to call the original routine with the stack in the same state as you found it (ie, with the same return address). Larry Rosenstein, Object Specialist Apple Computer, Inc. 20525 Mariani Ave, MS 46-B Cupertino, CA 95014 AppleLink:Rosenstein1 domain:lsr@Apple.COM UUCP:{sun,voder,nsc,decwrl}!apple!lsr
jln@eecs.nwu.edu (John Norstad) (08/04/88)
In article <10050005@eecs.nwu.edu> bob@eecs.nwu.edu (my friend Bob Hablutzel) writes: >processes AFTER the ROM code). MultiFinder is making tail patches very >hard to impliment, as the MultiFinder code often checks to see where >it comes from, or it can depend on the ROM code leaving certain registers >in specific states. I think Apple is quietly saying that tail patches >are no longer valid, although I have not heard this verbatum from Apple. Sorry Bob, but Inside Mac does warn against these "tail patches". On page II-383 IM says "a number of ROM routines have been patched with corrected versions in RAM; if you intercept a patched routine, you must not do any processing after the existing patch, and you must be sure to preserve the registers and the stack (or the system won't work properly)." This doesn't make it clear exactly why tail patches should be avoided, but it does warn against them. Thanks to Larry Rosenstein for explaining "come-from patches". This is a neat idea, and if you think about it for a while it becomes clear why "tail patches" are taboo. If you want to write a tail patch despite all these warnings, you should at least check to make sure that a come-from patch hasn't already been written for the same trap. You also, of course, run the risk of having your code break with new system releases. There's another problem to watch out for when writing patches. I recently patched GetNextEvent, and noticed that under MultiFinder it wasn't working quite perfectly. Under MF, when a desktop icon (disk or trash) was uncovered after a window drag, it wasn't being redrawn. After much investigation I discovered that in this particular circumstance MF was expecting GetNextEvent to return a full zero word if the function result was false. This is much stricter than the usual rule for Boolean values on the stack, which says that only the low-order bit of the high-order byte of the word is significant. The ROM version of GetNextEvent does indeed always return a full zero word if the function result is false, but my patch, which was written in a high-level language, was only setting the high-order byte of the function result. I added some in-line assembly language code to clear the low-order byte, and this fixed the problem. So beware - sometimes parts of the system rely on traps behaving in very particular, undocumented ways. Your patch must perfectly imitate the trap in every way.
jmunkki@santra.HUT.FI (Juri Munkki) (08/06/88)
In article <1133@lzsc.ATT.COM> mkg@lzsc.ATT.COM (Marsh Gosnell) writes: >When I patch traps I make it a point to save/restore everything (D0-D7/A0-A4). >No telling what assumptions the ROM makes or, worse yet, what assumptions >some other programmer who patches the same trap as you made (or forgot to). > Marsh Gosnell Ithink we should program according to apple documentation. Since register- saving is one of the most time-consuming things that can be done on a 68000, it should avoided when possible. Maybe someone could write a "register scramble" function for TMON. It would trash any registers that can be theoretically trashed when a trap is called. All apple code _should_ be able to survive this mode (probably wouldn't at first). Juri Munkki jmunkki@santra.hut.fi jmunkki@fingate.bitnet P.S. When is there going to be a 020 and 881 compatible TMON??
imp@crayview.msi.umn.edu (Chuck Lukaszewski) (08/09/88)
In article <15055@santra.UUCP>, jmunkki@santra.HUT.FI (Juri Munkki) writes: > In article <1133@lzsc.ATT.COM> mkg@lzsc.ATT.COM (Marsh Gosnell) writes: > >When I patch traps I make it a point to save/restore everything (D0-D7/A0-A4) There really is no need for this. Juri is right about the cycle consumption of register saving. At a minimum, you can ignore D0-D2 and A0-A1 because Apple says you can trash them. Indeed, the ROM code makes no assumptions about these five registers. In point of fact, given the above about D0-D2/A0-A1, you need no register store code at all because the trap dispatcher handles the other registers for you, so you're just wasting stack space and CPU cycles. ---===---===---===---===--/* Chuck Lukaszewski */--===---===---===---===--- ARPAnet/NSFnet/MRnet: AppleLink: SnailMail: Ma Bell: imp@crayview.msi.umn.edu UG0138 Minneapolis MN 55418 612/789-0931
carlton@ji.Berkeley.EDU (Mike Carlton) (08/10/88)
In article <6600@umn-cs.cs.umn.edu> imp@crayview.msi.umn.edu (Chuck Lukaszewski) writes: >In article <15055@santra.UUCP>, jmunkki@santra.HUT.FI (Juri Munkki) writes: >> In article <1133@lzsc.ATT.COM> mkg@lzsc.ATT.COM (Marsh Gosnell) writes: >> >When I patch traps I make it a point to save/restore everything (D0-D7/A0-A4) > >There really is no need for this. Juri is right about the cycle consumption >of register saving. At a minimum, you can ignore D0-D2 and A0-A1 because Apple >says you can trash them. Indeed, the ROM code makes no assumptions about these >five registers. > >In point of fact, given the above about D0-D2/A0-A1, you need no register store >code at all because the trap dispatcher handles the other registers for you, so >you're just wasting stack space and CPU cycles. Be careful here. Many traps pass args in D0, A0 and even A1. Many return results in A0 and D0. Presumably you would see this in the calling sequence and allow for it. More subtle problems could occur with traps that use bits in the trap word to pass paramaters (such as _UprString which uses bits for case sensitive and diactritical sensitive). The trap dispatcher stuffs the trap number in D2 and the trap word in D1 (I may have these backwords). The code for the trap will then check one of these words and branch accordingly. So you better not munge D1 or D2 in these cases. Another potential problem could be tail patches on register based traps. (I know, tail patches are frowned upon, but they're useful sometimes). If a result is returned in D0 the dispatcher tests D0 before returning to set the condition codes. I don't know if any code branches immediately, but to be safe you'd have to retest D0 to reset the condition codes if you've changed them. I agree, save only what is necessary. However, there are some gotchas. Ease of use != ease of programming. Ease of use == !ease of programming. regards, mike (carlton@ji.berkeley.edu ...!ucbvax!ji!carlton)
schoaff@gefion.cs.cornell.edu (Peter Schoaff) (08/10/88)
Excuse this basic question, but could someone explain to me what is meant by a tail patch on a trap. Thanks | P. Chris Schoaff | We are the coffee generation, we can't afford cocaine | | | We need a healthy dose to make it through the day | | schoaff@ | Don't Care about nuclear war or poverty or pain | | cs.cornell.edu | We are the coffee generation and life is just a game. |
darin@Apple.COM (Darin Adler) (08/10/88)
In <6600@umn-cs.cs.umn.edu> imp@crayview.msi.umn.edu (Chuck Lukaszewski) writes: > In article <15055@santra.UUCP>, jmunkki@santra.HUT.FI (Juri Munkki) writes: > > In article <1133@lzsc.ATT.COM> mkg@lzsc.ATT.COM (Marsh Gosnell) writes: > > >When I patch traps I make it a point to save/restore ... (D0-D7/A0-A4) > >In point of fact, given the above about D0-D2/A0-A1, you need no register store >code at all because the trap dispatcher handles the other registers for you, so >you're just wasting stack space and CPU cycles. Wrong! Here is what happens: OS traps -------- Callers: expect result in D0 (and possibly A0), nothing else trashed Dispatcher: saves D1-D2/A1 and sometimes A0, depending on the trap word Traps: can trash D0-D2/A0-A1, must preserve D3-D7/A2-A6 Toolbox traps (except Resource Manager) --------------------------------------- Callers: expect D0-D2/A0-A1 trashed Dispatcher: saves nothing Traps: can trash D0-D2/A0-A1, must preserve D3-D7/A2-A6 Resource Manager traps (except LoadResource) -------------------------------------------- Callers: expect D0/A0 trashed Dispatcher: saves nothing Traps: can trash D0/A0, must preserve D1-D7/A1-A6 LoadResource ------------ Callers: expect nothing trashed Dispatcher: saves nothing Traps: must preserve D0-D7/A0-A6 You MUST save registers D2-D7/A2-A6 if you use them in a routine. Usually, you can't use A5, since most routines (QuickDraw, the Toolbox) requires that it point at QuickDraw globals. Also, the LINK and UNLK instructions save the specified register, so it is not usually necessary to save A6. If the patch that you are writing is not called often (or not in time-critical places), saving all the registers is probably an OK idea, since it's almost always safe, and prevents the subtle errors that can occur otherwise. By the way, I agree with Juri about the need for a "register scramble" function to test applications and system software with. There are currently a number of places in the ROM and System that do not follow the above rules. For example, there are a number of places in the ROM that rely on SetPort changing only A0! -- Darin Adler AppleLink: Adler4 UUCP: {sun,voder,nsc,mtxinu,dual}!apple!darin CSNET: darin@Apple.com
imp@crayview.msi.umn.edu (Chuck Lukaszewski) (08/10/88)
Mike Carlton writes in response to my article on register saving: > and diactritical sensitive). The trap dispatcher stuffs the trap number in > D2 and the trap word in D1 (I may have these backwords). The code for the > trap will then check one of these words and jranch accordingly. So you > better not munge D1 or D2 in these cases. > > Another potential problem could be tail patches on register based traps. > (I know, tail patches are frowned upon, but they're useful sometimes). If > a result is returned in D0 the dispatcher tests D0 before returning to set But Mike, you haven't given any reason to save any registers in a trap patch. In your first example, you are discussing operating system traps, which take it upon themselves to save D1 and D2 in addition to the usual D3-D7/A2-A4! Also, you can touch them all you want if you are providing a complete patch. If you are doing a 'header' patch, then you need to avoid them, but you do not need to save them. As far as trailer patches go, D0 is never saved anyways. Implicit in the idea of a 'patch' is the test that you talk about, or you haven't properly emulated the routine you are replacing. So, as I see it, there is still no reason to save any registers in replacement traps. ---===---===---===---===--/* Chuck Lukaszewski */--===---===---===---===--- ARPAnet/NSFnet/MRnet: AppleLink: SnailMail: Ma Bell: imp@crayview.msi.umn.edu UG0138 Minneapolis MN 55418 612/789-0931
imp@crayview.msi.umn.edu (Chuck Lukaszewski) (08/10/88)
Darin is absolutely right...I goofed. I just peeked at my handy Mac ROM disassembly, where I should have looked to begin with, instead of at some quick patches I've written which don't use 'nontrashable' regs. Actually all of this makes sense if you realize that traps RTS back to the location that invoked the trap + 2, not to the trap dispatcher. I guess I've got a lot on my mind or something. ---===---===---===---===--/* Chuck Lukaszewski */--===---===---===---===--- ARPAnet/NSFnet/MRnet: AppleLink: SnailMail: Ma Bell: imp@crayview.msi.umn.edu UG0138 Minneapolis MN 55418 612/789-0931
kent@lloyd.camex.uucp (Kent Borg) (08/11/88)
>From: schoaff@gefion.cs.cornell.edu (Peter Schoaff) >Excuse this basic question, but could someone explain to me what is >meant by a tail patch on a trap. If you want to change the behavior of one the routines in the Macintosh ROM, you can install your own routine that gets called first. You work your special custom magic and then possibly jump back to the original routine to do what it does. Because you jumped to the original routine, when it returns it will return back to the original calling code, not to your patch. If, on the misbehaving other hand, you arrange to have the original routine return control to your patch, you have installed a tail patch. I can't remember why tail patches are bad (I've never patched the Macintosh), but I think it has to do with interference between multiple patches (and Apple's tail patches?). Kent Borg kent@lloyd.uucp or hscfvax!lloyd!kent
jwhitnell@cup.portal.com (08/11/88)
mike (carlton@ji.berkeley.edu ...!ucbvax!ji!carlton) writes...
|(I know, tail patches are frowned upon, but they're useful sometimes).
They are not just frowned upon, they may also break current or future system
upgrades! Using tail patches is a good recipe for guraenteeing your code
is not compatible with future system releases.
Jerry
--
Jerry Whitnell
jwhitnell@cup.portal.com
..!sun!cup.portal.com!jwhitnell
tedj@hpcilzb.HP.COM (Ted Johnson) (08/11/88)
>Excuse this basic question, but could someone explain to me what is >meant by a tail patch on a trap. A tail patch is a patch that gets called *after* the normal trap is done. The other kind of a patch is a "head patch" ;-) A head patch gets called *before* the normal trap gets called. -Ted
jmunkki@santra.HUT.FI (Juri Munkki) (08/14/88)
In article <130@lloyd.camex.uucp> kent@lloyd.UUCP (Kent Borg) writes: >I can't remember why tail patches are bad (I've never patched the >Macintosh), but I think it has to do with interference between >multiple patches (and Apple's tail patches?). They are bad because Apple does something very stupid in order to save a few bytes (well maybe KB) when patching traps. Since Apple installed patches look for the return address from a trap, using a jsr instead of a jmp in your code fools the patch into thinking that it is called from a normal program instead of a buggy ROM routine and the Apple patch is never actually applied. If it fixes a bad problem, your program will probably "cause" a crash in some cituations...if it is something less obvious, you might get away with your code. ***** FLAME <<ON>> ***** Why is it stupid for Apple to make patches this way? I can think of a few reasons: 1) It slows down some traps that are actually ok. Since you usually end up patching a simple and very often called trap to fix an obscure problem in a very complex trap, you slow down the execution of innocent trap and the buggy trap. 2) You can't write programs that monitor and change the results from traps. 3) These patches are much harder to document and explain to new innocent system systems programmers that arrive at Apple. The system should be kept as simple as possible, since we already have lost the elegance and speed of the theoretical perfect Mac ROM. So: Keep it simple, keep it simple to document, keep it simple to understand and don't forget that there are people out there who would never think that something as stupid as this can be done at Apple... **** FLAME <<OFF>> ***** Ok, when will be the totally rewritten Mac system be ready? I don't think that the future system releases are going to be any better than 6.0 until this thing is ready. I can only hope that Apple has some good people hired to do this thing. The original Mac team did a good job. Can anyone repeat it? I also hope that it won't be built to be compatible with Mac OS. Launching Mac applications should start an emulation mode. OS/2 is good in this respect. Juri Munkki jmunkki@santra.hut.fi jmunkki@fingate.bitnet P.S. I only like newborn computers...the Mac is getting too old for me.