/* * Copyright (c) 1982 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char sccsid[] = "@(#)assyms.c 5.1 (Berkeley) 4/30/85"; #endif not lint #include #include #include "as.h" #include "asscan.h" #include "assyms.h" /* * Managers for chunks of symbols allocated from calloc() * We maintain a linked list of such chunks. * */ struct allocbox *allochead; /*head of chunk list*/ struct allocbox *alloctail; /*tail*/ struct allocbox *newbox; /*for creating a new chunk*/ struct symtab *nextsym; /*next symbol free*/ int symsleft; /*slots left in current chunk*/ struct symtab **symptrs; struct symtab **symdelim[NLOC + NLOC +1]; struct symtab **symptrub; /* * Managers for the dynamically extendable hash table */ struct hashdallop *htab; Iptr *itab[NINST]; /*maps opcodes to instructions*/ /* * Counts what went into the symbol table, so that the * size of the symbol table can be computed. */ int nsyms; /* total number in the symbol table */ int njxxx; /* number of jxxx entrys */ int nforgotten; /* number of symbols erroneously entered */ int nlabels; /* number of label entries */ /* * Managers of the symbol literal storage. */ struct strpool *strplhead = 0; symtabinit() { allochead = 0; alloctail = 0; nextsym = 0; symsleft = 0; strpoolalloc(); /* get the first strpool storage area */ htab = 0; htaballoc(); /* get the first part of the hash table */ } /* * Install all known instructions in the symbol table */ syminstall() { register Iptr ip; register struct symtab **hp; register char *p1, *p2; register int i; for (i = 0; i < NINST; i++) itab[i] = (Iptr*)BADPOINT; for (ip = (Iptr)instab; FETCHNAME(ip)[0]; ip++) { p1 = FETCHNAME(ip); p2 = yytext; while (*p2++ = *p1++); hp = lookup(0); /* 0 => don't install this*/ if (*hp==NULL) { *hp = (struct symtab *)ip; if ( (ip->s_tag!=INSTn) && (ip->s_tag!=INST0) && (ip->s_tag!=0)) continue; /* was pseudo-op */ if (itab[ip->i_eopcode] == (Iptr*)BADPOINT){ itab[ip->i_eopcode] = (Iptr*)ClearCalloc(256, sizeof(Iptr)); for (i = 0; i < 256; i++) itab[ip->i_eopcode][i] = (Iptr)BADPOINT; } itab[ip->i_eopcode][ip->i_popcode] = ip; } } } /*end of syminstall*/ #define ISLABEL(sp) \ ( (!savelabels) \ && (sp->s_tag == LABELID) \ && (STRPLACE(sp) & STR_CORE) \ && (FETCHNAME(sp)[0] == 'L')) /* * Assign final values to symbols, * and overwrite the index field with its relative position in * the symbol table we give to the loader. */ extern struct exec hdr; freezesymtab() { register struct symtab *sp; long bs; register int relpos = 0; register struct symtab *ubsp; register struct allocbox *allocwalk; DECLITERATE(allocwalk, sp, ubsp) { if (sp->s_tag >= IGNOREBOUND) continue; /*totally ignore jxxx entries */ /* * Ignore stabs, but give them a symbol table index */ if (sp->s_type & STABFLAG) goto assignindex; if ((sp->s_type&XTYPE)==XUNDEF) sp->s_type = XXTRN+XUNDEF; else if ((sp->s_type&XTYPE)==XDATA) sp->s_value += usedot[sp->s_index].e_xvalue; else if ((sp->s_type&XTYPE)==XTEXT) sp->s_value += usedot[sp->s_index].e_xvalue; else if ((sp->s_type&XTYPE)==XBSS) { bs = sp->s_value; sp->s_value = hdr.a_bss + datbase; hdr.a_bss += bs; } assignindex: if (!ISLABEL(sp)) sp->s_index = relpos++; } } /* * For all of the stabs that had their final value undefined during pass 1 * and during pass 2 assign a final value. * We have already given stab entrys a initial approximation * when we constsructed the sorted symbol table. * Iteration order doesn't matter. */ stabfix() { register struct symtab *sp, **cosp; register struct symtab *p; SYMITERATE(cosp, sp){ if(sp->s_ptype && (sp->s_type & STABFLAG)) { p = sp->s_dest; /* * STABFLOATING indicates that the offset has been saved in s_desc, s_other */ if(sp->s_tag == STABFLOATING) { sp->s_value = ( ( ((unsigned char) sp->s_other) << 16) | ( (unsigned short) sp->s_desc ) ); sp->s_value = sp->s_value + p->s_value; } else sp->s_value = p->s_value; sp->s_index = p->s_index; sp->s_type = p->s_type; } } } char *Calloc(number, size) int number, size; { register char *newstuff; char *sbrk(); newstuff = sbrk(number*size); if ((int)newstuff == -1){ yyerror("Ran out of Memory"); delexit(); } return(newstuff); } char *ClearCalloc(number, size) int number, size; { register char *newstuff; /* r11 */ register int length = number * size; /* r10 */ #ifdef lint length = length; #endif length newstuff = Calloc(number, size); asm("movc5 $0, (r0), $0, r10, (r11)"); return(newstuff); } struct symtab *symalloc() { if (symsleft == 0){ newbox = (struct allocbox *)ClearCalloc(1,ALLOCQTY); symsleft = SYMDALLOP; nextsym = &newbox->symslots[0]; if (alloctail == 0){ allochead = alloctail = newbox; } else { alloctail->nextalloc = newbox; alloctail = newbox; } } --symsleft; ++nsyms; return(nextsym++); } strpoolalloc() { register struct strpool *new; new = (struct strpool *)Calloc(1, sizeof (struct strpool)); new->str_nalloc = 0; new->str_next = strplhead; strplhead = new; } symcmp(Pptr, Qptr) struct symtab **Pptr, **Qptr; { register struct symtab *p = *Pptr; register struct symtab *q = *Qptr; if (p->s_index < q->s_index) return(-1); if (p->s_index > q->s_index) return(1); if (p->s_value < q->s_value) return(-1); if (p->s_value > q->s_value) return(1); /* * Force jxxx entries to virtually preceed labels defined * to follow the jxxxx instruction, so that bumping the * jxxx instruction correctly fixes up the following labels */ if (p->s_tag >= IGNOREBOUND) /*p points to a jxxx*/ return(-1); if (q->s_tag >= IGNOREBOUND) return(1); /* * both are now just plain labels; the relative order doesn't * matter. Both can't be jxxxes, as they would have different * values. */ return(0); } /*end of symcmp*/ /* * We construct the auxiliary table of pointers, symptrs and * symdelim * We also assign preliminary values to stab entries that did not yet * have an absolute value (because they initially referred to * forward references). We don't worry about .stabds, as they * already have an estimated final value */ sortsymtab() { register struct symtab *sp; register struct symtab **cowalk; register struct allocbox *allocwalk; struct symtab *ubsp; int segno; int slotno; int symsin; /*number put into symptrs*/ symptrs = (struct symtab **)Calloc(nsyms + 2, sizeof *symptrs); /* * Allocate one word at the beginning of the symptr array * so that backwards scans through the symptr array will * work correctly while scanning through the zeroth segment */ *symptrs++ = 0; cowalk = symptrs; symsin = 0; DECLITERATE(allocwalk, sp, ubsp) { if (sp->s_ptype && (sp->s_type &STABFLAG)){ sp->s_value = sp->s_dest->s_value; sp->s_index = sp->s_dest->s_index; } if (symsin >= nsyms) yyerror("INTERNAL ERROR: overfilled symbol table indirection table"); *cowalk++ = sp; symsin++; } if (symsin != nsyms) yyerror("INTERNAL ERROR: installed %d syms, should have installed %d", symsin, nsyms); symptrub = &symptrs[nsyms ]; qsort(symptrs, nsyms, sizeof *symptrs, symcmp); symdelim[0] = symptrs; for (cowalk = symptrs, sp = *cowalk, segno = 0, slotno = 1; segno < NLOC + NLOC; segno++, slotno++){ for (; sp && sp->s_index == segno; sp = *++cowalk); symdelim[slotno] = cowalk; /*forms the ub delimeter*/ } } /*end of sortsymtab*/ #ifdef DEBUG dumpsymtab() { register int segno; register struct symtab *sp, **cosp, *ub; char *tagstring(); printf("Symbol Table dump:\n"); for (segno = 0; segno < NLOC + NLOC; segno++){ printf("Segment number: %d\n", segno); SEGITERATE(segno, 0, 0, cosp, sp, ub, ++){ printf("\tSeg: %d \"%s\" value: %d index: %d tag %s\n", segno, FETCHNAME(sp), sp->s_value, sp->s_index, tagstring(sp->s_tag)); printf("\t\ttype: %d jxbump %d jxfear: %d\n", sp->s_type, sp->s_jxbump, sp->s_jxfear); } printf("\n\n"); } } static char tagbuff[4]; char *tagstring(tag) unsigned char tag; { switch(tag){ case JXACTIVE: return("active"); case JXNOTYET: return("notyet"); case JXALIGN: return("align"); case JXQUESTIONABLE: return("jxquestionable"); case JXINACTIVE: return("inactive"); case JXTUNNEL: return("tunnel"); case OBSOLETE: return("obsolete"); case IGNOREBOUND: return("ignorebound"); case STABFLOATING: return("stabfloating"); case STABFIXED: return("stabfixed"); case LABELID: return("labelid"); case OKTOBUMP: return("oktobump"); case ISET: return("iset"); case ILSYM: return("ilsym"); default: sprintf(tagbuff,"%d", tag); return(tagbuff); } } #endif DEBUG htaballoc() { register struct hashdallop *new; new = (struct hashdallop *)ClearCalloc(1, sizeof (struct hashdallop)); if (htab == 0) htab = new; else { /* add AFTER the 1st slot */ new->h_next = htab->h_next; htab->h_next = new; } } #define HASHCLOGGED (NHASH / 2) /* * Lookup a symbol stored in extern yytext. * All strings passed in via extern yytext had better have * a trailing null. Strings are placed in yytext for hashing by * syminstall() and by yylex(); * * We take pains to avoid function calls; this functdion * is called quite frequently, and the calls overhead * in the vax contributes significantly to the overall * execution speed of as. */ struct symtab **lookup(instflg) int instflg; /* 0: don't install */ { static int initialprobe; register struct symtab **hp; register char *from; register char *to; register int len; register int nprobes; static struct hashdallop *hdallop; static struct symtab **emptyslot; static struct hashdallop *emptyhd; static struct symtab **hp_ub; emptyslot = 0; for (nprobes = 0, from = yytext; *from; nprobes <<= 2, nprobes += *from++) continue; nprobes += from[-1] << 5; nprobes %= NHASH; if (nprobes < 0) nprobes += NHASH; initialprobe = nprobes; for (hdallop = htab; hdallop != 0; hdallop = hdallop->h_next){ for (hp = &(hdallop->h_htab[initialprobe]), nprobes = 1, hp_ub = &(hdallop->h_htab[NHASH]); (*hp) && (nprobes < NHASH); hp += nprobes, hp -= (hp >= hp_ub) ? NHASH:0, nprobes += 2) { from = yytext; to = FETCHNAME(*hp); while (*from && *to) if (*from++ != *to++) goto nextprobe; if (*to == *from) /*assert both are == 0*/ return(hp); nextprobe: ; } if (*hp == 0 && emptyslot == 0 && hdallop->h_nused < HASHCLOGGED) { emptyslot = hp; emptyhd = hdallop; } } if (emptyslot == 0) { htaballoc(); hdallop = htab->h_next; /* aren't we smart! */ hp = &hdallop->h_htab[initialprobe]; } else { hdallop = emptyhd; hp = emptyslot; } if (instflg) { *hp = symalloc(); hdallop->h_nused++; for (from = yytext, len = 0; *from++; len++) continue; (*hp)->s_name = (char *)savestr(yytext, len + 1, STR_BOTH); } return(hp); } /*end of lookup*/ /* * save a string str with len in the places indicated by place */ struct strdesc *savestr(str, len, place) char *str; int len; int place; { reg struct strdesc *res; int tlen; /* * Compute the total length of the record to live in core */ tlen = sizeof(struct strdesc) - sizeof(res->sd_string); if (place & STR_CORE) tlen += len; /* * See if there is enough space for the record, * and allocate the record. */ if (tlen >= (STRPOOLDALLOP - strplhead->str_nalloc)) strpoolalloc(); res = (struct strdesc *)(strplhead->str_names + strplhead->str_nalloc); /* * Save the string information that is always present */ res->sd_stroff = strfilepos; res->sd_strlen = len; res->sd_place = place; /* * Now, save the string itself. If str is null, then * the characters have already been dumped to the file */ if ((place & STR_CORE) && str) movestr(res[0].sd_string, str, len); if (place & STR_FILE){ if (str){ fwrite(str, 1, len, strfile); } strfilepos += len; } /* * Adjust the in core string pool size */ strplhead->str_nalloc += tlen; return(res); } /* * The relocation information is saved internally in an array of * lists of relocation buffers. The relocation buffers are * exactly the same size as a token buffer; if we use VM for the * temporary file we reclaim this storage, otherwise we create * them by mallocing. */ #define RELBUFLG TOKBUFLG #define NRELOC ((TOKBUFLG - \ (sizeof (int) + sizeof (struct relbufdesc *)) \ ) / (sizeof (struct relocation_info))) struct relbufdesc{ int rel_count; struct relbufdesc *rel_next; struct relocation_info rel_reloc[NRELOC]; }; extern struct relbufdesc *tok_free; #define rel_free tok_free static struct relbufdesc *rel_temp; struct relocation_info r_can_1PC; struct relocation_info r_can_0PC; initoutrel() { r_can_0PC.r_address = 0; r_can_0PC.r_symbolnum = 0; r_can_0PC.r_pcrel = 0; r_can_0PC.r_length = 0; r_can_0PC.r_extern = 0; r_can_1PC = r_can_0PC; r_can_1PC.r_pcrel = 1; } outrel(xp, reloc_how) register struct exp *xp; int reloc_how; /* TYPB..TYPH + (possibly)RELOC_PCREL */ { struct relocation_info reloc; register int x_type_mask; int pcrel; x_type_mask = xp->e_xtype & ~XFORW; pcrel = reloc_how & RELOC_PCREL; reloc_how &= ~RELOC_PCREL; if (bitoff&07) yyerror("Padding error"); if (x_type_mask == XUNDEF) yyerror("Undefined reference"); if ( (x_type_mask != XABS) || pcrel ) { if (ty_NORELOC[reloc_how]) yyerror("Illegal Relocation of floating or large int number."); reloc = pcrel ? r_can_1PC : r_can_0PC; reloc.r_address = dotp->e_xvalue - ( (dotp < &usedot[NLOC] || readonlydata) ? 0 : datbase ); reloc.r_length = ty_nlg[reloc_how]; switch(x_type_mask){ case XXTRN | XUNDEF: reloc.r_symbolnum = xp->e_xname->s_index; reloc.r_extern = 1; break; default: if (readonlydata && (x_type_mask&~XXTRN) == XDATA) x_type_mask = XTEXT | (x_type_mask&XXTRN); reloc.r_symbolnum = x_type_mask; break; } if ( (relfil == 0) || (relfil->rel_count >= NRELOC) ){ if (rel_free){ rel_temp = rel_free; rel_free = rel_temp->rel_next; } else { rel_temp = (struct relbufdesc *) Calloc(1,sizeof (struct relbufdesc)); } rel_temp->rel_count = 0; rel_temp->rel_next = relfil; relfil = rusefile[dotp - &usedot[0]] = rel_temp; } relfil->rel_reloc[relfil->rel_count++] = reloc; } /* * write the unrelocated value to the text file */ dotp->e_xvalue += ty_nbyte[reloc_how]; if (pcrel) xp->e_xvalue -= dotp->e_xvalue; switch(reloc_how){ case TYPO: case TYPQ: case TYPF: case TYPD: case TYPG: case TYPH: bignumwrite(xp->e_number, reloc_how); break; default: bwrite((char *)&(xp->e_xvalue), ty_nbyte[reloc_how], txtfil); break; } } /* * Flush out all of the relocation information. * Note that the individual lists of buffers are in * reverse order, so we must reverse them */ off_t closeoutrel(relocfile) BFILE *relocfile; { int locindex; u_long Closeoutrel(); trsize = 0; for (locindex = 0; locindex < NLOC; locindex++){ trsize += Closeoutrel(rusefile[locindex], relocfile); } drsize = 0; for (locindex = 0; locindex < NLOC; locindex++){ drsize += Closeoutrel(rusefile[NLOC + locindex], relocfile); } return(trsize + drsize); } u_long Closeoutrel(relfil, relocfile) struct relbufdesc *relfil; BFILE *relocfile; { u_long tail; if (relfil == 0) return(0L); tail = Closeoutrel(relfil->rel_next, relocfile); bwrite((char *)&relfil->rel_reloc[0], relfil->rel_count * sizeof (struct relocation_info), relocfile); return(tail + relfil->rel_count * sizeof (struct relocation_info)); } #define NOUTSYMS (nsyms - njxxx - nforgotten - (savelabels ? 0 : nlabels)) int sizesymtab() { return (sizeof (struct nlist) * NOUTSYMS); } /* * Write out n symbols to file f, beginning at p * ignoring symbols that are obsolete, jxxx instructions, and * possibly, labels */ int symwrite(symfile) BFILE *symfile; { int symsout; /*those actually written*/ int symsdesired = NOUTSYMS; reg struct symtab *sp, *ub; char *name; /* temp to save the name */ int totalstr; /* * We use sp->s_index to hold the length of the * name; it isn't used for anything else */ register struct allocbox *allocwalk; symsout = 0; totalstr = sizeof(totalstr); DECLITERATE(allocwalk, sp, ub) { if (sp->s_tag >= IGNOREBOUND) continue; if (ISLABEL(sp)) continue; symsout++; name = sp->s_name; /* save pointer */ /* * the length of the symbol table string * always includes the trailing null; * blast the pointer to its a.out value. */ if (sp->s_name && (sp->s_index = STRLEN(sp))){ sp->s_nmx = totalstr; totalstr += sp->s_index; } else { sp->s_nmx = 0; } if (sp->s_ptype != 0) sp->s_type = sp->s_ptype; else sp->s_type = (sp->s_type & (~XFORW)); if (readonlydata && (sp->s_type&~N_EXT) == N_DATA) sp->s_type = N_TEXT | (sp->s_type & N_EXT); bwrite((char *)&sp->s_nm, sizeof (struct nlist), symfile); sp->s_name = name; /* restore pointer */ } if (symsout != symsdesired) yyerror("INTERNAL ERROR: Wrote %d symbols, wanted to write %d symbols\n", symsout, symsdesired); /* * Construct the string pool from the symbols that were written, * possibly fetching from the string file if the string * is not core resident. */ bwrite(&totalstr, sizeof(totalstr), symfile); symsout = 0; DECLITERATE(allocwalk, sp, ub) { if (sp->s_tag >= IGNOREBOUND) continue; if (ISLABEL(sp)) continue; symsout++; if (STRLEN(sp) > 0){ if (STRPLACE(sp) & STR_CORE){ bwrite(FETCHNAME(sp), STRLEN(sp), symfile); } else if (STRPLACE(sp) & STR_FILE){ char rbuf[2048]; int left, nread; fseek(strfile, STROFF(sp), 0); for (left = STRLEN(sp); left > 0; left -= nread){ nread = fread(rbuf, sizeof(char), min(sizeof(rbuf), left), strfile); if (nread == 0) break; bwrite(rbuf, nread, symfile); } } } } if (symsout != symsdesired) yyerror("INTERNAL ERROR: Wrote %d strings, wanted %d\n", symsout, symsdesired); }