371 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			371 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* $Header$ */
 | |
| /*
 | |
|  * (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"
 | |
| 
 | |
| newequate(ip, typ)
 | |
| register item_t *ip;
 | |
| register short 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);
 | |
| }
 | |
| 
 | |
| newident(ip, typ)
 | |
| register item_t *ip;
 | |
| {
 | |
| 	register 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),
 | |
| 			(short)0,
 | |
| 			load(ip)
 | |
| 		);
 | |
| }
 | |
| 
 | |
| newlabel(ip)
 | |
| register item_t *ip;
 | |
| {
 | |
| #if DEBUG != 0
 | |
| #ifdef THREE_PASS
 | |
| 	register 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 - ip->i_valu == DOTGAIN);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| newsect(ip)
 | |
| register item_t *ip;
 | |
| {
 | |
| 	register short typ;
 | |
| 	register 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*/
 | |
| newbase(base)
 | |
| valu_t base;
 | |
| {
 | |
| #ifdef ASLD
 | |
| 	register 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
 | |
|  */
 | |
| newcomm(ip, val)
 | |
| register 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");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| switchsect(newtyp)
 | |
| short newtyp;
 | |
| {
 | |
| 	register 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;
 | |
| }
 | |
| 
 | |
| align(bytes)
 | |
| valu_t bytes;
 | |
| {
 | |
| 	register valu_t gap;
 | |
| 	register 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
 | |
| newrelo(s, n)
 | |
| short s;
 | |
| {
 | |
| 	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
 | |
| 	 */
 | |
| 	iscomm = s & S_COM;
 | |
| 	s &= ~S_COM;
 | |
| 	if ((n & RELPC) == 0 && s == 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(s)
 | |
| 	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;
 | |
| }
 | |
| 
 | |
| newsymb(name, type, desc, valu)
 | |
| register char *name;
 | |
| short type;
 | |
| short 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 & ~(((0xFFFFFFFF)<<(4*sizeof(valu_t)))<<(4*sizeof(valu_t)));
 | |
| 	wr_name(&outname, 1);
 | |
| }
 | |
| 
 | |
| new_common(ip)
 | |
| 	item_t *ip;
 | |
| {
 | |
| 	register 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;
 | |
| }
 |