/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 *
 */

#include		<stdio.h>
#include        "ass00.h"
#include        "assex.h"
#include		"asscm.h"
#include		"assrl.h"



#define COPYFINAL       1
#define COPYTEMP        0

/*
 * collection of routines to deal with relocation business
 */


static void dataprocess(FILE *, FILE *);
static void textprocess(FILE *, FILE *);

relc_t * text_reloc(glob_t *glosym, FOFFSET off, int typ)
{

	/*
	 * prepare the relocation that has to be done at text-offset off
	 * according to global symbol glosym.
	 * NOTE: The pointer glosym will point into mglobs[], while at
	 *       the time copyout() is called all the symbols here
	 *       will have disappeared.
	 *       The procedure upd_reloc() will change this pointer
	 *       into the one in xglobs[] later.
	 */

	register relc_t *nxtextreloc;

	nxtextreloc = rlp_cast getarea(sizeof *nxtextreloc);
	if (!f_text)
	{
		f_text = nxtextreloc;
	}
	else
	{
		l_text->r_next = nxtextreloc;
	}
	nxtextreloc->r_next = rlp_cast 0;
	l_text = nxtextreloc;
	nxtextreloc->r_off = off;
	nxtextreloc->r_val.rel_gp = glosym;
	nxtextreloc->r_typ = typ; /* flags of instruction */
	return (nxtextreloc);
}

relc_t * data_reloc(char *arg ,FOFFSET off, int typ)
{

	/*
	 * Same as above.
	 */

	register relc_t *nxdatareloc;

	nxdatareloc = rlp_cast getarea(sizeof *nxdatareloc);
	if (!f_data)
	{
		f_data = nxdatareloc;
	}
	else
	{
		l_data->r_next = nxdatareloc;
	}
	nxdatareloc->r_next = rlp_cast 0;
	l_data = nxdatareloc;
	nxdatareloc->r_off = off;
	nxdatareloc->r_val.rel_lp = lbp_cast arg;
	nxdatareloc->r_typ = typ;
	return (nxdatareloc);
}

void copyout(void)
{
	register int i;
	int remtext;

	/*
	 * Make the e.out file that looks as follows:
	 *
	 *      __________________________
	 *      |      MAGIC             | \
	 *      |      FLAGS             |  \
	 *      |      UNRESOLVED        |   \
	 *      |      VERSION           |    | 8*(2-byte word) header
	 *      |      WORDSIZE          |    | for interpreter selection
	 *      |      PTRSIZE           |   /
	 *      |      <UNUSED>          |  /
	 *      |      <UNUSED>          | /
	 *      |      NTEXT             | \
	 *      |      NDATA             |  \
	 *      |      NPROC             |   \
	 *      |      ENTRY-POINT       |    | 8*(wordsize-word) header
	 *      |      NLINES            |    | for interpreter proper
	 *      |      <UNUSED>          |   /
	 *      |      <UNUSED>          |  /
	 *      |      <UNUSED>          | /
	 *      |________________________|
	 *      |                        |
	 *      |      TEXT              |        zero filled
	 *      |                        |        if not word multiple
	 *      |________________________|
	 *      |                        |
	 *      |      DATA              |
	 *      |                        |
	 *      |________________________|
	 *      |                        |
	 *      |      PROCTABLE         |
	 *      |                        |
	 *      |________________________|
	 *
	 *
	 */

	remtext = textbytes % wordsize;
	if (remtext != 0)
		remtext = wordsize - remtext;

	if ((ifile = fopen(eout, "wb")) == 0)
		fatal("can't create e.out");

	rewind(tfile);
	rewind(dfile);

	xput16(as_magic, ifile);
	xput16(intflags, ifile);
	xput16(unresolved, ifile);
	xput16(VERSION, ifile);
	xput16(wordsize, ifile);
	xput16(ptrsize, ifile);
	xput16(0, ifile);
	xput16(0, ifile);
	xputa(textbytes + remtext, ifile);
	xputa((cons_t) datablocks, ifile);
	xputa((cons_t) procnum, ifile);
	xputa((cons_t) searchproc(MAIN, xprocs, oursize->n_xproc)->p_num, ifile);
	xputa((cons_t) sourcelines, ifile);
	xputa((cons_t) databytes, ifile);
	xputa((cons_t) 0, ifile);
	xputa((cons_t) 0, ifile);

	textprocess(tfile, ifile);
	while (remtext--)
		xputc(0, ifile);

	dataprocess(dfile, ifile);
	for (i = 0; i < procnum; i++)
	{
		xputarb(ptrsize, proctab[i].pr_loc, ifile);
		xputarb(ptrsize, proctab[i].pr_off, ifile);
	}
	if (fclose(ifile) == EOF)
		;
}

static void dataprocess(FILE *f1, FILE *outf)
{
	relc_t datareloc;
	FOFFSET i;
	register int ieof;

	rewind(rdfile);
	ieof = getblk(rdfile, (char *) (&datareloc.r_off),
			sizeof datareloc - sizeof datareloc.r_next);
	for (i = 0; i < dataoff && !ieof; i++)
	{
		if (i == datareloc.r_off)
		{
			switch (datareloc.r_typ)
			{
			case RELADR:
				xputa(xgeta(f1) + datareloc.r_val.rel_i, outf);
				i += ptrsize - 1;
				break;
			case RELGLO:
				if (datareloc.r_val.rel_gp->g_status & DEF)
				{
					xputa(xgeta(f1) + datareloc.r_val.rel_gp->g_val.g_addr, outf);
					i += ptrsize - 1;
					break;
				}
				if (unresolved == 0)
					fatal("Definition botch");
			case RELHEAD:
				xputc((int) (xgetc(f1) + datareloc.r_val.rel_i), outf);
				break;
			default:
				fatal("Bad r_typ in dataprocess");
			}
			ieof = getblk(rdfile, (char *) (&datareloc.r_off),
					sizeof datareloc - sizeof datareloc.r_next);
		}
		else
			xputc(xgetc(f1), outf);
	}
	for (; i < dataoff; i++)
		xputc(xgetc(f1), outf);
	if (!ieof && !getblk(rdfile, (char *) &datareloc, 1))
		fatal("data relocation botch");
}

static void textprocess(FILE *f1, FILE *outf)
{
	relc_t textreloc;
	cons_t n;
	FOFFSET i;
	FILE *otfile;
	int insl;
	register int ieof;
	char *op_curr;
	register FOFFSET keep;

	rewind(rtfile);
	keep = textoff;
	textoff = 0;
	otfile = tfile;
	tfile = outf;
	/* This redirects the output of genop */
	ieof = getblk(rtfile, (char *) (&textreloc.r_off),
			sizeof textreloc - sizeof textreloc.r_next);
	for (i = 0; i < keep && !ieof; i++)
	{
		if (i == textreloc.r_off)
		{
			if (textreloc.r_typ & RELMNS)
			{
				n = textreloc.r_val.rel_i;
			}
			else
			{
				if (textreloc.r_val.rel_gp->g_status & DEF)
				{
					n = textreloc.r_val.rel_gp->g_val.g_addr;
				}
				else
				{
					if (unresolved == 0)
						fatal("Definition botch");
					xputc(xgetc(f1), outf);
					ieof = getblk(rtfile, (char *) (&textreloc.r_off),
							sizeof textreloc - sizeof textreloc.r_next);
					continue;
				}
			}
			op_curr = &opchoice[textreloc.r_typ & ~RELMNS];
			insl = oplength(*op_curr);
			genop(op_curr, n + xgetarb(insl, f1), PAR_G);
			i += insl - 1;
			ieof = getblk(rtfile, (char *) (&textreloc.r_off),
					sizeof textreloc - sizeof textreloc.r_next);
		}
		else
		{
			xputc(xgetc(f1), outf);
		}
	}
	for (; i < keep; i++)
		xputc(xgetc(f1), outf);
	if (!ieof && !getblk(rtfile, (char *) &textreloc, 1))
		fatal("text relocation botch");
	textoff = keep;
	tfile = otfile;
}

void upd_reloc(void)
{
	register relc_t *p;
	register glob_t *gbp;

	/*
	 * Change reloc-tables such that for every pointer into mglobs
	 * either the corresponding pointer into xglobs or its value
	 * is substituted.
	 *
	 * Use is made of the known order of mglobs and xglobs
	 * see also getcore()
	 */

	while ( (p = f_text) != NULL)
	{
		gbp = p->r_val.rel_gp;
		if (gbp->g_status & DEF)
		{
			p->r_typ |= RELMNS;
			p->r_val.rel_i = gbp->g_val.g_addr;
		}
		else
			p->r_val.rel_gp = gbp->g_val.g_gp;
		putblk(rtfile, (char *) (&(p->r_off)), sizeof *p - sizeof p);
		f_text = p->r_next;
		freearea((area_t) p, sizeof *p);
	}

	while ( (p = f_data) != NULL)
	{
		if (p->r_typ == RELGLO)
		{
			gbp = p->r_val.rel_gp;
			if (gbp->g_status & DEF)
			{
				p->r_typ = RELADR;
				p->r_val.rel_i = gbp->g_val.g_addr;
			}
			else
				p->r_val.rel_gp = gbp->g_val.g_gp;
		}
		putblk(rdfile, (char *) (&(p->r_off)), sizeof *p - sizeof p);
		f_data = p->r_next;
		freearea((area_t) p, sizeof *p);
	}
	l_data = rlp_cast 0;
}
