
/* linksyms.c - write binary file for linker */

/* Copyright (C) 1994 Bruce Evans */

#include "syshead.h"
#include "const.h"
#include "obj.h"
#include "type.h"
#undef EXTERN
#include "globvar.h"

FORWARD void linkrefs P((struct modstruct *modptr));
PUBLIC bool_t reloc_output = 0;

/* link all symbols connected to entry symbols */

PUBLIC void linksyms(argreloc_output)
bool_pt argreloc_output;
{
    char needlink;
    struct entrylist *elptr;
    struct modstruct *modptr;
    struct symstruct *symptr;

#ifdef REL_OUTPUT
    reloc_output = argreloc_output;
    if (argreloc_output)
    {
	if (modfirst->modnext != NUL_PTR)
	    fatalerror("relocatable output only works for one input file");
	for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
	    modptr->loadflag = TRUE;
	return;
    }
#endif
    if ((symptr = findsym("_start")) != NUL_PTR ||
        (symptr = findsym("_main")) != NUL_PTR)
	entrysym(symptr);
    do
    {
	if ((elptr = entryfirst) == NUL_PTR)
	    fatalerror("no start symbol");
	for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
	    modptr->loadflag = FALSE;
	for (; elptr != NUL_PTR; elptr = elptr->elnext)
	    linkrefs(elptr->elsymptr->modptr);
	if ((symptr = findsym("start")) != NUL_PTR)
	    linkrefs(symptr->modptr);
	needlink = FALSE;
	{
	    struct redlist *prlptr = 0;
	    struct redlist *rlptr;

	    for (rlptr = redfirst; rlptr != NUL_PTR;
		 rlptr = (prlptr = rlptr)->rlnext)
		if (rlptr->rlmodptr->loadflag &&
		    rlptr->rlmodptr->class > rlptr->rlsymptr->modptr->class)
		{
		    rlptr->rlsymptr->modptr = rlptr->rlmodptr;
		    rlptr->rlsymptr->value = rlptr->rlvalue;
		    if (rlptr == redfirst)
			redfirst = rlptr->rlnext;
		    else
			prlptr->rlnext = rlptr->rlnext;
		    needlink = TRUE;
		}
	}
    }
    while (needlink);
}

PRIVATE void linkrefs(modptr)
struct modstruct *modptr;
{
    register struct symstruct **symparray;
    register struct symstruct *symptr;

    modptr->loadflag = TRUE;
    for (symparray = modptr->symparray;
	 (symptr = *symparray) != NUL_PTR; ++symparray)
	if (symptr->modptr->loadflag == FALSE)
	    linkrefs(symptr->modptr);
}

