[comp.sys.mac.programmer] Legal Tail Patches

alexis@ccnysci.UUCP (Alexis Rosen) (02/17/89)

I'm astonished that I've only gotten one letter (and no flames) asking
"how does this scheme overcome the problem with tail patches, since the
problem is a come-from address check?"

The answer is, it doesn't. I've got to admit, it was pretty harebrained.
Especially the business about going through the trap dispatcher twice.
HOWEVER- when I first thought of the idea, I got it right (I think).
When I sat down to type it up my mind had wandered (_far_away_).

The revised scheme, with better explanation:

This method is not 100% general, in that the patch won't always execute.
It will execute when it knows that your application called it, otherwise
not. This may be a significant restriction, but I think it's still useful.

1) Test if the caller is the application
2) If it is, save the return address off of the stack, and JSR to the
    original routine
3) Otherwise, JMP to the original routine
4) Return to the caller

The tricky part is #1, but since you are writing your application, you have
a priori knowledge of where your app lives (usually in the app heap). So
it shouldn't be too dificult to tell when to do what. Anything calling from
the Application heap is OK. Anything else is verboten.

I wonder how useful this would be for INITs and such. After all, they
can't always be certain who is calling the trap, but it seems that
anything sitting in the application heap or above MemTop should be OK.
The system heap is out (that's where Apple's patches go, right?). Also,
if the trap you are patching has a true ROM address, it can't have the
kind of come-from checking code that tail patches break, so it should be
OK to patch regardless of who calls it. (This assumes that Apple won't
ship ROMs that have these ugly-but-useful hacks- they only get installed
as bug fixes in the System Software). That would seem to leave a lot of
room open for INITs. On the other hand, I've never written an INIT that
does anything, so I'm not sure...

Now, what say you?  (this time :-)

Alexis Rosen
alexis@ccnysci.uucp

tim@hoptoad.uucp (Tim Maroney) (02/18/89)

In article <1285@ccnysci.UUCP> alexis@ccnysci.UUCP (Alexis Rosen) writes:
>This method is not 100% general, in that the patch won't always execute.
>It will execute when it knows that your application called it, otherwise
>not. This may be a significant restriction, but I think it's still useful.
>
>1) Test if the caller is the application
>2) If it is, save the return address off of the stack, and JSR to the
>    original routine
>3) Otherwise, JMP to the original routine
>4) Return to the caller
>
>The tricky part is #1, but since you are writing your application, you have
>a priori knowledge of where your app lives (usually in the app heap). So
>it shouldn't be too dificult to tell when to do what. Anything calling from
>the Application heap is OK. Anything else is verboten.

This should work for an application-specific patch.  However, no such
patch is ever neccessary.  Let's say you want to patch SetHandleSize to
use what a source at Apple informs me is generally faster: allocate a
new handle at the new size, then copy memory, then free the old
handle.  You can do it with a patch, or you can declare a new routine
called MySetHandleSize and call that instead.  If you structure the
patch as you've mentioned above, the effect is identical; the only
difference is that the patching approach is a lot messier, since it
requires assembly langauge and mucks about with the OS.

>I wonder how useful this would be for INITs and such. After all, they
>can't always be certain who is calling the trap, but it seems that
>anything sitting in the application heap or above MemTop should be OK.
>The system heap is out (that's where Apple's patches go, right?). Also,
>if the trap you are patching has a true ROM address, it can't have the
>kind of come-from checking code that tail patches break, so it should be
>OK to patch regardless of who calls it. (This assumes that Apple won't
>ship ROMs that have these ugly-but-useful hacks- they only get installed
>as bug fixes in the System Software). That would seem to leave a lot of
>room open for INITs. On the other hand, I've never written an INIT that
>does anything, so I'm not sure...

It's not too useful for INITs.  At the very least, you would usually
want the patch to work for DAs as well as applications.  Usually you
want it to be used by the OS internally as well.  Suppose that, say,
Suitcase only patched appl. traps as you suggest.  Then when internal
system routines tried to deal with fonts and DAs requested by the user,
they wouldn't be able to see them.

So I think you have come up with a legal but useless way to do tail
patching.  I wish Apple would just stop using come-from tests
altogether, and if the OS eats another 64K of RAM as a result, big fat
hairy deal.  Maybe when RAM prices fall again next year....
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"Gorbachev is returning to the heritage of the great Lenin" - Ronald Reagan

dean@mars.Berkeley.EDU (R. Drew Dean) (02/19/89)

In article <6562@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>...  I wish Apple would just stop using come-from tests
>altogether, and if the OS eats another 64K of RAM as a result, big fat
>hairy deal.  Maybe when RAM prices fall again next year....

>Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim

No, Tim, why doesn't Apple issue new ROMS, so we don't need these stupid
patches to begin with...They already take 60+K of RAM, which is very
significant for those of us who have to pay for our own memory, and therefore
currently have 1Mb..:-( [As a student who bought an SE in Oct. 87, I couldn't
save the money up to buy RAM before all h*ll broke loose....]  I suspect,
that with a little work, Apple could also plug some security holes in the
Resource Manager, as well...Remember that every SE ever shipped has 88Kb
of digitized pictures floating in the ROMs.  Get your code right, Apple !
Apple -- make new ROMs a upgrade that the user only pays for installation,
which should be about $30....(The ROMs are still socketed, right ?  If not,
foget this idea....)



Drew Dean
Internet: dean@xcssun.berkeley.edu
UUCP: ...!ucbvax!xcssun!dean
FROM Disclaimers IMPORT StandardDisclaimer;

alexis@ccnysci.UUCP (Alexis Rosen) (02/19/89)

Tim Maroney remarks that my tail patch method is not terribly useful
because you usually want the patch to always be in place. He uses the
example of suitcase (actually, that was the first thing I tought of too).

To be honest, this reaction doesn't surprise me much, because I think he's
right in most cases. There is one exception, though, which is the case for
which I developed this technique: parasitic (or symbiotic?) code modules,
like XCMDs. In this case, you can't replace a trap for the application by
just calling a different routine because you didn't write the app in the
first place. This technique overcomes that and lets you monitor or alter
a closed application in many ways (in my case, FoxBase, which is remarkably
tolerant about parasites...)

Anyway, it has proven a useful, if somewhat off-the-wall technique. While
I'm comfortable with the compatibility, I still wonder if there's a better
(read: faster to code) way...

Alexis Rosen
alexis@ccnysci.uucp

tim@hoptoad.uucp (Tim Maroney) (02/20/89)

In article <1288@ccnysci.UUCP> alexis@ccnysci.UUCP (Alexis Rosen) writes:
>
>Tim Maroney remarks that my tail patch method is not terribly useful
>because you usually want the patch to always be in place. He uses the
>example of suitcase (actually, that was the first thing I tought of too).
>
>To be honest, this reaction doesn't surprise me much, because I think he's
>right in most cases. There is one exception, though, which is the case for
>which I developed this technique: parasitic (or symbiotic?) code modules,
>like XCMDs. In this case, you can't replace a trap for the application by
>just calling a different routine because you didn't write the app in the
>first place.

Correct; I hadn't considered extensible applications or "gene-spliced"
ones (I'm tempted to use the term "benign virus", but presumably the
patches you're talking about don't reproduce).  Your technique would be
useful and legal (enough) in those cases.  Sorry for the oversight, and
thanks for the idea.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"Philosophy is the talk on a cereal box
 Religion is the smile on a dog" -- Edie Brickell, "What I Am"

lsr@Apple.COM (Larry Rosenstein) (02/21/89)

In article <1285@ccnysci.UUCP> alexis@ccnysci.UUCP (Alexis Rosen) writes:
>
>1) Test if the caller is the application
>2) If it is, save the return address off of the stack, and JSR to the
>    original routine
>3) Otherwise, JMP to the original routine
>4) Return to the caller
>
>The tricky part is #1, but since you are writing your application, you have

You are looking at this from the wrong point of view.  Look at it from the
system's point of view.  

It seems to me that the only time a come-from patch is used is to fix a bug
in the ROM (if the bug was in RAM, we would simply release a totally new
piece of code).  This means:

(A) The only traps that would have a come-from patch are ones called by the
ROM.  If you know (or can convince yourself) that a certain patch is never
called from the ROM, then it probably can't have a come-from patch.  

(B) If you patch a trap and find the return address is not in ROM (ie, the
call was not made from ROM), then it should be safe to JSR to the original
trap routine.  This is similar to test #1 above, except you don't check to
see if the return address is in you application, you test to see if it is in
RAM. 

>if the trap you are patching has a true ROM address, it can't have the
>kind of come-from checking code that tail patches break, so it should be
>OK to patch regardless of who calls it. (This assumes that Apple won't

Some system patches don't look at the return address, because the entire
trap routine is being replaced (eg, TextEdit).  These patches don't look at
the return address at all.

The only caveat about the above info is that I don't work on system patches,
so I don't have the definitive word about them.

Also, you can still get into trouble with any patch, tail or not.  I had a
problem with QUED/M because one of my trap patches called _OSEventAvail.
(It turned out that QUED/M patches _OSEventAvail and their patches were not
reentrant.)

Another problem I had was assuming that anytime a trap is patched the
original trap is always called.  That is not the case for some of the traps
patched by Suitcase and MultiFinder.

It is always a good idea with any patch to review the assumptions you are
making about how the system works, and how likely those assumptions might be
violated.  If you make a tail patch, you are assuming that the system won't
patch the same trap with a come-from patch.  That might be a relatively safe
assumption in certain cases, but a bad assumption in others.


		 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

bob@accuvax.nwu.edu (Bob Hablutzel) (02/21/89)

> It seems to me that the only time a come-from patch is used is to fix a bug
> in the ROM (if the bug was in RAM, we would simply release a totally new
> piece of code).  This means:

> (A) The only traps that would have a come-from patch are ones called by the
> ROM.  If you know (or can convince yourself) that a certain patch is never
> called from the ROM, then it probably can't have a come-from patch.  

> (B) If you patch a trap and find the return address is not in ROM (ie, the
> call was not made from ROM), then it should be safe to JSR to the original
> trap routine.  This is similar to test #1 above, except you don't check to
> see if the return address is in you application, you test to see if it is in
> RAM. 

Lemme jump in here with a question, and a comment...

Are Apple people the only people blessed to do come-from patches? Let us assume,
for the sake of argument, that I have an application which does come-from
patches (very carefully). Am I breaking the rules?

Also, if I am not breaking the rules, I would really appreciate it if Apple
did not tail-patch. (gotcha!) I know of at least one: the _Open patch in MPW,
which seems to be concerned with having too many files open. Why couldn't this
be handled in a subroutine? This is MPW 3.0, btw, which I got with my TML II
upgrade. MPW 2.0.2 is fine. And, hey, if I'm wrong about this I'll happily
eat, er, crow.

Bob Hablutzel	Wildwood Software	BOB@NUACC.ACNS.NWU.EDU

lsr@Apple.COM (Larry Rosenstein) (02/22/89)

In article <10050076@accuvax.nwu.edu> bob@accuvax.nwu.edu (Bob Hablutzel) writes:
>
>Are Apple people the only people blessed to do come-from patches? Let us
>assume, for the sake of argument, that I have an application which does
>come-from patches (very carefully). Am I breaking the rules?

By definition, a come-from patch means you are looking at the return address
to decide whether to do something.  In the System's case, these patches fix
ROM bugs, and are hard wired with ROM addresses.

If you want to do a similar thing, then you will have to hard-wire or
somehow figure out what the desired come-from address is for each ROM.  So
if you are prepared to deal with different ROMs, then I suppose you can do a
come-from patch.  You are almost guaranteed not to work on new machines.
The same cautions about any patch apply in this case.


>Also, if I am not breaking the rules, I would really appreciate it if Apple
>did not tail-patch. (gotcha!) I know of at least one: the _Open patch in MPW,
>which seems to be concerned with having too many files open. Why couldn't this
>be handled in a subroutine? This is MPW 3.0, btw, which I got with my TML II

I don't know.  One reason might be to support tools compiled for an earlier
version of MPW.

Presumably the MPW people talked to the System Software people and know what
they are doing.  

MPW is not a typical application.  It has to hook into the File Manager in
several places to provide the appearance that files and windows are the
same.  It also sets up separate worlds for the tools it runs, etc.  Plus the
MPW people have the benefits of working for Apple.

Doing any kind of patch is a risk, since there are many applications out
there that have subtle bugs in them that patches may being out.  (There are
lots of programs out there that pass the wrong thing to MenuSelect, which
screwed me up.)  Anytime you want to write a patch you have to weigh the
benefits vs. the risks.  Some patches are riskier than others.

As I said before, you should think carefully about what assumptions your
patches are making, and how those assumptions may be violated in the future.

The bottom line is that its your machine, and you can do whatever you want
with it.  A good example of this is my "sure-fire Tetris beating" INIT, which
patches the _Random trap and returns the same value each time.  (Tetris is
much easier if all you get are straight pieces. :-))

		 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

jmunkki@kampi.hut.fi (Juri Munkki) (02/22/89)

In article <10050076@accuvax.nwu.edu> bob@accuvax.nwu.edu (Bob Hablutzel) writes:
>Are Apple people the only people blessed to do come-from patches?

Yes. I would never write a come-from patch even if I knew it was allowed.

The problem is that come-from patches prevent tail-patching. There is a
rather complicated way in which apple could allow tail-patching while
still doing their own come-from patching. Apple could change SetTrapAddr
aj GetTrapAddr so that the actual trap dispatch table is not changed for
the come-from patched traps, but the current patch is "told" that someone
wants to patch it. The come-from patch could then still do the come-from
stuff and it could then safely jsr/jmp to the patched routine. GetTrapAddr
should return the address that the come-from patch calls. This way no one
will loose, but programmers will be allowed to do tail patching.

To illustrate:
Before patching				After patching
_______________				______________
Program calls a trap			Program calls a trap
Trap dispatcher calls routine		Trap dispatcher calls routine
Come-from patch does something 		Come-from patch does something
Come-from patch calls ROM		Come-from patch calls new patch.
					New patch calls ROM...

Apple: Please implement this in the next system release...


_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

siegel@endor.harvard.edu (Rich Siegel) (02/23/89)

In article <19886@santra.UUCP> jmunkki@kampi.hut.fi.UUCP (Juri Munkki) writes:

>Before patching				After patching
>_______________				______________
>Program calls a trap			Program calls a trap
>Trap dispatcher calls routine		Trap dispatcher calls routine
>Come-from patch does something 		Come-from patch does something
>Come-from patch calls ROM		Come-from patch calls new patch.
>					New patch calls ROM...

	Unless I'm mistaken, Radius pulls a trick like this in their
display INITs. 

		--Rich



Rich Siegel
Staff Software Developer
THINK Technologies Division, Symantec Corp.
Internet: siegel@endor.harvard.edu
UUCP: ..harvard!endor!siegel
Phone: (617) 275-4800 x305

tecot@Apple.COM (Ed Tecot) (02/25/89)

In article <19886@santra.UUCP> jmunkki@kampi.hut.fi.UUCP (Juri Munkki) writes:
>To illustrate:
>Before patching				After patching
>_______________				______________
>Program calls a trap			Program calls a trap
>Trap dispatcher calls routine		Trap dispatcher calls routine
>Come-from patch does something 		Come-from patch does something
>Come-from patch calls ROM		Come-from patch calls new patch.
>					New patch calls ROM...
>
>Apple: Please implement this in the next system release...

The major problem with this is that it will make the trap dispatcher
significantly slower.  Considering that it is the most executed code in
Macintosh, it would probably translate into a significant performance
degradation.  So I ask, is it worth it?

						_emt

jmunkki@kampi.hut.fi (Juri Munkki) (02/25/89)

In article <26341@apple.Apple.COM> tecot@Apple.COM (Ed Tecot) writes:
>In article <19886@santra.UUCP> jmunkki@kampi.hut.fi.UUCP (Juri Munkki) writes:
>>To illustrate:
>>Before patching				After patching
>>_______________				______________
>>Program calls a trap			Program calls a trap
>>Trap dispatcher calls routine		Trap dispatcher calls routine
>>Come-from patch does something 		Come-from patch does something
>>Come-from patch calls ROM		Come-from patch calls new patch.
>>					New patch calls ROM...
>>
>>Apple: Please implement this in the next system release...
>
>The major problem with this is that it will make the trap dispatcher
>significantly slower.  Considering that it is the most executed code in
>Macintosh, it would probably translate into a significant performance
>degradation.  So I ask, is it worth it?

Why would it slow down the trap dispatcher?

You wouldn't have to change the trap dispatcher. Here's how you would do it...

1.  Normally apple patches have jmp instructions directly into the ROM after
    they check for tail patches. Change this so that they jump into a table
    of jmp instructions into ROM. This doesn't significantly slow down the
    system.

2.  Change SetTrapAddress so that it first checks to see if the trap needs
    come-from patching. If it does, don't change the trap dispatch table, but
    write the new address into a jump table within the system patches. You
    have to clear the cache in order to safely write into the jump table, but
    apple has the right to do stuff like this...

3.  Change GetTrapAddress so that it first checks if the trap does come-from
    patching. If it does, return the address that is contained in the jump
    table. If the routine only has the apple patch, the ROM address will be
    returned.

So, why would this scheme slow down the trap dispatcher?

BTW: MacTutor once published the code for the MacPlus trap dispatcher.
     I looked at it and could see an improvement of 2 cycles... Maybe
     I was wrong... maybe I should have tried it.

_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

lsr@Apple.COM (Larry Rosenstein) (02/27/89)

In article <19971@santra.UUCP> jmunkki@kampi.hut.fi (Juri Munkki) writes:
> 3.  Change GetTrapAddress so that it first checks if the trap does 
>come-from patching. If it does, return the address that is contained in
>the jump table. If the routine only has the apple patch, the ROM address 
>will be returned.

No good.  A program may do a GetTrapAddress, and JSR directly to that as a
way to save time (although I doubt that you save much time at all).
GetTrapAddress must therefore return the same address you would jump to by
executing the trap.

Your approach tries to keep the come-from patch as the "last" patch for 
the particular trap (ie, the code that gets control first).  I don't think 
you can change the way Get/SetTrapAddress works and still maintain 
compatibility.

Larry Rosenstein, Apple Computer, Inc.

Internet: lsr@Apple.com   UUCP: {nsc, sun}!apple!lsr
AppleLink: Rosenstein1

jmunkki@kampi.hut.fi (Juri Munkki) (03/01/89)

In article <785@internal.Apple.COM> lsr@Apple.COM (Larry Rosenstein) writes:
>In article <19971@santra.UUCP> jmunkki@kampi.hut.fi (Juri Munkki) writes:
>> 3.  Change GetTrapAddress so that it first checks if the trap does 
>>come-from patching. If it does, return the address that is contained in
>>the jump table. If the routine only has the apple patch, the ROM address 
>>will be returned.
>
>No good.  A program may do a GetTrapAddress, and JSR directly to that as a
>way to save time (although I doubt that you save much time at all).
>GetTrapAddress must therefore return the same address you would jump to by
>executing the trap.
>
>Your approach tries to keep the come-from patch as the "last" patch for 
>the particular trap (ie, the code that gets control first).  I don't think 
>you can change the way Get/SetTrapAddress works and still maintain 
>compatibility.
>
Oh, but it does work! The code that doesn't get called is only the come-from
patch. This code only patches ROM code anyway. If an application gets the
trap address and calls it, it is in RAM and won't be affected by the come-from
patch. SectRect is one of the come-from patches. It doesn't have any bugs
of its own. A buggy routien would have to have two levels of patching. One
for the come-from patch and one for the real patch. Since come-from patched
traps seem to be simple and short (like SectRect), they do not usually contain
any bugs.

This way some complex traps would take a little more time (one jsr/rts), but
overall you wouldn't loose anything.

I'm starting to get the feeling that Apple is afraid to touch the system
software in case they introduce new incompatibilities. The only way out is
to write a new partly source-compatible OS. Long ROM routines should be
broken into several subroutines so that patches replace only one subroutine.
If the new apple OS is good and Apple adds some new coprocessors (graphics
and signal) as standard hardware on some of their new machines, I might
drop the line about NeXT in my signature...I'm not all that enthusiastic
about Unix...it seems even harder to patch/change than Mac OS.


_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

bob@accuvax.nwu.edu (Bob Hablutzel) (03/02/89)

> Oh, but it does work! The code that doesn't get called is only the come-from
> patch. This code only patches ROM code anyway. 

Wrong. Come-from patches can patch RAM code also. Trust me.

Bob Hablutzel	Wildwood Software	BOB@NUACC.ACNS.NWU.EDU

Disclaimer:	I work for myself. If I wanted to say more, I would.

jmunkki@kampi.hut.fi (Juri Munkki) (03/03/89)

In article <10050084@accuvax.nwu.edu> bob@accuvax.nwu.edu (Bob Hablutzel) writes:
>> Oh, but it does work! The code that doesn't get called is only the come-from
>> patch. This code only patches ROM code anyway. 
>
>Wrong. Come-from patches can patch RAM code also. Trust me.
>
Oh? Why would they do that? (Is it the MultiFinder patching?)

What I should have said is that they patch known code. It doesn't matter
if a random program bypasses the come-from code. The only occasion that
I can think of is where the come-from patch tries to see if it is called
from a vague area in memory (like the system or application heap), but I
don't think this is done...

_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

bob@accuvax.nwu.edu (Bob Hablutzel) (03/04/89)

> What I should have said is that they patch known code. It doesn't matter
> if a random program bypasses the come-from code. The only occasion that
> I can think of is where the come-from patch tries to see if it is called
> from a vague area in memory (like the system or application heap), but I
> don't think this is done...

Wrong again. Can't say who or what or why.

Bob Hablutzel	Wildwood Software	BOB@NUACC.ACNS.NWU.EDU