shithub: scc

ref: 21674aabd645829b4be407b084e399c46f5ccd6f
dir: /src/cmd/ld/section.c/

View raw version
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <scc/mach.h>
#include <scc/scc.h>

#include "ld.h"

#define NR_SECTION 32

/*
 * struct sectab has a Section as first field because
 * the code is going to cast from the sections to the tab.
 */
struct sectab {
	Section sec;
	FILE *tmpfp;
	struct sectab *hash;
	struct sectab *next, *prev;
};

static struct sectab *sectab[NR_SECTION];
static struct sectab secs = {.next = &secs, .prev = &secs};

static Section *
linksec(struct sectab *lst, Section *sec)
{
	struct sectab *sp = (struct sectab *) sec;

	sp->next = lst;
	sp->prev = lst->prev;
	lst->prev->next = sp;
	lst->prev = sp;

	return sec;
}

Section *
lookupsec(char *name)
{
	unsigned h;
	size_t len;
	char *s;
	Section *sec;
	struct sectab *sp;

	h = genhash(name) % NR_SECTION;
	for (sp = sectab[h]; sp; sp = sp->hash) {
		if (!strcmp(name, sp->sec.name))
			return &sp->sec;
	}

	len = strlen(name) + 1;
	s = malloc(len);
	sp = malloc(sizeof(*sp));
	if (!s || !sp) {
		error(strerror(errno));
		exit(EXIT_FAILURE);
	}

	sec = &sp->sec;
	sec->name = memcpy(s, name, len);
	sec->type = 'U';
	sec->base = 0;
	sec->size = 0;
	sec->align = 0;
	sec->index = 0;
	sec->flags = 0;
	sp->tmpfp;
	sp->hash = sectab[h];
	sectab[h] = sp;

	return linksec(&secs, sec);
}

void
copy(Obj *obj, Section *osec, Section *sec)
{
	struct sectab *sp = (struct sectab *) sec;

	if (sec->size > ULLONG_MAX - osec->size) {
		error("%s: section too long", sec->name);
		return;
	}

	if (!sp->tmpfp && (sp->tmpfp = tmpfile()) == NULL) {
		error(strerror(errno));
		exit(EXIT_FAILURE);
	}

/*
	if (mapsec(obj, osec->index, sp->tmpfp) < 0) {
		error(strerror(errno));
		return;
	}
*/

	sec->size += osec->size;
}

void
grow(Section *sec, int nbytes)
{
	struct sectab *sp = (struct sectab *) sec;

	if (sec->size > ULLONG_MAX - nbytes) {
		error("%s: section too long", sec->name);
		return;
	}

	if (!sp->tmpfp && (sp->tmpfp = tmpfile()) == NULL) {
		error(strerror(errno));
		exit(EXIT_FAILURE);
	}

	while (nbytes-- > 0)
		putc(0, sp->tmpfp);

	sec->size += nbytes;
}

#ifndef NDEBUG
void
debugsec(void)
{
	struct sectab **spp, *sp;
	Section *sec;

	fputs("Sections:\n", stderr);
	for (spp = sectab; spp < &sectab[NR_SECTION]; spp++) {
		for (sp = *spp; sp; sp = sp->hash) {
			sec = &sp->sec;
			fprintf(stderr,
			        "sec: %s - %c (%#llx,%#lx)\n",
			        sec->name,
			        sec->type,
			        sec->base,
			        sec->size);
		}
	}
}
#endif