From: absurd@apple.apple.com (Tim Dierks, software saboteur)
Newsgroups: comp.sys.mac.programmer
Subject: Re: Need BOOK that explains how to write an INIT
Date: 4 Jan 93 00:29:13 GMT
Followup-To: comp.sys.mac.programmer
Distribution: comp.sys.mac.programmer
Organization: MacDTS Marauders

In article <1992Dec21.113758.1944@random.ccs.northeastern.edu>,
chuck@ccs.northeastern.edu (Chuck Wells) wrote:
> 
> I have quite a few Mac programming books, but none that explain the art of
> INIT writing.  Can anyone recommend such a book?
> 
> Specifically, the init I am currently hoping to write just has to:
> 	1) Modify some files when I restart the computer
> 	2) Modify some files when I shutdown the computer
> If I can do those things with an INIT, that will keep me happy for now.  Later,
> I'll need to be able to: tell what keys the user is pressing, no matter what
> application he is in, yet still allow the user to get those keypress events
> to the applications.
> 
> Any book recommendations?  A while ago, Tim Dierks posted a long message on
> how to write an INIT, but since I don't know how to patch traps, I was a bit
> confused.  Thanks for any help.

Well, as far as I know, there isn't a book specifically on
writing INITs, (although I'm currently toying with the idea of writing
one);
however, I believe a couple of books may have passing examples on doing it.
Here's some info you might find helpful on traps and patching them:

   A lot (as in virtually all) of the Mac relies on the toolbox and
operating system, a collection of routines which are used by virtually
all Mac programs.  The code for these routines is shared by all the
applications on a Mac; it is loaded by the system and made available to
the routines.  The problem is how to link up the code loaded by the
system with the code in the application so the application can easily
call the system routines reliably.  Because code on the Mac can be loaded
into any RAM address, and the ROMs on different Macs vary greatly, you
can't just have a single address for each routine which the application
can jump to; you need some kind of flexible mechanism to dispatch
the application's requests to the appropriate system code.  This
mechanism is the a-trap dispatcher.
   The 68000 series of processors use a 16 bit instruction set; any
processor instruction can be specified in one 16-bit word (which may
be followed by more data specifying the operands).  For convenience
and simplicity, information about the instruction is encoded into the
bit pattern of the hex value that specifies it.  For example, any
68000 instruction which begins with the hex digit $D is some variety
of an ADD instruction.  Some of the binary patterns were reserved
for later expansion; for example, any instruction intended for the
floating-point co-processor bgins with the hex digit $F.  Similarly,
any instruction beginning with the hex digit $A is unassigned; if
the processor encounters one, it stops what it is doing and calls
a routine to deal with this problem; as far as it is concerned, you've
just executed an illegal instruction.  On the Mac, the routine which
deals with this problem is the trap dispatcher; it looks at the
instruction which caused the problem and matches it up with a routine
in the system software.  It then jumps to this routine, which
returns to the application after it has completed its work.
Because these instructions begin with the hex digit $A and because
they act like a trap door, interrupting the program's flow and taking
it elsewhere, we call these instructions A-traps.
    Let's look at a concrete example.  Let's say I'm writing a program
and I want to call PaintRect; I insert the following line into my
application:

    PaintRect(&myRect);

    This results in the compiler placing the following assembly code
in my program:

    Assembly code                                Machine code

    PEA        -$0008(A6)                        486E FFF8
    _PaintRect                                   A8A2

(Note the hex machine code translation on the left).  First, we put the
address of the rectangle I want to paint on the stack, then we
have one of these mysterious A-traps.  When the processor is bipping
along and hits this A-trap, it is mystified.  Unlike $486E (the PEA
instruction), there isn't any processor instruction specified by $A8A1;
the the processor doesn't know how to handle it in hardware, so it
calls a software routine to deal with it.  This software routine is
the trap dispatcher; it looks at what instruction you're trying to
execute (in this case $A8A1) and looks in a table it has to find
the routine that matches up with this trap.  In this case, the
table holds the address $4082C48C, which is where the code for
_PaintRect sits in the ROM on my machine.  The trap dispatcher then
cleans up the stack and jumps to this routine; the end result is
that to the system software, it looks like the application called
it directly in the same way any routine linked in with the application
would be.  When the system code is done, it returns to the code that
called the A-trap, in this case my application; to the application,
it all looks just like as if it had called a routine linked in in a
more traditional manner.
    OK, that covers the basic facts behind the dispatcher.  You can
patch traps by replacing the address of the system supplied routine
with the address of a routine of your own; the routines
GetTrapAddress and SetTrapAddress manipulate the trap table.
Basically, you can then intercept the calls the application makes;
rather than the system software getting called when the application
uses an a-trap, you will get control, allowing you to do your own
nefarious acts.  It's your responsibility to pass control on to the
system software when you're done, so you need to use GetTrapAddress
to get the address of the trap before you patch it and remember that
address; when you're done doing your stuff, you can jump to this
address to allow the system code to do what the application is asking.

Well, I'm getting tired and I want to go home and play pinball, so
I'm going to leave this there.  I've still got the previous post
I wrote on this, which discusses a specific question and details a
lot of how to pick which trap to patch; mail me if you want a copy.

Tim Dierks
MacDTS, but I speak for myself