shithub: scc

ref: 0645a868520feb0fac8932b08b6c4e1258b58c0c
dir: /as/ins.c/

View raw version
static char sccsid[] = "@(#) ./as/ins.c";

#include "../inc/scc.h"
#include "as.h"

extern Section *sabs, *sbss, *sdata, *stext;

enum {
	EQU,
	COMMON,
	SIZE,
};

char *
tobytes(TUINT v, int nbytes, int inc)
{
	static char buf[sizeof(TUINT)];
	int idx;

	idx = (inc < 0) ? nbytes-1 : 0;
	while (nbytes--) {
		buf[idx] = v;
		idx += inc;
		v >>= 8;
	}

	if (v)
		error("overflow in immediate value");
	return buf;
}

void
noargs(Op *op, Node **args)
{
	emit(op->bytes, op->size);
}

void
def(Node **args, int siz)
{
	Node *np;

	for ( ; np = *args; ++args) {
		Symbol *sym = np->sym;

		if (sym->flags & FRELOC)
			reloc(sym, 0, siz, siz * 8, 0);
		emit(tobytes(sym->value, siz, endian), siz);
	}
}

void
defb(Op *op, Node **args)
{
	def(args, 1);
}

void
defw(Op *op, Node **args)
{
	def(args, 2);
}

void
defd(Op *op, Node **args)
{
	def(args, 4);
}

void
defq(Op *op, Node **args)
{
	def(args, 8);
}

static void
symexp(int which, Op *op, Node **args)
{
	Symbol *sym, *exp;
	static char *cmds[] = {
		[EQU] = "equ",
		[COMMON] = "common",
		[SIZE] = "size",
	};
	char *cmd = cmds[which];

	if (args[1]) {
		sym = args[0]->sym;
		exp = args[1]->sym;
	} else if (linesym) {
		sym = linesym;
		exp = args[0];
	} else {
		error("%s pseudo instruction lacks a label", cmd);
	}

	if ((exp->flags & FABS) == 0)
		error("%s expression is not an absolute expression", cmd);

	switch (which) {
	case EQU:
		if (pass == 1 && (sym->flags & FUNDEF) == 0)
			error("redefinition of symbol '%s'", sym->name.buf);
		sym->value = exp->value;
		sym->flags &= ~FUNDEF;
		break;
	case COMMON:
		sym->flags |= FCOMMON;
	case SIZE:
		sym->size = exp->value;
		break;
	}
}

void
equ(Op *op, Node **args)
{
	symexp(EQU, op, args);
}

void
common(Op *op, Node **args)
{
	symexp(COMMON, op, args);
}

void
size(Op *op, Node **args)
{
	symexp(SIZE, op, args);
}

void
section(Op *op, Node **args)
{
	Symbol *sym = args[0]->sym;
	char *attr = NULL;

	if (args[1])
		attr = args[1]->sym->name.buf;

	setsec(sym->name.buf, attr);
}

void
text(Op *op, Node **args)
{
	cursec = stext;
}

void
data(Op *op, Node **args)
{
	cursec = sdata;
}

void
bss(Op *op, Node **args)
{
	cursec = sbss;
}