Page 1 of 1

new sumacc rmaker with dynamic relocation

Posted: February 21st, 1985, 11:51 pm
by Info-Mac
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.2 9/18/84; site uw-beaver
Path: utzoo!watmath!clyde!burl!ulysses!mhuxr!mhuxj!houxm!vax135!cornell!uw-beaver!info-mac
From: info-mac@uw-beaver
Newsgroups: fa.info-mac
Subject: new sumacc rmaker with dynamic relocation
Message-ID:
Date: Fri, 25-Jan-85 05:08:16 EST
Article-I.D.: uw-beave.543
Posted: Fri Jan 25 05:08:16 1985
Date-Received: Sun, 27-Jan-85 05:57:42 EST
Sender: daemon@uw-beaver
Organization: U of Washington Computer Science
Lines: 1500

From: edmoy%ucbopal.CC@UCB-VAX

Here is a new version of rmaker that supports dynamic relocation for drivers
and window, menu and control definition procedures. It's in shar format.

This dynamic relocation scheme was needed, above the existing self relocating
scheme because desk accessories created by sumacc have a nasty bug in them.
If you run one, the crtdrvr routine will relocate the driver as needed.
If you close this desk accessory and open another, then while the second
is still open, try to reopen the first (sumacc) desk accessory, the Mac
will most certainly bomb. This is because the desk accessory has been moved
in memory when the second was started up, the the summac desk accessory
can't then relocate itself again.

My method of dynamic relocation causes the size to increase as relocation info
has to be kept around. But other than that it seems to work.

Also included in this file are a crtdrvr.s and crtwdef.s that implement
the dynamic relocation.

(Currently, the code segment is not dynamically relocating as normally it is
locked in memory when used and when the application is over, the heap is
cleared.)

Edward Moy
Computing Services
University of California
Berkeley, CA 94720

[email protected]
ucbvax!ucbopal!edmoy

----- cut here -------------------------------------- cut here -----------
#! /bin/sh
: This is a shar archive. Extract with sh, not csh.
echo x - rmaker.c
cat > rmaker.c
#include "res.h"
#include "b.out.h"
#include "quickdraw.h"
#include "toolintf.h"

#define bh filhdr

struct bhdr bh; /* b.out header */
char *malloc();
char *index();
char *rindex();
unsigned short htons(); /* host to "net" byte order, short. */
unsigned long htonl();

char seg0[sizeof(struct jumphead) + sizeof(struct jumptab)] = {
0,0,0,0x28, 0,0,2,0, 0,0,0,8, 0,0,0,0x20,
0,0, 0x3F,0x3C, 0,1, 0xA9,0xF0
}; /* "standard" segment 0 jump header/table */
char seg1[sizeof(struct codehead)] = { 0,0, 0,1 };

#define CRTMAGIC 0x602C /* jump at beginning of crtmac.s */
#define CRTLEN 10 /* length of relocation table in crtmac.s */
#define RELMAGIC 0x6034 /* jump at beginning of crt*.s */
#define RELLEN 12 /* length of relocation table in crt*.s */

#define NRESCOMP 50 /* max number of resources per compile */

struct rescomp { /* resource being compiled */
char rc_type[8]; /* resource type (e.g. "CODE") */
char *rc_name; /* resource name */
int rc_id; /* resource id number */
int rc_att; /* attributes */
int rc_length; /* length in resource file */
char *rc_data; /* pointer to data */
int rc_datalen; /* length of data */
FILE *rc_file; /* file to read data from */
int rc_filelen; /* length of data in file */
int rc_bss; /* number of zero pad bytes */
char *rc_rel; /* relocation info */
int rc_rellen; /* length of relocation info */
} rescomp[NRESCOMP], *rcp;

struct resfile rf; /* compiled resource file header */
struct resmap rm; /* compiled resource map header */
struct restype rt[NRESCOMP]; /* compiled resource type list */
struct resid ri[NRESCOMP]; /* compiled resource id list */

#define NAMELEN 1024
char rn[NAMELEN]; /* compiled resource name list */

char debugtype[8]; /* debug type switch */
FILE *fout; /* file for compiler output */
FILE *fin; /* file for compiler commands */
char fineof; /* true after all commands read */
char line[256]; /* line buffer */
char *lp; /* current position in line */
int linenum; /* line number in command file */

char *relpnt; /* current position in longrun area */
char *relrel; /* current position in reloc area */
int rellen; /* length of longrun area */
int reloff; /* current relocation offset */

char token[128]; /* current token being parsed */
char data[8*1024]; /* area to build simple resource data */
char *datap; /* pointer to data area */

/* type format handlers */
extern handstr(), handhexa(), handcode(), handdrvr(), handxdef();
extern handdlog(), handalrt(), handditl();
extern handwind(), handmenu(), handcntl();

struct typehand { /* type string to handler table */
char th_type[8]; /* e.g. "CODE" */
int (*th_handler)(); /* format handler function */
} typehand[] = {
"STR ", handstr,
"HEXA", handhexa,
"CODE", handcode,
"DRVR", handdrvr,
"ALRT", handalrt,
"DITL", handditl,
"DLOG", handdlog,
"WIND", handwind,
"MENU", handmenu,
"CNTL", handcntl,
"ICON", handhexa,
"ICN#", handhexa,
"CURS", handhexa,
"PAT ", handhexa,
"CDEF", handxdef,
"MDEF", handxdef,
"WDEF", handxdef,
0, 0
};


main(argc, argv)
char **argv;
{
for (argc--,argv++ ; argc > 0 ; argc--,argv++) {
if (argv[0][0] != '-')
break;
switch (argv[0][1]) {
case 'd':
argc--,argv++;
if (argc rc_type, type);
if (items == 3) {
checktype(format);
strcpy(type, format);
}
if (getline() == 0)
abort("bad id");
if (skipsp() == 0)
abort("bad id");
for (i=0 ; *lp != ',' && *lp != 0 ; lp++,i++)
infile = *lp;
infile = 0;
if (*lp != ',')
abort("bad id");
lp++;
id = att = 0;
items = sscanf(lp, " %d(%d) ", &id, &att);
ip = index(infile, '|');
if (ip) {
*ip++ = 0;
if ((rcp->rc_name = malloc(strlen(ip) + 1)) == 0)
abort("name malloc");
strcpy(rcp->rc_name, ip);
} else
rcp->rc_name = 0;
if (items rc_file = fopen(infile, "r")) == NULL)
abort("can't open input file %s", infile);
} else {
rcp->rc_file = 0;
}
rcp->rc_id = id;
rcp->rc_att = att;
/* search for type handler */
for (thp = &typehand[0] ; ; thp++) {
if (thp->th_handler == 0)
abort("type %s not implemented", type);
if (strcmp(thp->th_type, type) == 0)
break;
}
datap = data;
(*thp->th_handler)();
if (datap != data) {
int len = datap - data;
if (len & 1) {
len++;
*datap++ = 0;
}
if ((rcp->rc_data = malloc(len)) == 0)
abort("data malloc");
bcopy(data, rcp->rc_data, len);
rcp->rc_datalen = rcp->rc_length = len;
}
if (strcmp(type, debugtype) == 0)
printrcp();
rcp++;
if ((rcp - &rescomp[0]) > NRESCOMP - 3)
abort("too many resources");
}
if (rcp == &rescomp[0] || fout == 0)
abort("nothing to do");
}


/*
* Build resource file output from incore rescomp structure.
*/
buildrf()
{
register struct rescomp *rcpp;
register struct resid *rip;
register struct restype *rtp;
register char *rnp;
struct restype *rtpp;
int offdata, roundtomap, sizetypes, sizemap;
register i;
register char *cp;
numtypes_t numtypes;
lendata_t lendata;

/* XXX TODO: before scanning, sort rescomp by type/id */
rtp = &rt[0];
rip = &ri[0];
rnp = rn;
rcpp = &rescomp[0];
offdata = 0;
/*
* Scan through the resources making type and id lists. In this
* 1st pass, the rt_offids field is set to the offset from the
* start of the id's list. Below, the 2nd pass adds the size
* of the type list to this field.
*/
bcopy(rcpp->rc_type, rtp->rt_type, 4); /* preset 1st type */
for ( ; rcpp rc_type, rtp->rt_type, 4) != 0) {
rtp++; /* we've found a new type */
bcopy(rcpp->rc_type, rtp->rt_type, 4);
rtp->rt_offids = (rip - &ri[0]) * sizeof *rip;
}
rtp->rt_numids++;
rip->ri_id = htons(rcpp->rc_id); /* ensure final byte order */
if (rcpp->rc_name) {
rip->ri_offname = htons(rnp - rn);
i = strlen(rcpp->rc_name);
if (((rnp - rn) + i + 2) > NAMELEN)
abort("namemap exhausted");
if (strncmp(rcpp->rc_type, "DRVR", 4))
*rnp++ = (char) i;
else {
*rnp++ = (char)(i + 1);
*rnp++ = 0;
}
bcopy(rcpp->rc_name, rnp, i);
rnp += i;
}
else
rip->ri_offname = htons(-1);
rip->ri_att = rcpp->rc_att;
rip->ri_offdata = htons(offdata & 0xFFFF);
rip->ri_offdatahi = ((offdata >> 16) & 0xFF);
rip++;
offdata += (rcpp->rc_length + sizeof lendata);
}
rtp++;
/*
* Write the file header and pad it out.
*/
rf.rf_offdata = htonl(OFFDATA);
offdata += OFFDATA;
roundtomap = (offdata & (ROUNDMAP-1));
if (roundtomap)
roundtomap = ROUNDMAP - roundtomap; /* # of pad bytes */
rf.rf_offmap = offdata + roundtomap;
rf.rf_lendata = htonl(rf.rf_offmap - OFFDATA);
rf.rf_offmap = htonl(rf.rf_offmap);
sizetypes = ((numtypes = rtp - &rt[0]) * sizeof *rtp);
if ((rnp - rn) & 1) /* to be conservative */
*rnp++ = 0;
sizemap = sizeof rm + sizetypes + sizeof numtypes
+ ((rip - &ri[0]) * sizeof *rip) + (rnp - rn);
rf.rf_lenmap = htonl(sizemap);
fwrite(&rf, sizeof rf, 1, fout);
i = OFFDATA - sizeof rf;
do { putc(0, fout); } while (--i);
/*
* correct type list.
*/
for (rtpp = &rt[0] ; rtpp rt_offids = htons(rtpp->rt_offids
+ sizetypes + sizeof numtypes);
rtpp->rt_numids = htons(rtpp->rt_numids - 1);
}
/*
* For each resource, write data, file, and bss.
*/
for (rcpp = &rescomp[0] ; rcpp rc_length);
fwrite(&lendata, sizeof lendata, 1, fout);
if ((cp = rcpp->rc_data))
for (i = rcpp->rc_datalen ; i > 0 ; i--)
putc(*cp++, fout);
if (rcpp->rc_file)
for (i = rcpp->rc_filelen ; i > 0 ; i--)
putc(getc(rcpp->rc_file), fout);
for (i = rcpp->rc_bss ; i > 0 ; i--)
putc(0, fout);
if ((cp = rcpp->rc_rel))
for (i = rcpp->rc_rellen ; i > 0 ; i--)
putc(*cp++, fout);
}
for (i = roundtomap ; i > 0 ; i--)
putc(0, fout);
/*
* Write the resource map.
*/
rm.rm_offtype = htons(sizeof rm);
rm.rm_offname = htons(sizemap - (rnp - rn));
fwrite(&rm, sizeof rm, 1, fout);
numtypes--;
numtypes = htons(numtypes);
fwrite(&numtypes,sizeof numtypes, 1, fout);
fwrite(&rt[0], sizeof *rtp, rtp - &rt[0], fout);
fwrite(&ri[0], sizeof *rip, rip - &ri[0], fout);
fwrite(rn, rnp - rn, 1, fout);
}


/*
* Get next command line.
* Returns 0 if end of block, 1 if normal line.
*/
getline()
{
register i;

again:
if ((fgets(line, sizeof line, fin)) == NULL) {
fineof++;
return (0);
}
linenum++;
if ((i = strlen(line)) 4)
abort("bad type");
if (len == 3) {
s[3] = ' ';
s[4] = 0;
}
}


/*
* Copy bytes.
*/
bcopy(a, b, n)
register n;
register char *a, *b;
{
if (n rc_type, rcp->rc_id, rcp->rc_length, rcp->rc_datalen);
cp = rcp->rc_data; /* pick up the data pointer */
for (i=0 ; i rc_datalen ; i++) {
j = *cp++ & 0xFF;
if ((i % 16) == 15)
printf("%02X\n",j);
else
printf("%02X ",j);
}
printf("\n");
}


#define VAX
#define nohtonl
#ifdef nohtonl /* if not in library */
#ifdef VAX
/*
* "Host" to "net" byte order swappers.
*/
unsigned short htons(a)
unsigned short a;
{
unsigned short result;
register char *sp = (char *)&a;
register char *dp = (char *)&result;

dp[1] = *sp++;
dp[0] = *sp;
return (result);
}

unsigned long htonl(a)
unsigned long a;
{
unsigned long result;
register char *sp = (char *)&a;
register char *dp = (char *)&result;

dp[3] = *sp++;
dp[2] = *sp++;
dp[1] = *sp++;
dp[0] = *sp;
return (result);
}

#else /* if running on a native 68K, don't need byte swapping */

unsigned short htons(a)
unsigned short a;
{
return (a);
}

unsigned long htonl(a)
unsigned long a;
{
return (a);
}

#endif VAX

#endif nohtonl



/*
* T Y P E H A N D L E R S
*/


/*
* Handle string format data.
*/
handstr()
{
if (getline() == 0)
abort("missing string");
datastring(lp,1);
}


/*
* Handle hexadecimal format data.
*/
handhexa()
{
char hex[4];
int val, items, len;

hex[2] = 0;
while (getline() != 0) {
for (len = strlen(lp) ; len > 0 ; ) {
if (*lp == ' ') {
lp++; len--;
continue;
}
strncpy(hex, lp, 2);
items = sscanf(hex, "%x", &val);
if (items != 1)
abort("bad digits");
*datap++ = val;
lp += 2; len -= 2;
if ((datap - data) >= sizeof data)
abort("too much data");
}
}
len = datap - data;
if (len & 1) {
len++;
*datap++ = 0;
}
}


/*
* Handle program (code) data.
*/
handcode()
{
register i;
struct reloc rl;

/*
* setup CODE, id=0 (jumptable)
*/
if (rcp->rc_id == 0) {
rcp[1] = rcp[0]; /* duplicate rescomp entry */
rcp->rc_att = ATT_PURGEABLE;
rcp->rc_datalen = rcp->rc_length = sizeof seg0;
rcp->rc_data = seg0;
rcp->rc_file = (FILE *)0;
rcp->rc_bss = 0;
rcp++;
}
/*
* setup CODE, id=1 (text/data)
*/
if (fread(&bh, sizeof bh, 1, rcp->rc_file) != 1
|| bh.fmagic != FMAGIC)
abort("bad b.out header");
if ((rcp->rc_data = malloc(rcp->rc_datalen = bh.tsize
+ bh.dsize + sizeof seg1)) == 0)
abort("code malloc");
rcp->rc_id++; /* normally id is now 1 */
seg1[3] = rcp->rc_id; /* put id in jump table */
bcopy(seg1, rcp->rc_data, sizeof seg1);
rcp->rc_data += sizeof seg1;
if (fread(rcp->rc_data, rcp->rc_datalen - sizeof seg1,
1, rcp->rc_file) != 1)
abort("code readerror");
rcp->rc_bss = bh.bsize;
rcp->rc_length = rcp->rc_datalen + rcp->rc_bss;
if (!rcp->rc_att) /* set default attributes if none supplied */
rcp->rc_att = ATT_PURGEABLE | ATT_LOCKED | ATT_PRELOAD;
if ((bh.rtsize + bh.rdsize) rc_file, RTEXTPOS, 0);
if (*(short *)rcp->rc_data != htons(CRTMAGIC))
abort("no crtmac.s prefix");
relpnt = rcp->rc_data + 2; /* start of longrun table */
rellen = CRTLEN; /* length of longrun table */
reloff = 0;
readrel(0, bh.rtsize/sizeof rl); /* reloc text */
readrel(bh.tsize, bh.rdsize/sizeof rl); /* reloc data */
*(rcp->rc_data+reloff) = 0377; /* signals end of reloc data */
rcp->rc_data -= sizeof seg1;
fclose(rcp->rc_file);
rcp->rc_file = 0;
fprintf(stderr, " text %d, data %d, bss %d, longruns %d\n",
bh.tsize, bh.dsize, bh.bsize, CRTLEN - rellen);
}


/*
* Read relocation data and run length encode it.
*/
readrel(off, nrel)
{
struct reloc rl;
register char *cp;
int run, newoff;

for ( ; nrel > 0 ; nrel--) {
if (fread(&rl, sizeof rl, 1, rcp->rc_file) != 1)
abort("error reading reloc");
if (rl.rsize != RLONG || (rl.rpos & 1)
|| rl.rsymbol || rl.rsegment == REXT)
abort("impossible relocation");
newoff = (rl.rpos + off);
run = (newoff - reloff) >> 1;
if (reloff == 0 || run >= 0377) {
*(long *)relpnt = htonl(newoff);
relpnt += sizeof (long);
if (--rellen rc_data+reloff) = run;
}
reloff = newoff;
}
}


/*
* Handle device driver (or desk accessory.).
*/

#define DRVROFF 50 /* offset of longruns in DRVR resource */
#define DRVRMAGIC

handdrvr()
{
register i;
struct reloc rl;

if (fread(&bh, sizeof bh, 1, rcp->rc_file) != 1
|| bh.fmagic != FMAGIC)
abort("bad b.out header");
if((rcp->rc_rellen = (bh.rtsize + bh.rdsize) / sizeof(rl)) & 1)
rcp->rc_rellen++;
if ((rcp->rc_data = malloc((rcp->rc_datalen = bh.tsize
+ bh.dsize) + rcp->rc_rellen)) == 0)
abort("drvr malloc");
rcp->rc_rel = rcp->rc_data + rcp->rc_datalen;
if (fread(rcp->rc_data, rcp->rc_datalen, 1, rcp->rc_file) != 1)
abort("drvr readerror");
rcp->rc_bss = bh.bsize;
rcp->rc_length = rcp->rc_datalen + rcp->rc_bss + rcp->rc_rellen;
if ((bh.rtsize + bh.rdsize) rc_file, RTEXTPOS, 0);
if (*(short *)(rcp->rc_data+DRVROFF) != htons(RELMAGIC))
abort("no crtdrvr.s prefix");
relpnt = rcp->rc_data + DRVROFF + 2; /* start of longrun table */
rellen = RELLEN; /* length of longrun table */
*(long *)relpnt = htonl(rcp->rc_length
- rcp->rc_rellen); /* offset to reloc table */
relpnt += sizeof(long);
relrel = rcp->rc_rel; /* start of reloc table */
reloff = 0;
rdreloc(0, bh.rtsize/sizeof rl); /* reloc text */
rdreloc(bh.tsize, bh.rdsize/sizeof rl); /* reloc data */
*relrel = 0377; /* signals end of reloc data */
fclose(rcp->rc_file);
rcp->rc_file = 0;
fprintf(stderr,
" drvr text %d, data %d, bss %d, reloc %d, longruns %d\n",
bh.tsize, bh.dsize, bh.bsize, rcp->rc_rellen, RELLEN - rellen);
}

/*
* Read relocation data and run length encode it in a dynamically relocatable
* form.
*/
rdreloc(off, nrel)
{
struct reloc rl;
register char *cp;
int run, newoff;

for ( ; nrel > 0 ; nrel--) {
if (fread(&rl, sizeof rl, 1, rcp->rc_file) != 1)
abort("error reading reloc");
if (rl.rsize != RLONG || (rl.rpos & 1)
|| rl.rsymbol || rl.rsegment == REXT)
abort("impossible relocation");
newoff = (rl.rpos + off);
run = (newoff - reloff) >> 1;
if (reloff == 0 || run >= 0377) {
*(long *)relpnt = htonl(newoff);
relpnt += sizeof (long);
if (--rellen rc_file) != 1
|| bh.fmagic != FMAGIC)
abort("bad b.out header");
if((rcp->rc_rellen = (bh.rtsize + bh.rdsize) / sizeof(rl)) & 1)
rcp->rc_rellen++;
if ((rcp->rc_data = malloc((rcp->rc_datalen = bh.tsize
+ bh.dsize) + rcp->rc_rellen)) == 0)
abort("[cmw]def malloc");
rcp->rc_rel = rcp->rc_data + rcp->rc_datalen;
if (fread(rcp->rc_data, rcp->rc_datalen, 1, rcp->rc_file) != 1)
abort("[cmw]def readerror");
rcp->rc_bss = bh.bsize;
rcp->rc_length = rcp->rc_datalen + rcp->rc_bss + rcp->rc_rellen;
if ((bh.rtsize + bh.rdsize) rc_file, RTEXTPOS, 0);
if (*(short *)(rcp->rc_data) != htons(RELMAGIC))
abort("no crt[cmw]def.s prefix");
relpnt = rcp->rc_data + 2; /* start of longrun table */
rellen = RELLEN; /* length of longrun table */
*(long *)relpnt = htonl(rcp->rc_length
- rcp->rc_rellen); /* offset to reloc table */
relpnt += sizeof(long);
relrel = rcp->rc_rel; /* start of reloc table */
reloff = 0;
rdreloc(0, bh.rtsize/sizeof rl); /* reloc text */
rdreloc(bh.tsize, bh.rdsize/sizeof rl); /* reloc data */
*relrel = 0377; /* signals end of reloc data */
fclose(rcp->rc_file);
rcp->rc_file = 0;
fprintf(stderr,
" [cmw]def text %d, data %d, bss %d, reloc %d, longruns %d\n",
bh.tsize, bh.dsize, bh.bsize, rcp->rc_rellen, RELLEN - rellen);
}


/*
* Handle dialog template (DLOG).
*/

/*
* This structure is defined in toolintf.h, but to avoid byte swap
* and alignment problems, we fill it "by hand".
*
* typedef struct {
* Rect boundsRect;
* short procID;
* char visible;
* char filler1;
* char goAwayFlag;
* char filler2;
* long refCon;
* short itemsID;
* Str255 title;
* } DialogTemplate;
*/

handdlog()
{
int vis,go,pid,ref;
register i;

if (getline() == 0)
abort("no dlog rectangle");
for (i=0 ; i 0 ; val--) {
datalong(0);
if (getline() == 0) /* line with item types */
abort("Missing DITL item type");
types = 0;
while (scanft()) {
for (dk = &ditlkeys[0] ; dk->ditl_name ; dk++)
if (strcmp(dk->ditl_name,token) == 0)
goto found;
abort("bad DITL item type %s",token);
found:
types += dk->ditl_value;
}
if (getline() == 0)
abort("Missing DITL rectangle");
for ( i=0 ; i rc_id);
datalong(0);
datalong(0);
flagsp = (long *)datap; /* remember where the flags were */
flags = -1; /* enable all items */
datalong(-1); /* placeholder */
getline();
scanft();
datastring(token,0);
for (item = 1 ; getline() && item crtdrvr.s crtwdef.s << '28336!Funky!Stuff!'
|
| crtwdef.s - dynamically relocating C runtime startoff for window
| definition procedures
|
| Copyright (C) 1984, Stanford Univ. SUMEX project
| May be used but not sold without permission.
|
| history
| 01/10/85 Moy Created
|

.data
.text
.globl _savea5
.globl wdef
.globl MyWindow

wdef: jra .L21 | magic number
reloff: .long 0
.long 0,0,0,0,0,0,0,0,0,0 | longruns from rmaker
reladdr:.long 0
_savea5:.long 0

.L21:
moveml #0x3ffc,sp@-
lea pc@([reladdr-.-2]),a2 | reloc addr
lea pc@([wdef-.-2]),a3 | reloc factor
movl a3,d1
andl #0xffffff,d1 | clear out trash in high byte
subl a2@,d1 | have we moved?
beqs call
addl d1,a2@ | adjust reladdr
lea pc@([reloff-.-2]),a3
addl d1,a3@ | adjust addr of reloc table
movl a3@+,a4 | get addr of reloc table
addl d1,a3@ | adjust 1st relocation
movl a3@+,a2 | pickup 1st relocation

|
| a2 = current reloc address
| a3 = next longrun address
| a4 = next reloc table address
| d1 = relocation factor
|
| for(;;) {
| *(u_long *)a2 += (u_long)d1;
| if ((i = (*a4++ & 0377)) == 0) {
| *a3 += d1;
| a2 = *a3++;
| continue;
| }
| if (i == 0377)
| goto start;
| a2 += (i << 1);
| }
.L16:
addl d1,a2@
movb a4@+,d7
andl #255,d7
bnes .L19
addl d1,a3@
movl a3@+,a2
bras .L16
.L19:
cmpl #255,d7
beqs .L20
roll #1,d7
addl d7,a2
bras .L16
.L20:
movl a5,_savea5
call:
moveml sp@+,#0x3ffc
jmp MyWindow
28336!Funky!Stuff!