shithub: scc

Download patch

ref: 06a51397e166e3027b606b3dd5f29389a3976bf8
parent: ed6d85067b2e8dbd1e1a6bcc8317114cfc583ef1
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Sun Feb 10 05:09:53 EST 2019

[ld] Rewrite ld using libmach

--- a/src/cmd/ld/Makefile
+++ b/src/cmd/ld/Makefile
@@ -4,7 +4,6 @@
 include $(PROJECTDIR)/scripts/rules.mk
 
 OBJS = main.o \
-       obj.o \
 
 TARGET = $(BINDIR)/ld
 
@@ -13,7 +12,7 @@
 $(TARGET): $(LIBDIR)/libscc.a
 
 $(TARGET): $(OBJS)
-	$(CC) $(SCC_LDFLAGS) $(OBJS) -lscc -o $@
+	$(CC) $(SCC_LDFLAGS) $(OBJS) -lmach -o $@
 
 dep: inc-dep
 
--- a/src/cmd/ld/ld.h
+++ /dev/null
@@ -1,84 +1,0 @@
-#define INSTALL   1
-#define NOINSTALL 0
-
-typedef struct obj Obj;
-typedef struct symbol Symbol;
-typedef struct section Section;
-
-struct obj {
-	char *fname;
-	char *member;
-	FILE *fp;
-	long offset;
-
-	void *filhdr;
-	void *scnhdr;
-	void *enthdr;
-
-	char *strtbl;
-	size_t strsiz;
-
-	int (*unpack)(unsigned char *, char *, ...);
-	int align;
-
-	struct obj *next;
-};
-
-enum symflg {
-	SDEFINED = 1 << 1,
-};
-
-struct symbol {
-	char *name;
-	unsigned char flags;
-	long size;
-	TUINT base;
-	TUINT value;
-	Section *section;
-	Obj *where;
-	struct symbol *hash, *next;
-};
-
-struct section {
-	char *name;
-	TUINT base;
-	TUINT size;
-	struct section *next;
-};
-
-/* obj.c */
-extern Obj *newobj(char *fname, char *member, FILE *fp);
-extern Obj *add(Obj *obj);
-extern void delobj(Obj *obj);
-extern Section *slookup(char *name);
-extern Symbol *lookup(char *name, int install);
-
-/* main.c */
-extern void outmem(void);
-extern void corrupted(char *fname, char *member);
-extern void redefined(Obj *obj, Symbol *sym);
-
-/* object format */
-extern Obj *probe(char *fname, char *member, FILE *fp);
-extern Obj *load(Obj *obj);
-extern void writeout(FILE *fp);
-
-
-/*
- * Definition of globals variables
- */
-extern int pass;
-extern int sflag;
-extern int xflag;
-extern int Xflag;
-extern int rflag;
-extern int dflag;
-extern int gflag;
-extern Obj *objlst;
-extern Section *sectlst;
-extern long numsects;
-extern long numsymbols;
-extern TUINT tsize, dsize, bsize;
-extern char *output;
-extern char *entry;
-extern char *datasiz;
--- a/src/cmd/ld/main.c
+++ b/src/cmd/ld/main.c
@@ -3,17 +3,44 @@
 #include <ctype.h>
 #include <errno.h>
 #include <limits.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <scc/mach.h>
 #include <scc/scc.h>
 #include <scc/ar.h>
 #include <scc/syslibs.h>
-#include "ld.h"
 
+#define NR_SYMBOL 128
+
+typedef struct objlst Objlst;
+typedef struct symbol Symbol;
+
+struct objlst {
+	Obj *obj;
+	struct objlst *next;
+};
+
+struct symbol {
+	char *name;
+	Obj *obj;
+	Objsym *sym;
+	struct symbol *next, *prev;
+	struct symbol *hash;
+};
+
 char *output = "a.out", *entry = "start", *datasiz;
-int pass;
+
+static char *filename, *membname;
+static Objlst *objhead, *objlast;
+static Symbol *symtab[NR_SYMBOL];
+static Symbol refhead = {
+	.next = &refhead,
+	.prev = &refhead,
+};
+
 int sflag;		/* discard all the symbols */
 int xflag;		/* discard local symbols */
 int Xflag;		/* discard locals starting with 'L' */
@@ -21,181 +48,232 @@
 int dflag;		/* define common even with rflag */
 int gflag;              /* preserve debug symbols */
 
-static int done;
+static int status;
 
-Obj *
-probe(char *fname, char *member, FILE *fp)
+static char *
+errstr(void)
 {
+	return strerror(errno);
 }
 
-Obj *
-load(Obj *obj)
+static void
+error(char *fmt, ...)
 {
-}
+	va_list va;
 
-void
-writeout(FILE *fp)
-{
+	va_start(va, fmt);
+	fprintf(stderr, "nm: %s: ", filename);
+	if (membname)
+		fprintf(stderr, "%s: ", membname);
+	vfprintf(stderr, fmt, va);
+	putc('\n', stderr);
+	va_end(va);
+
+	status = EXIT_FAILURE;
 }
 
-void
-redefined(Obj *obj, Symbol *sym)
+static void
+cleanup(void)
 {
-	/* TODO: add infotmation about where it is defined */
-	fprintf(stderr,
-		"ld: %s: redifinition of symbol '%s'\n",
-		obj->fname, sym->name);
+	if (status != EXIT_FAILURE)
+		remove(output);
 }
 
-void
-corrupted(char *fname, char *member)
+static Symbol *
+lookup(Objsym *osym)
 {
-	char *fmt;
+	char *s;
+	unsigned h;
+	Symbol *sym;
+	char *name = osym->name;
 
-	fmt = (member) ?
-		"ld: %s(%s): corrupted file\n" : "ld: %s: corrupted file\n";
-	fprintf(stderr, fmt, fname, member);
-	exit(EXIT_FAILURE);
-}
+	h = 0;
+	for (s = name; *s; s++)
+		h += *s;
+	h %= NR_SYMBOL;
 
-void
-outmem(void)
-{
-	fputs("ld: out of memory\n", stderr);
-	exit(EXIT_FAILURE);
+	for (sym = symtab[h]; sym; sym = sym->hash) {
+		if (!strcmp(name, sym->name))
+			return sym;
+	}
+
+	if ((sym = malloc(sizeof(*sym))) == NULL) {
+		error("out of memory");
+		exit(EXIT_FAILURE);
+	}
+
+	sym->obj = NULL;
+	sym->name = osym->name;
+	sym->hash = symtab[h];
+	symtab[h] = sym;
+
+	refhead.next->prev = sym;
+	sym->next = refhead.next;
+	refhead.next = sym;
+	sym->prev = &refhead;
+
+	return sym;
 }
 
-static void
-cleanup(void)
+static Symbol *
+define(Objsym *osym, Obj *obj)
 {
-	if (!done)
-		remove(output);
+	Symbol *sym = lookup(osym);
+
+	if (sym->obj) {
+		error("%s: symbol redefined", osym->name);
+		return NULL;
+	}
+
+	sym->obj = obj;
+	sym->sym = osym;
+
+	sym->next->prev = sym->prev;
+	sym->prev->next = sym->next;
+	sym->next = sym->prev = NULL;
+
+	return sym;
 }
 
 static int
-object(char *fname, char *member, FILE *fp)
+newsym(Objsym *osym, void *obj)
 {
-	Obj *obj;
+	switch (osym->type) {
+	case 'U':
+		lookup(osym);
+	case '?':
+	case 'N':
+		break;
+	default:
+		if (isupper(osym->type))
+			define(osym, obj);
+		break;
+	}
 
-	obj = probe(fname, member, fp);
-	if (!obj)
-		return 0;
-	load(obj);
-
 	return 1;
 }
 
-static char *
-getfname(struct ar_hdr *hdr, char *dst)
+static void
+load(Obj *obj)
 {
-	char *p;
-	int i;
+	Objlst *lst;
 
-	memcpy(dst, hdr->ar_name, SARNAM);
-	dst[SARNAM] = '\0';
-
-	for (i = SARNAM-1; i >= 0; i--) {
-		if (dst[i] != ' ' && dst[i] != '/')
-			break;
-		dst[i] = '\0';
+	if ((lst = malloc(sizeof(*lst))) == NULL) {
+		error("out of memory");
+		return;
 	}
-	return dst;
+
+	lst->obj = obj;
+	lst->next = NULL;
+
+	if (!objlast)
+		objlast = objhead = lst;
+	else
+		objlast = objlast->next = lst;
+
+	forsym(obj, newsym, obj);
 }
 
 static void
-ar(char *fname, FILE *fp)
+newobject(FILE *fp, int type)
 {
-	struct ar_hdr hdr;
-	long pos, siz;
-	char member[SARNAM+1];
+	Obj *obj;
 
-	if (fseek(fp, SARMAG, SEEK_SET) == EOF)
-		goto file_error;
+	if ((obj = objnew(type)) == NULL) {
+		error("out of memory");
+		return;
+	}
 
-	while (fread(&hdr, sizeof(hdr), 1, fp) == 1) {
-		if (strncmp(hdr.ar_fmag, ARFMAG, sizeof(hdr.ar_fmag)))
-			corrupted(fname, NULL);
+	if (objread(obj, fp) < 0) {
+		error("object file corrupted");
+		goto error;
+	}
 
-		siz = 0;
-		sscanf(hdr.ar_size, "%10ld", &siz);
-		if (siz & 1)
-			siz++;
-		if (siz == 0)
-			corrupted(fname, NULL);
+	load(obj);
 
-		pos = ftell(fp);
-		if (pos == -1 || pos > LONG_MAX - siz) {
-			fprintf(stderr,
-			        "ld: %s(%s): overflow in size of archive",
-			         fname, member);
-			exit(EXIT_FAILURE);
-		}
-		pos += siz;
+	return;
 
-		getfname(&hdr, member);
-		object(fname, member, fp);
-		if (fseek(fp, pos, SEEK_SET) == EOF)
-			break;
-	}
+error:
+	objdel(obj);
+	return;
+}
 
-file_error:
-	if (ferror(fp)) {
-		fprintf(stderr, "ld: %s: %s\n", fname, strerror(errno));
-		exit(EXIT_FAILURE);
-	}
+static int
+newmember(FILE *fp, char *name, void *data)
+{
+	return 1;
 }
 
 static int
-archive(char *fname, FILE *fp)
+newlibrary(FILE *fp)
 {
-	char magic[SARMAG];
-	fpos_t pos;
 
-	fgetpos(fp, &pos);
-	fread(magic, SARMAG, 1, fp);
-	fsetpos(fp, &pos);
+	return artraverse(fp, newmember, NULL);
+}
 
-	if (ferror(fp))
-		return 0;
-	if (strncmp(magic, ARMAG, SARMAG) != 0)
-		return 0;
+static FILE *
+openfile(char *name, char *buffer)
+{
+	size_t len;
+	FILE *fp;
 
-	ar(fname, fp);
-	return 1;
+	filename = name;
+	membname = NULL;
+
+	if (name[0] != '-' || name[1] != 'l') {
+		if ((fp = fopen(name, "rb")) == NULL)
+			error(errstr());
+		return fp;
+	}
+
+	len = strlen(name+2);
+	if (len > FILENAME_MAX-4) {
+		error("library name too long");
+		return NULL;
+	}
+
+	strcat(strcpy(buffer, "lib"), name+2);
+	filename = buffer;
+
+	/* TODO: search the library now */
 }
 
 static void
 pass1(int argc, char *argv[])
 {
+	int t;
 	FILE *fp;
-	char *s;
+	char buff[FILENAME_MAX];
 
-	while ((s = *argv++) != NULL) {
-		if ((fp = fopen(s, "rb")) == NULL) {
-			fprintf(stderr, "ld: %s: %s\n", s, strerror(errno));
-			exit(EXIT_FAILURE);
-		}
-		if (!object(s, NULL, fp) && !archive(s, fp)) {
-			fprintf(stderr, "ld: %s: File format not recognized\n", s);
-			exit(EXIT_FAILURE);
-		}
+	for ( ; *argv; ++argv) {
+		if ((fp = openfile(*argv, buff)) == NULL)
+			continue;
+
+		if ((t = objtype(fp, NULL)) != -1)
+			newobject(fp, t);
+		else if (archive(fp))
+			newlibrary(fp);
+		else
+			error("bad format");
+
 		fclose(fp);
 	}
+
+	if (refhead.next != &refhead) {
+		Symbol *sym;
+
+		for (sym = refhead.next; sym != &refhead; sym = sym->next) {
+			fprintf(stderr,
+			        "ld: symbol '%s' not defined\n",
+			        sym->name);
+		}
+		exit(EXIT_FAILURE);
+	}
 }
 
 static void
 pass2(int argc, char *argv[])
 {
-	FILE *fp;
-
-	if ((fp = fopen(output, "wb")) != NULL) {
-		writeout(fp);
-		if (fclose(fp) != EOF)
-			return;
-	}
-
-	fprintf(stderr, "ld: %s: %s\n", output, strerror(errno));
-	exit(EXIT_FAILURE);
 }
 
 static void
@@ -202,7 +280,7 @@
 usage(void)
 {
 	fputs("usage: ld [options] file ...\n", stderr);
-	exit(1);
+	exit(EXIT_FAILURE);
 }
 
 static void
@@ -219,6 +297,24 @@
 	*bp = path;
 }
 
+static void
+refer(char *name)
+{
+	Objsym *osym;
+
+	if ((osym = malloc(sizeof(*osym))) == NULL) {
+		fputs("ld: out of memory\n", stderr);
+		return;
+	}
+
+	osym->name = name;
+	osym->type = 'U';
+	osym->size = osym->value = 0;
+	osym->next = osym->hash = NULL;
+
+	lookup(osym);
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -262,7 +358,7 @@
 				if (argc == 0)
 					goto usage;
 				++argv, --argc;
-				lookup(*argv, INSTALL);
+				refer(*argv);
 				break;
 			case 'o':
 				if (argc == 0)
@@ -297,7 +393,5 @@
 	pass1(argc, argv);
 	pass2(argc, argv);
 
-	done = 1;
-
-	return 0;
+	return status;
 }
--- a/src/cmd/ld/obj.c
+++ /dev/null
@@ -1,153 +1,0 @@
-static char sccsid[] = "@(#) ./ld/obj.c";
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <scc/scc.h>
-#include "ld.h"
-
-#define NR_SYM_HASH 64
-
-TUINT tsize, dsize, bsize;
-
-Obj *objlst;
-static Obj *objtail;
-
-long numsects, numsymbols;
-static Symbol *secttail;
-static Symbol *symtbl[NR_SYM_HASH];
-
-Section *sectlst;
-
-Obj *
-add(Obj *obj)
-{
-	obj->next = NULL;
-
-	if (!objlst) {
-		objtail = objlst = obj;
-	} else {
-		objtail->next = obj;
-		objtail = obj;
-	}
-}
-
-void
-delobj(Obj *obj)
-{
-	free(obj->strtbl);
-	free(obj->scnhdr);
-	free(obj->filhdr);
-	free(obj->fname);
-	free(obj->member);
-	free(obj);
-}
-
-Obj *
-newobj(char *fname, char *member, FILE *fp)
-{
-	Obj *obj;
-	char *s, *t;
-	size_t len;
-
-	len = strlen(fname);
-	obj = malloc(sizeof(*obj));
-	s = malloc(len) + 1;
-	if (!obj || !s)
-		outmem();
-	memset(obj, 0, sizeof(*obj));
-	obj->fname = memcpy(s, fname, len);
-
-	if (!member) {
-		obj->member = NULL;
-	} else {
-		len = strlen(member) + 1;
-		if ((s = malloc(len)) == NULL)
-			outmem();
-		obj->member = memcpy(s, member, len);
-	}
-
-	obj->fp = fp;
-	if ((obj->offset = ftell(fp)) == EOF) {
-		fprintf(stderr, "ld: %s: %s\n", fname, strerror(errno));
-		exit(1);
-	}
-
-	return obj;
-}
-
-Section *
-slookup(char *name)
-{
-	char *s;
-	Section *prev, *sp;
-	size_t len = strlen(name);
-
-	for (prev = sp = sectlst; sp; prev = sp, sp = sp->next) {
-		if (!memcmp(sp->name, name, len))
-			return sp;
-	}
-
-	sp = malloc(sizeof(*sp));
-	s = malloc(len);
-	if (!sp || !s)
-		outmem();
-	sp->name = s;
-	sp->base = 0;
-	sp->size = 0;
-	sp->next = NULL;
-
-	if (!prev)
-		sectlst = sp;
-	else
-		prev->next = sp;
-	numsects++;
-
-	return sp;
-}
-
-static unsigned
-hash(char *s)
-{
-	unsigned h, c;
-
-	for (h = 0; c = *s; ++s)
-		h = h*33 ^ c;
-	return h & NR_SYM_HASH-1;
-}
-
-Symbol *
-lookup(char *name, int install)
-{
-	unsigned h;
-	char *s;
-	size_t len;
-	Symbol *sym;
-
-	h = hash(name);
-	for (sym = symtbl[h]; sym; sym = sym->hash) {
-		s = sym->name;
-		if (*name == *s && !strcmp(name, s))
-			return sym;
-	}
-
-	if (!install)
-		return NULL;
-
-	len = strlen(name) + 1;
-	sym = malloc(sizeof(*sym));
-	s = malloc(len);
-	if (!sym || !s)
-		outmem();
-	memset(sym, 0, sizeof(*sym));
-	memcpy(s, name, len);
-
-	sym->hash = symtbl[h];
-	symtbl[h] = sym;
-	sym->name = s;
-	numsymbols++;
-
-	return sym;
-}