664 lines
14 KiB
C
664 lines
14 KiB
C
/* CODE.C -- CODE-GENERATION SUPPORT FUNCTIONS */
|
|
|
|
/* history: */
|
|
|
|
/* n/a E. Wilner -- created */
|
|
|
|
/* 8/25/88 RJK -- rev 0.16 */
|
|
/* 9/12/88 RJK -- rev 0.17 */
|
|
/* 10/15/88 RJK -- rev 0.18 */
|
|
/* 11/22/88 RJK -- rev 0.19 */
|
|
/* 2/28/89 RJK -- rev 0.21 (1.0e0) */
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
#include "asm29.h"
|
|
|
|
#define CBUFSIZE 8192
|
|
#define RELBSIZE 400
|
|
|
|
static char codebuf[CBUFSIZE], *cptr;
|
|
static int crem, nrel;
|
|
static struct reloc relbuf[RELBSIZE];
|
|
|
|
static void genval(struct value*);
|
|
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/*
|
|
* Clear the object-code buffer.
|
|
*/
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
void
|
|
initbuf(void)
|
|
{
|
|
cptr = codebuf;
|
|
crem = CBUFSIZE;
|
|
nrel = 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/*
|
|
* Output the object-code and relocatable buffers to the COFF file and
|
|
* update the count of relocatable items.
|
|
*/
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
flushbuf()
|
|
{
|
|
long save;
|
|
int j;
|
|
|
|
if ((cptr > codebuf) && (pass == 3))
|
|
{
|
|
if (crem < 0) crem = 0;
|
|
fwrite (codebuf,1,CBUFSIZE-crem,outf);
|
|
}
|
|
|
|
if (nrel)
|
|
{
|
|
if (pass == 3)
|
|
{
|
|
save = ftell (outf);
|
|
|
|
fseek (outf, (cursegp->sg_head.s_relptr +
|
|
cursegp->sg_head.s_nreloc*RELSZ), 0);
|
|
|
|
for (j = 0; j < nrel; j++)
|
|
{
|
|
fwrite ((char *) &relbuf[j],1,RELSZ,outf);
|
|
}
|
|
fseek (outf,save,0);
|
|
}
|
|
cursegp->sg_head.s_nreloc += nrel;
|
|
}
|
|
|
|
initbuf();
|
|
}
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/* "cs_flags(mask)" returns true (nonzero) if the current */
|
|
/* segment's STYP_XXXX flag bits intersect the bits in "mask", */
|
|
/* and false (zero) otherwise. */
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
int cs_flags(mask)
|
|
int mask; /* segment flag bit mask */
|
|
{
|
|
long l_flags; /* flag bits found */
|
|
long l_mask; /* mask (as a long value) */
|
|
|
|
if (cursegp == NULL) panic ("cs_flags");
|
|
l_mask = ((long) (unsigned) mask) & 0xFFFF;
|
|
l_flags = (cursegp->sg_head.s_flags) & l_mask;
|
|
return (l_flags ? TRUE : FALSE);
|
|
}
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/*
|
|
* "End" a segment by emptying the object & relocatable buffers, saving the
|
|
* current program counter in the segment structure, and padding the section
|
|
* to the next word boundary.
|
|
*/
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
void
|
|
endseg(int alignit)
|
|
{
|
|
int i;
|
|
long lx;
|
|
int nb;
|
|
|
|
if (cursegp != NULL) {
|
|
nb = (int) (4L - (pc & 0x03));
|
|
|
|
if (alignit && (nb < 4) && !cs_flags (no_align)) {
|
|
for (i = 0; i < nb; i++)
|
|
genbyte(0);
|
|
}
|
|
|
|
if (!cs_flags (STYP_DSECT)) {
|
|
lx = pc - cursegp->sg_head.s_paddr;
|
|
cursegp->sg_head.s_size = lx;
|
|
}
|
|
}
|
|
|
|
flushbuf();
|
|
cursegp = NULL;
|
|
}
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/* "algn_tree()" is a support function for "algn_data()". */
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
static void
|
|
algn_tree(struct sym *symp)
|
|
{
|
|
if (symp == NULL) return;
|
|
algn_tree (symp->sy_llink);
|
|
use_ps (symp);
|
|
if (cs_flags (STYP_DATA)) endseg (1);
|
|
algn_tree (symp->sy_rlink);
|
|
}
|
|
|
|
|
|
/* aligns all data segments. */
|
|
static void
|
|
algn_data(void)
|
|
{
|
|
endseg (1); /* end current segment */
|
|
no_align &= ~STYP_DATA;
|
|
algn_tree (segtab->sy_rlink);
|
|
no_align |= STYP_DATA;
|
|
endseg (1); /* end current segment */
|
|
}
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/* "post_algn()" handles the segment wrapup and/or alignment */
|
|
/* operations required after each pass. */
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
post_algn()
|
|
{
|
|
endseg (1); /* end current segment */
|
|
algn_data(); /* align data segments */
|
|
}
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/*
|
|
* Write a byte, halfword (2 bytes), or fullword (4 bytes) to the object-code
|
|
* buffer, and flush the buffer when full.
|
|
*/
|
|
void
|
|
genbyte(int b)
|
|
{
|
|
if (curseg == DSECT) /* don't write to dummy section ! */
|
|
{
|
|
error (e_dsect);
|
|
return;
|
|
}
|
|
/* listing the PC is interesting */
|
|
listpc = 1;
|
|
listovr = 1;
|
|
if (--crem < 0)
|
|
{
|
|
flushbuf();
|
|
crem--;
|
|
}
|
|
*cptr++ = b;
|
|
pc++;
|
|
}
|
|
|
|
genhword (h)
|
|
int h;
|
|
{
|
|
genbyte (h>>8);
|
|
genbyte (h);
|
|
}
|
|
|
|
genword (w)
|
|
long w;
|
|
{
|
|
genhword ((int)(w>>16));
|
|
genhword ((int)w);
|
|
}
|
|
|
|
/*
|
|
* Align the PC to a specified byte boundary (pad output with zeros and
|
|
* advance the PC).
|
|
*/
|
|
|
|
void
|
|
align(int n)
|
|
{
|
|
while (pc % n)
|
|
{
|
|
genbyte (0);
|
|
lpc++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check that the PC is aligned to a specified boundary (error if not!).
|
|
*/
|
|
void
|
|
ck_align(int n)
|
|
{
|
|
if (pc % n)
|
|
error(e_noalign);
|
|
}
|
|
|
|
/*
|
|
* Write a COFF relocatable item to the relocatable buffer, and output the
|
|
* buffer if it is full.
|
|
*/
|
|
void
|
|
genrel(long index, /* item index in COFF symbol table */
|
|
char type) /* COFF relocatable type */
|
|
{
|
|
struct reloc *rp;
|
|
|
|
/* >>><<< assume relocation type assigned -- no default */
|
|
|
|
rp = &relbuf[nrel++];
|
|
rp->r_vaddr = pc;
|
|
rp->r_symndx = index;
|
|
rp->r_type = type;
|
|
|
|
#ifdef SWAP_COFF
|
|
if (target_order != host_order) {
|
|
/* target here is processing machine */
|
|
putswap(rp->r_vaddr, &rp->r_vaddr, sizeof (long));
|
|
putswap(rp->r_symndx, &rp->r_symndx, sizeof (long));
|
|
putswap((long)rp->r_type, &rp->r_type, sizeof (short));
|
|
}
|
|
#endif
|
|
|
|
if (nrel == RELBSIZE)
|
|
flushbuf();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
genvrel(struct value *vp) /* value pointer */
|
|
{
|
|
struct scnhdr *shp; /* section header pointer */
|
|
int sn; /* section-number referenced */
|
|
|
|
if (vp->v_ext) { /* external reference? */
|
|
/* yes, generate relocation */
|
|
genrel(vp->v_ext->sy_index,vp->v_reloc);
|
|
return;
|
|
}
|
|
|
|
/* local reference? */
|
|
|
|
sn = vp->v_seg;
|
|
if ((sn == 0) || (vp->v_reloc == 0))
|
|
return;
|
|
|
|
/* The value references a local label. The reference will be resolved
|
|
* through the use of a dummy section symbol located at the section
|
|
* base address.*/
|
|
|
|
/* get reference section header */
|
|
|
|
if (sn == curseg) { /* used in current segment? */
|
|
shp = &(cursegp->sg_head); /* yes -- already have header */
|
|
} else if (sn > 0) {
|
|
shp = num_hdr(sn); /* get header using section # */
|
|
} else {
|
|
shp = 0;
|
|
}
|
|
|
|
/* suppress absolute relocation */
|
|
|
|
if ((shp != NULL) && (shp->s_flags & STYP_ABS))
|
|
return;
|
|
|
|
/* generate special relocation */
|
|
|
|
genrel (((sn-1) * 2) + viSegs,vp->v_reloc);
|
|
}
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/*
|
|
* Write relocatable items and object-code from a specified value structure.
|
|
* The object code is saved in a buffer for the listing routine.
|
|
*/
|
|
static void
|
|
genval(struct value *v)
|
|
{
|
|
#ifdef OLD
|
|
if (v->v_ext) { /* an external only */
|
|
genrel (v->v_ext->sy_index, v->v_reloc);
|
|
} else if ((v->v_seg) && (v->v_reloc)) {
|
|
/* a local label that will be resolved via a
|
|
* dummy section symbol at base address */
|
|
genrel ((v->v_seg * 2) - 2 + viSegs, v->v_reloc);
|
|
}
|
|
#else
|
|
genvrel(v);
|
|
#endif
|
|
|
|
switch (v->v_flags & VF_SIZE) {
|
|
case VF_BYTE:
|
|
genbyte ((int)v->v_val);
|
|
break;
|
|
case VF_HWORD:
|
|
genhword ((int)v->v_val);
|
|
break;
|
|
case VF_WORD:
|
|
genword(v->v_val);
|
|
}
|
|
if (lwords < 50)
|
|
lcode[lwords++] = *v;
|
|
}
|
|
|
|
/*
|
|
* Set the byte, halfword, or fullword flag in a specified value structure and
|
|
* then write out relocatable items and object code.
|
|
*/
|
|
void
|
|
genvbyte(struct value *v)
|
|
{
|
|
v->v_flags = (v->v_flags & ~VF_SIZE) | VF_BYTE;
|
|
genval (v);
|
|
}
|
|
|
|
void
|
|
genvhword(struct value *v)
|
|
{
|
|
v->v_flags = (v->v_flags & ~VF_SIZE) | VF_HWORD;
|
|
genval (v);
|
|
}
|
|
|
|
void
|
|
genvword(struct value *v)
|
|
{
|
|
v->v_flags = (v->v_flags & ~VF_SIZE) | VF_WORD;
|
|
genval (v);
|
|
}
|
|
|
|
/*
|
|
* Generate a relocatable item of type R_BYTE, for instructions containing
|
|
* multiple relocatable items.
|
|
*/
|
|
|
|
genbrel(vp, vad)
|
|
struct value *vp; /* pointer to value structure */
|
|
long vad; /* virtual address of relocatable byte */
|
|
{
|
|
long save;
|
|
|
|
save = pc;
|
|
pc = vad;
|
|
|
|
if (vp->v_ext)
|
|
{
|
|
genrel (vp->v_ext->sy_index,R_BYTE);
|
|
pr_reloc = R_EXT;
|
|
}
|
|
else
|
|
{
|
|
if (vp->v_seg)
|
|
{
|
|
genrel (vp->v_seg * 2 - 2 + viSegs,R_BYTE);
|
|
pr_reloc = R_SEG;
|
|
}
|
|
}
|
|
|
|
pc = save;
|
|
}
|
|
|
|
/*
|
|
* Convert an internal symbol-table entry to COFF symbol-table format and
|
|
* write it to the appropriate place in the COFF file, along with the
|
|
* string-table entry if needed.
|
|
*/
|
|
|
|
wrsym(ps)
|
|
struct sym *ps;
|
|
{
|
|
int i;
|
|
long save;
|
|
|
|
#ifdef SWAP_COFF
|
|
if (target_order != host_order)
|
|
{
|
|
putswap (ps->se.n_value, (char *)&s.n_value, sizeof (long));
|
|
putswap ((long)ps->se.n_scnum, (char *)&s.n_scnum, sizeof (short));
|
|
putswap ((long)ps->se.n_type, (char *)&s.n_type, sizeof (short));
|
|
}
|
|
#endif
|
|
|
|
if ((i = strlen (ps->sy_name)) > 8)
|
|
{
|
|
ps->se.n_zeroes = 0;
|
|
ps->se.n_offset = cur_strgoff;
|
|
|
|
#ifdef SWAP_COFF
|
|
if (target_order != host_order)
|
|
{
|
|
putswap (cur_strgoff, (char *)&s.n_offset, sizeof (long));
|
|
}
|
|
#endif
|
|
|
|
save = ftell (outf);
|
|
fseek (outf,stringptr + cur_strgoff,0);
|
|
fwrite (ps->sy_name, 1, i+1, outf);
|
|
fseek (outf,save,0);
|
|
cur_strgoff += i+1;
|
|
}
|
|
fwrite ((char *) &ps->se,1,SYMESZ,outf);
|
|
}
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/* export local symbols */
|
|
|
|
exp_loc(ps)
|
|
struct sym *ps;
|
|
{
|
|
int c,d; /* characters from symbol name */
|
|
char *cp; /* scratch */
|
|
int lf; /* "L*"-symbol flag */
|
|
long lx; /* flag bits */
|
|
long sf; /* symbol flags */
|
|
|
|
if ((ps == NULL) || (pass != 1)) return;
|
|
exp_loc (ps->sy_llink);
|
|
sf = ps->sy_flags;
|
|
|
|
if (sf & F_LOCSYM)
|
|
{
|
|
cp = ps->sy_name;
|
|
c = cp[0];
|
|
d = cp[1];
|
|
|
|
lf = (c == 'L') || ((c == '.') && (d == 'L'));
|
|
lx = sf & (F_EXTERN | F_MULDEF | F_SETSYM | F_UNDEF);
|
|
|
|
if ((lx == 0) && (lcflag || !lf) && !ps->se.n_sclass)
|
|
{ /* export the symbol */
|
|
ps->sy_flags |= F_PUBLIC;
|
|
ps->se.n_sclass = C_STAT;
|
|
}
|
|
}
|
|
|
|
exp_loc (ps->sy_rlink);
|
|
}
|
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/*
|
|
* Write out global symbols to the COFF file in alphabetical order.
|
|
*/
|
|
|
|
wrdefs(st)
|
|
struct sym *st; /* ptr to start of internal symbol table */
|
|
{
|
|
if (st == NULL) return;
|
|
wrdefs (st->sy_llink);
|
|
|
|
if ((st->sy_flags & F_PUBLIC) && (st->sy_index >= ndbsyms))
|
|
{
|
|
wrsym (st);
|
|
}
|
|
|
|
wrdefs (st->sy_rlink);
|
|
}
|
|
|
|
/*
|
|
* Write all external symbols to the DCOFF file.
|
|
*/
|
|
|
|
wrrefs(st)
|
|
struct sym *st;
|
|
{
|
|
if (st == NULL) return;
|
|
wrrefs (st->sy_llink);
|
|
|
|
if ((st->sy_flags & (F_EXTERN | F_UNDEF)) && (st->sy_index >= ndbsyms))
|
|
{
|
|
wrsym (st);
|
|
}
|
|
|
|
wrrefs (st->sy_rlink);
|
|
}
|
|
|
|
/*
|
|
* Write all section symbols to the COFF file (with auxiliary entries).
|
|
*/
|
|
|
|
wrsects()
|
|
{
|
|
int i, j = 1;
|
|
struct syment coffsym;
|
|
union auxent asym;
|
|
struct seglist *sp;
|
|
|
|
sp = sectlist;
|
|
|
|
while (sp != NULL)
|
|
{
|
|
zap(&coffsym);
|
|
zap(&asym);
|
|
|
|
for (i = 0; i < S_LEN; i++)
|
|
{
|
|
if ((coffsym.n_name[i] = sp->sg_head.s_name[i]) == '\0')
|
|
break;
|
|
}
|
|
|
|
coffsym.n_numaux = 1;
|
|
coffsym.n_sclass = C_STAT;
|
|
coffsym.n_scnum = j;
|
|
asym.xx_nreloc = sp->sg_head.s_nreloc;
|
|
asym.xx_nlinno = sp->sg_head.s_nlnno;
|
|
asym.xx_scnlen = sp->sg_head.s_size;
|
|
|
|
#ifdef SWAP_COFF
|
|
if (target_order != host_order)
|
|
{
|
|
putswap ((long)j, (char *)&coffsym.n_scnum, sizeof (short));
|
|
putswap (sp->sg_head.s_size, (char *)&asym.xx_scnlen,
|
|
sizeof (long));
|
|
putswap ((long)sp->sg_head.s_nlnno, (char *)&asym.xx_nlinno,
|
|
sizeof (short));
|
|
putswap ((long)sp->sg_head.s_nreloc, (char *)&asym.xx_nreloc,
|
|
sizeof (short));
|
|
}
|
|
#endif
|
|
|
|
fwrite ((char *)&coffsym, 1, SYMESZ, outf);
|
|
j++;
|
|
fwrite ((char *)&asym, 1, SYMESZ, outf);
|
|
sp = sp->sg_link;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write a section header to the COFF file, swapping bytes if requested.
|
|
*/
|
|
|
|
wrhead(isp,fp)
|
|
struct scnhdr *isp;
|
|
FILE *fp;
|
|
{
|
|
#ifdef SWAP_COFF
|
|
if (target_order == host_order)
|
|
#endif
|
|
{
|
|
fwrite ((char *) isp,1,SCNHSZ,fp);
|
|
return;
|
|
}
|
|
|
|
#ifdef SWAP_COFF
|
|
putswap (isp->s_paddr, (char *)&osp.s_paddr, sizeof (long));
|
|
putswap (isp->s_vaddr, (char *)&osp.s_vaddr, sizeof (long));
|
|
putswap (isp->s_size, (char *)&osp.s_size, sizeof (long));
|
|
putswap (isp->s_scnptr, (char *)&osp.s_scnptr, sizeof (long));
|
|
putswap (isp->s_relptr, (char *)&osp.s_relptr, sizeof (long));
|
|
putswap (isp->s_lnnoptr, (char *)&osp.s_lnnoptr, sizeof (long));
|
|
putswap (isp->s_flags, (char *)&osp.s_flags, sizeof (long));
|
|
putswap ((long)isp->s_nreloc, (char *)&osp.s_nreloc, sizeof (short));
|
|
putswap ((long)isp->s_nlnno, (char *)&osp.s_nlnno, sizeof (short));
|
|
|
|
for (i = 0; i < S_LEN; i++)
|
|
{
|
|
osp.s_name[i] = isp->s_name[i];
|
|
}
|
|
|
|
fwrite ((char *) &osp,1,SCNHSZ,fp);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Write a line-number entry to the COFF file.
|
|
*/
|
|
|
|
wrline(ilp,fp)
|
|
struct lineno *ilp;
|
|
FILE *fp;
|
|
{
|
|
#ifdef SWAP_COFF
|
|
if (target_order == host_order)
|
|
#endif
|
|
{
|
|
fwrite ((char *) ilp,1,LINESZ,fp);
|
|
return;
|
|
}
|
|
|
|
#ifdef SWAP_COFF
|
|
putswap (ilp->l_addr.l_symndx, (char *)&olp.l_addr.l_symndx, sizeof(long));
|
|
putswap ((long)ilp->l_lnno, (char *)&olp.l_lnno, sizeof (short));
|
|
fwrite ((char *)&olp, 1, LINESZ, fp);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Write the COFF object-file header.
|
|
*/
|
|
|
|
wrfhead(fp)
|
|
FILE *fp;
|
|
{
|
|
#ifdef SWAP_COFF
|
|
struct filehdr ohead;
|
|
|
|
if (target_order == host_order)
|
|
#endif
|
|
{
|
|
fwrite ((char *) &head,1,FILHSZ,fp);
|
|
return;
|
|
}
|
|
|
|
#ifdef SWAP_COFF
|
|
putswap ((long)head.f_magic, (char *)&ohead.f_magic, sizeof (short));
|
|
putswap ((long)head.f_nscns, (char *)&ohead.f_nscns, sizeof (short));
|
|
putswap (head.f_timdat, (char *)&ohead.f_timdat, sizeof (long));
|
|
putswap (head.f_symptr, (char *)&ohead.f_symptr, sizeof (long));
|
|
putswap (head.f_nsyms, (char *)&ohead.f_nsyms, sizeof (long));
|
|
putswap ((long)head.f_opthdr, (char *)&ohead.f_opthdr, sizeof (short));
|
|
putswap ((long)head.f_flags, (char *)&ohead.f_flags, sizeof (short));
|
|
fwrite ((char *) &ohead,1,FILHSZ,fp);
|
|
#endif
|
|
}
|