TweetFollow Us on Twitter

INITs, Patches
Volume Number:5
Issue Number:6
Column Tag:Forth Forum

Related Info: Resource Manager TrapWords

INITs and Patches

By Jörg Langowski, MacTutor Editorial Staff

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

“INITs and trap patches”

This month’s program started off as an attempt to write a ‘logging’ utility, that is, a routine that will record when applications are launched and closed. Simple, I thought. Just patch the _Launch and _ExittoShell traps and install some code that writes a line to a file giving the time, date and name of the application each time these traps are called. However, I soon realized that it’s not as simple as that. Under Finder, yes, that strategy works; but imagine my surprise when I found that _Launch is never called when an application is started under Multifinder! This ‘feature’ seems not to be documented in the technical notes that I have, nor in the Multifinder documentation.

If you record trap calls with TMON, you’ll find the following sequence for launching an application under Finder:

 _Launch
 _LoadSeg 
 _LoadSeg
 ... (until all necessary segments are loaded)

and for exiting, _ExittoShell is called. Multifinder seems to use the same sequence of calls, except for the first call to _Launch, which is left out.

Therefore, if we want to build a routine that logs application launches, we have to find another indicator. One trap call is always made when an application is started: _GetResource is called for CODE ID=0. If we patch _GetResource such that this particular call is intercepted, we have a ‘hook’ that allows us to install any routine to be called at application startup.

Patching traps under Multifinder

Traps cannot be easily patched in a permanent way under Multifinder. Since different application might need different trap patches, Multifinder intercepts (I believe) _SetTrapAddress and switches the trap patches when control is transferred from one program to another. So, when you write a short application that patches a trap, that patch will only be valid in the context of that application - and disappear when the application quits again. Not very useful for a routine that logs application launches, which will have to work independently of any particular context. So we’ll have to install the patch before Multifinder is started, and this is best done with an INIT.

This month’s example will show you how to write an INIT under Mach2 that installs permanent patches to _GetResource and _ExittoShell. For the moment, all these patches do is beep once when the application starts and when it quits. These patches would then have to be extended to write some text to a file that gives the name and time of the application.

I’ll also give an example of a small application that can be used to run an INIT from a file in the same folder as the application. It uses the same mechanism as the system itself to call the INIT. This program is based on an idea of Eric Carrasco from the Calvacom bulletin board in Paris, who wrote a similar program in Pascal.

The INIT

The mechanism by which an INIT resource is called has been outlined already by Bob Denny in V1#9. In case you’re missing that issue, I’ll quickly repeat it here: First, the INIT resource is loaded into the system heap. Then, _DetachResource is called which tells the resource manager to forget this resource. Finally, the system jumps to the first location of the INIT resource via a JSR. When the INIT later returns via RTS, the first two words in its code are overwritten by NOP instructions. The reason for this procedure, which might seem a little strange, is that an INIT code might consist of a JMP to some installation code at the end, and have the actual memory-resident part at its beginning. That way, when the JMP at the beginning is overwritten by NOPs, any code that jumps to the start of the INIT will now execute its main part. The initialization part at the end can be given back to the memory manager, once the INIT is installed.

Listing 1 shows the INIT code in Mach2. The kernel-independent code is produced in the usual way, using the external definition words which make sure the JMP at the first location if the INIT points to the right piece of code, and which set up the local Forth stack.

The INIT (word INITrun) first creates a handle to its own memory block by calling _RecoverHandle, then locks this handle. A temporary area for the Quickdraw globals is then created in the local variable space. Remember that local variables in Mach2 are allocated from top to bottom in memory, so that the sequence

newA5 myGlobals [ 202 lallot ]

with A5 later pointing to the address of newA5 will have the QD globals allocated correctly below A5. If your INIT needs to use any of them, simply reference them starting at myGlobals.

Our INIT code sets up A5 and the low memory global CurrentA5, then calls the usual manager initialization traps necessary for setting up a dialog box. After these calls, the environment is ready for calling the main Forth code of the INIT, myINIT in our case. From myINIT, all toolbox traps may be used since A5 points to valid QD global space and the managers have been initialized (oh not the menu manager, of course, but you probably wouldn’t want to use menus from an INIT. I doubt whether it would be possible, anyway. Try it out).

For an INIT that is supposed to stay in the system heap ‘as is’, you don’t need to take any special action in the code to free its memory space. However, when - as in our case - the INIT copies part of itself to a non-relocatable block in the system heap and is not needed anymore, we want to purge the memory space after action. This is done by calling _DisposHandle after myINIT has returned.

gINIT is the glue code that calls the standard ‘INIT interface’ INITrun. Here, the registers are saved, stacks are set up, and CurrentA5 is restored after INITrun has returned.

The main INIT code, myINIT, first moves the patch code into a non-relocatable block in the system heap. It then patches _GetResource, using _SetTrapAddress, and moves a vector to the trap’s old address into the appropriate location inside the patch. The user is notified of the patch by an alert. The _GetResource patch itself (GetResPatch) checks whether this trap has been called with resource type CODE, ID=0. In that case, it beeps once. Instead of the beep, one could insert some code that writes a line to a file which has been opened in the installation part of the INIT. Something left as an exercise

There is also a patch to _ExittoShell, ExitPatch, which is supposed to beep when an application quits. Now look at the code where the INIT installs that patch. We do a _GetTrapAddress, right, but then the ugly part starts. If _ExittoShell is patched by _SetTrapAddress at system INIT time, the patch gets installed correctly, and you hear the beep when the Finder quits and calls the Multifinder, but then, silence. The patch has disappeared. Multifinder patches _ExittoShell as well and probably doesn’t conserve previous patches. I don’t know whether this is a bug or a feature (such as not calling _Launch when starting an application); but it makes life a great deal more difficult. Apple, can you hear me?

Here’s the workaround that I thought up, which works under System 6.0.2, and is not guaranteed to work under a new release (no, don’t leave the room yet, PLEASE!). When Multifinder patches _ExittoShell, it installs a JMP instruction to its patch code in RAM. Our INIT code tests whether the pointer returned by _GetTrapAddress points to a JMP <absolute> instruction. In that case, it patches the next two words with a pointer to our patch code and saves the old JMP address in the patch code. If the first instruction is not a JMP <absolute>, we assume we’re running under Finder and use _SetTrapAddress to patch the trap. Ugly, isn’t it. The worst part is that if you run under Multifinder your patch will be installed and then removed again; then you have to run the INIT again under Multifinder to install the _ExittoShell patch permanently. But I couldn’t find an easier way, please tell me if you have one.

How can you run an INIT at all when Multifinder runs already? This is where the short runINIT application comes in (Listing 2). This program will simulate the way the system calls an INIT resource. It will locate the file ‘theINIT’ which must be in the same folder, get the INIT ID=12 resource from that file and execute it the same way the system boot code would do it. So for installing the _ExittoShell patch under Multifinder, you simply double-click runINIT in the system folder, or make it one of your startup applications.

INIT incompatibilities

Our INIT is also a practical case where we can document that frequent disease of Mac system folders, INIT incompatibility. This INIT calls all the toolbox managers necessary to set up an alert, and then actually displays one. That means, _WaitNextEvent will be called from the alert. Other INITs might patch _WaitNextEvent, _GetNextEvent or _SystemTask to take some action when the system is fully booted up. That way, for instance, the ‘Remember’ INIT seems to call its associated desk accessory when some important dates are coming up. The problem is, when Remember is executed before an INIT that displays a dialog, the patch will open the desk accessory, which produces disaster in form of a bomb box.

I guess this incompatibility will always occur when you have one INIT which patches _SystemTask or similar routines to execute some other application or DA later on. If another INIT happens to call the patched trap and the system is not ready yet for whatever the first INIT wanted to be executed, a crash will probably follow. Make sure that this INIT is executed before any INITs that patch _WaitNextEvent, _GetNextEvent or _SystemTask.

Mach2 news

Finally I want to advertise the GEnie Mach2 and FIG round tables again. There is simply more interesting stuff in the software libraries than I could ever discuss here; the Mach2 system has been extended by hundreds of useful words already (by the way, v2.15 is on its way), and you find more in the FIG Forth libraries. Especially with the ANSI Forth standard coming up, a lot of the discussion on that new standard - and its implications on Mach2 - takes place on GEnie. For those of you who can’t access GEnie, but have access to Bitnet directly or via a gateway, I’ll try to get a compilation of the most important new words to you if you send me electronic mail:

LANGOWSKI@FREMBL51.BITNET

Happy threading.

Listing 1: Trap patch INIT
\ INIT example which patches _GetResource 
\ with a call to _Sysbeep if type=CODE id=0
\ Also patches _ExitToShell, using an absolutely
\ AWFUL hack, but a _SetTrapAddress patch
\ seems to be removed under Multifinder
\ J. Langowski / MacTutor April 1989
only forth also mac also assembler
( *** compiler support words for external definitions *** )
: :xdef 
 create -4 allot
 $4EFA w, ( JMP )
 0 w,  ( entry point to be filled later )
 0 ,   ( length of routine to be filled later )
 here 6 - 76543
;

: ;xdef { branch marker entry | -- }
 marker 76543 <> abort” xdef mismatch”
 entry branch - branch w!
 here branch - 2+ branch 2+ !
; 
 
: xlen 4 + @ ; ( get length word of external definition )

\ **** ext procedure glue macros

CODE ext.prelude
 LINK A6,#-700   ( 700 bytes of local Forth stack )
 MOVEM.L A0-A5/D0-D7,-(A7)( save registers )
 MOVE.L A6,A3    ( setup local loop return stack )
 SUBA.L #500,A3  ( in the low 200 local stack bytes )
 RTS    \ just to indicate the MACHro stops here 
END-CODE MACH

CODE ext.epilogue
 MOVEM.L (A7)+,A0-A5/D0-D7( restore registers )
 UNLK A6
 RTS
END-CODE MACH

.trap _newPtr,SYS$A51E

-4 CONSTANT thePort
$904    CONSTANT CurrentA5
$A9A0 CONSTANT tGetRes  \ GetResource
$A9F4   CONSTANT tExit    \ ExitToShell

\ |--------------------------------|
\ | INIT resource code starts here |
\ |--------------------------------|

:xdef beeperINIT

header PatchStart
header oldGetRes
 DC.L 0
header oldExit
 DC.L 0

: GetResPatch
 ext.prelude
 CLR.L  D0
 MOVE.W 8(A6),D0
 MOVE.L 10(A6),D1
 MOVE.L D0,-(A6)
 MOVE.L D1,-(A6)

\ main FORTH code starts here
\ this can be used to log any launch
\ (i.e. GetResource CODE 0 ) to a log file
\ which has to be created/opened by the INIT code

 ascii CODE = swap 0= and IF
 \ (call) debugger
 1 (call) sysbeep
 THEN
\ end of main code

 ext.epilogue
 LEA    oldGetRes,A0
 MOVE.L (A0),A0
 JMP    (A0) 
;

: ExitPatch
 ext.prelude

\ main FORTH code starts here
\ this can eventually be used to write a line to 
\ the same log file as before
\(call) debugger
 1 (call) sysbeep
\ end of main code

 ext.epilogue
 LEA    oldExit,A0
 MOVE.L (A0),A0
 JMP    (A0) 
;

header PatchEnd

: movePatch { | length -- patch }
 [‘] patchEnd [‘] PatchStart -   -> length
 length
 MOVE.L (A6)+,D0
 _newPtr,sys
 MOVE.L A0,-(A6)
 dup IF ( we have space in system heap )
 [‘] PatchStart over length swap 
 (call) blockMove drop
 THEN
;
 
: myINIT { | patch pExit -- }
 movePatch -> patch
 patch IF
 \ patch _GetResource
 tGetRes (call) GetTrapAddress
 patch !\  old GetResource
 [‘] GetResPatch [‘] PatchStart -
 patch + tGetRes (call) SetTrapAddress
 “ GetResource patch has been installed.” 
 0 0 0 (call) ParamText
 1000 0 (call) NoteAlert drop

 \ patch _ExitToShell, using hack
 tExit (call) GetTrapAddress -> pExit
 pExit w@ $4EF9 = 
 IF \ is it a JMP <absolute> 
 \ ? we’re probably in Multifinder...
 pExit 2+ @
 patch 4+ ! \  old ExitToShell
 [‘] ExitPatch [‘] PatchStart -
 patch + pExit 2+ ! 
 \ patch directly into Juggler’s innards. BOO!
 “ ExitToShell patch in Multifinder.” 
 0 0 0 (call) ParamText
 1000 0 (call) NoteAlert drop
 ELSE
 pExit patch 4+ !
 [‘] ExitPatch [‘] PatchStart -
 patch + tExit (call) SetTrapAddress
 “ ExitToShell patch in Finder.” 
 0 0 0 (call) ParamText
 1000 0 (call) NoteAlert drop
 THEN
 ELSE
 “ Can’t get memory for patches.”
  0 0 0 (call) ParamText
 1000 0 (call) NoteAlert drop
 THEN
;

: INITrun { | newA5 myGlobals [ 202 lallot ] theHandle -- } 
\(call) debugger 
 [‘] beeperINIT (call) recoverHandle -> theHandle
 theHandle (call) Hlock drop
 ^ newA5
 MOVE.L (A6)+,A5 \ create area for QD globals
 MOVE.L A5,CurrentA5 \ A5 points to it
 ^ newA5 thePort + (call) InitGraf
 (call) InitFonts
 (call) InitWindows
 (call) TEInit
 0 (call) InitDialogs
 (call) InitCursor

 myINIT \ call main INIT routine

 theHandle (call) HUnLock drop
 theHandle (call) DisposHandle drop
;

: gINIT
 ext.prelude INITrun ext.epilogue
 MOVE.L A5,CurrentA5 
;

‘ gINIT ;xdef

( *** creating the INIT file *** )
: $create-res call CreateResFile call ResError L_ext ;

: $open-res { addr | refNum -- result }
 addr call openresfile -> refNum
 call ResError L_ext
 dup not IF drop refNum THEN 
;

: $close-res call CloseResFile call ResError L_ext ;

: make-init { | refNum -- }
 “ theINIT” dup $create-res drop
 $open-res dup -> refNum call UseResFile 
 ascii INIT 12 call GetResource 
 ?dup IF call RmveResource THEN
 [‘] beeperINIT dup xlen
 call PtrToHand drop ( result code )
 ascii INIT 12 call GetResource 
 ?dup IF call RmveResource THEN
 ascii INIT 12 “ Beeper” call AddResource
 refNum $close-res drop ( result code )
;
Listing 2: INIT runner application
\ INIT 12 starter
\ J. Langowski / MacTutor April 1989
\ Thanks to Eric Carrasco (Calvacom EC10) to this idea
\ which he implemented in Pascal
: $open-res { addr | refNum -- result }
 addr call openresfile -> refNum
 call ResError L_ext
 dup not IF drop refNum THEN 
;

: $close-res call CloseResFile call ResError L_ext ;

$4E714E71 CONSTANT nopnop

: runINIT { | refNum hINIT -- }
 “ theInit” $open-res -> refNum
 refNum 0 > IF
 ascii INIT 12 call GetResource -> hINIT
 hINIT IF
 hINIT call HomeResFile
 refNum = IF
 hINIT call DetachResource
 hINIT @ execute \ run the INIT
 nopnop hINIT @ !  
 \ fill first 2 words with NOPs
 ELSE
 “ INIT not from my file” 0 0 0 call ParamText
 1000 0 call NoteAlert drop
 THEN
 ELSE
 “ Can’t find INIT 12 resource” 
 0 0 0 call ParamText
 1000 0 call NoteAlert drop
 THEN
 ELSE
 “ Can’t open file ‘theINIT’” 0 0 0 call ParamText
 1000 0 call NoteAlert drop
 THEN
 bye
;
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

CleanMyMac 3.9.2 - $39.95
CleanMyMac makes space for the things you love. Sporting a range of ingenious new features, CleanMyMac lets you safely and intelligently scan and clean your entire system, delete large, unused files... Read more
Printopia 3.0.4 - Share Mac printers wit...
Run Printopia on your Mac to share its printers to any capable iPhone, iPad, or iPod Touch. Printopia will also add virtual printers, allowing you to save print-outs to your Mac and send to apps.... Read more
Tinderbox 7.3.1 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more
ExpanDrive 6.1.6 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
Printopia 3.0.4 - Share Mac printers wit...
Run Printopia on your Mac to share its printers to any capable iPhone, iPad, or iPod Touch. Printopia will also add virtual printers, allowing you to save print-outs to your Mac and send to apps.... Read more
Tinderbox 7.3.1 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more
ExpanDrive 6.1.6 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
VOX 3.0.1 - Music player that supports m...
VOX just sounds better! The beauty is in its simplicity, yet behind the minimal exterior lies a powerful music player with a ton of features and support for all audio formats you should ever need.... Read more
Merlin Project 4.3.3 - $289.00
Merlin Project is the leading professional project management software for OS X. If you plan complex projects on your Mac, you won’t get far with a simple list of tasks. Good planning raises... Read more
Mac DVDRipper Pro 7.1 - Copy, backup, an...
Mac DVDRipper Pro is the DVD backup solution that lets you protect your DVDs from scratches, save your batteries by reading your movies from your hard disk, manage your collection with just a few... Read more

Latest Forum Discussions

See All

Mille Bornes (Games)
Mille Bornes 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: | Read more »
Blob gets a new look in Give It Up! 3
Blob makes his triumphant return, as Yoozoo Games and Invictus Gaming have joined forces to create Give It Up! 3, the third in a series of delightful action-adventure games featuring our wobbly friend Blob. In this newest adventure, you’ll get to... | Read more »
148Apps' Ultimate Guide to Black Fr...
Black Friday is here, and there are a whole lot of discounts running right now for folks on the lookout for new mobile devices, accessories, and yes, even games. Here's a helpful rundown of what you'll find both in stores and online. Happy... | Read more »
The best Black Friday mobile game deals
Black Friday's upon us, and if you've happened to nab a fancy new phone during the week's big savings, you might be searching for some new games to fill up space on your new gadget. There are a lot of great games on sale right now for Black Friday... | Read more »
The best mobile games to play while your...
Thanksgiving is a time to reconnect with loved ones, eat lots of food, and all of that jazz, but once the festivities start to wind down, folks tend to head to the couch to watch whatever football is happening for Turkey Day. | Read more »
The best Black Friday deals for Apple ga...
Black Friday is hours away at this point, but many popular retailers are getting a jump on things with plenty of pre-Black Friday sales already available. Many of those early bird sales including some sharp discounts on the latest Apple phones... | Read more »
The Inner World 2 (Games)
The Inner World 2 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Solve mind-bending puzzles in a world full of mystery and save the family of the flute-noses! Their dynasty has been... | Read more »
warbot.io wants you for the robot wars
Fans of epic gundam-style battles will find a lot to love in warbot.io, the first game for up and coming developer Wondersquad. The game saw a lot of success when it first launched for browsers and Facebook, and now even more people are getting the... | Read more »
Uncover alien mysteries in cross-genre s...
If the Alien franchise taught us anything, it’s that landing on a strange planet at the behest of a faceless corporation is probably asking for trouble. And Eldritch Game’s Deliria doesn’t prove otherwise. In 2107, Dimension LG7 is rich with... | Read more »
The best mobile games to play during dre...
| Read more »

Price Scanner via MacPrices.net

Apple Black Friday sale for 2017: $150 Apple...
BLACK FRIDAY Apple has posted their Black Friday deals for 2017. Receive a $150 Apple gift card with the purchase of select Macs and up to $100 with various iPads, iPhones, and Apple Watches. The... Read more
Black Friday 2017: Where to find the best dea...
B&H Photo has 15″ and 13″ MacBook Pros on sale for up to $200 off MSRP as part of the Black Friday and Holiday sale. Shipping is free, and B&H charges sales tax for NY & NJ residents only... Read more
Black Friday 2017: Where to find the best dea...
B&H Photo has 12″ MacBooks on sale for $150 off MSRP as part of the Black Friday and Holiday sale. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 12″ 1.2GHz... Read more
Black Friday 2017: Where to find the best dea...
B&H Photo has 10.5″ iPad Pros in stock today and on sale for up to $130 off MSRP. Each iPad includes free shipping, and B&H charges sales tax in NY & NJ only: – 10.5″ 64GB WiFi iPad Pro... Read more
Black Friday 2017: Where to find the best dea...
B&H Photo has 13″ MacBook Airs on sale for up to $150 off MSRP as part of the Black Friday and Holiday sale. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13″... Read more
Black Friday 2017: Where to find the best dea...
B&H Photo has 27″ and 21″ iMacs on sale for up to $200 off MSRP as part of the Black Friday and Holiday sale. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 27... Read more
Black Friday 2017: Where to find the best dea...
B&H Photo has Mac minis on sale for $100 off MSRP as part of their Black Friday sale, each including free shipping plus NY & NJ sales tax only: – 1.4GHz Mac mini: $399 $100 off MSRP – 2.6GHz... Read more
Black Friday 2017: Find the best deals and lo...
Scan our exclusive price trackers for the latest Black Friday 2017 sales & deals and the lowest prices available on Apple Macs, iPads, and gear from Apple’s authorized resellers. We update the... Read more
Black Friday: 27″ 3.4GHz iMac for $1599, save...
Amazon has the 27″ 3.4GHz Apple iMac on sale for $1599.99 as part of their Black Friday sale. That’s $200 off MSRP, and shipping is free. Their price is currently the lowest price available for this... Read more
Black Friday: 13″ 2.3GHz/256GB MacBook Pro fo...
Amazon has the 13″ 2.3GHz/256GB Apple MacBook Pro on sale for $1299.99 as part of their Black Friday sale. Shipping is free: – 13-inch 2.3GHz/256GB Space Gray MacBook Pro (MPXT2LL/A): $1299.99 $200... Read more

Jobs Board

Business Development Manager, *Apple* Pay -...
# Business Development Manager, Apple Pay Job Number: 112919084 Santa Clara Valley, California, United States Posted: 18-Aug-2017 Weekly Hours: 40.00 **Job Summary** Read more
Digital Marketing Media Planner, *Apple* Se...
# Digital Marketing Media Planner, Apple Services Job Number: 113080212 Culver City, California, United States Posted: 03-Oct-2017 Weekly Hours: **Job Summary** Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Business Development Manager, *Apple* Pay -...
# Business Development Manager, Apple Pay Job Number: 112919084 Santa Clara Valley, California, United States Posted: 18-Aug-2017 Weekly Hours: 40.00 **Job Summary** Read more
*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 56553863 North Wales, Pennsylvania, United States Posted: 17-Jun-2017 Weekly Hours: 40.00 **Job Summary** Are you passionate Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.