home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
oxcc1433.zip
/
SRC
/
OXCCB.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-05
|
198KB
|
9,117 lines
/*
oxccb.c -- v1.430 architecture neutral format (anf) to bytecode generator
Copyright (c) 1995
Norman D. Culver dba
Oxbow Software
1323 S.E. 17th Street #662
Ft. Lauderdale, FL 33316
(305) 527-1663 Voice
(305) 760-7584 Fax
(305) 760-4679 Data
norman.culver@channel1.com
All rights reserved.
* Redistribution and use in source and binary forms are permitted
* provided that: (1) source distributions retain this entire copyright
* notice and comment, and (2) distributions including binaries display
* the following acknowledgement: ``This product includes software
* developed by Norman D. Culver dba Oxbow Software''
* in the documentation or other materials provided with the distribution
* and in all advertising materials mentioning features or use of this
* software.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#define MAJOR_VERSION 1
#define MINOR_VERSION 433
void oxcc_debug();
int __builtin_iv();
void bterpdebug(void);
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <setjmp.h>
#include <time.h>
#define SUPPORT_LONG_DOUBLE 1
#define SUPPORT_LONG_LONG 1
#define NEED_SPELLING 1
#define NEED_BYTECODES 1
#define NEED_AOUT_FORMAT 1
#include "oxbytes.h"
#define NEED_FUNCTHUNK 1
#define NEED_ANFDEFS 1
#include "oxanf.h"
#define PROG oxccb
#define USING_FRAMEWORK 1
#define HOST_IS_LITTLE_ENDIAN 1
#define REALLY_NEED_OFFSETS 1
#define FUNCDATA (iv->category+1)
#define VFPRINTF(a,b) vfprintf(stderr,a,b)
#define PERROR prerror
#define PWARN prwarn
#define PRINTF info
static void prerror(const char *, ...);
static void prwarn(const char *, ...);
static void info(const char *, ...);
int cfeprintf(const char *, ...);
#define FILEWRITE(buf, cnt)\
{if(!iv->errors){if(fwrite(buf, 1, cnt, iv->outfile) != cnt)iv->errors = 12;}}
#define ROUNDING(a,b) ((b-(a&(b-1)))&(b-1))
#define ROUNDUP(a,b) a += ROUNDING(a,b)
#define KEYEQ(a,b) ((a)[0] == (b)[0] && (a)[1] == (b)[1])
#define KEYLT(a,b) (((a)[1] < (b)[1]) || ((a)[1] == (b)[1] && (a)[0] < (b)[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
/* ======================== CONCATENIZATION MACROS ==================== */
#define _cat2_(a, b) a##b
#define _cat_(a, b) _cat2_(a, b)
#define Global(a) _cat_(PROG, a)
#define _pname2_(x) #x
#define _pname1_(x) _pname2_(x)
#define pName _pname1_(PROG)
/* ============== ENDIAN MACROS (input format is litle endian) ==== */
#if HOST_IS_LITTLE_ENDIAN
#define GL(a) a
#define GS(a) a
#define PL(a) a
#define PS(a) a
#else
#endif
/* =================== INPUT DATA FORMATS ========================== */
#define INFILE_SYMNUM 1
#define OUTFILE_SYMNUM 2
static unsigned char binops[] = {0,0,
ADD,SUB,MUL,DIV,LSH,RSH,MOD,OR,XOR,AND,EQ,NE,LT,GT,LE,GE,
NEG,COMP,NOT
};
/* ====================== STRUCTURES AND TYPEDEFS ======================== */
typedef struct _jl {
struct _jl *next;
void *p;
char *q;
long *plabelval;
long offset;
} *PJL;
typedef struct _el {
struct _el *next;
long spot;
short symnum;
} *PEL;
typedef struct _afile {
unsigned char *file_p;
PopI header_p;
PopI size_p;
unsigned char *symtext_p;
unsigned char *prog_p;
unsigned char *data_p;
unsigned char *switch_p;
unsigned char *decl_p;
unsigned char *maxtemp_p;
unsigned char *seg_p;
unsigned char **symaddr;
unsigned char **decladdr;
unsigned long thunk_offset;
unsigned long bss_offset;
int maxtemp;
int maxtempclass;
void *datatbl;
short *symtran;
unsigned short *decltran;
int filenum;
int numsyms;
int numdecls;
int numrelocs;
int numsegs;
} *Pafile;
typedef struct _iv {
int category;
FILE *outfile;
struct exec *header;
unsigned char **symaddr;
unsigned char **decladdr;
int remove_infile;
int argc;
char **argv;
int numfiles;
int lastlabel;
int errors;
int numsyms;
int numdecls;
int numsegs;
int maxtemp;
int maxtempclass;
unsigned long total_size;
unsigned long thunk_offset;
unsigned long bss_offset;
struct _nodeO *ob_usedhead;
struct _nodeO *ob_usedtail;
struct _nodeO *ob;
unsigned char *ob_buf;
int ob_bufcnt;
struct _nodeO *first_ob;
struct _nodeC *cod_usedhead;
struct _nodeC *cod_usedtail;
struct _nodeC *cod;
unsigned char *cod_buf;
int cod_bufcnt;
struct _nodeC *first_cod;
struct _nodeC *regcode;
long first_temp;
long killop;
long stackdepth;
long maxdepth;
long mindepth;
long numnested;
long lastline;
void *reloctbl;
void *extrntbl;
void *gbltbl;
void *symtbl;
void *labeltbl;
void *newlabeltbl;
void *tmptbl;
void *segtbl;
void *functbl;
void *finalsymtbl;
void *finalstringpack;
long finalpacksize;
void *datatbl;
void *builtintbl;
int in_builtin;
int has_structret;
int temps_written;
unsigned char *obuf;
unsigned char *obufstart;
PEL extbuf;
void *extbufstart;
int extcnt;
int extbufcnt;
PEL finextbuf;
void *finextbufstart;
int finextcnt;
int finextbufcnt;
PJL jbuf;
void *jbufstart;
int jmpcnt;
int jbufcnt;
long obufcnt;
long out_offset;
long func_offset;
int extmark;
short markedsym[10];
char *markedbuf[10];
int filenum;
Pafile files[1024];
char debug;
char only_debug;
char strip;
char listing_wanted;
} *Piv;
struct _gloval {
char *symname;
int symnum;
unsigned char *p;
Pafile pf;
};
struct _rkey {/* key area of reloctbl node */
unsigned long spot;
short fileno;
unsigned char opcode;
char rsize;
};
struct _rval {/* value area of reloctbl node */
unsigned char *p;
unsigned long *base;
long offset;
short rsym;
};
/* Internal User API */
static void *Cmalloc(int category, unsigned amount);
static void *Ccalloc(int category, unsigned nelems, unsigned elemsize);
static void *Crealloc(int category, void* buf, unsigned newsize);
static void Cfree(int category, void* buf);
static void Cfreecat(int category);
static int Cmemrange(int category, unsigned* minp, unsigned* maxp);
static int Cusedrange(int category, unsigned* minp, unsigned* maxp);
static void Ctotrange(unsigned* minp,unsigned* maxp);
static int Cnewcat(void);
static void Cguard(int category);
static void* NewSymTable(int category, int nbins);
static int SymFind(void *tbl, void *key, void *result);
static int SymFindRange(void *tbl, void *key, void *result);
static void *SymInsert(void *tbl, void *key, void *value, int datsiz);
static int StringInsert(void *tbl, char *string, void *result);
static int StringFind(void *tbl, char *string, void *result);
static void SymDelete(void *tbl, void *key);
static int SymHead(void *tbl);
static int SymNext(void *tbl);
static void SymGetMark(void *tbl, void *markptr);
static int SymMarkNext(void *tbl, void *mark);
static void SymSetMark(void *tbl, void *markptr);
static void SymKey(void *tbl, void *keyptr);
static void SymValue(void *tbl, void *datptr);
static void *seg_find(Piv iv, int id);
static char *filenameof(char *path);
static char *propernameof(Piv iv, char *name);
/* END: User API */
/* ====================== PUT UNIQUE CODE HERE ========================= */
static void newlabel_insert(Piv iv, long label);
static long newlabel_fix(Piv iv, long label);
static void *do_stmt(Piv iv, unsigned char *p);
static void *do_expr(Piv iv, unsigned char *p);
static void do_bracket(Piv iv, unsigned char *p, unsigned char *q);
static void *do_something(Piv iv, unsigned char *p);
extern char *ctime();
/* ===================== BYTECODE OUTPUT GENERATOR ======================= */
struct _nodeOBUF
{
struct _nodeOBUF *next;
long cnt;
char buf[1];
};
typedef struct _nodeC
{
struct _nodeC *next;
struct _nodeOBUF *ee;
} NODEC, *PNODEC;
typedef struct _nodeO
{
struct _nodeO *next;
unsigned char *p;
ND d;
ND l;
ND r;
PNODEC startinst;
PNODEC endinst;
} NODEO, *PNODEO;
static unsigned char get_datasize(unsigned char, PND);
static void link_cod(Piv);
static char *notice =
" Generated by Oxbow Software Bytecode Backend version %d.%d\n*/\n\n";
static struct _nd longtype = {D_SIGNED,0,B4,0,4,0,0};
static struct _nd longlongtype = {D_SIGNED,0,B8,0,8,0,0};
static char padit[8]; /* in bss */
void
bterpdebug(){}
static long
symnumof(Piv iv, char *symb)
{
struct _gloval *valp;
if(StringFind(iv->gbltbl, symb, &valp))
return (long)valp->pf->symtran[valp->symnum];
return 0;
}
static void
buildin(Piv iv, char *symb, unsigned char code)
{
long key[2];
if((key[0] = symnumof(iv, symb)))
{
key[1] = 0;
SymInsert(iv->builtintbl, key, &code, 1);
}
}
static void
install_builtins(Piv iv)
{/* USE THIS TO INSTALL WHATEVER BUILTINS ARE IN THE TARGET INTERPRETER */
#define BUILDIN(a,b) buildin(iv,#a,b)
iv->builtintbl = NewSymTable(iv->category, 191);
BUILDIN(alloca,ALLOCA);
BUILDIN(strlen,STRLEN);
BUILDIN(strcpy,STRCPY);
BUILDIN(strcat,STRCAT);
BUILDIN(memcpy,MEMCPY);
BUILDIN(memmove,MEMMOVE);
BUILDIN(bzero,BZERO);
BUILDIN(malloc,MALLOC);
BUILDIN(calloc,CALLOC);
BUILDIN(realloc,REALLOC);
BUILDIN(setjmp,SETJMP);
BUILDIN(longjmp,LONGJMP);
BUILDIN(abort,ABORT);
BUILDIN(exit, EXIT);
BUILDIN(_exit,EXIT);
BUILDIN(bterpdebug,DEBUG);
BUILDIN(bterpnodebug,NODEBUG);
#undef BUILDIN
}
static long
final_strofs(Piv iv, char *string)
{
long *result;
if(StringFind(iv->finalsymtbl, string, &result))
return result[2];
return 0;
}
static short
final_symnum(Piv iv, short symnum)
{
long *result;
if(StringFind(iv->finalsymtbl, iv->symaddr[symnum], &result)) {
return result[1]-1;
}
return 0;
}
static void
make_final_symtab(Piv iv)
{
int i;
iv->finalsymtbl = NewSymTable(iv->category, 0);
if(SymHead(iv->gbltbl))
{
i = 0;
while(SymNext(iv->gbltbl))
{
long *result;
struct _gloval *valp;
SymValue(iv->gbltbl, &valp);
if(*(valp->p))
{
long key[2];
key[0] = valp->pf->symtran[valp->symnum];
key[1] = 0;
if(!SymFind(iv->builtintbl, key, NULL))
{
if(!StringInsert(iv->finalsymtbl, valp->symname, &result))
{/* New Entry */
result[1] = ++i;
}
}
}
}
}
}
static void
adjust_labels(Piv iv, long base, long adjust)
{
long *key;
long *val;
if(SymHead(iv->newlabeltbl))
{
while(SymNext(iv->newlabeltbl))
{
SymKey(iv->newlabeltbl, &key);
SymValue(iv->newlabeltbl, &val);
if(key[1] == iv->filenum && val[0] > base) {
val[0] += adjust;
}
}
}
}
static void
addto_extlist(Piv iv, char *buf)
{
void *next;
while(iv->extmark > 0)
{
long offset = iv->markedbuf[iv->extmark] - buf;
next = iv->extbuf;
if(iv->extbufcnt >= sizeof(struct _el))
{
iv->extbuf++;
}
else
{
iv->extbufcnt = 4080;
iv->extbuf = Ccalloc(FUNCDATA, 1, iv->extbufcnt);
}
*((void**)next) = iv->extbuf;
iv->extbuf->spot = iv->out_offset+iv->func_offset+offset;
iv->extbuf->symnum = iv->markedsym[iv->extmark];
++iv->extcnt;
--iv->extmark;
iv->extbufcnt -= sizeof(struct _el);
}
}
static void
save_extlocs(Piv iv)
{
PEL pel = iv->extbufstart;
void *next;
while(pel)
{
next = iv->finextbuf;
if(iv->finextbufcnt >= sizeof(struct _el))
{
iv->finextbuf++;
}
else
{
iv->finextbufcnt = 4080;
iv->finextbuf = Ccalloc(iv->category, 1, iv->finextbufcnt);
}
*((void**)next) = iv->finextbuf;
iv->finextbuf->spot = pel->spot;
iv->finextbuf->symnum = pel->symnum;
++iv->finextcnt;
iv->finextbufcnt -= sizeof(struct _el);
pel = pel->next;
}
}
static void
adjust_externs(Piv iv, long base, long adjust)
{
PEL pel = iv->extbufstart;
while(pel)
{
if(pel->spot > base)
pel->spot += adjust;
pel = pel->next;
}
}
static int
shorten_jmps(Piv iv)
{
int scnt;
PJL jp;
long jmp_offset;
long label_offset;
long diff;
long offset_adjust;
int sign;
unsigned char *q, *osiz;
int cursize, newsize;
scnt = 0;
jp = iv->jbufstart;
offset_adjust = 0;
while(jp)
{
osiz = jp->q+4; /* points to size in obuf */
q = osiz+4; /* points to the JMP inst in obuf */
cursize = *q & 3; /* from the output bytecode */
jmp_offset = jp->offset + offset_adjust;
jp->offset = jmp_offset; /* reset the offset for this inst */
label_offset = *jp->plabelval;
diff = label_offset - jmp_offset;
sign = 1;
if(diff < 0)
{
sign = -1;
diff = -diff;
}
if(diff < 0x7fL)
newsize = 0;
else if(diff < 0x7fffL)
newsize = 1;
else if(diff < 0x007fffffL)
newsize = 2;
else
newsize = 3;
if(cursize != newsize)
{/* DO SOMETHING */
long adj;
static long codesize[4] = {2L,3L,4L,5L};
++scnt; /* something changed */
*q &= 0xfc; /* mask opcode */
*q |= newsize; /* set size in opcode */
*((long*)osiz) = codesize[newsize]; /* set new output size */
adj = codesize[newsize] - codesize[cursize];
offset_adjust += adj; /* jmps below this point have new offset */
if(sign > 0) diff += adj; /* label is below this point */
/* Adjust all labels below this point */
adjust_labels(iv, jmp_offset, adj);
/* adjust all external address spots (text relocs) below this point */
adjust_externs(iv, jmp_offset, adj);
}
diff *= sign; /* restore sign to the relative address */
/* generate the pc relative address */
++q; /* points the the address field of the JMP inst */
if(newsize == 0)
*((signed char*)q) = (signed char)(diff & 0xff);
else if(newsize == 1)
*((short*)q) = (short)(diff & 0xffff);
else if(newsize == 2)
*((long*)q) = diff<<8;
else
*((long*)q) = diff;
jp = jp->next;
}/* END: while (jp) */
return scnt;
}
static void
setup_jmps(Piv iv, unsigned char *pdef)
{
struct {
long k1;
long k2;
} key;
long *result;
PJL jp;
unsigned char *p;
jp = iv->jbufstart;
while(jp)
{
p = jp->p;
key.k1 = GL( POP->data ); /* label number from source code */
key.k2 = iv->filenum; /* source file number */
if(SymFind(iv->newlabeltbl, &key, &result))
{
jp->plabelval = result; /* save pointer to label value */
}
else
{
PERROR(pName ":Syserr: jmp setup failed for `%s' label=%d file=%d p=%x code=%d\n",
iv->symaddr[GL(((Pop)pdef)->data)], key.k1, key.k2, p, *p);
}
jp = jp->next;
}
}
static void
addto_jmplist(Piv iv, unsigned char *p, void *q)
{
void *next = iv->jbuf;
if(iv->jbufcnt >= sizeof(struct _jl))
{
iv->jbuf++;
}
else
{
iv->jbufcnt = 4080;
iv->jbuf = Ccalloc(FUNCDATA, 1, iv->jbufcnt);
}
*((void**)next) = iv->jbuf;
iv->jbuf->p = p;
iv->jbuf->q = q;
iv->jbuf->offset = iv->out_offset+iv->func_offset-5;
iv->jbufcnt -= sizeof(struct _jl);
}
static void
save_maxdepth(Piv iv, long symnum)
{
long key[2];
long val[3];
if(iv->functbl == 0)
{
iv->functbl = NewSymTable(iv->category, 277);
}
key[0] = symnum;
key[1] = 0;
val[0] = iv->maxdepth + (4*iv->numnested);
val[1] = iv->mindepth;
val[2] = 0;
SymInsert(iv->functbl, key, val, 12);
}
static long
get_maxdepth(Piv iv, short symnum)
{
long key[2];
long *result;
key[0] = symnum;
key[1] = 0;
if(SymFind(iv->functbl, key, &result))
{
return result[0];
}
return 0;
}
static void
printline(Piv iv, void *ptr)
{
fprintf(iv->outfile, "Line:%ld:\n", *((long*)ptr));
}
static int
print8(Piv iv, unsigned char *ptr, int size, long offset, int lf)
{
char buf[40];
int i, j=0;
i = sprintf(buf, "%8.8lx: ", offset);
while(j < size && j < 8)
{
i += sprintf(&buf[i], "%2.2x ", *ptr++);
++j;
}
if(lf)
buf[i++] = '\n';
else
{
while(i < 35)
buf[i++] = ' ';
}
buf[i] = 0;
fprintf(iv->outfile, buf);
return j;
}
static void
printinst(Piv iv, unsigned char *pc, long size)
{
int i, bufcnt;
unsigned char *epc;
char *pbuf[20];
bufcnt = 0;
epc = pc + size;
for( ;pc < epc; ++pc)
{
switch(*pc)
{
case LOCATE|J1:
case LOCATE|J2:
case LOCATE|J3:
case LOCATE|J4:
pbuf[bufcnt++] = "locate|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;
case LS|A1|B1:
case LS|A1|B2:
case LS|A1|B4:
case LS|A1|B8:
case LS|A2|B1:
case LS|A2|B2:
case LS|A2|B4:
case LS|A2|B8:
case LS|A3|B1:
case LS|A3|B2:
case LS|A3|B4:
case LS|A3|B8:
pbuf[bufcnt++] = "ls|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += Acnt[(*pc>>2) & 0x03];
break;
case NEG|BYTE:
case NEG|SHORT:
case NEG|LONG:
case NEG|UBYTE:
case NEG|USHORT:
case NEG|ULONG:
case NEG|FLOAT:
case NEG|DOUBLE:
pbuf[bufcnt++] = "neg|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case LM|A1|B1:
case LM|A1|B2:
case LM|A1|B4:
case LM|A1|B8:
case LM|A2|B1:
case LM|A2|B2:
case LM|A2|B4:
case LM|A2|B8:
case LM|A3|B1:
case LM|A3|B2:
case LM|A3|B4:
case LM|A3|B8:
case LM|A4|B1:
case LM|A4|B2:
case LM|A4|B4:
case LM|A4|B8:
pbuf[bufcnt++] = "lm|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += Acnt[(*pc>>2) & 0x03];
break;
case COMP|B1:
case COMP|B2:
case COMP|B4:
case COMP|B8:
pbuf[bufcnt++] = "comp|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;
case JMP|J1:
case JMP|J2:
case JMP|J3:
case JMP|J4:
pbuf[bufcnt++] = "jmp|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;
case JMPT|J1:
case JMPT|J2:
case JMPT|J3:
case JMPT|J4:
pbuf[bufcnt++] = "jmpt|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;
case LJMPT|J1:
case LJMPT|J2:
case LJMPT|J3:
case LJMPT|J4:
pbuf[bufcnt++] = "ljmpt|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;
case JMPF|J1:
case JMPF|J2:
case JMPF|J3:
case JMPF|J4:
pbuf[bufcnt++] = "jmpf|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;
case LJMPF|J1:
case LJMPF|J2:
case LJMPF|J3:
case LJMPF|J4:
pbuf[bufcnt++] = "ljmpf|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;
case NOT|B1:
case NOT|B2:
case NOT|B4: /* also FLOAT */
case NOT|B8: /* also DOUBLE */
pbuf[bufcnt++] = "not|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;
case SS|A1|B1:
case SS|A1|B2:
case SS|A1|B4:
case SS|A1|B8:
case SS|A2|B1:
case SS|A2|B2:
case SS|A2|B4:
case SS|A2|B8:
case SS|A3|B1:
case SS|A3|B2:
case SS|A3|B4:
case SS|A3|B8:
pbuf[bufcnt++] = "ss|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += Acnt[(*pc>>2) & 0x03];
break;
case TRUTHOF|B2:
case TRUTHOF|B4:
case TRUTHOF|B8:
pbuf[bufcnt++] = "truthof|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;
case CVT:
{
unsigned char cvs,cvd;
pbuf[bufcnt++] = "cvt ";
++pc;
cvs = (*pc & 0x70)>>4;
cvd = (*pc & 0x07);
pbuf[bufcnt++] = Tbuf[cvd];
pbuf[bufcnt++] = "<-";
pbuf[bufcnt++] = Tbuf[cvs];
break;
}
case LI|B1:
case LI|B2:
case LI|B4:
case LI|B8:
pbuf[bufcnt++] = "li|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
pc += Bcnt[*pc & 0x03];
break;
case LAI|D1:
case LAI|D2:
case LAI|D3:
case LAI|D4:
pbuf[bufcnt++] = "lai|";
pbuf[bufcnt++] = Dbuf[*pc & 0x03];
pc += Dcnt[*pc & 0x03];
break;
case LUI|B1:
case LUI|B2:
case LUI|B4:
case LUI|B8:
pbuf[bufcnt++] = "lui|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
pc += Bcnt[*pc & 0x03];
break;
case IMMED:
{
++pc;
switch(*pc)
{
case SMI|A1|B1:
case SMI|A1|B2:
case SMI|A1|B4:
case SMI|A1|B8:
case SMI|A2|B1:
case SMI|A2|B2:
case SMI|A2|B4:
case SMI|A2|B8:
case SMI|A3|B1:
case SMI|A3|B2:
case SMI|A3|B4:
case SMI|A3|B8:
case SMI|A4|B1:
case SMI|A4|B2:
case SMI|A4|B4:
case SMI|A4|B8:
pbuf[bufcnt++] = "smi|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += ABcnt[*pc & 0x0f];
break;
case SSI|A1|B1:
case SSI|A1|B2:
case SSI|A1|B4:
case SSI|A1|B8:
case SSI|A2|B1:
case SSI|A2|B2:
case SSI|A2|B4:
case SSI|A2|B8:
case SSI|A3|B1:
case SSI|A3|B2:
case SSI|A3|B4:
case SSI|A3|B8:
pbuf[bufcnt++] = "ssi|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += ABcnt[*pc & 0x0f];
break;
case MODI|BYTE:
case MODI|SHORT:
case MODI|LONG:
case MODI|UBYTE:
case MODI|USHORT:
case MODI|ULONG:
pbuf[bufcnt++] = "modi|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
pc += 2;
break;
case DEREF|BYTE:
case DEREF|SHORT:
case DEREF|LONG:
case DEREF|UBYTE:
case DEREF|USHORT:
case DEREF|ULONG:
case DEREF|FLOAT:
case DEREF|DOUBLE:
pbuf[bufcnt++] = "deref|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case DEREF1|BYTE:
case DEREF1|SHORT:
case DEREF1|LONG:
case DEREF1|UBYTE:
case DEREF1|USHORT:
case DEREF1|ULONG:
case DEREF1|FLOAT:
case DEREF1|DOUBLE:
pbuf[bufcnt++] = "deref1|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
}
break;
}
case SM|A1|B1:
case SM|A1|B2:
case SM|A1|B4:
case SM|A1|B8:
case SM|A2|B1:
case SM|A2|B2:
case SM|A2|B4:
case SM|A2|B8:
case SM|A3|B1:
case SM|A3|B2:
case SM|A3|B4:
case SM|A3|B8:
case SM|A4|B1:
case SM|A4|B2:
case SM|A4|B4:
case SM|A4|B8:
pbuf[bufcnt++] = "sm|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += Acnt[(*pc>>2) & 3];
break;
case ADD|BYTE:
case ADD|SHORT:
case ADD|LONG:
case ADD|UBYTE:
case ADD|USHORT:
case ADD|ULONG:
case ADD|FLOAT:
case ADD|DOUBLE:
pbuf[bufcnt++] = "add|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case SUB|BYTE:
case SUB|SHORT:
case SUB|LONG:
case SUB|UBYTE:
case SUB|USHORT:
case SUB|ULONG:
case SUB|FLOAT:
case SUB|DOUBLE:
pbuf[bufcnt++] = "sub|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case MUL|BYTE:
case MUL|SHORT:
case MUL|LONG:
case MUL|UBYTE:
case MUL|USHORT:
case MUL|ULONG:
case MUL|FLOAT:
case MUL|DOUBLE:
pbuf[bufcnt++] = "mul|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case DIV|BYTE:
case DIV|SHORT:
case DIV|LONG:
case DIV|UBYTE:
case DIV|USHORT:
case DIV|ULONG:
case DIV|FLOAT:
case DIV|DOUBLE:
pbuf[bufcnt++] = "div|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case OR|B1:
case OR|B2:
case OR|B4:
case OR|B8:
pbuf[bufcnt++] = "or|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;
case AND|B1:
case AND|B2:
case AND|B4:
case AND|B8:
pbuf[bufcnt++] = "and|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;
case MOD|BYTE:
case MOD|SHORT:
case MOD|LONG:
case MOD|UBYTE:
case MOD|USHORT:
case MOD|ULONG:
pbuf[bufcnt++] = "mod|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case XTD:
{
++pc;
switch(*pc)
{
case LI:
pbuf[bufcnt++] = "li";
pc += XSZ;
break;
case LSH|B1:
case LSH|B2:
case LSH|B4:
case LSH|B8:
pbuf[bufcnt++] = "lsh|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;
case LSHI|B1:
case LSHI|B2:
case LSHI|B4:
case LSHI|B8:
pbuf[bufcnt++] = "lshi|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
break;
case RSH|BYTE:
case RSH|SHORT:
case RSH|LONG:
case RSH|UBYTE:
case RSH|USHORT:
case RSH|ULONG:
pbuf[bufcnt++] = "rsh|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case RSHI|BYTE:
case RSHI|SHORT:
case RSHI|LONG:
case RSHI|UBYTE:
case RSHI|USHORT:
case RSHI|ULONG:
pbuf[bufcnt++] = "rshi|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
++pc;
break;
case BUILTIN:
{
pbuf[bufcnt++] = "builtin ";
++pc;
pbuf[bufcnt++] = BUbuf[*pc];
break;
} /* END: XTD BUILTIN */
case CLRDAT:
pbuf[bufcnt++] = "clrdat";
break;
case SWITCH:
pbuf[bufcnt++] = "switch";
pc += 2;
break;
case CALLSETUP:
pbuf[bufcnt++] = "callsetup";
pc += 4;
break;
case RETSTRUCT:
pbuf[bufcnt++] = "retstruct";
pc += 4;
break;
case PRUNESTRUCT:
pbuf[bufcnt++] = "prunestruct";
break;
case GETBITFIELD:
pbuf[bufcnt++] = "getbitfield";
pc += 3;
break;
case PUTBITFIELD:
pbuf[bufcnt++] = "putbitfield";
pc += 3;
break;
case IMMED:
{
++pc;
switch(*pc)
{
case SMI|A1:
case SMI|A2:
case SMI|A3:
case SMI|A4:
pbuf[bufcnt++] = "smi|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03] + XSZ;
break;
case SSI|A1:
case SSI|A2:
case SSI|A3:
pbuf[bufcnt++] = "ssi|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03] + XSZ;
break;
case MODI|LONGLONG:
case MODI|ULONGLONG:
pbuf[bufcnt++] = "modi|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
pc += 2;
break;
case DEREF|LONGLONG:
case DEREF|ULONGLONG:
case DEREF|LONGDOUBLE:
pbuf[bufcnt++] = "deref|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case DEREF1|LONGLONG:
case DEREF1|ULONGLONG:
case DEREF1|LONGDOUBLE:
pbuf[bufcnt++] = "deref1|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
}
break;
}/* END: XTD IMMED */
case ADD|LONGLONG:
case ADD|ULONGLONG:
case ADD|LONGDOUBLE:
pbuf[bufcnt++] = "add|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case SUB|LONGLONG:
case SUB|ULONGLONG:
case SUB|LONGDOUBLE:
pbuf[bufcnt++] = "sub|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
case MUL|LONGLONG:
case MUL|ULONGLONG:
case MUL|LONGDOUBLE:
pbuf[bufcnt++] = "mul|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case DIV|LONGLONG:
case DIV|ULONGLONG:
case DIV|LONGDOUBLE:
pbuf[bufcnt++] = "div|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case LT|LONGLONG:
case LT|ULONGLONG:
case LT|LONGDOUBLE:
pbuf[bufcnt++] = "lt|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case GT|LONGLONG:
case GT|ULONGLONG:
case GT|LONGDOUBLE:
pbuf[bufcnt++] = "gt|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case LE|LONGLONG:
case LE|ULONGLONG:
case LE|LONGDOUBLE:
pbuf[bufcnt++] = "le|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case GE|LONGLONG:
case GE|ULONGLONG:
case GE|LONGDOUBLE:
pbuf[bufcnt++] = "ge|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case NE|LONGLONG:
case NE|ULONGLONG:
case NE|LONGDOUBLE:
pbuf[bufcnt++] = "ne|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case EQ|LONGLONG:
case EQ|ULONGLONG:
case EQ|LONGDOUBLE:
pbuf[bufcnt++] = "eq|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case NEG|LONGLONG:
case NEG|ULONGLONG:
case NEG|LONGDOUBLE:
pbuf[bufcnt++] = "neg|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case NOT|BX:
pbuf[bufcnt++] = "not|BX";
break;
case COMP|LONGLONG:
case COMP|ULONGLONG:
pbuf[bufcnt++] = "comp|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case RSH|SLONGLONG:
case RSH|SULONGLONG:
pbuf[bufcnt++] = "rsh|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case MOD|LONGLONG:
case MOD|ULONGLONG:
pbuf[bufcnt++] = "mod|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case RSHI|SLONGLONG:
case RSHI|SULONGLONG:
pbuf[bufcnt++] = "rshi|";
pbuf[bufcnt++] = XTbuf[*pc & 0x07];
++pc;
break;
case TRUTHOF|BX:
pbuf[bufcnt++] = "truthof|BX";
break;
case LS|A1:
case LS|A2:
case LS|A3:
pbuf[bufcnt++] = "xtd ls|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03];
break;
case LM|A1:
case LM|A2:
case LM|A3:
case LM|A4:
pbuf[bufcnt++] = "xtd lm|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03];
break;
case SS|A1:
case SS|A2:
case SS|A3:
pbuf[bufcnt++] = "xtd ss|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03];
break;
case SM|A1:
case SM|A2:
case SM|A3:
case SM|A4:
pbuf[bufcnt++] = "xtd sm|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03];
break;
case MOVSS:
pbuf[bufcnt++] = "xtd movss";
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case MOVSM:
pbuf[bufcnt++] = "xtd movsm";
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case MOVMS:
pbuf[bufcnt++] = "xtd movms";
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case MOVMM:
pbuf[bufcnt++] = "xtd movmm";
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
}
break;
}/* END: XTD */
case XOR|B1:
case XOR|B2:
case XOR|B4:
case XOR|B8:
pbuf[bufcnt++] = "xor|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;
case GT|BYTE:
case GT|SHORT:
case GT|LONG:
case GT|UBYTE:
case GT|USHORT:
case GT|ULONG:
case GT|FLOAT:
case GT|DOUBLE:
pbuf[bufcnt++] = "gt|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case LT|BYTE:
case LT|SHORT:
case LT|LONG:
case LT|UBYTE:
case LT|USHORT:
case LT|ULONG:
case LT|FLOAT:
case LT|DOUBLE:
pbuf[bufcnt++] = "lt|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case GE|BYTE:
case GE|SHORT:
case GE|LONG:
case GE|UBYTE:
case GE|USHORT:
case GE|ULONG:
case GE|FLOAT:
case GE|DOUBLE:
pbuf[bufcnt++] = "ge|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case LE|BYTE:
case LE|SHORT:
case LE|LONG:
case LE|UBYTE:
case LE|USHORT:
case LE|ULONG:
case LE|FLOAT:
case LE|DOUBLE:
pbuf[bufcnt++] = "le|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case NE|BYTE:
case NE|SHORT:
case NE|LONG:
case NE|UBYTE:
case NE|USHORT:
case NE|ULONG:
case NE|FLOAT:
case NE|DOUBLE:
pbuf[bufcnt++] = "ne|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case EQ|BYTE:
case EQ|SHORT:
case EQ|LONG:
case EQ|UBYTE:
case EQ|USHORT:
case EQ|ULONG:
case EQ|FLOAT:
case EQ|DOUBLE:
pbuf[bufcnt++] = "eq|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
case ARG:
pbuf[bufcnt++] = "arg";
break;
case ARGA:
pbuf[bufcnt++] = "arga";
break;
case ARGF:
pbuf[bufcnt++] = "argf";
break;
case MOVSS|B1:
case MOVSS|B2:
case MOVSS|B4:
case MOVSS|B8:
pbuf[bufcnt++] = "movss|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case MOVSM|B1:
case MOVSM|B2:
case MOVSM|B4:
case MOVSM|B8:
pbuf[bufcnt++] = "movsm|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case MOVMS|B1:
case MOVMS|B2:
case MOVMS|B4:
case MOVMS|B8:
pbuf[bufcnt++] = "movms|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case MOVMM|B1:
case MOVMM|B2:
case MOVMM|B4:
case MOVMM|B8:
pbuf[bufcnt++] = "movmm|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case DUMP:
pbuf[bufcnt++] = "dump ";
break;
case REGAIN:
pbuf[bufcnt++] = "regain ";
break;
case CALL:
pbuf[bufcnt++] = "call ";
break;
case RET:
pbuf[bufcnt++] = "ret ";
break;
case SWAP:
pbuf[bufcnt++] = "swap ";
break;
case SWAP4:
pbuf[bufcnt++] = "swap4 ";
break;
case SWAP4DEEP:
pbuf[bufcnt++] = "swap4deep ";
break;
case DUP:
pbuf[bufcnt++] = "dup ";
break;
case DUP4:
pbuf[bufcnt++] = "dup4 ";
break;
case ABSMEM:
pbuf[bufcnt++] = "absmem ";
break;
case ABSSTK:
pbuf[bufcnt++] = "absstk ";
break;
case MOVDA1:
pbuf[bufcnt++] = "movda1 ";
break;
case MOVDA2:
pbuf[bufcnt++] = "movda2 ";
break;
case MOVDA4:
pbuf[bufcnt++] = "movda4 ";
break;
case MOVDA8:
pbuf[bufcnt++] = "movda8 ";
break;
case MOVDAX:
pbuf[bufcnt++] = "movdax ";
break;
case MOVAA1:
pbuf[bufcnt++] = "movaa1 ";
break;
case MOVAA2:
pbuf[bufcnt++] = "movaa2 ";
break;
case MOVAA4:
pbuf[bufcnt++] = "movaa4 ";
break;
case MOVAA8:
pbuf[bufcnt++] = "movaa8 ";
break;
case MOVAAX:
pbuf[bufcnt++] = "movaax ";
break;
case MOVAAC:
pbuf[bufcnt++] = "movaac ";
break;
case NOP:
pbuf[bufcnt++] = "nop ";
break;
} /* END: switch(*pc) */
}/* END: for() */
for(i = 0; i < bufcnt; ++i)
fwrite(pbuf[i], 1, strlen(pbuf[i]), iv->outfile);
fwrite("\n", 1, 1, iv->outfile);
}/* END: printinst() */
static void
disassemble(Piv iv, void *ptr, long size)
{
int x;
long offset = iv->out_offset;
x = print8(iv, ptr, size, offset, 0);
printinst(iv, ptr, size);
while((size -= x) > 0)
{
offset += x;
((char*)ptr) += x;
x = print8(iv, ptr, size, offset, 1);
}
}
static void
reset_funcdata(Piv iv)
{
iv->obuf = (char*)&iv->obufstart;
iv->obufstart = 0;
iv->obufcnt = 0;
iv->func_offset = 0;
iv->jbuf = (PJL)&iv->jbufstart;
iv->jmpcnt = 0;
iv->jbufcnt = 0;
iv->jbufstart = 0;
iv->extbuf = (PEL)&iv->extbufstart;
iv->extcnt = 0;
iv->extbufcnt = 0;
iv->extbufstart = 0;
iv->stackdepth = 0;
iv->maxdepth = 0;
iv->mindepth = 0;
iv->numnested = 0;
iv->cod_bufcnt = 0;
iv->ob_bufcnt = 0;
iv->cod_usedhead = 0;
iv->ob_usedhead = 0;
iv->first_cod = 0;
iv->first_ob = 0;
Cfreecat(FUNCDATA);
}
static void
write_funcdata(Piv iv, unsigned char *pdef)
{
long *p;
if((p = (long*)iv->obufstart))
{
setup_jmps(iv, pdef);
while(shorten_jmps(iv))
;
while(p)
{
if(iv->listing_wanted)
{
if(((unsigned char*)p)[8] == LINENO)
{
printline(iv, &((unsigned char*)p)[9]);
}
else if(((unsigned char*)p)[8] == NFUNC)
{
char *funcname = *((char**)&(((char*)p)[9]));
fprintf(iv->outfile, "\n%8.8lx: .nested .function _%s\n",
iv->out_offset, funcname);
}
else
{
disassemble(iv, &p[2], p[1]);
iv->out_offset += p[1];
}
}
else
{
FILEWRITE(&p[2],p[1]);
iv->out_offset += p[1];
}
p = (void*)p[0];
}
}
if(iv->debug >= '1')
cfeprintf("MAXDEPTH=%d MINDEPTH=%d func=%s\n",
iv->maxdepth, iv->mindepth, iv->symaddr[GL( ((Pop)pdef)->data )]);
save_maxdepth(iv, GL( ((Pop)pdef)->data ));
}
static void *
write_obuf(Piv iv, unsigned char *buf, long cnt)
{/* Output first goes to a linked list */
void *next = iv->obuf;
if(iv->obuf != (unsigned char*)&iv->obufstart)
{/* Suppress duplicate RETs */
if(buf[0] == RET && (iv->obuf[8] == RET || iv->obuf[9] == RETSTRUCT) )
{
return iv->obuf;
}
}
if(iv->obufcnt >= cnt+8)
{/* There is sufficient room in the current chunk */
long size = ((long*)iv->obuf)[1];
iv->obuf += size+8;
}
else
{/* Allocate a new chunk of linked list space */
iv->obufcnt = 4080;
iv->obuf = Ccalloc(FUNCDATA, 1, iv->obufcnt);
}
*((void**)next) = iv->obuf; /* link back to old entry */
((long*)iv->obuf)[1] = cnt; /* record the size of the data */
iv->obufcnt -= cnt+8; /* deduct data size plus overhead */
memcpy(&((long*)iv->obuf)[2], buf, cnt); /* copy the data to this area */
if(buf[0] != LINENO && buf[0] != NFUNC)
{/* A line number record is an anomoly */
if(iv->extmark)
addto_extlist(iv, buf); /* reference to external variable here */
iv->func_offset += cnt; /* increase the program counter */
}
iv->cod->ee = (struct _nodeOBUF *)iv->obuf; /* points to obuf chunks */
link_cod(iv);
return iv->obuf; /* return the address of this sub chunk */
}
static void
do_conversion(Piv iv, PND dst, PND src)
{
unsigned char obuf[2];
int dsize = dst->size;
int ssize = src->size;
unsigned char ddtype = dst->dtype;
unsigned char sdtype = src->dtype;
#define SRC(a) (a<<4)
if(src->atype & (A_ABSOLUTE|A_POINTER|A_VALUE) == (A_POINTER|A_VALUE))
{
if(src->atype & A_DATA)
obuf[0] = ABSMEM;
else if(src->atype & (A_AUTO|A_PARAM))
obuf[0] = ABSSTK;
else
PERROR(pName ": Line:%d bad conversion0\n", iv->lastline);
write_obuf(iv, obuf, 1);
return;
}
obuf[0] = CVT;
switch(ddtype)
{
case D_SIGNED: /* dest is signed integer */
{
if(dsize == 1)
obuf[1] = BYTE;
else if(dsize == 2)
obuf[1] = SHORT;
else if(dsize == 4)
obuf[1] = LONG;
else if(dsize == 8)
obuf[1] = CLONGLONG;
switch(sdtype)
{
case D_SIGNED:
{/* src is signed integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(BYTE);
else if(ssize == 2)
obuf[1] |= SRC(SHORT);
else if(ssize == 4)
obuf[1] |= SRC(LONG);
else if(ssize == 8)
obuf[1] |= SRC(CLONGLONG);
break;
}
case D_UNSIGNED:
case D_SEGMENT:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
case D_FLOAT:
{/* src is floating point */
if(ssize == 4)
obuf[1] |= SRC(FLOAT);
else if(ssize == 8)
obuf[1] |= SRC(DOUBLE);
else
obuf[1] |= SRC(CLONGDOUBLE);
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* src is unsigned int */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
default:
PERROR(pName ": Line:%d bad conversion1\n", iv->lastline);
}
break;
}
case D_UNSIGNED: /* dest is unsigned integer */
case D_SEGMENT:
{
if(dsize == 1)
obuf[1] = UBYTE;
else if(dsize == 2)
obuf[1] = USHORT;
else if(dsize == 4)
obuf[1] = ULONG;
else if(dsize == 8)
obuf[1] = CULONGLONG;
switch(sdtype)
{
case D_SIGNED:
{/* src is signed integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(BYTE);
else if(ssize == 2)
obuf[1] |= SRC(SHORT);
else if(ssize == 4)
obuf[1] |= SRC(LONG);
else if(ssize == 8)
obuf[1] |= SRC(CLONGLONG);
break;
}
case D_UNSIGNED:
case D_SEGMENT:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
case D_FLOAT:
{/* src is floating point */
if(ssize == 4)
obuf[1] |= SRC(FLOAT);
else if(ssize == 8)
obuf[1] |= SRC(DOUBLE);
else
obuf[1] |= SRC(CLONGDOUBLE);
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
default:
PERROR(pName ": Line:%d bad conversion2\n", iv->lastline);
}
break;
}
case D_FLOAT: /* dest is float, double, long double */
{
if(dsize == 4)
obuf[1] = FLOAT;
else if(dsize == 8)
obuf[1] = DOUBLE;
else
obuf[1] = CLONGDOUBLE;
switch(sdtype)
{
case D_SIGNED:
{/* src is signed integer */
if(ssize == 1)
obuf[1] |= SRC(BYTE);
else if(ssize == 2)
obuf[1] |= SRC(SHORT);
else if(ssize == 4)
obuf[1] |= SRC(LONG);
else if(ssize == 8)
obuf[1] |= SRC(CLONGLONG);
break;
}
case D_UNSIGNED:
case D_SEGMENT:
{/* src is unsigned integer */
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
case D_FLOAT:
{/* src is floating point */
if(dsize == ssize)
return;
if(ssize == 4)
obuf[1] |= SRC(FLOAT);
else if(ssize == 8)
obuf[1] |= SRC(DOUBLE);
else
obuf[1] |= SRC(CLONGDOUBLE);
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* src is unsigned integer */
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
default:
PERROR(pName ": Line:%d bad conversion3\n", iv->lastline);
}
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* dest is unsigned integer */
if(dsize == 1)
obuf[1] = BYTE;
else if(dsize == 2)
obuf[1] = SHORT;
else if(dsize == 4)
obuf[1] = LONG;
else if(dsize == 8)
obuf[1] = CLONGLONG;
switch(sdtype)
{
case D_SIGNED:
{/* src is signed integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(BYTE);
else if(ssize == 2)
obuf[1] |= SRC(SHORT);
else if(ssize == 4)
obuf[1] |= SRC(LONG);
else if(ssize == 8)
obuf[1] |= SRC(CLONGLONG);
break;
}
case D_UNSIGNED:
case D_SEGMENT:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
case D_FLOAT:
{/* src is floating point */
if(ssize == 4)
obuf[1] |= SRC(FLOAT);
else if(ssize == 8)
obuf[1] |= SRC(DOUBLE);
else
obuf[1] |= SRC(CLONGDOUBLE);
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
default:
PERROR(pName ": Line:%d bad conversion4\n", iv->lastline);
}
break;
}
default:
PRINTF("Line:%d no conversion\n", iv->lastline);
return;
}
write_obuf(iv, obuf, 2);
#undef SRC
}
static int
check_assignment_conversion(PND dst, PND src)
{
long dsize = dst->size;
long ssize = src->size;
unsigned char ddtype = dst->dtype;
unsigned char sdtype = src->dtype;
int ret = 0;
if(src->atype & (A_ABSOLUTE|A_POINTER|A_VALUE) == (A_POINTER|A_VALUE))
return 1;
switch(ddtype)
{
case D_SIGNED: /* dest is signed integer */
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
case D_FLOAT:
{
ret = 1;
break;
}
}
break;
}
case D_UNSIGNED: /* dest is unsigned integer */
case D_SEGMENT:
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
case D_FLOAT:
{
ret = 1;
break;
}
}
break;
}
case D_FLOAT: /* dest is float, double, long double */
{
if(sdtype == D_FLOAT)
{
if(dsize != ssize)
ret = 1;
}
else ret = 1;
break;
}
case D_POINTER:
case D_FUNCPTR: /* dest is pointer */
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
case D_FLOAT:
{
ret = 1;
break;
}
}
break;
}
}
return ret;
}
static int
check_binop_conversion(PND dst, PND src)
{
long dsize = dst->size;
long ssize = src->size;
unsigned char ddtype = dst->dtype;
unsigned char sdtype = src->dtype;
int ret = 0;
switch(ddtype)
{
case D_SIGNED: /* dest is signed integer */
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
}
break;
}
case D_UNSIGNED: /* dest is unsigned integer */
case D_SEGMENT:
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
}
break;
}
case D_FLOAT: /* dest is float, double, long double */
{
if(sdtype == D_FLOAT)
{
if(dsize > ssize)
ret = 1;
}
else ret = 1;
break;
}
case D_POINTER:
case D_FUNCPTR: /* dest is pointer */
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
}
break;
}
}
return ret;
}
static int
get_size(int type, int size)
{
switch(type)
{
case D_ARRAY:
case D_STRUCT:
case D_FUNCTION:
return B4;
default:
switch(size)
{
case 1:
return B1;
case 2:
return B2;
case 4:
return B4;
case 8:
return B8;
default:
#if SUPPORT_LONG_DOUBLE
return BX;
#endif
}
}
return 0;
}
static int
load_addr(Piv iv, unsigned char *poc, void *buf, PND pnd, int shft)
{/* Use the shortest possible representation */
long offset = pnd->OFFSET;
long ofs = offset >> 2;
if(pnd->atype & (A_EXTERN|A_ABSOLUTE))
{/* 4 bytes for absolute values */
*poc |= 3<<shft;
*((long*)buf) = offset;
iv->extmark += 1;
iv->markedsym[iv->extmark] = pnd->SYMNUM;
iv->markedbuf[iv->extmark] = buf;
return 4;
}
if(offset & 0xff000000)
{/* Relative values are restricted to 28 bits max */
PERROR(pName ": Line:%d offset too large %x\n", iv->lastline, ofs);
return 0;
}
if(offset & 0xffff0000 || offset & 0x00000003)
{/* 3 bytes for large values and non-aligned values */
*poc |= 2<<shft;
*((long*)buf) = offset;
return 3;
}
else if(ofs & 0xffffff00)
{/* 2 or fewer bytes for small aligned values */
*poc |= 1<<shft;
*((short*)buf) = (short)ofs;
return 2;
}
else
{
*((char*)buf) = (char)ofs;
return 1;
}
}
static void
load_val(Piv iv, unsigned long val)
{
unsigned char obuf[10];
obuf[0] = LUI;
++iv->stackdepth;
if(val & 0xffff0000)
{
obuf[0] |= 2;
*((unsigned long*)&obuf[1]) = val;
write_obuf(iv, obuf, 5);
}
else if(val & 0xffffff00)
{
obuf[0] |= 1;
*((unsigned short*)&obuf[1]) = (unsigned short)val;
write_obuf(iv, obuf, 3);
}
else
{
obuf[1] = (unsigned char)val;
write_obuf(iv, obuf, 2);
}
}
static int
load_immed(Piv iv, unsigned char *poc, void *obuf, PND pnd, int osize)
{
unsigned short dtype = pnd->dtype;
unsigned char mosize = pnd->opsize;
void *ibuf = pnd->data;
if(osize >= 0)
{/* force the immediate value to conform to osize */
if(osize == mosize)
{
switch(osize)
{
case B1:
*((char*)obuf) = *((char*)ibuf);
return 1;
case B2:
*((short*)obuf) = *((short*)ibuf);
return 2;
case B4:
*((long*)obuf) = *((long*)ibuf);
return 4;
case B8:
*((double*)obuf) = *((double*)ibuf);
return 8;
case BX:
#if SUPPORT_LONG_DOUBLE
*((long double*)obuf) = *((long double*)ibuf);
#else
memcpy(obuf, ibuf, XSZ);
#endif
return XSZ;
default:
PERROR(pName ": Line:%d LOAD IMMED SYSERR osize=%d\n", iv->lastline, osize);
}
}
else /* osize != mosize */
{
if(dtype == D_FLOAT)
{
float f;
double d;
#if SUPPORT_LONG_DOUBLE
long double ld;
#endif
switch(osize)
{
case B4:
switch(mosize)
{
case B8:
f = (float)*((double*)ibuf);
*((float*)obuf) = f;
return 4;
case BX:
#if SUPPORT_LONG_DOUBLE
f = (float)*((long double*)ibuf);
*((float*)obuf) = f;
return 4;
#else
PERROR(pName ": Line:%d long double conversion not supported\n", iv->lastline);
#endif
default:
PERROR(pName ": Line:%d bad floating immediate input\n",iv->lastline);
}
case B8:
switch(mosize)
{
case B4:
d = (double)*((float*)ibuf);
*((double*)obuf) = d;
return 8;
case BX:
#if SUPPORT_LONG_DOUBLE
d = (double)*((long double*)ibuf);
*((double*)obuf) = d;
return 8;
#else
PERROR(pName ": Line:%d long double conversion not supported\n", iv->lastline);
#endif
default:
PERROR(pName ": Line:%d bad floating immediate input\n", iv->lastline);
}
case BX:
#if SUPPORT_LONG_DOUBLE
switch(mosize)
{
case B4:
ld = (long double)*((float*)ibuf);
*((long double*)obuf) = ld;
return XSZ;
case B8:
ld = (long double)*((double*)ibuf);
*((long double*)obuf) = ld;
return XSZ;
default:
PERROR(pName ": Line:%d bad floating immediate input\n", iv->lastline);
}
break;
#else
PERROR(pName ": Line:%d long double conversion not supported\n", iv->lastline);
#endif
break;
default:
PERROR(pName ": Line:%d bad floating immediate output\n", iv->lastline);
}
}/* END: dtype == D_FLOAT */
else if(dtype == D_UNSIGNED || dtype == D_POINTER)
{
switch(osize)
{
case B1:
*((unsigned char*)obuf) = *((unsigned char *)ibuf);
return 1;
case B2:
switch(mosize)
{
case B1:
*((unsigned short*)obuf) = *((unsigned char*)ibuf);
return 2;
case B4:
case B8:
*((unsigned short*)obuf) = *((unsigned short*)ibuf);
return 2;
case BX:
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
default:
PERROR(pName ": Line:%d invalid immediate input\n", iv->lastline);
}
case B4:
switch(mosize)
{
case B1:
*((unsigned long*)obuf) = *((unsigned char*)ibuf);
return 4;
case B2:
*((unsigned long*)obuf) = *((unsigned short*)ibuf);
return 4;
case B8:
*((unsigned long*)obuf) = *((unsigned long*)ibuf);
return 4;
case BX:
PERROR(pName ": Line: invalid integer size\n", iv->lastline);
default:
PERROR(pName ": Line:%d invalid immediate input\n", iv->lastline);
}
case B8:
{
unsigned long l[2];
l[0] = 0;
l[1] = 0;
if(mosize == B4)
l[0] = *((unsigned long*)ibuf);
else if(mosize == B2)
l[0] = *((unsigned short*)ibuf);
else if(mosize == B1)
l[0] = *((unsigned char*)ibuf);
else
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
memcpy(obuf, l, 8);
return 8;
}
default:
PERROR(pName ": Line:%d invalid integer size=%d\n",
iv->lastline, osize);
}
}
else /* signed integer */
{
switch(osize)
{
case B1:
*((char*)obuf) = *((char *)ibuf);
return 1;
case B2:
switch(mosize)
{
case B1:
*((short*)obuf) = *((char*)ibuf);
return 2;
case B4:
case B8:
*((short*)obuf) = *((short*)ibuf);
return 2;
case BX:
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
default:
PERROR(pName ": Line:%d invalid immediate input\n",iv->lastline);
}
case B4:
switch(mosize)
{
case B1:
*((long*)obuf) = *((char*)ibuf);
return 4;
case B2:
*((long*)obuf) = *((short*)ibuf);
return 4;
case B8:
*((long*)obuf) = *((long*)ibuf);
return 4;
case BX:
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
default:
PERROR(pName ": Line:%d invalid immediate input\n", iv->lastline);
}
case B8:
{
long l[2];
l[0] = 0;
l[1] = 0;
if(mosize == B4)
l[0] = *((long*)ibuf);
else if(mosize == B2)
l[0] = *((short*)ibuf);
else if(mosize == B1)
l[0] = *((char*)ibuf);
else
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
if(l[0] < 0)
l[1] = -1;
memcpy(obuf, l, 8);
return 8;
}
default:
PERROR(pName ": Line:%d invalid integer size=%d\n",
iv->lastline, osize);
}
}/* END: signed integer */
}/* END: osize != mosize */
/* NOT REACHED */
PERROR(pName ": Line:%d LOAD IMMED SYSERR1 osize=%d mosize=%d\n", iv->lastline, osize, mosize);
return 0; /* suppress compiler warning */
}
else
{/* generate the shortest possible immediate value */
int thesize = 0;
if(dtype == D_FLOAT)
{
switch(mosize)
{
case B4:
*((float*)obuf) = *((float*)ibuf);
thesize = 4;
break;
case B8:
*((double*)obuf) = *((double*)ibuf);
thesize = 8;
break;
case BX:
#if SUPPORT_LONG_DOUBLE
*((long double*)obuf) = *((long double*)ibuf);
#else
memcpy(obuf, ibuf, XSZ);
#endif
thesize = XSZ;
break;
default:
PERROR(pName ": Line:%d wrong sized floating immediate\n", iv->lastline);
}
}
else /* dtype not D_FLOAT */
{
int negative;
int sgned;
unsigned long ul[2];
long *sl;
ul[1] = 0;
negative = 0;
sl = ul;
if(dtype == D_UNSIGNED || dtype == D_POINTER)
{
sgned = 0;
if(mosize == B8)
{
ul[0] = *((unsigned long*)ibuf);
ul[1] = *((unsigned long*)(((char*)ibuf)+4));
}
else
{
if(mosize == B4)
ul[0] = *((unsigned long*)ibuf);
else if(mosize == B2)
ul[0] = *((unsigned short*)ibuf);
else if(mosize == B1)
ul[0] = *((unsigned char*)ibuf);
else
PERROR(pName ": Line:%d invalid integer immediate\n", iv->lastline);
}
}
else /* sgned */
{
sgned = 1;
if(mosize == B8)
{
sl[0] = *((long*)ibuf);
sl[1] = *((long*)(((char*)ibuf)+4));
if(sl[1] < 0)
{
negative = 1;
ul[1] = ~ul[1];
ul[0] = ~ul[0];
if(ul[0] == 0xffffffff)
{
ul[0] = 0;
ul[1] += 1;
}
else ul[0] += 1;
}
}
else
{
if(mosize == B4)
sl[0] = *((long*)ibuf);
else if(mosize == B2)
sl[0] = *((short*)ibuf);
else if(mosize == B1)
sl[0] = *((char*)ibuf);
else
PERROR(pName ": Line:%d invalid integer immediate\n",iv->lastline);
if(sl[0] < 0)
{
negative = 1;
sl[0] = -sl[0];
}
}
} /* END: sgned */
if(negative)
{
if(ul[1])
mosize = B8;
else if(ul[0] & 0xffff8000)
mosize = B4;
else if(ul[0] & 0xffffff80)
mosize = B2;
else
mosize = B1;
}
else
{
if(sgned)
{
if(ul[1])
mosize = B8;
else if(ul[0] & 0xffff8000)
{
if(!(ul[0] & 0xffff0000))
{
*poc = LUI;
mosize = B2;
}
else
mosize = B4;
}
else if(ul[0] & 0xffffff80)
{
if(!(ul[0] & 0xffffff00))
{
*poc = LUI;
mosize = B1;
}
else
mosize = B2;
}
else
mosize = B1;
}
else /* unsigned */
{
if(ul[1])
mosize = B8;
else if(ul[0] & 0xffff0000)
mosize = B4;
else if(ul[0] & 0xffffff00)
mosize = B2;
else
mosize = B1;
}
}
if(negative)
{
ul[1] = ~ul[1];
ul[0] = ~ul[0];
if(ul[0] == 0xffffffff)
{
ul[0] = 0;
ul[1] += 1;
}
else ul[0] += 1;
}
switch(mosize)
{
case B1:
*((char*)obuf) = *((char*)sl);
thesize = 1;
break;
case B2:
*((short*)obuf) = *((short*)sl);
thesize = 2;
break;
case B4:
*((long*)obuf) = *((long*)sl);
thesize = 4;
break;
case B8:
*((double*)obuf) = *((double*)sl);
thesize = 8;
break;
}
}/* END: not D_FLOAT */
*poc |= mosize;
return thesize;
}
}
static void
addr_toevalstack(Piv iv, PND pnd)
{
unsigned char obuf[20];
int atype = pnd->atype;
if(atype & (A_AUTO|A_PARAM|A_DATA))
{
int l;
obuf[0] = LAI;
l = 1;
l += load_addr(iv, &obuf[0], &obuf[1], pnd, 0);
write_obuf(iv, obuf, l);
if(atype & (A_AUTO|A_PARAM))
{
obuf[0] = ABSSTK;
write_obuf(iv, obuf, 1);
}
else if(l < 5)
{
obuf[0] = ABSMEM;
write_obuf(iv, obuf, 1);
}
++iv->stackdepth;
}
}
static void
data_toevalstack(Piv iv, PND pnd, PND dst)
{
unsigned char obuf[20];
int xtra, oc;
unsigned short dtype, atype;
unsigned char osize;
atype = pnd->atype;
dtype = pnd->dtype;
if(atype & A_IMMED)
{
if(dtype == D_UNSIGNED)
obuf[0] = LUI;
else
obuf[0] = LI;
xtra = load_immed(iv, &obuf[0], &obuf[1], pnd, -1);
write_obuf(iv, obuf, 1+xtra);
++iv->stackdepth;
return;
}
xtra = oc = 0;
osize = pnd->opsize;
if(osize == BX)
{
obuf[0] = XTD;
osize = 0;
oc = 1;
xtra = 1;
}
if(atype & (A_TEMP|A_RET))
{
if(atype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, pnd);
if(osize == B8 && dtype < D_FLOAT)
obuf[xtra++] = XTD;
if( dst
&& (pnd->TMPNUM == dst->TMPNUM)
&& ((dst->atype & (A_ABSOLUTE|A_MEMADDR))
== (A_ABSOLUTE|A_MEMADDR))
)
{/* generally used for a += b etc. */
obuf[xtra++] = IMMED;
obuf[xtra] = DEREF1|xsize;
write_obuf(iv, obuf, 1+xtra);
++iv->stackdepth;
}
else
{
obuf[xtra++] = IMMED;
obuf[xtra] = DEREF|get_datasize(0, pnd);
write_obuf(iv, obuf, 1+xtra);
}
pnd->atype &= ~A_MEMADDR;
pnd->atype |= A_VALUE;
}
return;
}
if(atype & (A_AUTO|A_PARAM))
{
if(atype & (A_POINTER|A_VALUE) == (A_POINTER|A_VALUE))
{/* Put address on eval stack */
addr_toevalstack(iv, pnd);
pnd->atype |= A_ABSOLUTE;
return;
}
else
{
obuf[oc] = LS|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], pnd, 2);
++iv->stackdepth;
}
}
else if(atype & A_DATA)
{
if(atype & (A_POINTER|A_VALUE) == (A_POINTER|A_VALUE))
{/* Put address on eval stack */
addr_toevalstack(iv, pnd);
pnd->atype |= A_ABSOLUTE;
return;
}
else
{
obuf[oc] = LM|osize;
xtra += load_addr(iv,&obuf[oc], &obuf[oc+1], pnd, 2);
++iv->stackdepth;
}
}
write_obuf(iv, obuf, 1+xtra);
}
static void
promote_arg(Piv iv, PND pnd, long argsize)
{
long dsize = pnd->size;
struct _nd dst;
if(dsize != argsize)
{
dst.size = argsize;
dst.dtype = pnd->dtype;
dst.atype = 0;
do_conversion(iv, &dst, pnd);
}
}
static unsigned char
arg_toevalstack(Piv iv, PND pnd, long argsize)
{
unsigned char dtype;
if(pnd->atype & A_IMMED)
{
data_toevalstack(iv, pnd, 0);
return ARG;
}
dtype = pnd->dtype;
if(dtype == D_STRUCT)
{
addr_toevalstack(iv, pnd);
return ARGA;
}
else if(dtype == D_FUNCTION)
{
addr_toevalstack(iv, pnd);
return ARGF;
}
else if(dtype == D_FUNCPTR)
{
data_toevalstack(iv, pnd, 0);
return ARGF;
}
else if(dtype == D_ARRAY)
{
addr_toevalstack(iv, pnd);
}
else
{
data_toevalstack(iv, pnd, 0);
promote_arg(iv, pnd, argsize);
}
return ARG;
}
static void
mov_esdata(Piv iv, unsigned short atype, int size)
{
unsigned char obuf[2];
if(atype & A_MEMADDR)
{
if(size == B1)
obuf[0] = MOVAA1;
else if(size == B2)
obuf[0] = MOVAA2;
else if(size == B4)
obuf[0] = MOVAA4;
else if(size == B8)
obuf[0] = MOVAA8;
#if SUPPORT_LONG_DOUBLE
else if(size == BX)
obuf[0] = MOVAAX;
#endif
else {obuf[0] = MOVAAC; size = XSZ;}
}
else
{
if(size == B1)
obuf[0] = MOVDA1;
else if(size == B2)
obuf[0] = MOVDA2;
else if(size == B4)
obuf[0] = MOVDA4;
else if(size == B8)
obuf[0] = MOVDA8;
#if SUPPORT_LONG_DOUBLE
else if(size == BX)
obuf[0] = MOVDAX;
#endif
else
PERROR(pName ": Line:%d illegal mov data size=%d\n", iv->lastline, size);
}
if(obuf[0] == MOVAAC)
{
load_val(iv, size);
--iv->stackdepth;
}
write_obuf(iv, obuf, 1);
iv->stackdepth -= 2;
}
static void
from_evalstack(Piv iv, PND d, PND s)
{
unsigned char obuf[20];
int xtra, oc;
unsigned short datype = d->atype;
unsigned char osize = d->opsize;
xtra = oc = 0;
if(datype & (A_TEMP|A_RET))
{
if(datype & A_MEMADDR)
{
mov_esdata(iv, s->atype, osize);
}
return;
}
if(osize == BX)
{
obuf[0] = XTD;
oc = 1;
osize = 0;
xtra = 1;
}
if(datype & (A_AUTO|A_PARAM))
{
obuf[oc] = SS|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
--iv->stackdepth;
}
else if(datype & OPDATA)
{
obuf[oc] = SM|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
--iv->stackdepth;
}
write_obuf(iv, obuf, 1+xtra);
}
static unsigned char
get_datasize(unsigned char opcode, PND pnd)
{
unsigned char dtype = pnd->dtype;
long dsize = pnd->size;
switch(dtype)
{
case D_ARRAY:
case D_FUNCTION:
case D_STRUCT:
return LONG;
}
if( opcode == orop
|| opcode == andop
|| opcode == notop
|| opcode == lshop
|| opcode == complop
|| opcode == xorop
)
{
if(dsize == 1)
return B1;
else if(dsize == 2)
return B2;
else if(dsize == 4)
return B4;
else if(dsize == 8)
return B8;
else
return BX;
}
else
{
if(dtype == D_UNSIGNED)
{
if(dsize == 1)
return UBYTE;
else if(dsize == 2)
return USHORT;
else if(dsize == 4)
return ULONG;
else
{
if(opcode == rshop)
return SULONGLONG;
return ULONGLONG;
}
}
else if(dtype == D_FLOAT)
{
if(dsize == 4)
return FLOAT;
else if(dsize == 8)
return DOUBLE;
else
return LONGDOUBLE;
}
else
{
if(dsize == 1)
return BYTE;
else if(dsize == 2)
return SHORT;
else if(dsize == 4)
return LONG;
else
{
if(opcode == rshop)
return SLONGLONG;
return LONGLONG;
}
}
}
return 0;
}
static void *
new_nodeO(Piv iv)
{
PNODEO p;
if(iv->ob_bufcnt < sizeof(NODEO))
{/* Allocate a new chunk of linked list space */
iv->ob_bufcnt = 4080;
iv->ob_buf = Ccalloc(FUNCDATA, 1, iv->ob_bufcnt);
}
p = (PNODEO)iv->ob_buf;
iv->ob_buf += sizeof(NODEO);
iv->ob_bufcnt -= sizeof(NODEO);
return p;
}
static void
link_ob(Piv iv)
{/* Attach to the used list */
if(!iv->ob_usedhead)
{
iv->ob_usedhead = iv->ob;
iv->ob_usedtail = iv->ob;
}
else
{
iv->ob_usedtail->next = iv->ob;
iv->ob_usedtail = iv->ob;
}
iv->ob = new_nodeO(iv);
}
static void *
new_nodeC(Piv iv)
{
PNODEC p;
if(iv->cod_bufcnt < sizeof(NODEC))
{/* Allocate a new chunk of linked list space */
iv->cod_bufcnt = 4080;
iv->cod_buf = Ccalloc(FUNCDATA, 1, iv->cod_bufcnt);
}
p = (PNODEC)iv->cod_buf;
iv->cod_buf += sizeof(NODEC);
iv->cod_bufcnt -= sizeof(NODEC);
return p;
}
static void
link_cod(Piv iv)
{/* Attach to the used list */
if(!iv->cod_usedhead)
{
iv->cod_usedhead = iv->cod;
iv->cod_usedtail = iv->cod;
}
else
{
iv->cod_usedtail->next = iv->cod;
iv->cod_usedtail = iv->cod;
}
iv->cod = new_nodeC(iv);
}
static PNODEC
gen_inst(Piv iv, PNODEO pnode)
{
unsigned char *p;
unsigned char obuf[40];
int xtra, oc;
unsigned char opcode;
PND d,l,r;
d = &pnode->d;
l = &pnode->l;
r = &pnode->r;
p = pnode->p;
opcode = *p;
xtra = oc = 0;
switch(opcode)
{
case regainop:
obuf[0] = REGAIN;
write_obuf(iv, obuf, 1);
++iv->stackdepth;
break;
case grabop:
obuf[0] = SWAP4DEEP;
write_obuf(iv, obuf, 1);
break;
case getvalop:
case derefop:
case assignop:
case duptmpop:
{
if( opcode == getvalop
&& !(l->atype & A_IMMED)
&& l->dtype == D_FUNCTION)
{
addr_toevalstack(iv, l);
}
else if( opcode != derefop
&& !(l->atype & A_IMMED)
&& check_assignment_conversion(d, l))
{/* Must move data through evaluation stack */
data_toevalstack(iv, l, d);
do_conversion(iv, d, l);
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;
if(opcode == assignop)
from_evalstack(iv, d, l);
}
else
{/* Can move data directly from memory to memory */
unsigned char ddtype = d->dtype;
unsigned char osize = d->opsize;
unsigned short latype = l->atype;
unsigned short datype = d->atype;
if(osize == BX)
{
obuf[0] = XTD;
oc = 1;
osize = 0;
xtra = 1;
}
if(latype & A_IMMED)
{
if(datype & (A_TEMP|A_RET))
{
if(l->dtype == D_UNSIGNED)
obuf[oc] = LUI;
else
obuf[oc] = LI;
xtra += load_immed(iv, &obuf[oc], &obuf[oc+1], l, -1);
++iv->stackdepth;
if(datype & A_MEMADDR)
{
write_obuf(iv, obuf, 1+xtra);
mov_esdata(iv, 0, osize);
break;
}
}
else if(datype & (A_AUTO|A_PARAM))
{
int lx;
obuf[0] = IMMED;
oc = 1;
xtra = 1;
obuf[oc] = SSI|osize;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
lx += load_immed(iv, &obuf[oc], &obuf[oc+1+lx], l, osize);
xtra += lx;
}
else if(datype & A_DATA)
{
int lx;
obuf[0] = IMMED;
oc = 1;
xtra = 1;
obuf[oc] = SMI|osize;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
lx += load_immed(iv, &obuf[oc], &obuf[oc+1+lx], l, osize);
xtra += lx;
}
else
{
return iv->cod_usedtail;
}
}
else if(latype & (A_TEMP|A_RET))
{
if(datype & (A_TEMP|A_RET))
{
if(opcode == duptmpop)
{
if(osize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
xtra = 0;
++iv->stackdepth;
}
else if(opcode == getvalop || opcode == derefop)
{
if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
if(osize == B8 && ddtype < D_FLOAT)
obuf[xtra++] = XTD;
if(datype & A_MEMADDR)
xsize = ULONG;
obuf[xtra++] = IMMED;
obuf[xtra] = DEREF|xsize;
}
else return iv->cod_usedtail; /* nop */
}
else if(datype & A_MEMADDR)
{
mov_esdata(iv, latype, osize);
break;
}
else
{/* move a value temp to a value temp, effective nop */
return iv->cod_usedtail;
}
}
else if(datype & (A_AUTO|A_PARAM))
{
if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
int qc = 1;
if( osize == BX
|| (osize == B8 && ddtype < D_FLOAT))
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc] = DEREF|xsize;
write_obuf(iv, obuf+1, qc);
}
obuf[oc] = SS|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
--iv->stackdepth;
}
else if(datype & A_DATA)
{
if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
int qc = 1;
if( osize == BX
|| (osize == B8 && ddtype < D_FLOAT))
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc] = DEREF|xsize;
write_obuf(iv, obuf+1, qc);
}
obuf[oc] = SM|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
--iv->stackdepth;
}
else
{
return iv->cod_usedtail;
}
}
else if(latype & (A_AUTO|A_PARAM))
{
int lx;
if((latype & (A_POINTER|A_VALUE)) == (A_POINTER|A_VALUE))
{/* Put address on eval stack */
addr_toevalstack(iv, l);
if(opcode == assignop)
from_evalstack(iv, d, l);
break;
}
if(datype & (A_TEMP|A_RET))
{
if(opcode == derefop)
osize = B4;
obuf[oc] = LS|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
++iv->stackdepth;
if(opcode == assignop)
{
/* Here we need a 'store from stack addr' inst */
if(datype & A_MEMADDR)
{/* Address was on the eval stack */
write_obuf(iv, obuf, 1+xtra);
mov_esdata(iv, 0, osize);
break;
}
}
}
else if(datype & (A_AUTO|A_PARAM))
{
obuf[oc] = MOVSS|osize;
obuf[++oc] = 0;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
lx += load_addr(iv, &obuf[oc], &obuf[oc+1+lx], d, 0);
xtra += lx+1;
}
else if(datype & A_DATA)
{
obuf[oc] = MOVSM|osize;
obuf[++oc] = 0;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
lx += load_addr(iv, &obuf[oc], &obuf[oc+1+lx], d, 0);
xtra += lx+1;
}
else
{
return iv->cod_usedtail;
}
}
else if(latype & A_DATA)
{
int lx;
if((latype & (A_POINTER|A_VALUE)) == (A_POINTER|A_VALUE))
{/* Put address on eval stack */
addr_toevalstack(iv, l);
if(opcode == assignop)
from_evalstack(iv, d, l);
break;
}
if(datype & (A_TEMP|A_RET))
{
if(opcode == derefop)
osize = B4;
obuf[oc] = LM|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
++iv->stackdepth;
if(opcode == assignop)
{
/* Here we need a 'store from stack addr' inst */
if(datype & A_MEMADDR)
{/* Address was on the eval stack */
write_obuf(iv, obuf, 1+xtra);
mov_esdata(iv, 0, osize);
break;
}
}
}
else if(datype & (A_AUTO|A_PARAM))
{
obuf[oc] = MOVMS|osize;
obuf[++oc] = 0;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
lx += load_addr(iv, &obuf[oc], &obuf[oc+1+lx], d, 0);
xtra += lx+1;
}
else if(datype & A_DATA)
{
obuf[oc] = MOVMM|osize;
obuf[++oc] = 0;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
lx += load_addr(iv, &obuf[oc], &obuf[oc+1+lx], d, 0);
xtra += lx+1;
}
else
{
return iv->cod_usedtail;
}
}
else
{
return iv->cod_usedtail;
}
write_obuf(iv, obuf, 1+xtra);
}/* END: move data directly */
if(opcode == assignop && iv->has_structret)
{
obuf[0] = XTD;
obuf[1] = PRUNESTRUCT;
write_obuf(iv, obuf, 2);
iv->has_structret = 0;
}
break;
}
case plusop:
case minusop:
case mulop:
case divop:
case orop:
case xorop:
case andop:
case eqop:
case neqop:
case ltop:
case gtop:
case leop:
case geop:
{/* BINOPS */
unsigned char ddtype;
unsigned char osize;
unsigned short latype = l->atype;
unsigned short ratype = r->atype;
PND bestptr = 0;
if(latype & A_IMMED || ratype & A_IMMED)
{
if(ratype & A_IMMED)
{/* IMMEDIATE IS ON THE RIGHT */
bestptr = l;
data_toevalstack(iv, l, d);
if(check_binop_conversion(r, l))
do_conversion(iv, r, l);
data_toevalstack(iv, r, d);
ddtype = bestptr->dtype;
osize = l->opsize;
if(osize == BX || (osize == B8 && ddtype != D_FLOAT))
obuf[oc++] = XTD;
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
--iv->stackdepth;
write_obuf(iv, obuf, oc);
}
else /* IMMEDIATE IS ON THE LEFT */
{
bestptr = r;
if(ratype & (A_TEMP|A_RET))
{
data_toevalstack(iv, r, d);
if(check_binop_conversion(l, r))
do_conversion(iv, l, r);
data_toevalstack(iv, l, d);
ddtype = bestptr->dtype;
osize = r->opsize;
if( opcode != plusop
&& opcode != eqop
&& opcode != neqop
&& opcode != andop
&& opcode != orop
&& opcode != mulop
&& opcode != xorop
)
{/* stack order relevant */
if(osize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
else
{
data_toevalstack(iv, l, d);
data_toevalstack(iv, r, d);
if(check_binop_conversion(l, r))
do_conversion(iv, l, r);
ddtype = r->dtype;
osize = r->opsize;
}
if(osize == BX || (osize == B8 && ddtype != D_FLOAT))
obuf[oc++] = XTD;
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, oc);
--iv->stackdepth;
}/* END: IMMEDIATE IS ON LEFT */
}/* IMMEDIATES */
else
{/* NOT IMMEDIATES */
if(ratype & (A_TEMP|A_RET))
{/* RIGHT HAND SIDE IS ALREADY ON STACK */
data_toevalstack(iv, r, d);
if(latype & (A_TEMP|A_RET))
{/* LEFT HAND SIDE WAS ALSO ON STACK */
/* Is it the same data as right hand side ?? */
if(l->TMPNUM == r->TMPNUM)
{
if(r->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
write_obuf(iv, obuf, 1);
++iv->stackdepth;
l->atype = r->atype;
}
else
{
unsigned char lltype = l->dtype;
unsigned lsize = l->opsize;
if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
int qc = 0;
if( (l->TMPNUM == d->TMPNUM)
&& ((d->atype & (A_ABSOLUTE|A_MEMADDR))
== (A_ABSOLUTE|A_MEMADDR))
)
{/* it must expand with a DEREF1 */
if(lsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
obuf[1] = DUMP;
obuf[2] = DUMP;
write_obuf(iv, obuf, 3);
if( lsize == BX
|| (lsize == B8 && lltype < D_FLOAT))
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF1|xsize;
write_obuf(iv, obuf, qc);
++iv->stackdepth;
}
else
{
obuf[0] = DUMP;
write_obuf(iv, obuf, 1);
if( lsize == BX
|| (lsize == B8 && lltype < D_FLOAT))
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF|xsize;
write_obuf(iv, obuf, qc);
}
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;
if(check_binop_conversion(r, l))
{
bestptr = r;
do_conversion(iv, r, l);
}
obuf[0] = REGAIN;
write_obuf(iv, obuf, 1);
if(!bestptr)
if(check_binop_conversion(l, r))
{
bestptr = l;
do_conversion(iv, l, r);
}
}
}
}
else
{/* LEFT HAND SIDE IS NOT ON STACK */
if(check_binop_conversion(l, r))
{
bestptr = l;
do_conversion(iv, l, r);
}
data_toevalstack(iv, l, d);
if(!bestptr)
if(check_binop_conversion(r, l))
{
bestptr = r;
do_conversion(iv, r, l);
}
if( opcode != plusop
&& opcode != eqop
&& opcode != neqop
&& opcode != andop
&& opcode != orop
&& opcode != mulop
&& opcode != xorop
)
{/* stack order relevant */
if(r->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
}
else /* ONLY LEFT HAND SIDE CAN BE ON STACK */
{
data_toevalstack(iv, l, d);
if(check_binop_conversion(r, l))
{
bestptr = r;
do_conversion(iv, r, l);
}
data_toevalstack(iv, r, d);
if(!bestptr)
if(check_binop_conversion(l, r))
{
bestptr = l;
do_conversion(iv, l, r);
}
}
if(!bestptr)
bestptr = l;
ddtype = bestptr->dtype;
osize = bestptr->opsize;
if(osize == BX || (osize==B8 && ddtype != D_FLOAT))
obuf[oc++] = XTD;
obuf[oc++] = binops[opcode]|get_datasize(opcode, bestptr);
write_obuf(iv, obuf, oc);
--iv->stackdepth;
}/* END: NOT IMMEDIATES */
if(opcode >= eqop)
{
bestptr = &longtype;
}
if(check_assignment_conversion(d, bestptr))
do_conversion(iv, d, bestptr);
bestptr->atype &= ~A_MEMADDR;
bestptr->atype |= A_VALUE;
from_evalstack(iv, d, bestptr);
break;
}/* END: BINOPS */
case lshop:
case rshop:
{/* SHIFTS */
unsigned short latype = l->atype;
unsigned short ratype = r->atype;
PND bestptr;
if(latype & A_IMMED || ratype & A_IMMED)
{
if(ratype & A_IMMED)
{/* IMMEDIATE IS ON THE RIGHT */
data_toevalstack(iv, l, d);
obuf[0] = XTD;
if(opcode == lshop)
{
obuf[1] = LSHI|get_datasize(opcode, l);
obuf[2] = r->data->Uuchar;
}
else if(opcode == rshop)
{
obuf[1] = RSHI|get_datasize(opcode, l);
obuf[2] = r->data->Uuchar;
}
write_obuf(iv, obuf, 3);
}
else /* IMMEDIATE IS ON THE LEFT */
{
if(ratype & (A_TEMP|A_RET))
{
data_toevalstack(iv, r, d);
data_toevalstack(iv, l, d);
if(r->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
else
{
data_toevalstack(iv, l, d);
data_toevalstack(iv, r, d);
}
obuf[0] = XTD;
obuf[1] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, 2);
--iv->stackdepth;
}
}
else
{/* NOT IMMEDIATES */
if(ratype & (A_TEMP|A_RET))
{/* RIGHT HAND SIDE IS ALREADY ON STACK */
data_toevalstack(iv, r, d);
if(latype & (A_TEMP|A_RET))
{/* LEFT HAND SIDE WAS ALSO ON STACK */
/* Is it the same data as right hand side ?? */
if(l->TMPNUM == r->TMPNUM)
{
if(l->opsize <= B4 && r->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
write_obuf(iv, obuf, 1);
++iv->stackdepth;
l->atype = r->atype;
}
else
{/* reversed stack and not same data */
if(latype & A_MEMADDR)
{
unsigned char xsize = l->opsize;
int qc = 0;
if( (l->TMPNUM == d->TMPNUM)
&& ((d->atype & (A_ABSOLUTE|A_MEMADDR))
== (A_ABSOLUTE|A_MEMADDR))
)
{/* it must expand with a DEREF1 */
if(l->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
obuf[1] = DUMP;
obuf[2] = DUMP;
write_obuf(iv, obuf, 3);
if(l->opsize == B8)
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF1|xsize;
write_obuf(iv, obuf, qc);
++iv->stackdepth;
}
else
{
obuf[0] = DUMP;
write_obuf(iv, obuf, 1);
if(l->opsize == B8)
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF|xsize;
write_obuf(iv, obuf, qc);
}
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;
obuf[0] = REGAIN;
write_obuf(iv, obuf, 1);
}
}
}
else
{/* LEFT HAND SIDE IS NOT ON STACK */
data_toevalstack(iv, l, d);
if(r->opsize <= B4 && l->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
else /* ONLY LEFT HAND SIDE CAN BE ON STACK */
{
data_toevalstack(iv, l, d);
data_toevalstack(iv, r, d);
}
/* ENSURE THAT THE RIGHT SIDE IS A LONG OR A LONG LONG */
bestptr = (l->size > 4) ? &longlongtype : &longtype;
if(check_assignment_conversion(bestptr, r))
do_conversion(iv, bestptr, r);
obuf[0] = XTD;
obuf[1] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, 2);
--iv->stackdepth;
}/* END: NOT IMMEDIATES */
if(check_assignment_conversion(d, l))
do_conversion(iv, d, l);
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;
from_evalstack(iv, d, l);
break;
}/* END: SHIFTS */
case modop:
{/* MODULUS */
unsigned short latype = l->atype;
unsigned short ratype = r->atype;
PND bestptr;
if(latype & A_IMMED || ratype & A_IMMED)
{
if(ratype & A_IMMED)
{/* IMMEDIATE IS ON THE RIGHT */
data_toevalstack(iv, l, d);
if(l->opsize == B8)
{
obuf[oc++] = XTD;
}
if(d->size == 2)
{
obuf[oc++] = IMMED;
obuf[oc++] = MODI|get_datasize(opcode, l);
*((short*)&obuf[oc]) = r->data->Uushort;
xtra = 2;
}
else
{/* no fast instructions available */
data_toevalstack(iv, r, d);
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
--iv->stackdepth;
}
write_obuf(iv, obuf, oc+xtra);
}
else /* IMMEDIATE IS ON THE LEFT */
{
if(ratype & (A_TEMP|A_RET))
{
data_toevalstack(iv, r, d);
data_toevalstack(iv, l, d);
if(r->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
else
{/* load eval stack without regard for conversion */
data_toevalstack(iv, l, d);
data_toevalstack(iv, r, d);
}
if(r->opsize == B8)
{
obuf[oc++] = XTD;
}
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, oc);
--iv->stackdepth;
}
}
else
{/* NOT IMMEDIATES */
if(ratype & (A_TEMP|A_RET))
{/* RIGHT HAND SIDE IS ALREADY ON STACK */
data_toevalstack(iv, r, d);
if(latype & (A_TEMP|A_RET))
{/* LEFT HAND SIDE WAS ALSO ON STACK */
/* Is it the same data as right hand side ?? */
if(l->TMPNUM == r->TMPNUM)
{
if(l->opsize <= B4 && r->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
write_obuf(iv, obuf, 1);
++iv->stackdepth;
l->atype = r->atype;
}
else
{/* reversed stack and not same data */
if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
int qc = 0;
if( (l->TMPNUM == d->TMPNUM)
&& ((d->atype & (A_ABSOLUTE|A_MEMADDR))
== (A_ABSOLUTE|A_MEMADDR))
)
{/* it must expand with a DEREF1 */
if(r->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
obuf[1] = DUMP;
obuf[2] = DUMP;
write_obuf(iv, obuf, 3);
if(r->opsize == B8)
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF1|xsize;
write_obuf(iv, obuf, qc);
++iv->stackdepth;
}
else
{
obuf[0] = DUMP;
write_obuf(iv, obuf, 1);
if(r->opsize == B8)
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF|xsize;
write_obuf(iv, obuf, qc);
}
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;
obuf[0] = REGAIN;
write_obuf(iv, obuf, 1);
}
}
}
else
{/* LEFT HAND SIDE IS NOT ON STACK */
data_toevalstack(iv, l, d);
if(r->opsize <= B4 && l->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
else /* ONLY LEFT HAND SIDE CAN BE ON STACK */
{
data_toevalstack(iv, l, d);
data_toevalstack(iv, l, d);
}
/* ENSURE THAT THE RIGHT SIDE IS A LONG OR A LONG LONG */
bestptr = (l->size > 4) ? &longlongtype : &longtype;
if(check_assignment_conversion(bestptr, r))
do_conversion(iv, bestptr, r);
if(l->opsize == B8)
{
obuf[oc++] = XTD;
}
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, oc);
--iv->stackdepth;
}/* END: NOT IMMEDIATES */
if(check_assignment_conversion(d, l))
do_conversion(iv, d, l);
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;
from_evalstack(iv, d, l);
break;
}/* END: MODULUS */
case truthop:
case aliastmpop:
{/* no immediates */
data_toevalstack(iv, l, d);
if(l->opsize != B1)
{/* no need to get truth of byte sized elements */
if(l->opsize == BX)
{
obuf[oc++] = XTD;
}
obuf[oc++] = TRUTHOF|l->opsize;
write_obuf(iv, obuf, oc);
}
break;
}
case complop:
case notop:
{/* no immediates */
unsigned char osize = get_datasize(opcode, l);
data_toevalstack(iv, l, d);
if(osize == BX)
{/* only notop can operate on long double */
obuf[oc++] = XTD;
}
obuf[oc++] = binops[opcode]|osize;
write_obuf(iv, obuf, oc);
break;
}
case negop:
{/* no immediates */
data_toevalstack(iv, l, d);
if(l->opsize == BX || (l->opsize==B8 && l->dtype != D_FLOAT))
{
obuf[oc++] = XTD;
}
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, oc);
break;
}
case copyop:
{
if(d->atype & (A_TEMP|A_RET))
{
if(!(l->atype & (A_TEMP|A_RET)))
{
data_toevalstack(iv, l, d);
}
}
else
{
if(!(l->atype & (A_TEMP|A_RET)))
{
data_toevalstack(iv, d, d);
data_toevalstack(iv, l, d);
}
else
{
data_toevalstack(iv, d, d);
obuf[0] = SWAP4;
write_obuf(iv, obuf, 1);
}
}
load_val(iv, d->size);
obuf[0] = MOVAAC;
write_obuf(iv, obuf, 1);
iv->stackdepth -= 3;
break;
}
case castop:
{
data_toevalstack(iv, l, d);
if(check_assignment_conversion(d, l))
do_conversion(iv, d, l);
break;
}
case jmploopop:
case jmpcontinueop:
case jmpbreakop:
case jmpgotoop:
case ljmptrueop:
case jmptrueop:
case ljmpfalseop:
case jmpfalseop:
case funcstartop:
case funcstopop:
{/* start with max sized jmps, they will be shortened later */
void *fixjmp;
if(opcode == jmptrueop)
{
obuf[0] = JMPT|J4;
--iv->stackdepth;
}
else if(opcode == ljmptrueop)
{
obuf[0] = LJMPT|J4;
}
else if(opcode == jmpfalseop)
{
obuf[0] = JMPF|J4;
--iv->stackdepth;
}
else if(opcode == ljmpfalseop)
{
obuf[0] = LJMPF|J4;
}
else if(opcode == funcstartop || opcode == funcstopop)
{
obuf[0] = LOCATE|J4;
}
else
obuf[0] = JMP|J4;
fixjmp = write_obuf(iv, obuf, 5);
addto_jmplist(iv, p, fixjmp);
break;
}
case clrdatop:
{
addr_toevalstack(iv, d);
data_toevalstack(iv, l, 0);
obuf[0] = XTD;
obuf[1] = CLRDAT;
write_obuf(iv, obuf, 2);
iv->stackdepth -= 2;
break;
}
case getbitfieldop:
{
data_toevalstack(iv, r, d);
obuf[0] = XTD;
obuf[1] = GETBITFIELD;
obuf[2] = l->data->uchr.d[0]; /* shift */
obuf[3] = l->data->uchr.d[1]; /* size */
obuf[4] = l->data->uchr.d[2]; /* sign */
write_obuf(iv, obuf, 5);
break;
}
case putbitfieldop:
{
if(!(d->atype & (A_TEMP|A_RET)))
{/* destination address to stack */
addr_toevalstack(iv, d);
if(!(r->atype & (A_TEMP|A_RET)))
{
data_toevalstack(iv, r, d);
}
else
{/* data was on stack */
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
else
{/* destination address is on stack */
data_toevalstack(iv, r, d);
}
if(check_assignment_conversion(d, r))
do_conversion(iv, d, r);
obuf[0] = XTD;
obuf[1] = PUTBITFIELD;
obuf[2] = l->data->uchr.d[0]; /* shift */
obuf[3] = l->data->uchr.d[1]; /* size */
obuf[4] = d->size;
write_obuf(iv, obuf, 5);
iv->stackdepth -= 2;
break;
}
case retstructop:
{
addr_toevalstack(iv, d);
obuf[0] = XTD;
obuf[1] = RETSTRUCT;
*((unsigned short*)&obuf[2]) = l->data->ulng.d[0] >>2; /* size */
*((unsigned short*)&obuf[4]) = l->data->ulng.d[1] >>2; /* offset */
write_obuf(iv, obuf, 6);
break;
}
case retdataop:
case retvoidop:
{
obuf[0] = RET;
write_obuf(iv, obuf, 1);
break;
}
case callfuncop:
{
obuf[0] = XTD;
obuf[1] = CALLSETUP;
*((long*)&obuf[2]) = l->data->ulng.d[0]; /* argsize */
write_obuf(iv, obuf, 6);
break;
}
case switchop:
{
void *fixjmp;
obuf[0] = XTD;
obuf[1] = SWITCH;
*((short*)(&obuf[2])) = d->data->ulng.d[1]; /* swnode */
write_obuf(iv, obuf, 4);
/* Default jmp */
obuf[0] = JMP|D4;
fixjmp = write_obuf(iv, obuf, 5);
addto_jmplist(iv, p, fixjmp);
--iv->stackdepth;
break;
}
case compsavop:
case totmpop:
{
data_toevalstack(iv, l, d);
break;
}
case argop:
{
unsigned char op = arg_toevalstack(iv, l, d->ARGSIZE);
if(!(iv->in_builtin))
{
load_val(iv, d->ARGOFS);
load_val(iv, d->ARGSIZE);
obuf[0] = op;
write_obuf(iv, obuf, 1);
iv->stackdepth -= 3;
}
break;
}
default:
{
#if 0
obuf[0] = NOP;
write_obuf(iv, obuf, 1);
#endif
break;
}
}/* END: switch(opcode) */
if(iv->stackdepth > iv->maxdepth)
iv->maxdepth = iv->stackdepth;
if(iv->stackdepth < iv->mindepth)
iv->mindepth = iv->stackdepth;
return iv->cod_usedtail;
}/* END: gen_inst() */
static void
set_op(PND pnd, PopA ptr, unsigned char otype)
{
unsigned char optype = otype & 0xe0;
unsigned char isize = otype & 0x1f;
pnd->data = (DATUM *)ptr;
if(optype <= OPIMMED4)
{
pnd->dtype = optype >> 5;
pnd->quals = Q_CONST;
pnd->size = isize;
pnd->opsize = get_size(pnd->dtype, isize);
pnd->atype = A_IMMED;
} /* END: OPIMMED */
else
{
unsigned short type = GS(ptr->dtype);
pnd->dtype = type & 0xff;
pnd->quals = (type >> 8) & 0xff;
pnd->size = GL(ptr->dsize);
pnd->opsize = get_size(pnd->dtype, pnd->size);
pnd->atype = GS(ptr->atype);
if(optype == OPAUTO)
{
if(GL(ptr->pofs) >= 0)
{
pnd->atype &= ~A_AUTO;
pnd->atype |= A_PARAM;
}
}
}
}/* END: set_op() */
static void *
decode_anf(Piv iv, unsigned char *p)
{
void *dptr;
void *lptr;
void *rptr;
if(iv->debug >= '4')
cfeprintf("DECODE inst(%u) `%s'\n", *p, oxgenops[*p]);
if(*p == 0)
return POP->next;
iv->ob->p = p;
switch(*p)
{
case regainop:
case grabop:
case retvoidop:
{/* 0 address mode */
break;
}
case jmploopop:
case jmpcontinueop:
case jmpbreakop:
case jmpgotoop:
case ljmptrueop:
case jmptrueop:
case ljmpfalseop:
case jmpfalseop:
case funcstartop:
case funcstopop:
case retdataop:
{/* 1 address mode */
dptr = (p+8);
set_op(&iv->ob->d, dptr, p[1]);
break;
}
case getvalop:
case derefop:
case assignop:
case duptmpop:
case truthop:
case aliastmpop:
case negop:
case complop:
case notop:
case copyop:
case castop:
case clrdatop:
case compsavop:
case totmpop:
case retstructop:
case switchop:
case argop:
{/* 2 address mode */
dptr = (p+8);
lptr = (((char*)dptr) + (p[1] & 0x1f));
set_op(&iv->ob->d, dptr, p[1]);
set_op(&iv->ob->l, lptr, p[2]);
break;
}
case plusop:
case minusop:
case mulop:
case divop:
case modop:
case orop:
case xorop:
case andop:
case eqop:
case neqop:
case ltop:
case gtop:
case leop:
case geop:
case lshop:
case rshop:
case getbitfieldop:
case callfuncop:
case putbitfieldop:
{/* 3 address mode */
dptr = (p+8);
lptr = (((char*)dptr) + (p[1] & 0x1f));
rptr = (((char*)lptr) + (p[2] & 0x1f));
set_op(&iv->ob->d, dptr, p[1]);
set_op(&iv->ob->l, lptr, p[2]);
set_op(&iv->ob->r, rptr, p[3]);
break;
}
default:
{
return POP->next;
}
}/* END: switch(*p) */
/* Save pointers to the machine instructions generated by this ANF code */
iv->ob->startinst = iv->cod;
iv->ob->endinst = gen_inst(iv, iv->ob);
if(iv->cod != iv->ob->startinst)
{/* instructions were generated */
link_ob(iv);
}
return POP->next;
}/* END: decode_anf() */
static void *
skip_bracket(unsigned char *p)
{
long opcode = *p;
int opcount = 0;
for(;;)
{
if(*p == opcode)
++opcount;
else if(*p == endop && GL(POP->data) == opcode)
{
if(--opcount == 0) {
return p;
}
}
else if(*p == endfileop || *p == endallop)
{
PERROR(pName ": Malformed input file3=%u=%p",*p, p);
}
p = POP->next;
}
return 0;
}
static void *
do_strelem(Piv iv, unsigned char *p)
{
void *sp = p;
unsigned char *q = skip_bracket(p);
void *elem[20];
void *elemq[20];
int elemcnt, i;
elemcnt = 0;
p = POP->next;
while(p < q)
{/* Pick up nested elements */
unsigned char opcode = *p;
if(opcode == strelemop || opcode == ptrelemop || opcode == arrayelemop)
{
void *qq = skip_bracket(p);
elem[elemcnt] = p;
elemq[elemcnt++] = qq;
p = qq;
}
p = POP->next;
}
/* Dump the nested elements in the order encountered */
for(i = 0; i < elemcnt; ++i)
{
do_something(iv, elem[i]);
}
/* Dump the remainder of bracket */
p = sp;
elemcnt = 0;
p = POP->next;
while(p < q)
{
unsigned char opcode = *p;
if(opcode == strelemop || opcode == ptrelemop || opcode == arrayelemop)
p = ((Pop)elemq[elemcnt++])->next;
else
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_ptrelem(Piv iv, unsigned char *p)
{
void *sp = p;
unsigned char *q = skip_bracket(p);
void *elem[20];
void *elemq[20];
int elemcnt, i;
elemcnt = 0;
p = POP->next;
while(p < q)
{/* Pick up nested elements */
unsigned char opcode = *p;
if(opcode == arrayelemop || opcode == ptrelemop || opcode == strelemop)
{
void *qq = skip_bracket(p);
elem[elemcnt] = p;
elemq[elemcnt++] = qq;
p = qq;
}
p = POP->next;
}
/* Dump the nested elements in the order encountered */
for(i = 0; i < elemcnt; ++i)
{
do_something(iv, elem[i]);
}
/* Dump the remainder of bracket */
p = sp;
elemcnt = 0;
p = POP->next;
while(p < q)
{
unsigned char opcode = *p;
if(opcode == arrayelemop || opcode == strelemop || opcode == ptrelemop)
p = ((Pop)elemq[elemcnt++])->next;
else
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_arrayelem(Piv iv, unsigned char *p)
{/* Arrange output for the stack machine */
void *sp = p;
unsigned char *q = skip_bracket(p);
void *sadims[10];
void *sadimsq[10];
void *spdims[10];
void *spdimsq[10];
void *elem[20];
void *elemq[20];
int sacnt, spcnt, elemcnt, i;
/* Scan over the bracket and pick up the dimension computations */
elemcnt= sacnt = spcnt = 0;
p = POP->next;
while(p < q)
{
unsigned char opcode = *p;
if(opcode == arraydimsop)
{
void *qq = skip_bracket(p);
sadims[sacnt] = p;
sadimsq[sacnt++] = qq;
p = qq;
}
else if(opcode == ptrdimsop)
{
void *qq = skip_bracket(p);
spdims[spcnt] = p;
spdimsq[spcnt++] = qq;
p = qq;
}
else if(opcode==arrayelemop || opcode==ptrelemop || opcode==strelemop)
{
void *qq = skip_bracket(p);
elem[elemcnt] = p;
elemq[elemcnt++] = qq;
p = qq;
}
p = POP->next;
}
/* Dump the dimension computations in stack order */
for(i = spcnt-1; i >= 0; --i)
{
do_bracket(iv, spdims[i], spdimsq[i]);
}
for(i = sacnt-1; i >= 0; --i)
{
do_bracket(iv, sadims[i], sadimsq[i]);
}
/* Dump the nested elements in the order encountered */
for(i = 0; i < elemcnt; ++i)
{
do_something(iv, elem[i]);
}
/* Dump the remainder of the bracket */
p = sp;
elemcnt = sacnt = spcnt = 0;
p = POP->next;
while(p < q)
{
unsigned char opcode = *p;
if(opcode == arraydimsop)
p = ((Pop)sadimsq[sacnt++])->next;
else if(opcode == ptrdimsop)
p = ((Pop)spdimsq[spcnt++])->next;
else if(opcode==arrayelemop || opcode==ptrelemop || opcode==strelemop)
p = ((Pop)elemq[elemcnt++])->next;
else
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static int
funcret_used(PopT op, unsigned char *p)
{
long tmpnum;
if( op->dtype == 0
&& op->dsize == 0)
{
return 1; /* void function */
}
tmpnum = op->tmpnum;
while(*p != funcexitop)
{
if(*p && *p <= (unsigned char)100)
{
unsigned char *qp = p+8;
if(*p == callfuncop)
{/* function using same temp */
if(GL(((PopT)qp)->tmpnum) == tmpnum)
{
return 1; /* not used earlier */
}
}
else
{
if((p[1]&0xe0) == OPRET)
{
if(GL(((PopT)qp)->tmpnum) == tmpnum)
{
return 0; /* ret used */
}
}
qp += p[1]&0x1f;
if((p[2]&0xe0) == OPRET)
{
if(GL(((PopT)qp)->tmpnum) == tmpnum)
{
return 0; /* ret used */
}
}
qp += p[2]&0x1f;
if((p[3]&0xe0) == OPRET)
{
if(GL(((PopT)qp)->tmpnum) == tmpnum)
{
return 0; /* ret used */
}
}
}
}
p = POP->next;
}
return 1; /* ret not used */
}
static unsigned char
check_for_builtin(Piv iv, unsigned char *p, int flag)
{
short symnum;
long key[2];
unsigned char *result;
if(flag == 0)
{
symnum = GS(((PopA)(p+20))->symnum);
}
else if(flag == 1)
{
symnum = GS(((PopI)(p+16))->s.symnum);
}
else if(flag == 2)
{
symnum = GS(POPI->s.symnum);
}
else return 0;
key[0] = symnum;
key[1] = 0;
if(SymFind(iv->builtintbl, key, &result))
return *result;
return 0;
}
static void *
do_funcall(Piv iv, unsigned char *p)
{/* Arrange output for the stack machine */
char obuf[4];
void *sp = p;
unsigned char *q = skip_bracket(p);
int argcnt, i, dump;
void *argloads[100];
void *argloadsq[100];
char *callop = 0;
unsigned char builtin = 0;
/* Scan over the bracket and pick up argument loads */
argcnt = 0;
p = POP->next;
while(p < q)
{
if(*p == getvalop && callop == 0)
{
builtin = check_for_builtin(iv, p, 0);
}
else if(*p == callfuncop)
callop = p;
else if(*p == argloadop)
{
void *qq = skip_bracket(p);
argloads[argcnt] = p;
argloadsq[argcnt++] = qq;
p = qq;
}
p = POP->next;
}
/* Check out whether the function return is used */
dump = funcret_used((PopT)(callop+8), q);
/* Calling an interpreter builtin ?? */
if(builtin)
{
iv->in_builtin = 1;
/* Dump the argument loads in order */
/* The ARG instruction will be suppressed because iv->in_builtin > 0 */
for(i = 0; i < argcnt; ++i)
{
do_bracket(iv, argloads[i], argloadsq[i]);
}
iv->stackdepth -= argcnt;
/* Generate the BUILTIN instruction */
i = 3;
++iv->stackdepth;
obuf[0] = XTD;
obuf[1] = BUILTIN;
obuf[2] = builtin;
if(dump)
{
obuf[3] = DUMP;
--iv->stackdepth;
i = 4;
}
write_obuf(iv, obuf, i);
iv->in_builtin = 0;
}
else
{
/* Generate the CALLSETUP instruction */
p = sp;
p = POP->next;
while(p < q)
{
if(*p == argloadop)
break;
else
p = do_something(iv, p);
}
/* Dump the argument loads in order */
for(i = 0; i < argcnt; ++i)
{
do_bracket(iv, argloads[i], argloadsq[i]);
}
/* Generate the CALL instruction */
i = 1;
obuf[0] = CALL;
if(dump)
{
obuf[1] = DUMP;
--iv->stackdepth;
i = 2;
}
write_obuf(iv, obuf, i);
if((GL(((Pop)(callop))->data1) & 0xff) == D_STRUCT)
{
++iv->has_structret;
}
}
return ((Pop)q)->next;
}
static void *
do_expr(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
if(iv->debug >= '2')
cfeprintf("EXPR inst(%u) `%s'\n", *p, oxgenops[*p]);
while(p < q)
{
switch(*p)
{
case arrayelemop:
p = do_arrayelem(iv, p);
break;
case strelemop:
p = do_strelem(iv, p);
break;
case ptrelemop:
p = do_ptrelem(iv, p);
break;
case funcallop:
p = do_funcall(iv, p);
break;
case condop:
case twopathop:
case logicalop:
case binopop:
case argloadop:
case preincrdecop:
case postincrdecop:
case compoundop:
case unopop:
p = POP->next;
break;
default:
p = do_something(iv, p);
break;
}
}
return ((Pop)q)->next;
}
static void *
do_expstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return q;
}
static void *
do_ifstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_ifelsestmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_switchstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_whilestmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_dostmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_forstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_asmstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_initstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_anfblock(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static char *
nodot(Piv iv, char *name)
{
char *cp;
if((cp = strchr(name, '.')))
{
char *newname;
newname = Cmalloc(iv->category, strlen(name)+1);
strcpy(newname,name);
cp = strchr(newname, '.');
*cp = 0;
return newname;
}
return name;
}
static void
printfunc(Piv iv, unsigned char *p)
{
char *funcname = nodot(iv, iv->symaddr[GS(POPI->funcdef.symnum)]);
if(*p == gfuncdefop)
{
fprintf(iv->outfile, "\n%8.8lx: .global .function _%s\n",
iv->out_offset, funcname);
}
else if(*p == sfuncdefop)
{
fprintf(iv->outfile, "\n%8.8lx: .local .function _%s\n",
iv->out_offset, funcname);
}
}
static void *
do_stmt(Piv iv, unsigned char *p)
{
void *q;
if(iv->debug >= '2')
cfeprintf("STMT inst(%u) `%s'\n", *p, oxgenops[*p]);
q = POP->next;
switch(*p)
{
case labelop:
newlabel_insert(iv, GL( POP->data));
break;
case gfuncdefop:
case sfuncdefop:
case funcexitop:
PERROR(pName ": Malformed input file1=%u=%p",*p, p);
case nestedfuncdefop:
{
if(iv->listing_wanted)
{
char obuf[8];
obuf[0] = NFUNC;
*((char**)&obuf[1]) = nodot(iv, iv->symaddr[GS(POPI->funcdef.symnum)]);
write_obuf(iv, obuf, 5);
}
iv->numnested += 1;
break;
}
case nestedfuncexitop:
{
char obuf[2];
obuf[0] = RET;
write_obuf(iv, obuf, 1);
break;
}
case anfblockop:
q = do_anfblock(iv, p);
break;
case expstmtop:
q = do_expstmt(iv, p);
break;
case ifstmtop:
q = do_ifstmt(iv, p);
break;
case ifelsestmtop:
q = do_ifelsestmt(iv, p);
break;
case switchstmtop:
q = do_switchstmt(iv, p);
break;
case whilestmtop:
q = do_whilestmt(iv, p);
break;
case dostmtop:
q = do_dostmt(iv, p);
break;
case forstmtop:
q = do_forstmt(iv, p);
break;
case asmstmtop:
q = do_asmstmt(iv, p);
break;
case initstmtop:
q = do_initstmt(iv, p);
break;
case lineop:
if(iv->debug >= '3')
{
cfeprintf("Line=%u depth=%d\n", GL(POP->data), iv->stackdepth);
}
if(iv->listing_wanted)
{
char obuf[8];
obuf[0] = LINENO;
*((long*)&obuf[1]) = GL(POP->data);
write_obuf(iv, obuf, 5);
}
iv->lastline = GL(POP->data);
break;
default:
break;
}
return q;
}
static void *
do_something(Piv iv, unsigned char *p)
{
if(*p < labelop)
return decode_anf(iv, p);
else if(*p >= condop && *p < symbop)
return do_expr(iv, p);
else
return do_stmt(iv, p);
}
static void
do_bracket(Piv iv, unsigned char *p, unsigned char *q)
{
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
}
static void *
dumpa_func(Piv iv, unsigned char *p)
{
unsigned char obuf[2];
Pafile pf;
unsigned char *pdef = p;
iv->ob = new_nodeO(iv); /* setup first intermediate output node */
link_ob(iv); /* null node never unlinked */
iv->first_ob = iv->ob_usedtail;
iv->cod = new_nodeC(iv); /* setup first code node */
link_cod(iv); /* null node never unlinked */
iv->first_cod = iv->cod_usedtail;
pf = iv->files[iv->filenum];
if(iv->listing_wanted)
{
printfunc(iv, p);
}
p = POP->next;
for(;;)
{
if(*p == funcexitop)
{
obuf[0] = RET;
write_obuf(iv, obuf, 1);
write_funcdata(iv, pdef);
break;
}
else
p = do_something(iv, p);
}
save_extlocs(iv);
reset_funcdata(iv);
return p;
}
static void
dump_funcs(Piv iv)
{
long pad;
Pafile pf;
unsigned char *p;
int i;
#if 0
oxcc_debug(__builtin_iv(),0x40040);
#endif
reset_funcdata(iv);
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
p = pf->file_p;
if(iv->listing_wanted)
fprintf(iv->outfile, "\n\nFile:%s:\n\n", pf->symaddr[1]);
while(*p != endfileop)
{
if(*p == labelop)
{
newlabel_insert(iv, GL( POP->data ));
}
else if(*p == lineop)
{
iv->lastline = GL(POP->data);
if(iv->debug >= '3')
{
cfeprintf("Line=%u depth=%d\n", iv->lastline, iv->stackdepth);
}
if(iv->listing_wanted)
fprintf(iv->outfile, "Line:%ld:\n", iv->lastline);
}
else if(*p == gfuncdefop || *p == sfuncdefop)
{
p = dumpa_func(iv, p);
}
else if(*p == anfblockop)
{
PERROR(pName ": Sorry, Outer anf blocks not handled.\n");
}
p = POP->next;;
}
}
/* Start the data area on an 8 byte boundary */
if((pad = iv->out_offset & 7))
pad = 8-pad;
iv->out_offset += pad;
if(pad && !iv->listing_wanted)
FILEWRITE(padit, pad);
iv->header->a_text = iv->out_offset;
}
static void
fix_thunks(Piv iv)
{
Pafile pf;
int i;
unsigned char **vp;
unsigned char *p;
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
if(SymHead(pf->datatbl))
{
while(SymNext(pf->datatbl))
{
SymValue(pf->datatbl, &vp);
p = vp[1];
if(*p == thunkblockop)
{/* rearrange the FUNCTHUNK */
unsigned short mods;
mods = GS(POP->data7);
mods &= 0xc000;
mods |= GS(POP->data9) & 0x1f1f;
PS( POP->data7 ) = mods;
PS( POP->data9) = get_maxdepth(iv, GS( POP->data2 ));
if(mods & Fextern)
{/* Put symbol number in the offset slot */
PL( POP->data5 ) = final_symnum(iv, GS( POP->data2 ));
}
else
{/* Put function offset in the offset slot */
PL( POP->data5 ) = newlabel_fix(iv, GL( POP->data5 ));
}
}
}
}
}
}
static void
printdata(Piv iv, char *sym, char *msg, void *ptr, int size,
long offset, int locid)
{
int x;
x = print8(iv, ptr, size, offset, 0);
if(locid > 0)
fprintf(iv->outfile," _%s.%d (%s)\n", sym, locid, msg);
else
fprintf(iv->outfile," _%s (%s)\n", sym, msg);
while((size -= x) > 0)
{
offset += x;
((char*)ptr) += x;
x = print8(iv, ptr, size, offset, 1);
}
}
static void
printbss(Piv iv, char *sym, int size, int offset, unsigned char prevopcode,
int locid)
{
if(prevopcode == globssop)
fprintf(iv->outfile, "%8.8x: _%s (BSS %d)\n", offset, sym, size);
else
fprintf(iv->outfile, "%8.8x: _%s.%d (bss %d)\n", offset, sym, locid, size);
}
static void
dump_data(Piv iv)
{
struct _val {
unsigned long size;
unsigned char *p;
unsigned char *prevp;
long locid;
};
struct _val *val;
unsigned long *key;
long datsize = 0;
long bsssize = 0;
long curr_offset = iv->out_offset;
unsigned char opcode, prevopcode = 0;
if(SymHead(iv->datatbl))
{
void *savaddr;
if(iv->listing_wanted)
{
fprintf(iv->outfile, "\n\t.data\n\n");
savaddr = iv->symaddr[0];
iv->symaddr[0] = "STRING_";
}
while(SymNext(iv->datatbl))
{
unsigned char *p;
long size;
long pad;
SymKey(iv->datatbl, &key);
SymValue(iv->datatbl, &val);
p = val->p;
opcode = *p;
if(val->prevp)
prevopcode = *(val->prevp);
size = val->size;
if((pad = size & 3)) /* the interpreter requires 4 byte alignment */
pad = 4-pad;
if( opcode == datablockop
|| opcode == mallocblockop
|| opcode == thunkblockop
|| opcode == stringblockop)
{
if(iv->listing_wanted)
{
char *msg;
if( opcode == datablockop
|| opcode == stringblockop)
{
if(prevopcode == glodatop)
msg = "DATA";
else
{
msg = "data";
}
}
else if(opcode == mallocblockop)
{
msg = "alloced";
}
else /* thunkblockop */
{
if(prevopcode == extfuncop)
{
long bu;
if((bu = check_for_builtin(iv, p, 2)))
{
Pft ft = (Pft)(p+24);
ft->funcaddr = bu;
ft->fmods |= Fbuiltin;
ft->fmods &= ~Fextern;
*(val->prevp) = 0xff;
msg = "thunk";
}
else
msg = "EXTHUNK";
}
else if(prevopcode == glofuncop)
msg = "THUNK";
else
{
msg = "thunk";
}
}
printdata(iv, iv->symaddr[GS(POP->data2)],
msg, p+24, size, GL(POP->data1), val->locid);
}
else
{
if(opcode == thunkblockop)
{
if(prevopcode == extfuncop)
{
long bu;
if((bu = check_for_builtin(iv, p, 2)))
{
Pft ft = (Pft)(p+24);
ft->funcaddr = bu;
ft->fmods |= Fbuiltin;
ft->fmods &= ~Fextern;
*(val->prevp) = 0xff;
}
}
}
FILEWRITE(p+24, size);
if(pad > 0)
FILEWRITE(padit, pad);
}
datsize += size+pad;
iv->out_offset += size+pad;
}
else if(opcode == bssblockop)
{
if(iv->listing_wanted)
{
printbss(iv, iv->symaddr[GS(POP->data2)], size,
GL(POP->data1), prevopcode, val->locid);
}
bsssize += size+pad;
}
}
if(iv->listing_wanted)
{
iv->symaddr[0] = savaddr;
}
}
iv->header->a_data = iv->out_offset - curr_offset;
if(datsize != iv->header->a_data)
PERROR(pName,":Syserr: data size incorrect (%d)!=(%d)\n",
datsize, iv->header->a_data);
}
static void
dump_bss(Piv iv)
{
iv->header->a_bss = iv->total_size - iv->bss_offset;
}
static void
make_final_string_pack(Piv iv)
{
long strsize = 0;
int strcnt = 0;
char *pack;
char *cp;
struct {
char *str;
long symnum;
long symofs;
} *val;
if(SymHead(iv->finalsymtbl))
{
while(SymNext(iv->finalsymtbl))
{
SymValue(iv->finalsymtbl, &val);
++strcnt;
val->symofs = strsize+4;
strsize += strlen(val->str)+2;
}
}
pack = Ccalloc(iv->category, 1, strsize+4);
*((long*)pack) = strsize + 4;
cp = pack + 4;
if(SymHead(iv->finalsymtbl))
{
while(SymNext(iv->finalsymtbl))
{
SymValue(iv->finalsymtbl, &val);
*cp++ = '_';
strcpy(cp, val->str);
cp += strlen(val->str)+1;
}
}
iv->finalstringpack = pack;
iv->finalpacksize = strsize+4;
}
static unsigned char *
dump_switch(Piv iv, unsigned char *p, int filenum)
{
struct nlist nl;
unsigned char *q = skip_bracket(p);
nl.n_type = N_SWTAB;
nl.n_other = 0;
while(p < q)
{
if(*p == switchidop)
{
nl.n_desc = GS(POP->data1); /* id */
}
else if(*p == casevalop)
{
long key[2];
long *result;
nl.n_un.n_strx = GL(POP->data1); /* value */
key[0] = GL(POP->data); /* label number */
key[1] = filenum;
if(SymFind(iv->newlabeltbl, &key, &result))
{
nl.n_value = *result; /* offset */
}
else
{
PERROR(pName ":Syserr: case label not found\n");
}
if(iv->listing_wanted)
{
/* print nothing */
}
else
{
FILEWRITE(&nl, sizeof(struct nlist));
iv->out_offset += sizeof(struct nlist);
}
}
p = POP->next;
}
return ((Pop)q)->next;
}
static void
dump_symbols(Piv iv)
{
long curr_offset = iv->out_offset;
int i;
struct nlist nl;
nl.n_other = 0;
nl.n_desc = 0;
make_final_string_pack(iv);
if(SymHead(iv->gbltbl))
{
if(iv->listing_wanted)
{
fprintf(iv->outfile, "\n\t.symbols\n\n");
}
while(SymNext(iv->gbltbl))
{
struct _gloval *valp;
unsigned char opcode;
SymValue(iv->gbltbl, &valp);
if((opcode = *(valp->p)))
{
PopI pp;
pp = (PopI) (((Pop)(valp->p))->next+8);
nl.n_un.n_strx = final_strofs(iv, valp->symname);
if(opcode == glodatop)
{
nl.n_type = N_DATA|N_EXT;
nl.n_value = pp->s.offset + iv->header->a_text;
}
else if(opcode == globssop)
{
nl.n_type = N_BSS|N_EXT;
nl.n_value = pp->s.offset + iv->header->a_text;
}
else if(opcode == glofuncop || opcode == extfuncop)
{/* The symbol is really a thunk in the data section */
nl.n_type = N_NDC|N_EXT;
nl.n_value = pp->s.offset;
}
else if(opcode == extvarop)
{
nl.n_type = N_UNDF|N_EXT;
nl.n_value = 0;
}
else if(opcode == 0xff)
{/* Builtin thunk */
continue;
}
if(iv->listing_wanted)
{
int symval = nl.n_value;
if(nl.n_type & (N_DATA|N_BSS))
symval -= iv->header->a_text;
fprintf(iv->outfile, "%8.8x: _%s\n", symval, valp->symname);
}
else
{
FILEWRITE(&nl, sizeof(struct nlist));
}
iv->out_offset += sizeof(struct nlist);
}
}
}
/* DUMP SWITCH TABLE INFO */
for(i = 0; i < iv->numfiles; ++i)
{
Pafile pf = iv->files[i];
unsigned char *p;
if((p = pf->switch_p))
{
while(*p != endfileop)
{
if(*p == switchidop)
{
p = dump_switch(iv, p, i);
}
else p = POP->next;
}
}
}
iv->header->a_syms = iv->out_offset - curr_offset;;
}/* END: dump_symbols() */
static void
dump_text_relocs(Piv iv)
{
long curr_offset = iv->out_offset;
PEL pel = iv->finextbufstart;
struct relocation_info r;
r.r_pcrel = 0;
r.r_extern = 1;
r.r_length = 2;
r.r_pad = 0;
if(pel && iv->listing_wanted)
{
fprintf(iv->outfile,"\n\t.textrels\n\n");
}
while(pel)
{
r.r_symbolnum = final_symnum(iv, pel->symnum);
r.r_address = pel->spot;
if(pel->symnum > 0)
{
if(iv->listing_wanted)
{
fprintf(iv->outfile,"%8.8lx: .extern _%s\n",
r.r_address, iv->symaddr[pel->symnum]);
}
else
{
FILEWRITE(&r, sizeof(struct relocation_info));
}
iv->out_offset += sizeof(struct relocation_info);
}
pel = pel->next;
}
iv->header->a_trsize = iv->out_offset - curr_offset;
}/* END: dump_text_relocs() */
static void
dump_data_relocs(Piv iv)
{
long curr_offset = iv->out_offset;
struct relocation_info r;
r.r_pcrel = 0;
r.r_length = 2;
r.r_pad = 0;
if(SymHead(iv->reloctbl))
{
if(iv->listing_wanted)
{
fprintf(iv->outfile,"\n\t.datarels\n\n");
}
while(SymNext(iv->reloctbl))
{
struct _rkey *kp;
struct _rval *vp;
unsigned char *p;
int symnum;
SymKey(iv->reloctbl, &kp);
SymValue(iv->reloctbl, &vp);
p = vp->p; /* pointer to relocop in input buffer */
symnum = GS(POPI->reloc.rsym);
if(kp->rsize == 1)
r.r_length = 0;
else if(kp->rsize == 2)
r.r_length = 1;
else if(kp->rsize == 4)
r.r_length = 2;
else PERROR(pName ":error: reloc size too large\n");
r.r_address = GL( POPI->reloc.spot );
if(*p == extlocop)
{/* External variable */
r.r_extern = 1;
r.r_symbolnum = final_symnum(iv, symnum);
}
else if(*p)
{
r.r_extern = 0;
r.r_symbolnum = N_DATA;
}
if(*p)
{
if(iv->listing_wanted)
{
if(r.r_extern)
{
if(vp->rsym <= 0)
{/* an absolute value */
continue;
}
fprintf(iv->outfile,"%8.8lx: .extern _%s\n",
r.r_address, iv->symaddr[symnum]);
}
else
{
fprintf(iv->outfile, "%8.8lx: .segrel\n", r.r_address);
}
}
else
{
if(r.r_extern && vp->rsym <= 0)
{/* an absolute value */
continue;
}
FILEWRITE(&r, sizeof(struct relocation_info));
}
iv->out_offset += sizeof(struct relocation_info);
}
}
}
iv->header->a_drsize = iv->out_offset - curr_offset;
}/* END: dump_data_relocs() */
static void
prepare_data_relocs(Piv iv)
{
if(SymHead(iv->reloctbl))
{
while(SymNext(iv->reloctbl))
{
struct _rkey *kp;
struct _rval *vp;
unsigned char *p;
SymKey(iv->reloctbl, &kp);
SymValue(iv->reloctbl, &vp);
p = vp->p; /* pointer to relocop in input buffer */
if(*p == extlocop)
{/* External variable */
}
else if(*p)
{/* a.out format requires a flat address space for relocations */
if(kp->rsize == 1)
{
*((char*)vp->base) += iv->header->a_text;
}
else if(kp->rsize == 2)
{
*((short*)vp->base) += iv->header->a_text;
}
else if(kp->rsize == 4)
{
*(vp->base) += iv->header->a_text;
}
else PERROR(pName ":error: reloc size too large\n");
}
}
}
}/* END: prepare_data_relocs() */
static void
dump_symbol_strings(Piv iv)
{
if(iv->listing_wanted)
{
/* print nothing */
}
else
{
FILEWRITE(iv->finalstringpack, iv->finalpacksize);
}
}/* END: dump_symbol_strings() */
static int
gen_output(Piv iv, char *outpath)
{/* Bytecode output */
char *cp;
int i;
char outname[256];
strcpy(outname, outpath);
if((cp = strrchr(outname, '.')))
{
#if 0
if(iv->listing_wanted)
strcpy(cp, ".lst");
else
strcpy(cp, ".byt");
#endif
}
else
{
if(iv->listing_wanted)
strcat(outname, ".lst");
else
strcat(outname, ".byt");
}
for(i = 1; i < iv->argc; ++i)
{
if(!strcmp(outname, iv->argv[i]))
{
PERROR(pName ": ERROR output file `%s' is same as input file\n", outname);
}
}
if(!(iv->outfile = fopen(outname, "wb")))
{
PERROR(pName ": Cannot open output file %s\n", outname);
}
/* Allocate a header struct */
iv->header = Ccalloc(iv->category, 1, sizeof(struct exec));
if(iv->listing_wanted)
{
long tim = time(0);
char *date = ctime(&tim);
fprintf(iv->outfile,"/*\n `%s' %s", outname, date);
fprintf(iv->outfile,notice,MAJOR_VERSION,MINOR_VERSION);
}
else
{/* Seek past the header area */
iv->header->a_info = OMAGIC;
fseek(iv->outfile, sizeof(struct exec), SEEK_SET);
}
install_builtins(iv);
make_final_symtab(iv);
#if 0
if(iv->debug)
bterpdebug();
#endif
dump_funcs(iv);
fix_thunks(iv);
prepare_data_relocs(iv); /* adjust addresses for flat space */
dump_data(iv);
dump_bss(iv);
dump_text_relocs(iv);
dump_data_relocs(iv);
dump_symbols(iv);
dump_symbol_strings(iv);
/* Update the header block */
if(!iv->listing_wanted)
{
fseek(iv->outfile, 0, SEEK_SET);
FILEWRITE(iv->header, sizeof(struct exec));
}
fclose(iv->outfile);
iv->outfile = 0;
return iv->errors;
}
/* ======================= END BYTECODE OUTPUT GENERATOR ==================== */
/* ===================== GENERIC CODE BELOW THIS POINT ================== */
static jmp_buf run_env;
static void
prerror(const char *fmt, ...)
{
VFPRINTF(fmt, (char *)(((int *)(&fmt))+1));
longjmp(run_env, 3);
}
static void
prwarn(const char *fmt, ...)
{
VFPRINTF(fmt, (char *)(((int *)(&fmt))+1));
}
static void
info(const char *fmt, ...)
{
vfprintf(stdout, fmt, (char *)(((int *)(&fmt))+1));
}
/* ========================= MULTI HEAP MALLOC ========================== */
#define LOCAL static
#if USING_FRAMEWORK
#define THEWELL(a) mallocC(local_category, a)
static int local_category;
static int num_instance;
extern void *mallocC(int, int);
extern void freecat(int);
extern void oxlink_clear_bss();
extern int NewMallocCategory();
#endif /* USING_FRAMEWORK */
#define BASE_CATEGORY 0
#define MEMORY_BUG 0
#define PRINT_RAWDATA 0
#if MEMORY_BUG == 1
#define MPRINTF printf
#else
#define MPRINTF(args...)
#endif
#define PAGESIZE (4096) /* can use `pagesize' function in OS */
#define ALIGNMENTM (sizeof(unsigned long))
#define MAL_MAXLEVEL (12)
#define ROUNDINGM(a) ((ALIGNMENTM-(a&(ALIGNMENTM-1)))&(ALIGNMENTM-1))
#define ALLOCSIZE (4096)
#define FRNTGUARD (0x544e5246UL)
#define BACKGUARD (0x48434142UL)
#ifndef THEWELL
#define THEWELL do_sbrk
#endif
#define NUMTYPES 3
#define SIZEH 0
#define FREEH 1
#define USEDH 2
#define SKIPVARS NodePM update[MAL_MAXLEVEL+1];NodePM node,prev;int level
#define DELETENODE(TYPE) \
{for(level=0;level<=bp->TYPE##level; level++)\
{if(update[level]->fptr[level] == node)\
update[level]->fptr[level] = node->fptr[level];else break;}\
while(bp->TYPE##level>0 && bp->TYPE##header->fptr[bp->TYPE##level]==_NILLL)\
bp->TYPE##level--;free_Mnode(bp,node,TYPE);}
#define INSERT() \
{while(level >= 0){\
node->fptr[level] = update[level]->fptr[level];\
update[level]->fptr[level] = node;level--;}}
#define SETLEVEL(TYPE) \
{level = getMlevel(bp, bp->TYPE##level);\
while(bp->TYPE##level < level)update[++bp->TYPE##level]=bp->TYPE##header;}
#define FINDKEY(TYPE, KEYVAL)\
{node = bp->TYPE##header;\
for(level = bp->TYPE##level; level >= 0; level--){\
while(node->fptr[level]->key < KEYVAL)\
node = node->fptr[level];\
update[level] = node;}prev=node;node=node->fptr[0];}
#define DETACH(SN)\
{SN->bptr->fptr=SN->fptr;if(SN->fptr)SN->fptr->bptr=SN->bptr;}
#define UNLINK(SN, N)\
{if(!sp->fptr&&sp->bptr->bptr<=(AddrP)(MAL_MAXLEVEL+1))dsize[N]=sp->size;\
DETACH(SN);free_addr(bp,SN);}
#define CHECKGUARDS(MSG)\
{if(bp->guarded){\
unsigned *p2;\
p2 = (void*)((char*)address+cursize-ALIGNMENTM);\
if(*address != FRNTGUARD)\
PERROR(pName #MSG ":%d: corrupted at 0x%x\n", bp->bincat, addr);\
if(*p2 != BACKGUARD)\
PERROR(pName #MSG ":%d: corrupted by 0x%x\n", bp->bincat, addr);}}
#if MEMORY_BUG == 1
#define HEAPCHECK \
{void *lastaddr;\
if(category > 0){\
guardC(category);\
if((lastaddr = heapcheckC(category, NULL))){\
FINDKEY(USEDH, (unsigned)lastaddr-ALIGNMENTM)\
MPRINTF("bad heap at %x c:%u size=%u\n", lastaddr, category, node->value);\
(void)print_rawdata(lastaddr-ALIGNMENTM, node->value);\
abort();}}}
#else
#define HEAPCHECK
#endif
struct _catlocs {
void *addr;
struct _catlocs *fptr;
};
typedef struct _nodeM
{
unsigned key;
unsigned value;
unsigned levels; /* must always be after value */
struct _nodeM *fptr[1];
} NodeM, *NodePM;
typedef struct _addr
{
struct _addr *fptr;
struct _addr *bptr;
NodePM maddr;
unsigned size;
} *AddrP;
struct _bins {
unsigned bits;
unsigned nbits;
NodePM SIZEHheader;
int SIZEHlevel;
NodePM FREEHheader;
int FREEHlevel;
NodePM USEDHheader;
int USEDHlevel;
unsigned bincat;
unsigned maxloc;
unsigned minloc;
struct _catlocs *catlocs;
struct _bins *fptr;
NodePM freenodes[NUMTYPES][MAL_MAXLEVEL+2];
struct _addr *freeaddrlocs;
char *chunkbase[NUMTYPES];
int chunksize[NUMTYPES];
int guarded;
int addrbump;
};
static struct _bins zbp;
static struct _bins *hmap[1009];
static struct _nodeM _nilll = {0xffffffff,0,0,{0}};
static struct _nodeM *_NILLL = &_nilll;
static unsigned maxloc;
static unsigned minloc;
static struct _bins *freebinlocs;
static struct _catlocs *freecatlocs;
static char *binbase;
static int binsize;
static int chunksizes[] = {ALLOCSIZE,3*ALLOCSIZE,2*ALLOCSIZE};
static long randtbl[32] = { 0L,
0x9a319039L, 0x32d9c024L, 0x9b663182L, 0x5da1f342L,
0xde3b81e0L, 0xdf0a6fb5L, 0xf103bc02L, 0x48f340fbL,
0x7449e56bL, 0xbeb1dbb0L, 0xab5c5918L, 0x946554fdL,
0x8c2e680fL, 0xeb3d799fL, 0xb11ee0b7L, 0x2d436b86L,
0xda672e2aL, 0x1588ca88L, 0xe369735dL, 0x904f35f7L,
0xd7158fd6L, 0x6fa6f051L, 0x616e6b96L, 0xac94efdcL,
0x36413f93L, 0xc622c298L, 0xf5a42ab8L, 0x8a88d77bL,
0xf5ad9d0eL, 0x8999220bL, 0x27fb47b9L
};
static long *fptr = &randtbl[4];
static long *rptr = &randtbl[1];
/* ======================== START OF CODE =========================== */
#if PRINT_RAWDATA == 1
static char
hexbyte(unsigned int c)
{
char x = c & 0xf;
return x + ((x>9) ? 55 : 48);
}
static void
print_rawdata(void *rawdata, long size)
{
unsigned long vaddr = 0;
unsigned char *d = rawdata;
int i,j;
char addr[9];
char hex1[24];
char hex2[24];
char side1[9];
char side2[9];
addr[8] = 0;
hex1[23] = 0;
hex2[23] = 0;
side1[8] = 0;
side2[8] = 0;
while(size > 0)
{
unsigned long qaddr = vaddr;
memset(addr, '0', 8);
memset(hex1, ' ', 23);
memset(hex2, ' ', 23);
memset(side1, ' ', 8);
memset(side2, ' ', 8);
i = 7;
while(qaddr)
{
addr[i--] = hexbyte(qaddr);
qaddr >>= 4;
}
for(i=0,j=0; i < 8; ++i)
{
if(--size >= 0)
{
unsigned int c = *d++;
if(isprint(c))
side1[i] = c;
else
side1[i] = '.';
hex1[j++] = hexbyte(c>>4);
hex1[j++] = hexbyte(c);
++j;
}
else break;
}
for(i=0,j=0; i < 8; ++i)
{
if(--size >= 0)
{
unsigned int c = *d++;
if(isprint(c))
side2[i] = c;
else
side2[i] = '.';
hex2[j++] = hexbyte(c>>4);
hex2[j++] = hexbyte(c);
++j;
}
else break;
}
VPRINTF("%s %s%s%s %s%s%s\n",addr,hex1," | ",hex2,side1,"|",side2);
vaddr += 16;
}
}
#endif
/*
* Returns a really good 31-bit random number.
*/
static long
lrandom()
{
long i;
*fptr += *rptr;
i = (*fptr >> 1) & 0x7fffffffUL;
if(++fptr > &randtbl[31])
{
fptr = &randtbl[1];
++rptr;
}
else
{
if(++rptr > &randtbl[31])
rptr = &randtbl[1];
}
return( i );
}
#if !USING_FRAMEWORK
static void *
do_sbrk(unsigned amount)
{
void *address;
address = sbrk(amount); /* OR WHATEVER TO ACCESS THE OPERATING SYSTEM */
if(address == (void*)-1)
{
PERROR(pName "\nsystem out of memory, requested %u bytes\n", amount);
}
return address;
}
#endif
static struct _catlocs *
new_catloc(void)
{
struct _catlocs *p;
if((p=freecatlocs))
{
freecatlocs = p->fptr;
return p;
}
if(binsize < sizeof(struct _catlocs))
{
binbase = THEWELL(4096);
binsize = 4096;
}
binsize -= sizeof(struct _catlocs);
p = (void*)binbase;
binbase += sizeof(struct _catlocs);
return p;
}
static void
free_catloc(struct _catlocs *p)
{
p->fptr = freecatlocs;
freecatlocs = p;
}
static void *
new_chunk(struct _bins *bp, int size, int type)
{
char *p;
if(bp->chunksize[type] < size)
{
if(bp->bincat == 0) {
bp->chunkbase[type] = THEWELL(chunksizes[type]);
bp->chunksize[type] = chunksizes[type];
}
else {
struct _catlocs *cl;
bp->chunkbase[type] = Cmalloc(0,chunksizes[type]-zbp.guarded);
bp->chunksize[type] = chunksizes[type]-zbp.guarded;
cl = new_catloc();
cl->addr = bp->chunkbase[type];
cl->fptr = bp->catlocs;
bp->catlocs = cl;
}
}
bp->chunksize[type] -= size;
p = bp->chunkbase[type];
bp->chunkbase[type] += size;
return p;
}
static void *
new_Mnode(struct _bins *bp, int levels, int type)
{
int size;
NodePM p;
if((p=bp->freenodes[type][levels]))
{
bp->freenodes[type][levels] = p->fptr[0];
p->value = 0;
return p;
}
size = sizeof(struct _nodeM) + levels * sizeof(void*);
p = new_chunk(bp, size, type);
p->levels = levels;
p->value = 0;
return p;
}
static void
free_Mnode(struct _bins *bp, NodePM p, int type)
{
p->fptr[0] = bp->freenodes[type][p->levels];
bp->freenodes[type][p->levels] = p;
}
static struct _addr *
new_addr(struct _bins *bp)
{
struct _addr *p;
if((p=bp->freeaddrlocs))
{
bp->freeaddrlocs = p->fptr;
return p;
}
return new_chunk(bp, sizeof(struct _addr), FREEH);
}
static void
free_addr(struct _bins *bp, struct _addr *p)
{
p->fptr = bp->freeaddrlocs;
bp->freeaddrlocs = p;
}
static struct _bins *
new_bins(void)
{
struct _bins *p;
if((p=freebinlocs))
{
freebinlocs = p->fptr;
return p;
}
if(binsize < sizeof(struct _bins))
{
binbase = THEWELL(4096);
binsize = 4096;
}
binsize -= sizeof(struct _bins);
p = (struct _bins*)binbase;
binbase += sizeof(struct _bins);
return p;
}
static void
free_bins(struct _bins *p)
{
p->fptr = freebinlocs;
freebinlocs = p;
}
static int
getMlevel (struct _bins *p, int binlevel)
{
int level = -1;
int bits = 0;
while(bits == 0)
{
if (p->nbits == 0)
{
p->bits = lrandom();
p->nbits = 15;
}
bits = p->bits & 3;
p->bits >>= 2;
p->nbits--;
if(++level > binlevel)
break;
}
return (level > MAL_MAXLEVEL) ? MAL_MAXLEVEL : level;
}
static void
init_bins(struct _bins *bp, int category)
{
int i;
int binnum = category % 1009;
bzero(bp, sizeof(struct _bins));
bp->bincat = category;
bp->minloc = 0xffffffff;
bp->fptr = hmap[binnum];
hmap[binnum] = bp;
bp->SIZEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, SIZEH);
bp->FREEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, FREEH);
bp->USEDHheader = new_Mnode(bp, MAL_MAXLEVEL+1, USEDH);
for(i = 0; i <= MAL_MAXLEVEL; ++i)
{
bp->SIZEHheader->fptr[i] = _NILLL;
bp->FREEHheader->fptr[i] = _NILLL;
bp->USEDHheader->fptr[i] = _NILLL;
}
}
static struct _bins*
getcat(int category)
{
struct _bins *hbp;
hbp = hmap[category % 1009];
while(hbp)
{
if(hbp->bincat == category)
return hbp;
hbp = hbp->fptr;
}
return 0;
}
static struct _bins *
initcat(int category)
{
struct _bins *bp;
if(category == 0)
{
bp = &zbp;
if(zbp.SIZEHheader == 0)
init_bins(bp, category);
return bp;
}
/* do this to set zbp.guarded properly on startup */
if(zbp.SIZEHheader == 0)
initcat(0);
if((bp = new_bins()))
{
init_bins(bp, category);
return bp;
}
return 0;
}
static void *
getspace(struct _bins *bp, unsigned size, unsigned *remainder)
{
unsigned desired;
void *address;
desired = ((size+ALLOCSIZE-1)/ALLOCSIZE)*ALLOCSIZE;
if(bp->bincat == 0)
{
address = THEWELL(desired);
*remainder = desired - size;
}
else
{
struct _catlocs *cl;
if((desired-size) > zbp.guarded)
desired -= zbp.guarded;
address = Cmalloc(0, desired);
*remainder = desired - size;
/* save the gross allocations for the category */
cl = new_catloc();
cl->addr = address;
cl->fptr = bp->catlocs;
bp->catlocs = cl;
}
/* maintain address range info */
if((unsigned)address < bp->minloc)
bp->minloc = (unsigned)address;
if(((unsigned)address + desired) > bp->maxloc)
bp->maxloc = (unsigned)address + desired;
if(bp->minloc < minloc)
minloc = bp->minloc;
if(bp->maxloc > maxloc)
maxloc = bp->maxloc;
return address;
}
static void
addto_sizelist(struct _bins *bp, AddrP ap)
{
SKIPVARS;
/* INSERT IN SIZE LIST */
FINDKEY(SIZEH, ap->size)
if(node->key == ap->size)
{/* size node exists */
ap->fptr = (AddrP)node->value;
ap->bptr = (AddrP)&node->value;
if(ap->fptr) ap->fptr->bptr = ap;
node->value = (unsigned)ap;
}
else
{/* create new size node */
SETLEVEL(SIZEH)
node = new_Mnode(bp, level, SIZEH);
node->key = ap->size;
node->value = (unsigned)ap;
ap->fptr = 0;
ap->bptr = (AddrP)&node->value;
INSERT()
}
}
static void
addto_freelist(struct _bins *bp, void *addr, unsigned size)
{
SKIPVARS;
AddrP ap,sp;
unsigned dsize[2];
/* GET NEW ADDR STRUCT */
ap = new_addr(bp);
ap->size = size;
dsize[1] = dsize[0] = 0; /* sizenode deletion markers */
/* CHECK FREE LIST */
FINDKEY(FREEH, (unsigned)addr)
/* CHECK FOR MERGE OR INSERT */
if(prev->value && prev->key+((AddrP)prev->value)->size == (unsigned)addr)
{/* merge with previous block */
ap->size += ((AddrP)prev->value)->size;
if(prev->key + ap->size == node->key)
{/* merge with previous and next block */
sp = (AddrP) node->value;;
ap->size += sp->size;
/* delete size struct for next block */
UNLINK(sp, 0)
/* delete next block */
DELETENODE(FREEH);
}
/* delete size struct for prev block */
sp = (AddrP)prev->value;
UNLINK(sp, 1)
/* set new address struct */
prev->value = (unsigned)ap;
ap->maddr = prev;
}
else if(node->value && (char*)addr + size == (void*)node->key)
{/* merge with next block */
sp = (AddrP) node->value;;
node->key = (unsigned)addr;
ap->size += sp->size;
/* unlink size struct for next block */
UNLINK(sp,0)
/* set new address struct */
node->value = (unsigned)ap;
ap->maddr = node;
}
else
{/* insert in free list */
SETLEVEL(FREEH)
node = new_Mnode(bp, level, FREEH);
node->key = (unsigned)addr;
node->value = (unsigned)ap;
ap->maddr = node;
INSERT()
}
addto_sizelist(bp, ap);
/* Remove sizenodes eliminated by merge */
if(dsize[0])
{
FINDKEY(SIZEH, dsize[0])
if(node->value == 0)
DELETENODE(SIZEH)
}
if(dsize[1])
{
FINDKEY(SIZEH, dsize[1])
if(node->value == 0)
DELETENODE(SIZEH)
}
}
LOCAL void*
Cmemalign(int category, unsigned alignment, unsigned req)
{
SKIPVARS;
NodePM fnode;
unsigned remainder;
unsigned *address;
struct _bins *bp;
unsigned mask, size;
if(!(bp = getcat(category)))
if(!(bp = initcat(category)))
return 0;
HEAPCHECK
if(req == 0)
req = ALIGNMENTM;
else
req += ROUNDINGM(req);
size = req += bp->guarded;
if(alignment)
{
alignment += ROUNDINGM(alignment);
if(alignment > ALIGNMENTM)
{
mask = alignment -1;
size = req + alignment + bp->guarded;
}
else
{
alignment = 0;
}
}
/* check sizelist for candidate */
FINDKEY(SIZEH, size)
fnode = node;
trynext:
if(node->key != 0xffffffff)
{/* found an appropriately sized block */
AddrP sp = (AddrP)node->value;
if(!sp && node == fnode)
{
NodePM q;
q = node->fptr[0];
DELETENODE(SIZEH)
node = q;
goto trynext;
}
if(!sp)
{/* no available space at this size */
node = node->fptr[0];
goto trynext;
}
/* extract some space from this block */
remainder = node->key - size;
address = (void*)sp->maddr->key;
sp->maddr->key += size;
DETACH(sp);
if(node->value == 0)
{/* no more blocks of this size, delete sizenode */
if(node != fnode)
FINDKEY(SIZEH, size)
DELETENODE(SIZEH)
}
if(remainder == 0)
{/* no remaining space,the node in freelist is exhausted, delete it */
FINDKEY(FREEH, sp->maddr->key)
DELETENODE(FREEH)
free_addr(bp, sp);
}
else
{/* space remains in block, move it to new size loc */
sp->size = remainder;
addto_sizelist(bp, sp);
}
}
else
{
address = getspace(bp, size, &remainder);
if(remainder)
addto_freelist(bp, ((char*)address)+size, remainder);
}
if(alignment)
{
unsigned diff;
if((diff = (unsigned)address & mask))
{/* move address forward */
char *naddress;
unsigned lose;
lose = alignment - diff;
naddress = (char*)address + lose;
addto_freelist(bp, address, lose);
address = (unsigned*)naddress;
}
}
if(bp->guarded)
{
*address = FRNTGUARD;
*((unsigned*)(((char*)address)+req-ALIGNMENTM)) = BACKGUARD;
}
FINDKEY(USEDH, (unsigned)address)
if(node->key == (unsigned)address) {
PERROR(pName "allocC:%d: bookkeeping nodes are corrupted at:0x%x\n",
category, address);
}
SETLEVEL(USEDH)
node = new_Mnode(bp, level, USEDH);
node->key = (unsigned)address;
node->value = req;
INSERT()
return address+bp->addrbump;
}
LOCAL void*
Ccalloc(int category, unsigned cnt, unsigned elem_size)
{
unsigned size = cnt * elem_size;
void* buf;;
if((buf = Cmalloc(category, size)))
bzero(buf, size);
return buf;
};
LOCAL void
Cfree(int category, void* addr)
{
unsigned cursize;
unsigned *address;
struct _bins *bp;
SKIPVARS;
if(addr)
{
if(!(bp = getcat(category))) {
PERROR(pName "Cfree:%d: non-existant category at:0x%x\n",category,addr);
}
HEAPCHECK
address = (void*) ((unsigned*)addr - bp->addrbump);
FINDKEY(USEDH, (unsigned)address)
if(node->key != (unsigned)address) {
PERROR(pName "Cfree:%d: bogus address=0x%x\n", category, addr);
}
cursize = node->value;
CHECKGUARDS(Cfree)
DELETENODE(USEDH)
addto_freelist(bp, address, cursize);
}
else PERROR(pName "Cfree:%d: null pointer\n", category);
}
LOCAL void*
Crealloc(int category, void* addr, unsigned newsize)
{
SKIPVARS;
unsigned cursize;
unsigned *address;
struct _bins *bp;
NodePM onode;
if(addr == 0)
return Cmalloc(category, newsize);
else
{
if(!(bp = getcat(category))) {
PERROR(pName "reallocC:%d: non-existant category at:%x\n",category,addr);
}
HEAPCHECK
if(newsize == 0)
newsize = ALIGNMENTM;
else
newsize += ROUNDINGM(newsize);
newsize += bp->guarded;
address = (void*)(((char*)addr)-(bp->guarded/2));
FINDKEY(USEDH, (unsigned)address)
if(node->key != (unsigned)address) {
PERROR(pName "reallocC:%d: bogus address=0x%x\n", category, addr);
}
cursize = node->value;
node->value = newsize;
onode = node;
CHECKGUARDS(reallocC)
if(newsize == cursize)
return addr;
if(newsize > cursize)
{/* check if block can be extended */
void *taddr = ((char*)address) + cursize;
unsigned extendsize = newsize-cursize;
/* check freelist for an available block at the right address */
FINDKEY(FREEH, (unsigned)taddr)
if(node->key == (unsigned)taddr)
{
AddrP sp = (AddrP)node->value;
if(sp->size >= extendsize)
{/* BLOCK CAN BE EXTENDED INTERNALLY */
node->key += extendsize;
sp->size -= extendsize;
DETACH(sp)
if(sp->size == 0)
{/* the extension block is used up, delete this node */
free_addr(bp, sp);
DELETENODE(FREEH)
}
else
{/* shift the remainder in the sizelist */
addto_sizelist(bp, sp);
}
/* SUCCESS */
if(bp->guarded)
{
*((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
= BACKGUARD;
}
return addr;
}
}
/* HERE WE COULD CHECK OTHER SOURCES OF SPACE */
/* can't extend block, malloc some new space */
if((taddr = Cmalloc(category,newsize-bp->guarded)))
{
memmove(taddr,addr,cursize-bp->guarded);
onode->value = cursize;
Cfree(category, addr);
}
/* SUCCESS */
return taddr;
}
else
{/* shrink block */
if(bp->guarded)
{
*((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
= BACKGUARD;
}
addto_freelist(bp, ((char*)address)+newsize, cursize-newsize);
return addr;
}
}
}
LOCAL void
Cfreecat(int category)
{
struct _bins *bp;
if(category == 0)
return;
if((bp = getcat(category)))
{
struct _catlocs *cl = bp->catlocs;
struct _bins *hbp;
struct _bins *prev;
while(cl)
{/* Space allocated to the category is moved to category 0 */
void *ql = cl->fptr;
Cfree(0, cl->addr);
free_catloc(cl);
cl = ql;
}
/* space for the _bins struct is placed on a free list */
hbp = hmap[category % 1009];
prev = 0;
while(hbp)
{
if(hbp->bincat == category)
{
if(prev == 0)
hmap[category % 1009] = hbp->fptr;
else
prev->fptr = hbp->fptr;
free_bins(hbp);
return;
}
prev = hbp;
hbp = hbp->fptr;
}
}
}
LOCAL int
Cmemrange(int category, unsigned *min, unsigned *max)
{
struct _bins *bp;
if((bp = getcat(category)))
{
*min = bp->minloc;
*max = bp->maxloc;
return 1;
}
return 0;
}
LOCAL int
Cusedrange(int category, unsigned *min, unsigned *max)
{
struct _bins *bp;
NodePM node;
int level;
if((bp = getcat(category)))
{
node = bp->USEDHheader;
*min = node->fptr[0]->key;
for(level = bp->USEDHlevel; level >= 0; level--)
while(node->fptr[level]->key < 0xffffffff)
node = node->fptr[level];
*max = node->key;
return 1;
}
return 0;
}
LOCAL void
Ctotrange(unsigned *min, unsigned *max)
{
*min = minloc;
*max = maxloc;
}
LOCAL void
Cguard(int category)
{
struct _bins *bp;
if(!(bp = getcat(category)))
if(!(bp = initcat(category)))
return;
if(!bp->guarded)
{
bp->guarded = 2*ALIGNMENTM;
bp->addrbump = 1;
}
}
LOCAL void*
Cheapcheck(int category, void *start)
{
struct _bins *bp;
NodePM node,prev;
unsigned *p1,*p2;
if((bp = getcat(category)))
{
if(bp->guarded)
{
prev = 0;
node = bp->USEDHheader;
while( (node = node->fptr[0]) != (NodePM)0xffffffff
&& node->key != 0xffffffffUL)
{
if((void*)node->key > start)
{
p1 = (unsigned*)node->key;
if(*p1 != FRNTGUARD)
{
if(prev)
return (char*)prev->key+ALIGNMENTM;
else
return (void*)1;
}
p2 = (unsigned*)(((char*)p1)+node->value-ALIGNMENTM);
if(*p2 != BACKGUARD)
return (char*)node->key+ALIGNMENTM;
}
prev = node;
}
}
}
return 0;
}
LOCAL void*
Cmalloc(int category, unsigned size)
{
return Cmemalign(category, 0, size);
}
LOCAL void*
Cvalloc(int category, unsigned bytes)
{
return Cmemalign (category, PAGESIZE, bytes);
}
LOCAL unsigned
Cmallocsize(int category, void* addr)
{
struct _bins *bp;
SKIPVARS;
if(addr && (bp = getcat(category)))
{
unsigned address = (unsigned)((unsigned*)addr - bp->addrbump);
FINDKEY(USEDH, address)
if(node->key == address)
return node->value - bp->guarded;
}
return 0;
}
LOCAL int
Cnewcat()
{
static unsigned int cat = BASE_CATEGORY;
return ++cat;
}
/* ====================== END MULTI-HEAP MALLOC ============================ */
/* ====================== SYMBOL TABLE HANDLERS ============================ */
typedef struct _key
{
unsigned long k[2];
unsigned long hv;
} KEY, *KEYP;
typedef struct _nodeS
{/* 40 bytes -- adjust size to suit application */
unsigned long value[4]; /* 16 bytes */
unsigned long key[2]; /* 8 bytes */
struct _nodeS *fptr[4]; /* 16 bytes */
} NodeS, *NodePS;
typedef struct _pbuf
{/* symbol table object */
int nbins; /* number of bins in dictionary */
int lastbin; /* for seq access */
NodePS lastptr; /* ditto */
int category; /* heap number */
char *chunkbase; /* node allocation base */
int chunksize; /* number of bytes available in current chunk */
NodePS freelist; /* list of freed nodes for allocation */
int level; /* sorted level */
int bits; /* sorted bits */
int bitcnt; /* sorted bitcnt */
NodePS header; /* sorted header */
NodePS bins[0]; /* bins if hashed dictionary */
} *PbufP;
#define SYM_MAXLEVEL 12
#define TBL ((PbufP)tbl)
static struct _nodeS _nnil = {{0,0,0,0},{0xffffffff,0xffffffff},{0,0,0,0}};
static struct _nodeS *_NNIL = &_nnil;
static int
getSlevel (PbufP tbl)
{
int level = -1;
int bits = 0;
while (bits == 0)
{
if (tbl->bitcnt == 0)
{
tbl->bits = lrandom();
tbl->bitcnt = 15;
}
bits = tbl->bits & 3;
tbl->bits >>= 2;
tbl->bitcnt--;
if(++level > tbl->level)
break;
}
return (level > SYM_MAXLEVEL) ? SYM_MAXLEVEL : level;
}
static void
hash(void *key, KEY *cat)
{
cat->k[0] = ((unsigned long*)key)[0];
cat->k[1] = ((unsigned long*)key)[1];
cat->hv = ((cat->k[0] ^ cat->k[1]) * 1103515245UL) + 12345;
}
static void
sym_hash(unsigned long *key, char *symb)
{
int len = strlen(symb);
int i;
for(i = 0; i < len; ++i)
((unsigned char *)key)[i & 7] ^= symb[i];
key[0] = ((key[0] ^ key[1]) * 1103515245UL) + 12345;
key[1] = len;
}
static void *
new_Snode(PbufP tbl, int levels)
{
NodePS p;
int size;
if(levels <= 3)
{
if(tbl->freelist)
{
p = tbl->freelist;
tbl->freelist = p->fptr[0];
p->fptr[0] = 0;
return p;
}
}
size = sizeof(struct _nodeS) + ((levels-3) * sizeof(void*));
if(tbl->chunksize < size)
{
tbl->chunkbase = Ccalloc(tbl->category, 1, 4080);
tbl->chunksize = 4080;
}
tbl->chunksize -= size;
p = (NodePS)tbl->chunkbase;
tbl->chunkbase += size;
return p;
}
static void
free_Snode(PbufP tbl, NodePS node)
{
bzero(node, sizeof(struct _nodeS));
node->fptr[0] = tbl->freelist;
tbl->freelist = node;
}
static void*
NewSymTable(int category, int nbins)
{
PbufP tbl;
tbl = Ccalloc(category, 1, nbins*sizeof(NodePS) + sizeof(struct _pbuf));
if(nbins == 0)
{/* sorted dictionary */
int i;
tbl->header = new_Snode(tbl, SYM_MAXLEVEL+1);
for(i = 0; i <= SYM_MAXLEVEL; ++i)
tbl->header->fptr[i] = _NNIL;
}
tbl->nbins = nbins;
tbl->category = category;
return tbl;
}
static int
SymFind(void *tbl, void *key, void *result)
{
NodePS node;
if(tbl && key)
{
if(TBL->nbins)
{/* hashed dictionary */
KEY cat;
hash(key, &cat);
if((node = TBL->bins[cat.hv % TBL->nbins]))
{
do {
if( node->key[0] == cat.k[0]
&& node->key[1] == cat.k[1])
{
if(result)
*((NodePS *)result) = node;
TBL->lastbin = cat.hv % TBL->nbins;
TBL->lastptr = node;
return 1;
}
} while((node = node->fptr[0]));
}
return 0;
}
else
{/* sorted dictionary */
int level;
node = TBL->header;
for(level = TBL->level; level >= 0; level--)
{
while( KEYLT(node->fptr[level]->key, ((unsigned long*)key)) )
node = node->fptr[level];
}
node = node->fptr[0];
TBL->lastptr = node;
if(result)
*((NodePS *)result) = node;
return (KEYEQ(node->key, ((unsigned long*)key))) ? 1 : 0;
}
}
return 0;
}
static int
SymFindRange(void *tbl, void *key, void *result)
{/* assumes 4 byte key and value (the value can be bigger) */
NodePS node;
if(tbl && key)
{
if(TBL->nbins)
{/* hashed dictionary */
return 0;
}
else
{/* sorted dictionary */
NodePS prev;
int level;
node = TBL->header;
for(level = TBL->level; level >= 0; level--)
{
while ( node->fptr[level]->key[0] < ((unsigned long*)key)[0] )
node = node->fptr[level];
}
prev = node;
node = node->fptr[0];
if( node->key[0] == ((unsigned long*)key)[0] )
{
TBL->lastptr = node;
if(result)
*((NodePS *)result) = node;
return 1;
}
if( ((unsigned long*)key)[0] < prev->key[0]+prev->value[0] )
{
TBL->lastptr = prev;
if(result)
*((NodePS *)result) = prev;
return 1;
}
return 0;
}
}
return 0;
}
static void *
SymInsert(void *tbl, void *key, void *value, int datsiz)
{
NodePS node;
if(tbl && key)
{
if(TBL->nbins)
{/* hashed dictionary */
KEY cat;
NodePS *binp;
hash(key, &cat);
node = new_Snode(tbl, 0);
TBL->lastbin = cat.hv % TBL->nbins;
TBL->lastptr = node;
binp = &TBL->bins[TBL->lastbin];
if(value && datsiz)
memcpy(node, value, MIN(datsiz,16));
node->key[0] = cat.k[0];
node->key[1] = cat.k[1];
node->fptr[0] = *binp;
*binp = node;
return node;
}
else
{/* sorted dictionary */
int level;
NodePS update[SYM_MAXLEVEL+1];
node = TBL->header;
for (level = TBL->level; level >= 0; level--)
{
while ( KEYLT(node->fptr[level]->key,((unsigned long*)key)) )
node = node->fptr[level];
update[level] = node;
}
level = getSlevel(tbl);
while(TBL->level < level)
update[++TBL->level] = TBL->header;
node = new_Snode(tbl, level);
if(value && datsiz)
memcpy(node, value, MIN(datsiz,16));
node->key[0] = ((unsigned long*)key)[0];
node->key[1] = ((unsigned long*)key)[1];
while(level >= 0)
{
node->fptr[level] = update[level]->fptr[level];
update[level]->fptr[level] = node;
level--;
}
TBL->lastptr = node;
return node;
}
}
return 0;
}
static int
StringFind(void *tbl, char *string, void *result)
{
unsigned long key[2];
struct {
char *symname;
} *valp;
key[0] = 0;
key[1] = 0;
sym_hash(key, string);
if(SymFind(tbl, key, &valp))
{
unsigned long *key1;
do {
if(!strcmp(string, valp->symname))
{
if(result)
*((void**)result) = valp;
return 1;
}
/* Check duplicates */
if(!SymNext(tbl))
break;
SymKey(tbl, &key1);
SymValue(tbl, &valp);
} while(KEYEQ(key, key1));
}
return 0;
}
static int
StringInsert(void *tbl, char *string, void *result)
{
unsigned long key[2];
struct {
char *symname;
} *valp;
key[0] = 0;
key[1] = 0;
sym_hash(key, string);
if(SymFind(tbl, key, &valp))
{/* hash keys match */
unsigned long *key1;
do {
if(!strcmp(string, valp->symname))
{
if(result)
*((void**)result) = valp;
return 1;
}
/* Check duplicates */
if(!SymNext(tbl))
break;
SymKey(tbl, &key1);
SymValue(tbl, &valp);
} while(KEYEQ(key, key1));
}
/* NOMATCH */
valp = SymInsert(tbl, key, &string, 4);
if(result)
*((void**)result) = valp;
return 0;
}
static void
SymDelete(void *tbl, void *key)
{
NodePS node;
if(tbl && key)
{
if(TBL->nbins)
{/* hashed dictionary */
KEY cat;
NodePS *binp;
NodePS prev = 0;
hash(key, &cat);
binp = &TBL->bins[cat.hv % TBL->nbins];
if((node = *binp))
{
do {
if( node->key[0] == cat.k[0]
&& node->key[0] == cat.k[1])
{
if(prev)
prev->fptr[0] = node->fptr[0];
else
*binp = node->fptr[0];
free_Snode(tbl, node);
if(TBL->lastptr == node)
{
TBL->lastptr = 0;
TBL->lastbin = TBL->nbins;
}
return;
}
prev = node;
} while((node = node->fptr[0]));
}
}
else
{/* sorted dictionary */
int level;
NodePS update[SYM_MAXLEVEL+1];
node = TBL->header;
for(level = TBL->level; level >= 0; level--)
{
while ( KEYLT(node->fptr[level]->key, ((unsigned long*)key)) )
node = node->fptr[level];
update[level] = node;
}
node = node->fptr[0];
if( KEYEQ(node->key, ((unsigned long*)key)) )
{
for(level = 0; level <= TBL->level; level++)
{
if (update[level]->fptr[level] == node)
update[level]->fptr[level] = node->fptr[level];
else break;
}
while((TBL->level > 0) && (TBL->header->fptr[TBL->level] == _NNIL))
TBL->level--;
if(TBL->lastptr == node)
TBL->lastptr = 0;
free_Snode(tbl, node);
}
}
}
}
static int
SymHead(void *tbl)
{/* Set up for sequential access */
int nbins;
if(tbl)
{
if((nbins = TBL->nbins))
{/* hashed dictionary */
NodePS node;
int i;
TBL->lastptr = 0;
for(i = 0; i < nbins; ++i)
{
if( (node = TBL->bins[i]) != 0)
{
TBL->lastbin = i;
return 1;
}
}
TBL->lastbin = nbins;
return 0; /* empty */
}
else
{/* sorted dictionary */
TBL->lastptr = TBL->header;
return (TBL->lastptr->fptr[0] == _NNIL) ? 0 : 1;
}
}
return 0;
}
static int
SymNext(void *tbl)
{/* Move to next sequential entry */
int nbins;
if(tbl)
{
if((nbins = TBL->nbins))
{/* hashed dictionary */
if(TBL->lastptr && ((TBL->lastptr = TBL->lastptr->fptr[0])))
return 1;
else
{
int i;
for(i = TBL->lastbin; i < nbins; ++i)
{
if((TBL->lastptr = TBL->bins[i]) != 0)
{
TBL->lastbin = i+1;
return 1;
}
}
return 0;
}
}
else
{/* sorted dictionary */
if(TBL->lastptr)
{
if(TBL->lastptr != _NNIL)
TBL->lastptr = TBL->lastptr->fptr[0];
return (TBL->lastptr == _NNIL) ? 0 : 1;
}
}
}
return 0;
}
static void
SymGetMark(void *tbl, void *markptr)
{
if(tbl && markptr)
{
((long*)markptr)[0] = TBL->lastbin;
((long*)markptr)[1] = (long)TBL->lastptr;
}
}
static int
SymMarkNext(void *tbl, void *mark)
{/* Mark current position, and move to next sequential entry */
SymGetMark(tbl, mark);
return SymNext(tbl);
}
static void
SymSetMark(void *tbl, void *markptr)
{
if(tbl && markptr)
{
TBL->lastbin = ((long*)markptr)[0];
TBL->lastptr = (NodePS)((long*)markptr)[1];
}
}
static void
SymKey(void *tbl, void *keyptr)
{/* Retrieve key info pointer for current spot */
if(tbl && keyptr && TBL->lastptr)
*((unsigned long**)keyptr) = &TBL->lastptr->key[0];
}
static void
SymValue(void *tbl, void *datptr)
{/* Retrieve value pointer for current spot */
if(tbl && datptr && TBL->lastptr)
*((unsigned long**)datptr) = &TBL->lastptr->value[0];
}
/* ==================== END SYMBOL TABLE HANDLERS ========================== */
/* ========================== OPTIMIZATION ================================= */
static int
forward(unsigned char *p)
{
unsigned char *next;
do {
next = (void*)((Pop)p)->next;
while( *next == 0
|| *next == lineop
|| *next == labelop)
next = (void*)((Pop)next)->next;
if(*next == endop)
{
if(*p == *(next+8))
{
*p = 0;
*next = 0;
return 1;
}
return 0;
}
} while(forward(next));
return 0;
}
static void
eliminate_extraneous_infops(Piv iv, int level)
{
Pafile pf;
unsigned char *p;
int i;
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
if(!(p = pf->prog_p))
continue;
if(pf->header_p->hdr.opt_level >= level)
continue;
pf->header_p->hdr.opt_level = level;
while(*p != endfileop)
{
switch(*p)
{
case unopop:
case arrayelemop:
case ptrelemop:
case strelemop:
case ptrdimsop:
case arraydimsop:
forward(p);
break;
}
p = POP->next;
}
}
}
static void
clean_temps(Piv iv)
{
long *key;
long *val;
long hitemp = iv->first_temp & 0xffff0000;
if(iv->temps_written == 0)
return;
if(SymHead(iv->tmptbl))
{
while(SymNext(iv->tmptbl))
{
SymKey(iv->tmptbl, &key);
if((key[0] & 0xffff0000) == hitemp)
{
char *ptr;
long saveit;
SymValue(iv->tmptbl, &val);
saveit = val[1];
ptr = (void*)val[0];
val[0] = 0; /* allow reuse of this slot */
val[1] = 0;
while(ptr)
{
void *nptr = (void*)((PopT)ptr)->tmpnum;
((PopT)ptr)->tmpnum = key[0];
if(!saveit)
{
unsigned char *p = ptr-8;
unsigned char op = *p;
*p = 0;
++iv->killop;
if(op == duptmpop)
{/* special test for post increment */
p = POP->next;
p = POP->next;
if(*p == grabop)
*p = 0;
}
}
ptr = nptr;
}
}
}
if(!hitemp)
iv->temps_written = 0;
}
}
static void
read_temp(Piv iv, PopT ptr, unsigned long last)
{
unsigned long key[2];
long *result;
if(last == ptr->tmpnum)
return;
key[0] = ptr->tmpnum;
key[1] = 0;
if(SymFind(iv->tmptbl, key, &result))
{
result[1] = 1;
}
else PERROR(pName ":Syserr: read temp %d not found\n", key[0]);
}
static int
reading_self(unsigned char *p, long tmpnum)
{
if((p[2]&0xe0) == OPTEMP || (p[2]&0xe0) == OPRET)
{
return 1;
}
if((p[3]&0xe0) == OPTEMP || (p[3]&0xe0) == OPRET)
{
return 1;
}
return 0;
}
static long
write_temp(Piv iv, PopT ptr, unsigned char opcode)
{
long key[2];
long val[2];
long *result;
long hitemp = ptr->tmpnum & 0xffff0000;
if(ptr->atype & A_MEMADDR && opcode < duptmpop)
{/* actually reading from this destination slot */
read_temp(iv, ptr, 0);
return 0;
}
if(hitemp > (iv->first_temp & 0xffff0000))
{/* Inner block, CompoundExp or NestedFunc */
iv->first_temp = hitemp + 1;
}
else if(hitemp < (iv->first_temp & 0xffff0000))
{/* Exit inner block */
if(!reading_self(((char*)ptr)-8, ptr->tmpnum))
{
while(hitemp < (iv->first_temp & 0xffff0000))
{
clean_temps(iv);
iv->first_temp -= 0x00010000;
}
}
}
if(ptr->tmpnum == iv->first_temp)
{
if(!reading_self(((char*)ptr)-8, ptr->tmpnum))
clean_temps(iv);
}
++iv->temps_written;
key[0] = ptr->tmpnum;
key[1] = 0;
if(SymFind(iv->tmptbl, key, &result))
{
PopT optr = (PopT)result[0];
result[0] = (long)ptr;
ptr->tmpnum = (long)optr;
}
else
{
val[0] = (long)ptr;
val[1] = 0;
SymInsert(iv->tmptbl, key, val, 8);
ptr->tmpnum = 0;
}
return key[0];
}
static void
eliminate_unused_temps(Piv iv, int level)
{
Pafile pf;
unsigned char *p;
int i;
long last_write;
iv->tmptbl = NewSymTable(iv->category, 111);
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
if(pf->header_p->hdr.opt_level >= level)
continue;
pf->header_p->hdr.opt_level = level;
rekill:
if(!(p = pf->prog_p))
continue;
iv->first_temp = 1;
iv->temps_written = 0;
iv->killop = 0;
while(*p != endfileop)
{
while(*p < labelop)
{
if(*p == truthop)
{/* truthops of single chars are unnecessary */
if((p[2]&0xe0) == OPTEMP)
{
if(((PopT)(p+20))->dsize == 1)
{
if(((PopT)(p+8))->tmpnum == ((PopT)(p+20))->tmpnum)
{
if(!(((PopT)(p+20))->atype & A_MEMADDR))
*p = 0;
break;
}
else
{/* may be needed for code generation */
*p = aliastmpop;
}
}
}
}
if(*p)
{
if( *p == jmptrueop
|| *p == jmpfalseop
|| *p == ljmptrueop
|| *p == ljmpfalseop)
read_temp(iv,(PopT)(p+4), 0);
if(*p == retdataop)
{
read_temp(iv, (PopT)p, 0);
}
else
{
last_write = 0;
if((p[1]&0xe0) == OPTEMP)
last_write = write_temp(iv, (PopT)(p+8), *p);
if((p[2]&0xe0) == OPTEMP || (p[2]&0xe0) == OPRET)
read_temp(iv, (PopT)((p+8+(p[1]&0x1f))), last_write);
if((p[3]&0xe0) == OPTEMP || (p[3]&0xe0) == OPRET)
read_temp(iv, (PopT)((p+8+(p[1]&0x1f))+(p[2]&0x1f)), last_write);
}
}
break;
}
p = POP->next;
}
do {
clean_temps(iv);
iv->first_temp -= 0x00010000;
} while(iv->first_temp > 0);
if(iv->killop)
{
goto rekill;
}
}
}
static void
retarget_jmps(Piv iv, int level)
{
Pafile pf;
unsigned char *p;
int i;
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
if(!(p = pf->prog_p))
continue;
if(pf->header_p->hdr.opt_level >= level)
continue;
}
}
static void
optimize(Piv iv)
{
eliminate_extraneous_infops(iv, 50);
eliminate_unused_temps(iv, 51);
retarget_jmps(iv, 52);
}
/* ========================== END OPTIMIZATION ============================= */
/* ====================== BASIC INPUT FILE PROCESSING ====================== */
static long
label_insert(Piv iv, long label, int filenum, unsigned char *p)
{
long *result;
struct {
long k1;
long k2;
} key;
struct {
long newlabel;
} val;
key.k1 = label;
key.k2 = filenum;
/* check for duplicate label -- they happen */
if(SymFind(iv->labeltbl, &key, &result))
{
if(*p == labelop)
*p = 0; /* kill the instruction */
return 0;
}
val.newlabel = ++iv->lastlabel;
SymInsert(iv->labeltbl, &key, &val, 4);
#if REALLY_NEED_OFFSETS
key.k1 = val.newlabel;
val.newlabel = -1;
SymInsert(iv->newlabeltbl, &key, &val, 4);
#endif
return iv->lastlabel;
}
static long
label_find(Piv iv, long label, int filenum)
{
struct {
long k1;
long k2;
} key;
long *result;
key.k1 = label;
key.k2 = filenum;
if(SymFind(iv->labeltbl, &key, &result))
return *result;
else
return 0;
}
#if REALLY_NEED_OFFSETS
static void
newlabel_insert(Piv iv, long label)
{
struct {
long k1;
long k2;
} key;
long *result;
key.k1 = label;
key.k2 = iv->filenum;
if(SymFind(iv->newlabeltbl, &key, &result))
{
*result = iv->out_offset + iv->func_offset;
}
else PERROR(pName ":Syserr: Label %d not found\n", label);
}
static long
newlabel_fix(Piv iv, long label)
{
if(label)
{
struct {
long k1;
long k2;
} key ;
long *val;
key.k1 = label;
key.k2 = iv->filenum;
if(SymFind(iv->newlabeltbl, &key, &val))
{
return val[0];
}
}
return label;
}
#endif /* REALLY_NEED_OFFSETS */
static void
extern_insert(Piv iv, unsigned char *p, int filenum)
{
struct {
short k1;
short k2;
long k3;
} key;
struct {
unsigned char *p;
} val;
key.k1 = GS(POPI->s.symnum);
key.k2 = filenum;
key.k3 = 0;
val.p = p;
SymInsert(iv->extrntbl, &key, &val, 4);
}
static void
reloc_insert(Piv iv, int fileno, unsigned char *p)
{
struct _rkey key;
struct _rval val;
key.spot = GL(POPI->reloc.spot); /* reloc target offset */
key.fileno = (short)fileno; /* fileno */
key.opcode = *p; /* opcode */
key.rsize = GL(POPI->reloc.rsize); /* reloc size */
val.p = p; /* pointer to input buffer */
val.base = (void*)GL(POPI->reloc.base); /* base of data object pointed to */
val.offset = GL(POPI->reloc.offset); /* offset to be added to base */
val.rsym = GS(POPI->reloc.rsym); /* symbol number if external */
SymInsert(iv->reloctbl, &key, &val, 14);
}
static void
data_insert(void *tbl, unsigned long offset,
unsigned long size, void *p, void *prevp)
{
static long locid = 1;
struct {
unsigned long k1;
long k2;
} key;
struct {
unsigned long size;
void *p;
void *prevp;
long locid;
} val;
unsigned char opcode, prevopcode = 0;
key.k1 = offset;
key.k2 = 0;
val.size = size;
val.p = p;
val.prevp = prevp;
val.locid = 0;
opcode = *((unsigned char *)p);
if(prevp)
{
prevopcode = *((unsigned char*)prevp);
if( prevopcode != glodatop
&& prevopcode != glofuncop
&& prevopcode != extfuncop
&& prevopcode != globssop)
{
val.locid = locid++;
}
}
SymInsert(tbl, &key, &val, sizeof(val));
}
static void
global_insert(Piv iv, Pafile pf, unsigned char *p)
{
unsigned long key[2];
struct _gloval val;
PopI pp;
unsigned char opcode = *p;
if(opcode == extvarop)
pp = POPI;
else
pp = (PopI)(POP->next+8);
key[0] = 0;
key[1] = 0;
val.symnum = GS(pp->s.symnum);
val.symname = pf->symaddr[val.symnum];
val.p = p;
val.pf = pf;
if(val.symnum < 0 || val.symnum >= pf->numsyms)
{
PERROR(pName ":Syserr: BAD SYMNUM=%d opcode=%d\n", val.symnum, opcode);
}
sym_hash(key, val.symname);
/* Duplicate entries are allowed */
SymInsert(iv->gbltbl, key, &val, sizeof(val));
}
static int
setup_nodelinks(Piv iv, char *infile_name, void *inbuf, int insize)
{
unsigned char *p = inbuf;
unsigned char *endbuf = inbuf+insize;
Pafile pf=0;
int lastline = 0;
unsigned char *funcp;
unsigned char *nfuncp;
while(p < endbuf && *p != endallop)
{
unsigned char *q = p;
if(iv->debug >= '5')
{
cfeprintf("OP(%u '%s' p=%p line=%d)\n", *p, oxgenops[*p], p, lastline);
}
switch(*p)
{
case headerop:
if(iv->numfiles >= 1024) {
PERROR(pName ": Sorry, too many files\n");
}
pf = iv->files[iv->numfiles] =
Ccalloc(iv->category, 1, sizeof(struct _afile));
pf->filenum = iv->numfiles++;
pf->file_p = p;
pf->header_p = POPI;
if(iv->strip)
{/* Gonna strip declarations and line numbers */
pf->header_p->hdr.target_debugger = 0;
}
break;
case dataop:
pf->size_p = POPI;
pf->thunk_offset = GL(POPI->dat.thunk_offset);
pf->bss_offset = GL(POPI->dat.bss_offset);
break;
case gfuncdefop:
case sfuncdefop:
if(pf->prog_p == 0)
pf->prog_p = p;
funcp = p;
break;
case funcexitop:
PS(((PopI)(funcp+8))->funcdef.tempmax) = GL(POPI->funcexit.tempmax);
break;
case nestedfuncdefop:
nfuncp = p;
break;
case nestedfuncexitop:
PS(((PopI)(nfuncp+8))->funcdef.tempmax) = GL(POPI->funcexit.tempmax);
break;
case segdefop:
if(pf->seg_p == 0)
pf->seg_p = p;
pf->numsegs += 1;
iv->numsegs += 1;
break;
case lineop:
lastline = GL( POPI->line.line );
if(iv->strip)
*p = 0; /* strip line numbers */
break;
case declop:
if(iv->strip)
{/* strip declarations */
do {
*p = 0;
q += (long)GL(POP->next);
POP->next = q;
p = q;
} while(*p != endop);
*p = 0;
}
else
{
if(pf->decl_p == 0)
pf->decl_p = p;
pf->numdecls += 1;
iv->numdecls += 1;
}
break;
case switchidop:
if(pf->switch_p == 0)
pf->switch_p = p;
break;
case labelop:
PL( POP->data ) =
label_insert(iv, GL( POP->data ), pf->filenum, p);
break;
case symbop:
pf->numsyms = GL(POP->data);
iv->numsyms += pf->numsyms;
break;
case symblockop:
pf->symtext_p = p + 12;
goto blka;
case stringblockop:
case datablockop:
case mallocblockop:
case thunkblockop:
{
long size;
if(pf->data_p == 0)
pf->data_p = p;
blka:
size = GL(POP->data);
q += size+((4-(size&3))&3);
break;
}
case glofuncop:
case extfuncop:
case glodatop:
case globssop:
case extvarop:
case bssblockop:
if(pf->data_p == 0)
pf->data_p = p;
break;
case maxtempop:
pf->maxtemp = GL(POP->data);
pf->maxtempclass = GL(POP->data1);
pf->maxtemp_p = p;
break;
}
q += (long)GL(POP->next);
POP->next = q;
p = q;
}
if(*p != endallop)
{
PERROR(pName ": Malformed input file: %s\n", infile_name);
}
return 0;
}
static void
setup_syms_decls(Piv iv)
{
int i;
for(i = 0; i < iv->numfiles; ++i)
{
int symnum = 0;
Pafile pf = iv->files[i];
unsigned char *p = pf->file_p;
unsigned char *prevp = 0;
pf->symaddr = Ccalloc(iv->category, sizeof(void*), pf->numsyms+1);
pf->decladdr = Ccalloc(iv->category, sizeof(void*), pf->numdecls+1);
while(*p != endfileop)
{
switch(*p)
{
case symoffsetop:
pf->symaddr[symnum] = pf->symtext_p + GL(POP->data);
++symnum;
break;
case declop:
pf->decladdr[GS(POPI->dcl.declnum)] = p;
break;
case relocop:
case extlocop:
++pf->numrelocs;
reloc_insert(iv, i, p);
break;
case glodatop:
case globssop:
case glofuncop:
case extfuncop:
global_insert(iv, pf, p);
break;
case extvarop:
extern_insert(iv, p, i);
global_insert(iv, pf, p);
break;
case stringblockop:
case datablockop:
case mallocblockop:
case thunkblockop:
case bssblockop:
if(!pf->datatbl)
pf->datatbl = NewSymTable(iv->category, 0); /* sorted */
data_insert(pf->datatbl,GL(DATI.offset),GL(DATI.size),
p, prevp);
if(*p == thunkblockop) {
PL(POP->data5) = label_find(iv, GL(POP->data5), i);
}
break;
case jmploopop:
case jmpcontinueop:
case jmpbreakop:
case jmpgotoop:
case jmptrueop:
case jmpfalseop:
case ljmptrueop:
case ljmpfalseop:
case funcstartop:
case funcstopop:
case casevalop:
case switchop:
PL(POP->data) = label_find(iv, GL(POP->data), i);
break;
}
prevp = p;
p = POP->next;
}
}
}
static int
sym_insert(Piv iv, char *symname, int symnum)
{/* Used only for combining symbols in link phase */
struct {
char *symname;
int symnum;
} *valp;
if(StringInsert(iv->symtbl, symname, &valp))
return -valp->symnum; /* MATCH */
valp->symnum = symnum;
return symnum;
}
static void
combine_syms_decls(Piv iv)
{
int i,j;
Pafile pf;
int numsyms;
int numdecls;
/* COMBINE SYMBOLS */
pf = iv->files[0];
numsyms = pf->numsyms;
pf->symtran = Ccalloc(iv->category, sizeof(short), pf->numsyms+1);
memcpy(iv->symaddr, pf->symaddr, sizeof(void*) * numsyms);
for(i = 0; i < numsyms; ++i)
{/* file 0 */
sym_insert(iv, pf->symaddr[i], i);
pf->symtran[i] = i;
}
for(i = 1; i < iv->numfiles; ++i)
{
int start;
pf = iv->files[i];
pf->symtran = Ccalloc(iv->category, sizeof(short), pf->numsyms+1);
if(pf->header_p->hdr.target_debugger)
start = 1;
else
start = 3;
for(j = start; j < pf->numsyms; ++j)
{
int k;
if((k = sym_insert(iv, pf->symaddr[j], numsyms)) > 0)
{ /* new entry */
iv->symaddr[numsyms++] = pf->symaddr[j];
pf->symtran[j] = k;
}
else pf->symtran[j] = -k;
}
}
iv->numsyms = numsyms;
/* COMBINE DECLARATIONS */
pf = iv->files[0];
numdecls = pf->numdecls;
pf->decltran = Ccalloc(iv->category, sizeof(short), numdecls+1);
memcpy(iv->decladdr, pf->decladdr, sizeof(void*) * numdecls);
for(i = 0; i < numdecls; ++i)
{/* file 0 */
pf->decltran[i] = i;
}
for(i = 1; i < iv->numfiles; ++i)
{
pf = iv->files[i];
pf->decltran = Ccalloc(iv->category, sizeof(short), pf->numdecls+1);
if(pf->numdecls < 21)
continue;
for(j = 1; j <= 21; ++j)
pf->decltran[j] = j;
for(j = 22; j < pf->numdecls; ++j) {
iv->decladdr[numdecls] = pf->decladdr[j];
pf->decltran[j] = numdecls++;
}
}
iv->numdecls = numdecls;
}
static void
link_dups(Piv iv, int dupcnt, struct _gloval *valp[])
{
int i;
int vars[5] = {0,0,0,0,0};
unsigned long cdsize = 0;
unsigned long cdoffset = 0;
short cdfile = 0;
int cdnum = 0;
short segid = 0;
#define GDAT vars[0]
#define GBSS vars[1]
#define GFUNC vars[2]
#define EVAR vars[3]
#define EFUNC vars[4]
/* Count the types of matches */
for(i = 0; i <= dupcnt; ++i)
vars[*(valp[i]->p) - glodatop] += 1;
/* Check for errors */
if( GDAT > 1
|| GFUNC > 1
|| (GFUNC && (GDAT || GBSS || EVAR))
|| (EFUNC && (GDAT || GBSS || EVAR)))
{
++iv->errors;
for(i = 0; i < dupcnt; ++i)
{
PWARN(pName ": Symbol `%s' multiply defined or mistyped.\n",
valp[i]->symname);
PWARN(pName": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
}
return;
}
if(EFUNC && GFUNC)
{/* match up functions */
Pop dp;
for(i = 0; i <= dupcnt; ++i)
if(*(valp[i]->p) == glofuncop)
break;
dp = (Pop)((Pop)valp[i]->p)->next; /* points to thunkblockop */
cdoffset = GL(dp->data1); /* save this offset */
cdfile = valp[i]->pf->filenum; /* save this file */
for(i = 0; i <= dupcnt; ++i)
{
if(*(valp[i]->p) == extfuncop)
{
*(valp[i]->p) = 0; /* convert to nilop */
dp = (Pop)((Pop)valp[i]->p)->next; /* points to thunkblockop */
/* Kill the thunkblock */
*((char*)dp) = 0;
PL(dp->data4) = cdoffset; /* use this offset for access */
PS(((short*)dp)[1]) = cdfile; /* fileno to unused slots */
}
}
}
else if(EFUNC)
{/* multiple references to external function */
Pop dp = (Pop)((Pop)valp[0]->p)->next; /* points to first thunkblockop */
cdoffset = GL(dp->data1); /* save first offset */
cdfile = valp[0]->pf->filenum; /* save first file */
for(i = 1; i <= dupcnt; ++i)
{/* Kill all thunkblocks except the first */
*(valp[i]->p) = 0; /* convert to nilop */
dp = (Pop)((Pop)valp[i]->p)->next; /* points to thunkblockop */
*((char*)dp) = 0;
PL(dp->data4) = cdoffset; /* use this offset for access */
PS(((short*)dp)[1]) = cdfile; /* fileno to unused slots */
}
}
else if(GBSS)
{/* comdefs */
int multsize = 0;
/* PICK THE BIGGEST GLOBAL BSS (comdef) */
for(i = 0; i <= dupcnt; ++i)
{
Pop dp = (Pop)((Pop)valp[i]->p)->next; /* points to bssblockop */
if((short)dp->data4 && segid == 0)
{
segid = (short)dp->data4;
}
else if((short)dp->data4 && (short)dp->data4 != segid)
{
++iv->errors;
PWARN(pName ": Variable `%s' defined in multiple segments.\n",
valp[i]->symname);
PWARN(pName ": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
}
if(*(valp[i]->p) == globssop)
{
long size = GL(dp->data);
if(cdsize && size != cdsize)
multsize = 1;
if(size > cdsize) {
cdsize = size;
cdoffset = GL(dp->data1);
cdfile = valp[i]->pf->filenum;
cdnum = i;
}
}
}
if(GDAT)
{
/* INITIALIZED DATA WILL ALWAYS OVERRIDE BSS */
for(i = 0; i <= dupcnt; ++i)
{
if(*(valp[i]->p) == glodatop)
{
Pop dp = (Pop)((Pop)valp[i]->p)->next; /* points to datablockop */
long size = GL(dp->data);
if(cdsize && size != cdsize)
multsize = 1;
if(size < cdsize)
{
++iv->errors;
PWARN(pName ": Initialized variable `%s' of size (%d)\n",
valp[i]->symname, size);
PWARN(pName ": In file: `%s'\n",
valp[i]->pf->symaddr[INFILE_SYMNUM]);
PWARN(pName ": Is incommensurate with common size (%d).\n",
cdsize);
}
else
{
cdsize = size;
cdoffset = GL(dp->data1);
cdfile = valp[i]->pf->filenum;
cdnum = i;
}
}
}
}
if(multsize)
{
PWARN(pName ":warning: Common Variable `%s' has multiple sizes.\n",
valp[0]->symname);
for(i = 0; i <= dupcnt; ++i)
{
unsigned char opcode = *(valp[i]->p);
if(opcode == globssop || opcode == glodatop)
{
PWARN(pName ":warning:Size=%d in file: `%s'\n",
GL(((Pop)((Pop)valp[i]->p)->next)->data),
valp[i]->pf->symaddr[INFILE_SYMNUM]);
}
}
}
/* FINALLY, LINK COMMONS TO THE CHOSEN ONE */
for(i = 0; i <= dupcnt; ++i)
{
if(i != cdnum && *(valp[i]->p) == globssop)
{
Pop dp = (Pop)((Pop)valp[i]->p)->next; /* points to bssblockop */
*(valp[i]->p) = 0; /* globssop becomes nilop */
*((char*)dp) = 0; /* bssblockop becomes nilop */
PL(dp->data4) = cdoffset; /* use this new offset for access */
PS(((short*)dp)[1]) = cdfile; /* put fileno in unused slots */
}
}
}
else if(GDAT)
{
for(i = 0; i <= dupcnt; ++i)
{
Pop dp = (Pop)((Pop)valp[i]->p)->next; /* points to datablockop */
if((short)dp->data4 && segid == 0)
{
segid = (short)dp->data4;
}
else if((short)dp->data4 && (short)dp->data4 != segid)
{
++iv->errors;
PWARN(pName ": Variable `%s' defined in multiple segments.\n",
valp[i]->symname);
PWARN(pName ": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
}
if(*(valp[i]->p) == glodatop)
{
cdsize = GL(dp->data);
cdoffset = GL(dp->data1);
cdfile = valp[i]->pf->filenum;
cdnum = i;
break;
}
}
}
if(EVAR && (GDAT || GBSS))
{/* match up variables */
/* LINK EXTERNS TO THE CHOSEN ONE */
for(i = 0; i <= dupcnt; ++i)
{
if(*(valp[i]->p) == extvarop)
{
Pop dp = (Pop)valp[i]->p;
*((char*)dp) = 0; /* extvarop becomes nilop */
PL(dp->data1) = cdoffset; /* use this new offset for access */
PS(((short*)dp)[1]) = cdfile; /* put fileno in unused slots */
PS(dp->data4) = segid;
break;
}
}
}
#undef GDAT
#undef GBSS
#undef GFUNC
#undef EVAR
#undef EFUNC
}
static void
link_globals(Piv iv)
{
if(SymHead(iv->gbltbl))
{
struct _gloval *valp[1024]; /* pointers to symtable value structs */
/* Pass over the sorted symbol table and process duplicate entries */
while(SymNext(iv->gbltbl))
{
unsigned long *key;
long mark[2]; /* Table position saver */
int dupcnt = 0;
SymKey(iv->gbltbl, &key); /* Pointer to first key */
SymValue(iv->gbltbl, &valp[0]); /* Pointer to first value */
while(SymMarkNext(iv->gbltbl, mark))
{/* Look forward for duplicates */
unsigned long *key1;
SymKey(iv->gbltbl, &key1); /* Pointer to next key */
if(KEYEQ(key, key1))
{/* Hashed keys match, check the strings */
SymValue(iv->gbltbl, &valp[dupcnt+1]); /* Pointer to next value */
if(!strcmp(valp[dupcnt]->symname, valp[dupcnt+1]->symname))
{/* Duplicate entry found */
++dupcnt;
continue;
}
}
break;
}
if(dupcnt > 0)
{/* Process a collection of duplicate symbol names */
link_dups(iv, dupcnt, valp);
}
SymSetMark(iv->gbltbl, mark);
}/* END: while(SymNext) */
}/* END: if(SymHead) */
}
static void
realloc_data(Piv iv)
{
int i;
Pafile pf;
unsigned char *p, *prevp;
unsigned long offset = 0;
iv->datatbl = NewSymTable(iv->category, 0); /* sorted table */
for(i = 0; i < iv->numfiles; ++i)
{
pf = iv->files[i];
p = pf->data_p;
prevp = 0;
while(*p != endfileop)
{
if( *p == datablockop
|| *p == mallocblockop
|| *p == stringblockop)
{
PL(POP->data1) = offset;
data_insert(iv->datatbl, offset, GL(POP->data), p, prevp);
offset += GL(POP->data);
ROUNDUP(offset, 4);
}
prevp = p;
p = POP->next;
}
}
iv->thunk_offset = offset;
for(i = 0; i < iv->numfiles; ++i)
{
pf = iv->files[i];
p = pf->data_p;
prevp = 0;
while(*p != endfileop)
{
if(*p == thunkblockop)
{
PL(POP->data1) = offset;
data_insert(iv->datatbl, offset, GL(POP->data), p, prevp);
offset += GL(POP->data);
ROUNDUP(offset, 4);
}
prevp = p;
p = POP->next;
}
}
iv->bss_offset = offset;
for(i = 0; i < iv->numfiles; ++i)
{
pf = iv->files[i];
p = pf->data_p;
prevp = 0;
while(*p != endfileop)
{
if(*p == bssblockop)
{
PL(POP->data1) = offset;
data_insert(iv->datatbl, offset, GL(POP->data), p, prevp);
offset += GL(POP->data);
ROUNDUP(offset, 4);
}
prevp = p;
p = POP->next;
}
}
iv->total_size = offset;
}
static void
reset_data_relocs(Piv iv)
{/* Pass over initialized data and set new offsets in each relocatable slot */
struct _data {/* datatbl node */
/* value area 16 bytes */
unsigned long size;
unsigned char *p;
unsigned char opcode;
unsigned char unused[7];
/* key area 8 bytes */
unsigned long offset;
long unused1;
};
/* PASS OVER ALL THE ENTRIES IN `reloctbl' */
if(SymHead(iv->reloctbl))
{
while(SymNext(iv->reloctbl))
{
struct _rkey *kp;
struct _rval *vp;
struct _data *dp, *ndp;
unsigned char *p;
Pafile pf, npf;
unsigned long object_base;
int noset = 0;
SymKey(iv->reloctbl, &kp);
SymValue(iv->reloctbl, &vp);
npf = pf = iv->files[kp->fileno]; /* pointer to file struct */
p = vp->p; /* pointer to relocop in input buffer */
if(kp->opcode == extlocop)
{/* External variable */
short key[4];
struct {
unsigned char *p; /* pointer to extvarop in input buffer */
} *ep;
key[0] = vp->rsym; /* external symbol number */
key[1] = pf->filenum;
key[2] = 0;
key[3] = 0;
/* LOOK UP THE EXTERNAL SYMBOL */
if(SymFind(iv->extrntbl, key, &ep) && *(ep->p) == 0)
{/* symbol exists and the extvarop was filled in */
npf = iv->files[GS( ((short*)(ep->p))[1] )];
PL( POPI->reloc.base ) = GL( ((Pop)(ep->p))->data1 );
*p = relocop; /* switch input file from `extlocop' */
}
else
{/* Not found or not filled in, leave it alone */
noset = 1;
}
}
/* RESET THE ENTRY IN THE INITIALIZED DATA SLOT */
if(SymFindRange(pf->datatbl, &kp->spot, &dp))
{/* This entry describes a block of data containg the reloc target */
unsigned char *ip = dp->p; /* points to input buffer */
unsigned long extra = kp->spot - dp->offset; /* offset into data */
/* Reset the relocop target in the input file */
PL( POPI->reloc.spot ) = GL( ((PopI)(ip+8))->s.offset ) + extra;
if(noset)
continue;
if(kp->rsize == 4)
{/* 32 bit relocation */
unsigned long *lp;
lp = (unsigned long*)(ip+24+extra); /* pointer to target */
object_base = GL( POPI->reloc.base );
/* Find the object that the target points to */
relink32:
if(SymFindRange(npf->datatbl, &object_base, &ndp))
{
if(*(ndp->p) == 0)
{/* The found object is a discarded thunkblock, relink */
npf = iv->files[GS( ((short*)(ndp->p))[1] )];
object_base = GL( ((Pop)(ndp->p))->data4 );
goto relink32;
}
else
{/* Use the new offset in the input file */
object_base = GL( ((Pop)(ndp->p))->data1 );
}
PL( POPI->reloc.base ) = object_base; /* the `relocop' */
PL(*lp) = object_base + GL( POPI->reloc.offset );/* data */
vp->base = lp;
}
else
{
++iv->errors;
PWARN(pName ":syserr: 32 bit object at offset %d not found\n",object_base);
}
}
else if(kp->rsize == 2)
{/* 16 bit relocation (MORE WORK NEEDED) */
unsigned short *sp;
sp = (unsigned short*)(ip+24+extra); /* pointer to target */
object_base = GL( POPI->reloc.base );
relink16:
if(SymFindRange(npf->datatbl, &object_base, &ndp))
{
if(*(ndp->p) == 0)
{/* The found object is a discarded thunkblock, relink */
npf = iv->files[GS( ((short*)(ndp->p))[1] )];
object_base = GL( ((Pop)(ndp->p))->data4 );
goto relink16;
}
else
{/* Use the new offset in the input file */
object_base = GL( ((Pop)(ndp->p))->data1 );
}
PL( POPI->reloc.base ) = object_base; /* the `relocop' */
PS(*sp) = object_base + GL( POPI->reloc.offset );/* data */
}
else
{
++iv->errors;
PWARN(pName ":syserr: 16 bit object at offset %d not found\n", object_base);
}
}
}
else /* !SymFindRange */
{
++iv->errors;
PWARN(pName ":syserr: reloc not found at %d in file %d\n",
kp->spot, kp->fileno);
}
}/* END: While(SymNext) */
}/* END: if(SymHead) */
}
static void
reset_offset(Piv iv, Pafile pf, PopA pa)
{/* All offsets are guaranteed to be inside objects */
struct _data {/* datatbl node */
/* value area 16 bytes */
unsigned long size;
unsigned char *p;
unsigned long unused[2];
/* key area 8 bytes */
unsigned long offset;
long unused1;
};
unsigned long offset;
struct _data *dp;
unsigned long object_base;
long extra;
unsigned short atype;
short symnum;
offset = GL( pa->offset );
atype = GS( pa->atype );
symnum = GS( pa->symnum );
PS( pa->symnum ) = pf->symtran[symnum];
PS( pa->declnum ) = pf->decltran[GS(pa->declnum)];
if(atype & A_EXTERN)
{
short key[4];
struct {
unsigned char *p; /* pointer to extvarop in input buffer */
} *ep;
key[0] = symnum; /* external symbol number */
key[1] = pf->filenum;
key[2] = 0;
key[3] = 0;
/* LOOK UP THE EXTERNAL SYMBOL */
if(!SymFind(iv->extrntbl, key, &ep) && *(ep->p))
{/* symbol exists and the extvarop was filled in */
pf = iv->files[GS( ((short*)(ep->p))[1] )];
offset += GL( ((Pop)(ep->p))->data1 );
}
else
{/* Not found or not filled in, leave it alone */
return;
}
}
extra = 0; /* first time through */
/* Find the object that the offset points to */
relink:
if(SymFindRange(pf->datatbl, &offset, &dp))
{
if(extra == 0)
extra = offset - dp->offset;
object_base = dp->offset;
if(*(dp->p) == 0)
{/* The found object is a discarded block, relink */
pf = iv->files[GS( ((short*)(dp->p))[1] )];
offset = GL( ((Pop)(dp->p))->data4 );
goto relink;
}
else
{/* Use the adjusted offset in the input buffer */
object_base = GL( ((Pop)(dp->p))->data1 );
}
PL( pa->offset ) = object_base + extra;
if(atype & A_EXTERN)
{
PS( pa->atype ) = atype & ~A_EXTERN;
}
}
else
{
++iv->errors;
PWARN(pName ":syserr: object `%s' at offset %d not found\n",
pf->symaddr[symnum], offset);
}
}
static void
reset_text_relocs(Piv iv)
{/* Pass over text and set new offsets in instructions that reference data */
int i;
for(i = 0; i < iv->numfiles; ++i)
{
Pafile pf;
unsigned char *p;
pf = iv->files[i];
if(!(p = pf->prog_p))
continue;
while(*p != endfileop)
{
if(*p && *p <= (unsigned char)100)
{/* instruction */
int inc = 8;
if((p[1]&0xe0) == OPDATA)
reset_offset(iv, pf, POPA);
inc += (p[1]&0x1f);
if((p[2]&0xe0) == OPDATA)
reset_offset(iv, pf, POPA);
inc += (p[2]&0x1f);
if((p[3]&0xe0) == OPDATA)
reset_offset(iv, pf, POPA);
}
p = POP->next;
}
}
}
static void *
seg_find(Piv iv, int id)
{
long key[2];
void **result;
if(iv->segtbl)
{
key[0] = id;
key[1] = 0;
if(SymFind(iv->segtbl, key, &result))
return *result;
}
return 0;
}
static void
check_seg(Piv iv, unsigned char *p, Pafile pf)
{
PopI np, op;
if(!(iv->segtbl))
{
iv->segtbl = NewSymTable(iv->category, 111);
}
if((op = seg_find(iv, GS(POPI->segdef.segid))))
{
np = POPI;
if( GL(np->segdef.v1) == GL(op->segdef.v1)
&& GL(np->segdef.v2) == GL(op->segdef.v2)
&& GL(np->segdef.v3) == GL(op->segdef.v3))
{/* segments of same name have the same values */
*p = 0; /* kill the new definition */
return;
}
else
{/* segments of same name have different values */
++iv->errors;
PWARN(pName ":Segment `%s' defined differently.\n",
iv->symaddr[GS(POPI->segdef.segid)]);
PWARN(pName ": In file: `%s'\n", pf->symaddr[INFILE_SYMNUM]);
return;
}
}
else
{
long key[2];
PopI pp = POPI;
key[0] = GS(POPI->segdef.segid);
key[1] = 0;
SymInsert(iv->segtbl, key, &pp, 4);
}
}
static void
reset_syms_decls(Piv iv)
{
int i;
for(i = 0; i < iv->numfiles; ++i)
{
Pafile pf;
unsigned char *p;
pf = iv->files[i];
p = pf->file_p;
while(*p != endfileop)
{
if(*p == segdefop)
{
PS(POPI->segdef.segid) = pf->symtran[GS(POPI->segdef.segid)];
check_seg(iv, p, pf);
}
else if(i > 0)
{
switch(*p)
{
case declop:
if(GS(POPI->dcl.declnum) < 22)
{/* kill the base declarations */
*p = 0;
p = POP->next;
*p = 0;
}
else
PS(POPI->dcl.declnum)=pf->decltran[GS(POPI->dcl.declnum)];
break;
case extlocop:
PS(POPI->reloc.rsym) = pf->symtran[GS(POPI->reloc.rsym)];
break;
case gfuncdefop:
case sfuncdefop:
if(pf->numsegs)
PS(POPI->funcdef.segid) = pf->symtran[GS(POPI->funcdef.segid)];
case nestedfuncdefop:
PL(POPI->funcdef.symnum) = pf->symtran[GL(POPI->funcdef.symnum)];
break;
case bssblockop:
case datablockop:
if(pf->numsegs)
PS( POPI->s.segid ) = pf->symtran[GS(POPI->s.segid)];
case stringblockop:
case mallocblockop:
case thunkblockop:
case extvarop:
PS( POPI->s.symnum ) = pf->symtran[GS(POPI->s.symnum)];
PS( POPI->s.declnum ) = pf->decltran[GS(POPI->s.declnum)];
break;
case memberinfop:
case bfieldinfop:
PS(POPI->memb.symnum) = pf->symtran[GS(POPI->memb.symnum)];
PS(POPI->memb.declnum) = pf->decltran[GS(POPI->memb.declnum)];
PS(POPI->memb.cdeclnum) = pf->decltran[GS(POPI->memb.cdeclnum)];
break;
case structinfop:
PS(POPI->suinf.symnum) = pf->symtran[GS(POPI->suinf.symnum)];
break;
case funcptrinfop:
case ptrinfop:
PS(POPI->ptrinf.declnum) = pf->decltran[GS(POPI->ptrinf.declnum)];
break;
case funcinfop:
PS(POPI->funcd.declnum) = pf->decltran[GS(POPI->funcd.declnum)];
PS(POPI->funcd.symnum) = pf->symtran[GS(POPI->funcd.symnum)];
break;
case arrayinfop:
PS(POPI->ary.declnum) = pf->decltran[GS(POPI->ary.declnum)];
break;
case lineop:
PL(POPI->line.filenamenum) = pf->symtran[GL(POPI->line.filenamenum)];
break;
}/* END: switch(*p) */
}/* END: i > 0 */
p = POP->next;
}
}
}
static int
link_files(Piv iv)
{
iv->extrntbl = NewSymTable(iv->category, 4092); /* hashed table */
iv->reloctbl = NewSymTable(iv->category, 4092); /* hashed table */
iv->gbltbl = NewSymTable(iv->category, 0); /* sorted table */
setup_syms_decls(iv);
if(iv->numfiles > 1)
{
iv->symaddr = Ccalloc(iv->category, sizeof(void*), iv->numsyms+1);
iv->decladdr = Ccalloc(iv->category, sizeof(void*), iv->numdecls+1);
iv->symtbl = NewSymTable(iv->category, 0); /* sorted table */
combine_syms_decls(iv);
link_globals(iv);
realloc_data(iv);
reset_data_relocs(iv);
reset_text_relocs(iv);
reset_syms_decls(iv);
}
else
{
iv->symaddr = iv->files[0]->symaddr;
iv->decladdr = iv->files[0]->decladdr;
iv->symtbl = NewSymTable(iv->category, 0); /* sorted table */
combine_syms_decls(iv);
realloc_data(iv);
reset_data_relocs(iv);
reset_text_relocs(iv);
}
return iv->errors;
}
/* ======================== GLOBAL ROUTINES ========================== */
int
Global(readfile) (Piv iv, char *infile_name)
{
FILE *infile;
long infile_size;
char *inbuf;
if(!(infile = fopen(infile_name, "rb")))
{
PERROR(pName ": Can't open input file: %s\n", infile_name);
}
fseek(infile, 0, SEEK_END);
infile_size = ftell(infile);
fseek(infile, 0, SEEK_SET);
if(infile_size == 0)
{
PERROR(pName ": Empty input file: %s\n", infile_name);
}
inbuf = Cmalloc(iv->category, infile_size);
if(fread(inbuf, 1, infile_size, infile) != infile_size)
{
fclose(infile);
PERROR(pName ": Error reading input file: %s\n", infile_name);
}
fclose(infile);
if(setup_nodelinks(iv, infile_name, inbuf, infile_size))
return 4;
return 0;
}
int
Global(proc_files) (Piv iv, void *name)
{
int ret;
if(!(ret = link_files(iv)))
{
optimize(iv);
if(name)
iv->symaddr[2] = name; /* symbol 2 is the output filename */
ret = gen_output(iv, iv->symaddr[2]);
}
return ret;
}
void *
Global(open_instance) (void)
{
Piv iv;
int category;
#if USING_FRAMEWORK
if(num_instance <= 0)
{
oxlink_clear_bss(pName ".o"); /* reset global storage */
local_category = NewMallocCategory();
}
++num_instance;
#endif
category = Cnewcat();
iv = Ccalloc(category, 1, sizeof(struct _iv));
iv->category = category;
iv->finextbuf = (PEL)&iv->finextbufstart;
return iv;
}
void
Global(close_instance) (Piv iv)
{
if(iv->outfile)
fclose(iv->outfile);
if(iv->remove_infile)
{
int i;
for(i = 1; i < iv->argc; ++i)
unlink(propernameof(iv, iv->argv[i]));
}
Cfreecat(iv->category);
#if USING_FRAMEWORK
if(--num_instance == 0)
freecat(local_category);
#endif
}
/* =========================== THE MAIN PROGRAM ======================= */
static char *
filenameof(char *path)
{
char *ret = path;
int i;
for(i = 0; path[i]; ++i)
if(path[i] == '/')
ret = &path[i+1];
return ret;
}
static char *
propernameof(Piv iv, char *path)
{
char *name = filenameof(path);
int namlen = strlen(name);
int i;
for(i = namlen-1; i >= 0; --i)
{
if(name[i] == '/' || name[i] == '\\')
break;
else if(name[i] == '.')
return path;
}
name = Cmalloc(iv->category, strlen(path)+8);
strcpy(name, path);
strcat(name, ".anf");
return name;
}
static void
Usage()
{
fputs(
"Usage: " pName " [-odsDLR?] [infile...]\n"
" -o outfile == name of output file\n"
" -d == print debug output\n"
" -D == only print debug output\n"
" -s == strip declarations and line numbers\n"
" -L == generate listing only (to .lst)\n"
" -R == remove input file\n"
" -? == print this message\n"
" Default input file is `code.anf'.\n"
" Default output file is specified by the input.\n"
,stderr);
}
#if USING_FRAMEWORK
int
PROG (int argc, char **argv)
#else
int
main (int argc, char **argv)
#endif
{
int i,j;
char *outfilename = 0;
volatile Piv iv;
char debug, only_debug, strip, listing_wanted, remove_infile;
int ret;
remove_infile = listing_wanted = strip = debug = only_debug = 0;
/* Get options */
for(i = 1; i < argc; ++i)
{
int trimsize = 1;
if(argv[i][0] == '-')
{
for (j=1; argv[i][j]; j++)
{
switch(argv[i][j])
{
case 'D':
only_debug = 1;
/* FALL THROUGH */
case 'd':
debug = argv[i][++j];
break;
case 's':
strip = 1;
break;
case 'o':
if(argv[i][j+1]) {
outfilename = &argv[i][j+1];
}
else if(i < argc-1) {
outfilename = argv[i+1];
trimsize = 2;
} else {
PWARN(pName ": no output filename\n");
Usage();
return 0;
}
goto trim;
break;
case 'L':
listing_wanted = 1;
break;
case 'R':
remove_infile = 1;
break;
case '?':
Usage();
return 0;
default:
PWARN(pName ": Invalid switch: 0x%x\n", argv[i][j]);
Usage();
return 0;
}
}/* END: for(j) */
trim:
/* Trim switch */
for(j = i; j < argc-trimsize; ++j)
argv[j] = argv[j+trimsize];
argc -= trimsize;
--i;
}/* END: if('-') */
}/* END: for(argc) */
#if 0
oxcc_debug(__builtin_iv(),0x40000);
#endif
iv = Global(open_instance) ();
if((ret = setjmp(run_env))) {
Global(close_instance) (iv);
#if USING_FRAMEWORK
return ret;
#else
exit(ret);
#endif
}
iv->debug = debug;
iv->only_debug = only_debug;
iv->labeltbl = NewSymTable(iv->category, 4092);
#if REALLY_NEED_OFFSETS
iv->newlabeltbl = NewSymTable(iv->category, 4092);
#endif
iv->strip = strip;
iv->listing_wanted = listing_wanted;
iv->remove_infile = remove_infile;
iv->argc = argc;
iv->argv = argv;
if(argc < 2)
{/* Default input filename is 'code.anf' */
ret = Global(readfile) (iv, "code.anf");
}
else
{/* READ EACH INPUT FILE */
for(i = 1; i < argc; ++i)
if((ret = Global(readfile) (iv, propernameof(iv,argv[i]))))
break;
}
if(!ret && !iv->only_debug)
{
ret = Global(proc_files) (iv, outfilename);
}
Global(close_instance) (iv);
#if USING_FRAMEWORK
return ret;
#else
exit(ret);
#endif
}