123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- /* $Id$ */
- /*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
- /* @(#)comm6.c 1.7 */
- /*
- * implement pseudo instructions
- */
- #include "comm0.h"
- #include "comm1.h"
- #include "y.tab.h"
- void newequate(item_t *ip, int typ)
- {
- typ &= ~S_EXT;
- if (typ & S_COM)
- typ = S_UND;
- else if ((typ & S_VAR) && (typ & S_TYP) != S_ABS)
- typ = S_UND;
- #ifdef THREE_PASS
- else if (pass == PASS_1 && typ == S_UND)
- typ = S_VAR;
- else if (pass == PASS_2 && (ip->i_type & S_TYP) == S_UND)
- ip->i_type |= typ;
- #endif /* THREE_PASS */
- if (typ == S_UND)
- serror("illegal equate");
- if (pass == PASS_3)
- assert((ip->i_type & S_TYP) == (typ & S_TYP));
- newident(ip, typ);
- }
- void newident(item_t *ip, int typ)
- {
- int flag;
- #ifdef GENLAB
- static char genlab[] = GENLAB;
- #endif /* GENLAB */
- if (pass == PASS_1) {
- /* printf("declare %s: %o\n", ip->i_name, typ); */
- if (ip->i_type & ~S_EXT)
- serror("multiple declared");
- else
- --unresolved;
- ip->i_type |= typ;
- }
- if (PASS_SYMB == 0)
- return;
- #ifdef THREE_PASS
- if (ip->i_type & S_EXT)
- flag = SYM_EXT;
- else
- flag = SYM_LOC;
- #else
- flag = SYM_EXT|SYM_LOC; /* S_EXT not stable in PASS_1 */
- #endif /* THREE_PASS */
- #ifdef GENLAB
- if (!(flag & SYM_EXT) &&
- strncmp(ip->i_name, genlab, sizeof(genlab)-1) == 0)
- flag = SYM_LAB;
- #endif /* GENLAB */
- if (sflag & flag)
- newsymb(
- ip->i_name,
- ip->i_type & (S_EXT|S_TYP),
- 0,
- load(ip)
- );
- }
- void newlabel(item_t *ip)
- {
- #if DEBUG != 0
- #ifdef THREE_PASS
- ADDR_T oldval = ip->i_valu;
- #endif
- #endif
- if (DOTSCT == NULL)
- nosect();
- ip->i_type &= ~S_TYP;
- ip->i_type |= DOTTYP;
- if (store(ip, (valu_t) DOTVAL) == 0)
- return;
- #ifdef THREE_PASS
- assert(pass != PASS_2 || oldval - (ADDR_T) ip->i_valu == DOTGAIN);
- #endif
- }
- void newsect(item_t *ip)
- {
- int typ;
- sect_t *sp = NULL;
- typ = ip->i_type & S_TYP;
- if (typ == S_UND) {
- /*
- * new section
- */
- assert(pass == PASS_1);
- --unresolved;
- typ = outhead.oh_nsect + S_MIN;
- outhead.oh_nsect++;
- if (outhead.oh_nsect > SECTMAX || typ > S_MAX)
- fatal("too many sections");
- sp = §[typ - S_MIN];
- sp->s_item = ip;
- sp->s_lign = ALIGNSECT;
- #ifndef ASLD
- ip->i_type = typ;
- #else
- ip->i_type = typ | S_EXT;
- #endif
- ip->i_valu = 0;
- } else if (typ >= S_MIN) {
- sp = §[typ - S_MIN];
- if (sp->s_item != ip)
- sp = NULL;
- }
- if (sp == NULL)
- serror("multiple declared");
- else
- switchsect(typ);
- }
- /*ARGSUSED*/
- void newbase(valu_t base)
- {
- #ifdef ASLD
- sect_t *sp;
-
- if ((sp = DOTSCT) == NULL)
- nosect();
- if (sp->s_flag & BASED)
- serror("already based");
- sp->s_base = base;
- sp->s_flag |= BASED;
- DOTVAL += base;
- #else
- warning(".base ignored");
- #endif
- }
- /*
- * NOTE: A rather different solution is used for ASLD and not ASLD:
- * ASLD, or local commons:
- * - maximum length of .comm is recorded in i_valu during PASS_1
- * - address of .comm is recorded in i_valu in later passes:
- * assigned at end of PASS_1, corrected for s_gain at end of PASS_2
- * not ASLD:
- * - maximum length of .comm is recorded in i_valu during PASS_1
- * - i_valu is used for relocation info during PASS_3
- */
- void newcomm(item_t *ip, valu_t val)
- {
- if (pass == PASS_1) {
- if (DOTSCT == NULL)
- nosect();
- if (val == 0)
- serror("bad size");
- /* printf("declare %s: %o\n", ip->i_name, DOTTYP); */
- if ((ip->i_type & ~S_EXT) == S_UND) {
- --unresolved;
- ip->i_type = S_COM|DOTTYP|(ip->i_type&S_EXT);
- ip->i_valu = val;
- new_common(ip);
- } else if (ip->i_type == (S_COM|DOTTYP|(ip->i_type&S_EXT))) {
- if (ip->i_valu < val)
- ip->i_valu = val;
- } else
- serror("multiple declared");
- }
- }
- void switchsect(int newtyp)
- {
- sect_t *sp;
-
- if ( (sp = DOTSCT) )
- sp->s_size = DOTVAL - sp->s_base;
- if (newtyp == S_UND) {
- DOTSCT = NULL;
- DOTTYP = newtyp;
- return;
- }
- assert(newtyp >= S_MIN);
- sp = §[newtyp - S_MIN];
- DOTVAL = sp->s_size + sp->s_base;
- DOTSCT = sp;
- DOTTYP = newtyp;
- }
- void align(valu_t bytes)
- {
- valu_t gap;
- sect_t *sp;
- if ((sp = DOTSCT) == NULL)
- nosect();
- if (bytes == 0)
- bytes = ALIGNWORD;
- if (sp->s_lign % bytes)
- {
- if (bytes % sp->s_lign)
- {
- serror("illegal alignment");
- }
- else
- {
- sp->s_lign = bytes;
- }
- }
- if (pass == PASS_1)
- {
- /*
- * be pessimistic: biggest gap possible
- */
- gap = bytes - 1;
- }
- else
- {
- /*
- * calculate gap correctly;
- * will be the same in PASS_2 and PASS_3
- */
- if ((gap = DOTVAL % bytes) != 0)
- gap = bytes - gap;
- #ifdef THREE_PASS
- if (pass == PASS_2)
- /*
- * keep track of gain with respect to PASS_1
- */
- DOTGAIN += (bytes - 1) - gap;
- #endif
- }
- DOTVAL += gap;
- sp->s_zero += gap;
- }
- #ifdef RELOCATION
- void newrelo(int s, int n)
- {
- int iscomm;
- struct outrelo outrelo;
- if (rflag == 0)
- return;
- if (PASS_RELO == 0)
- return;
- s &= ~S_DOT;
- assert((s & ~(S_COM|S_VAR|S_TYP)) == 0);
- #ifdef ASLD
- #ifndef THREE_PASS
- if (s == S_UND)
- serror("bad relocation");
- #endif
- #endif
- /*
- * always relocation info if S_VAR to solve problems with:
- * move b,d0
- * b=a
- * a: .data2 0
- * but no relocation info if S_VAR is set, but type is S_ABS.
- */
- iscomm = s & S_COM;
- s &= ~S_COM;
- if ((n & RELPC) == 0 && ((s & ~S_VAR) == S_ABS))
- return;
- if ((n & RELPC) != 0 && s == DOTTYP
- #ifndef ASLD
- && ! iscomm
- #endif
- )
- return;
- if (pass != PASS_3) {
- outhead.oh_nrelo++;
- return;
- }
- s &= ~S_VAR;
- outrelo.or_type = (char)n;
- outrelo.or_sect = (char)DOTTYP;
- #ifndef ASLD
- if (s == S_UND || iscomm) {
- assert(relonami != 0);
- outrelo.or_nami = relonami-1;
- relonami = 0;
- } else
- #endif
- if (s < S_MIN)
- {
- assert(s == S_ABS);
- /*
- * use first non existing entry (argh)
- */
- outrelo.or_nami = outhead.oh_nname;
- }
- else
- {
- /*
- * section symbols are at the end
- */
- outrelo.or_nami = outhead.oh_nname
- - outhead.oh_nsect
- + (s - S_MIN)
- ;
- }
- outrelo.or_addr = (long)DOTVAL;
- wr_relo(&outrelo, 1);
- }
- #endif
- long new_string(char *s)
- {
- long r = 0;
- if (s) {
- long len = strlen(s) + 1;
- r = outhead.oh_nchar;
- if (pass == PASS_3) wr_string(s, len);
- outhead.oh_nchar += len;
- }
- return r;
- }
- void newsymb(char *name, int type, int desc, valu_t valu)
- {
- struct outname outname;
- if (name && *name == 0)
- name = 0;
- assert(PASS_SYMB);
- if (pass != PASS_3) {
- new_string(name);
- outhead.oh_nname++;
- return;
- }
- nname++;
- outname.on_foff = new_string(name);
- outname.on_type = type;
- outname.on_desc = desc;
- outname.on_valu = valu;
- if (sizeof(valu) != sizeof(long))
- outname.on_valu &= ~(((0xFFFFFFFF)<<(4*sizeof(valu_t)))<<(4*sizeof(valu_t)));
- wr_name(&outname, 1);
- }
- void new_common(item_t *ip)
- {
- struct common_t *cp;
- static nleft = 0;
- static struct common_t *next;
- if (--nleft < 0) {
- next = (struct common_t *) malloc(MEMINCR);
- if (next == 0) {
- fatal("out of memory");
- }
- nleft += (MEMINCR / sizeof (struct common_t));
- }
- cp = next++;
- cp->c_next = commons;
- cp->c_it = ip;
- commons = cp;
- }
|