shithub: scc

Download patch

ref: 845a4d450d705c86e557494e4661abddf4f157be
parent: d4f9d2c95f2fcc650b00fc39e6690df9ed953c89
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Tue Aug 27 08:10:33 EDT 2019

[libmach] Big rework of libmach (Symbol)

Libmach had a lot of different problems and one of them
was the definition of Objsym, that forced every tool to mess
with object symbol datatypes and specific types.

--- a/include/scc/scc/mach.h
+++ b/include/scc/scc/mach.h
@@ -1,7 +1,7 @@
 #define NR_SYMHASH 32
 
 typedef struct objsec Objsec;
-typedef struct objsym Objsym;
+typedef struct symbol Symbol;
 typedef struct objseg Objseg;
 typedef struct objops Objops;
 typedef struct obj Obj;
@@ -28,7 +28,7 @@
 	Objsec *next;
 };
 
-struct objsym {
+struct symbol {
 	char *name;
 	unsigned long long size;
 	unsigned long long value;
@@ -36,8 +36,6 @@
 	int index;
 	char class;
 	char type;
-
-	Objsym *next, *hash;
 };
 
 struct objseg {
@@ -51,23 +49,18 @@
 	void (*del)(Obj *obj);
 	int (*read)(Obj *obj, FILE *fp);
 	int (*write)(Obj *obj, FILE *fp);
-	int (*addseg)(Obj *obj, void *seg);
 	int (*strip)(Obj *obj);
 	int (*addr2line)(Obj *, unsigned long long , char *, int *);
+	int (*getsym)(Obj *obj, long *index, Symbol *sym);
 	int (*setidx)(long nsyms, char *names[], long offset[], FILE *fp);
 	int (*getidx)(long *nsyms, char ***names, long **offset, FILE *fp);
 };
 
 struct obj {
-	int type;
-	Objops *ops;
 	char *index;
-	Objsym *htab[NR_SYMHASH];
-	Objsym *syms;
-	Objsec *secs;
+	Objops *ops;
+	int type;
 	long pos;
-	int nsecs;
-	int nsyms;
 	void *data;
 };
 
@@ -76,5 +69,5 @@
 
 extern int objtype(FILE *fp, char **name);
 extern Obj *objnew(int type);
-extern Objsym *objlookup(Obj *obj, char *name, int install);
-extern int objpos(Obj *obj, FILE *fp, long pos);
+extern int readobj(Obj *obj, FILE *fp);
+extern int getsym(Obj *obj, long *index, Symbol *sym);
--- a/src/cmd/Makefile
+++ b/src/cmd/Makefile
@@ -4,13 +4,14 @@
 include $(PROJECTDIR)/scripts/rules.mk
 
 TARGET = $(BINDIR)/nm \
-         $(BINDIR)/strip \
-         $(BINDIR)/size \
          $(BINDIR)/ar \
-         $(BINDIR)/ranlib \
-         $(BINDIR)/objdump \
-         $(BINDIR)/objcopy \
-         $(BINDIR)/addr2line \
+
+#         $(BINDIR)/strip \
+#         $(BINDIR)/size \
+#         $(BINDIR)/ranlib \
+#         $(BINDIR)/objdump \
+#         $(BINDIR)/objcopy \
+#         $(BINDIR)/addr2line \
 
 DIRS   = as scc
 
--- a/src/cmd/nm.c
+++ b/src/cmd/nm.c
@@ -12,7 +12,7 @@
 
 
 struct symtbl {
-	Objsym **buf;
+	Symbol **buf;
 	size_t nsyms;
 };
 
@@ -45,8 +45,8 @@
 static int
 cmp(const void *p1, const void *p2)
 {
-	Objsym **s1 = (Objsym **) p1, **s2 = (Objsym **) p2;
-	Objsym *sym1 = *s1, *sym2 = *s2;
+	Symbol **s1 = (Symbol **) p1, **s2 = (Symbol **) p2;
+	Symbol *sym1 = *s1, *sym2 = *s2;
 
 	if (vflag) {
 		if (sym1->value > sym2->value)
@@ -66,17 +66,19 @@
 }
 
 static void
-printsyms(Objsym **syms, size_t nsym)
+printsyms(Symbol **syms, size_t nsym)
 {
 	size_t i;
 
 	qsort(syms, nsym, sizeof(syms), cmp);
 
-	if (multi)
-		printf("%s:\n", (membname) ? membname : filename);
+	if (!Aflag) {
+		if (multi || membname)
+			printf("%s:\n", (membname) ? membname : filename);
+	}
 
 	for (i = 0; i < nsym; i++) {
-		Objsym *sym = syms[i];
+		Symbol *sym = syms[i];
 		int type = sym->type;
 		char *fmt;
 
@@ -113,9 +115,9 @@
 }
 
 static int
-newsym(Objsym *sym, struct symtbl *tbl)
+newsym(Symbol *sym, struct symtbl *tbl)
 {
-	Objsym **p;
+	Symbol **p, *s;
 	size_t n, size;
 	int type = sym->type;
 
@@ -133,10 +135,16 @@
 		return 0;
 	size = n *sizeof(*p);
 
-	if ((p = realloc(tbl->buf, size)) == NULL)
-		return 0;
+	p = realloc(tbl->buf, size);
+	s = malloc(sizeof(*s));
+	if (!p || !s) {
+		error("out of memory");
+		exit(EXIT_FAILURE);
+	}
+
+	*s = *sym;
 	tbl->buf = p;
-	p[tbl->nsyms++] = sym;
+	p[tbl->nsyms++] = s;
 
 	return 1;
 }
@@ -145,20 +153,21 @@
 newobject(FILE *fp, int type)
 {
 	int err = 1;
+	long i;
 	Obj *obj;
-	Objsym *sym;
+	Symbol sym;
 	struct symtbl tbl = {NULL, 0};
 
 	if ((obj = objnew(type)) == NULL) {
 		error("out of memory");
-		return;
+		exit(EXIT_FAILURE);
 	}
 
-	if ((*obj->ops->read)(obj, fp) < 0)
+	if (readobj(obj, fp) < 0)
 		goto error;
 
-	for (sym = obj->syms; sym; sym = sym->next)
-		newsym(sym, &tbl);
+	for (i = 0; getsym(obj, &i, &sym); i++)
+		newsym(&sym, &tbl);
 
 	printsyms(tbl.buf, tbl.nsyms);
 	err = 0;
@@ -174,17 +183,29 @@
 newlib(FILE *fp)
 {
 	int t;
-	long r;
+	long off, cur;
 	char memb[SARNAM+1];
 
-	while ((r = armember(fp, memb)) > 0) {
-		membname = memb;
-		if ((t = objtype(fp, NULL)) != -1)
-			newobject(fp, t);
-		membname = NULL;
+	while (!feof(fp)) {
+		cur = ftell(fp);
+		off = armember(fp, memb);
+		switch (off) {
+		case -1:
+			error("library corrupted");
+		case 0:
+			return;
+		default:
+			membname = memb;
+			if ((t = objtype(fp, NULL)) != -1)
+				newobject(fp, t);
+			membname = NULL;
+			fseek(fp, cur, SEEK_SET);
+			fseek(fp, off, SEEK_CUR);
+			break;
+		}
 	}
-	if (r < 0)
-		error("library corrupted");
+
+	error("library corrupted:%s", strerror(errno));
 }
 
 static void
@@ -267,7 +288,9 @@
 	}
 
 	if (fflush(stdout)) {
-		fprintf(stderr, "nm: error writing in output");
+		fprintf(stderr,
+		        "nm: error writing in output:%s\n",
+		        strerror(errno));
 		status = 1;
 	}
 
--- a/src/libmach/Makefile
+++ b/src/libmach/Makefile
@@ -7,17 +7,11 @@
 OBJS = mach.o \
        objnew.o \
        objpos.o \
-       objfree.o \
-       objstrip.o \
-       objdel.o \
-       objaddseg.o \
-       objsync.o \
-       addr2line.o \
        archive.o \
        armember.o \
-       objlookup.o \
        objtype.o \
-       objwrite.o \
+       readobj.o \
+       getsym.o \
        pack.o \
        unpack.o \
 
--- a/src/libmach/coff32/Makefile
+++ b/src/libmach/coff32/Makefile
@@ -16,6 +16,7 @@
        coff32setidx.o \
        coff32getidx.o \
        coff32addr2line.o \
+       coff32getsym.o \
 
 all: $(OBJS)
 
--- a/src/libmach/coff32/coff32.c
+++ b/src/libmach/coff32/coff32.c
@@ -6,6 +6,7 @@
 #include "coff32.h"
 
 Objops coff32 = {
+	.probe = coff32probe,
 	.new = coff32new,
 	.read = coff32read,
 	.getidx = coff32getidx,
@@ -14,4 +15,5 @@
 	.strip = coff32strip,
 	.del = coff32del,
 	.write = coff32write,
+	.getsym = coff32getsym,
 };
--- a/src/libmach/coff32/coff32.h
+++ b/src/libmach/coff32/coff32.h
@@ -15,7 +15,7 @@
 
 struct coff32 {
 	FILHDR hdr;
-	AOUTHDR *aout;
+	AOUTHDR aout;
 	SCNHDR *scns;
 	SYMENT *ents;
 	RELOC **rels;
@@ -38,3 +38,5 @@
                          long nsymbols, char *names[], long offs[], FILE *fp);
 extern int coff32xgetidx(int order,
                          long *nsyms, char ***namep, long **offsp, FILE *fp);
+
+extern int coff32getsym(Obj *obj, long *idx, Symbol *sym);
\ No newline at end of file
--- a/src/libmach/coff32/coff32del.c
+++ b/src/libmach/coff32/coff32del.c
@@ -19,6 +19,5 @@
 	free(obj->data);
 	obj->data = NULL;
 
-	objdel(obj);
 	free(obj);
 }
--- /dev/null
+++ b/src/libmach/coff32/coff32getsym.c
@@ -1,0 +1,74 @@
+#include <ctype.h>
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "../libmach.h"
+#include "coff32.h"
+
+static int
+typeof(Coff32 *coff, SYMENT *ent)
+{
+	int c;
+	SCNHDR *scn;
+	long flags;
+
+	switch (ent->n_scnum) {
+	case N_DEBUG:
+		c = 'N';
+		break;
+	case N_ABS:
+		c = 'a';
+		break;
+	case N_UNDEF:
+		c = (ent->n_value != 0) ? 'C' : 'U';
+		break;
+	default:
+		scn = &coff->scns[ent->n_scnum-1];
+		flags = scn->s_flags;
+		if (flags & STYP_TEXT)
+			c = 't';
+		else if (flags & STYP_DATA)
+			c = 'd';
+		else if (flags & STYP_BSS)
+			c = 'b';
+		else
+			c = '?';
+		break;
+	}
+
+	if (ent->n_sclass == C_EXT)
+		c = toupper(c);
+
+	return c;
+}
+
+static char *
+symname(Coff32 *coff, SYMENT *ent)
+{
+	if (ent->n_zeroes != 0)
+		return ent->n_name;
+
+	return &coff->strtbl[ent->n_offset];
+}
+
+int
+coff32getsym(Obj *obj, long *idx, Symbol *sym)
+{
+	long n = *idx;
+	SYMENT *ent;
+	Coff32 *coff = obj->data;
+
+	if (*idx >= coff->hdr.f_nsyms)
+		return 0;
+
+	ent = &coff->ents[n];
+	sym->name = symname(coff, ent);
+	sym->type = typeof(coff, ent);
+	sym->value = ent->n_value;
+	sym->size = (sym->type == 'C') ? ent->n_value : 0;
+	sym->index = n;
+	*idx += ent->n_numaux;
+
+	return 1;
+}
--- a/src/libmach/coff32/coff32read.c
+++ b/src/libmach/coff32/coff32read.c
@@ -82,7 +82,7 @@
 
 	s = ent->n_name;
 	if (!s[0] && !s[1] && !s[2] && !s[3])
-		unpack(order, "ll", buf, &ent->n_zeroes, &ent->n_offset);
+		unpack(order, buf, "ll", &ent->n_zeroes, &ent->n_offset);
 }
 
 static void
@@ -153,10 +153,9 @@
 	if (fread(buf, 4, 1, fp) != 1)
 		return 0;
 	unpack(ORDER(obj->type), buf, "l", &siz);
-	siz -= 4;
-	if (siz < 0)
+	if (siz == 4)
 		return 0;
-	if (siz > 0) {
+	if (siz > 4) {
 		if (siz > SIZE_MAX)
 			return 0;
 		str = malloc(siz);
@@ -165,7 +164,7 @@
 		coff->strtbl = str;
 		coff->strsiz = siz;
 
-		if (fread(str, siz, 1, fp) != 1)
+		if (fread(str+4, siz-4, 1, fp) != 1)
 			return 0;
 	}
 	return 1;
@@ -185,7 +184,7 @@
 	coff  = obj->data;
 	hdr = &coff->hdr;
 
-	rels = calloc(obj->nsecs, sizeof(*rels));
+	rels = calloc(hdr->f_nscns, sizeof(*rels));
 	if (!rels)
 		return 0;
 	coff->rels = rels;
@@ -207,6 +206,8 @@
 			if (fread(buf, RELSZ, 1, fp) != 1)
 				return 0;
 			unpack_reloc(ORDER(obj->type), buf, &rp[i]);
+			if (rp[i].r_symndx >= hdr->f_nsyms)
+				return 0;
 		}
 	}
 
@@ -239,6 +240,8 @@
 		if (fread(buf, SYMESZ, 1, fp) != 1)
 			return 0;
 		unpack_ent(ORDER(obj->type), buf, &ent[i]);
+		if (ent->n_scnum > hdr->f_nscns)
+			return 0;		
 	}
 
 	return 1;
@@ -306,6 +309,8 @@
 			if (fread(buf, LINESZ, 1, fp) == 1)
 				return 0;
 			unpack_line(ORDER(obj->type), buf, &lp[j]);
+			if (lp[i].l_symndx >= hdr->f_nsyms)
+				return 0;
 		}
 	}
 
@@ -315,13 +320,10 @@
 static int
 readaout(Obj *obj, FILE *fp)
 {
-	FILHDR *hdr;
-	struct coff32 *coff;
+	struct coff32 *coff = obj->data;
+	FILHDR *hdr = &coff->hdr;
 	unsigned char buf[AOUTSZ];
 
-	coff  = obj->data;
-	hdr = &coff->hdr;
-
 	if (hdr->f_opthdr == 0)
 		return 1;
 
@@ -328,25 +330,18 @@
 	if (fread(buf, AOUTSZ, 1, fp) != 1)
 		return 0;
 
-	coff->aout = malloc(sizeof(AOUTHDR));
-	if (!coff->aout)
-		return 0;
+	unpack_aout(ORDER(obj->type), buf, &coff->aout);
 
-	unpack_aout(ORDER(obj->type), buf, coff->aout);
-
 	return 1;
 }
 
-static int
-readfile(Obj *obj, FILE *fp)
+int
+coff32read(Obj *obj, FILE *fp)
 {
-	long off;
+	long i;
+	struct coff32 *coff = obj->data;
+	FILHDR *hdr = &coff->hdr;
 
-	/* TODO: Add validation of the different fields */
-	if ((off = ftell(fp)) == EOF)
-		return -1;
-	obj->pos = off;
-
 	if (!readhdr(obj, fp))
 		return -1;
 	if (!readaout(obj, fp))
@@ -361,172 +356,12 @@
 		return -1;
 	if (!readlines(obj, fp))
 		return -1;
-	return 0;
-}
 
-static int
-convsecs(Obj *obj)
-{
-	int i;
-	unsigned sflags, type;
-	unsigned long flags;
-	FILHDR *hdr;
-	struct coff32 *coff;
-	SCNHDR *scn;
-	Objsec *secs, *sp;
-
-	coff  = obj->data;
-	hdr = &coff->hdr;
-
-	secs = malloc(sizeof(Objsec) * hdr->f_nscns);
-	if (!secs)
-		return -1;
-
-	for (i = 0; i < hdr->f_nscns; i++) {
-		sp = &secs[i];
-		sp->next = (i < hdr->f_nscns-1) ? &secs[i+1] : NULL;
-		scn = &coff->scns[i];
-		flags = scn->s_flags;
-
-		if (flags & STYP_TEXT) {
-			type = 'T';
-			sflags = SALLOC | SRELOC | SLOAD | SEXEC | SREAD;
-			if (flags & STYP_NOLOAD)
-				sflags |= SSHARED;
-		} else if (flags & STYP_DATA) {
-			type = 'D';
-			sflags = SALLOC | SRELOC | SLOAD | SWRITE | SREAD;
-			if (flags & STYP_NOLOAD)
-				sflags |= SSHARED;
-		} else if (flags & STYP_BSS) {
-			type = 'B';
-			sflags = SALLOC | SREAD | SWRITE;
-		} else if (flags & STYP_INFO) {
-			type = 'N';
-			sflags = 0;
-		} else if (flags & STYP_LIB) {
-			type = 'T';
-			sflags = SRELOC;
-		} else if (flags & STYP_DSECT) {
-			type = 'D';
-			sflags = SRELOC;
-		} else if (flags & STYP_PAD) {
-			type = 'D';
-			sflags = SLOAD;
-		} else {
-			type = 'D';  /* We assume that STYP_REG is data */
-			sflags = SALLOC | SRELOC | SLOAD | SWRITE | SREAD;
-		}
-
-		if (flags & STYP_NOLOAD)
-			sflags &= ~SLOAD;
-
-		sp->name = scn->s_name;
-		sp->id = i;
-		sp->seek = scn->s_scnptr;
-		sp->size = scn->s_size;
-		sp->type = type;
-		sp->flags = sflags;
-		sp->align = 4; /* TODO: Check how align is defined in coff */
-	}
-	obj->secs = secs;
-	obj->nsecs = i;
-
-	return 1;
-}
-
-static int
-typeof(Coff32 *coff, SYMENT *ent)
-{
-	int c;
-	SCNHDR *scn;
-	long flags;
-
-	switch (ent->n_scnum) {
-	case N_DEBUG:
-		c = 'N';
-		break;
-	case N_ABS:
-		c = 'a';
-		break;
-	case N_UNDEF:
-		c = (ent->n_value != 0) ? 'C' : 'U';
-		break;
-	default:
-		if (ent->n_scnum > coff->hdr.f_nscns)
+	for (i = 0; i < hdr->f_nsyms; i++) {
+		SYMENT *ent = &coff->ents[i];
+		if (ent->n_zeroes != 0 && ent->n_offset > coff->strsiz)
 			return -1;
-		scn = &coff->scns[ent->n_scnum-1];
-		flags = scn->s_flags;
-		if (flags & STYP_TEXT)
-			c = 't';
-		else if (flags & STYP_DATA)
-			c = 'd';
-		else if (flags & STYP_BSS)
-			c = 'b';
-		else
-			c = '?';
-		break;
 	}
 
-	if (ent->n_sclass == C_EXT)
-		c = toupper(c);
-
-	return c;
-}
-
-static char *
-symname(Coff32 *coff, SYMENT *ent)
-{
-	long off;
-
-	if (ent->n_zeroes != 0)
-		return ent->n_name;
-
-	off = ent->n_offset;
-	if (off >= coff->strsiz)
-		return NULL;
-	return &coff->strtbl[off];
-}
-
-static int
-convsyms(Obj *obj)
-{
-	int t;
-	long i;
-	char *s;
-	Objsym *sym;
-	SYMENT *ent;
-	Coff32 *coff = obj->data;
-
-	for (i = 0; i < coff->hdr.f_nsyms; i += ent->n_numaux + 1) {
-		ent = &coff->ents[i];
-
-		if ((t = typeof(coff, ent)) < 0)
-			return -1;
-
-		if ((s = symname(coff, ent)) == NULL)
-			return -1;
-
-		if ((sym = objlookup(obj, s, 1)) == NULL)
-			return -1;
-
-		sym->type = t;
-		sym->value = ent->n_value;
-		sym->size = (sym->type == 'C') ? ent->n_value : 0;
-		sym->index = ent->n_scnum-1;
-	}
-
-	return i;
-}
-
-int
-coff32read(Obj *obj, FILE *fp)
-{
-	if (readfile(obj, fp) < 0)
-		return -1;
-	if (convsecs(obj) < 0)
-		return -1;
-	if (convsyms(obj) < 0)
-		return -1;
 	return 0;
 }
--- a/src/libmach/coff32/coff32strip.c
+++ b/src/libmach/coff32/coff32strip.c
@@ -34,7 +34,6 @@
 	coff->ents = NULL;
 	coff->rels = NULL;
 	coff->lines = NULL;
-	objdel(obj);
 
 	return 0;
 }
--- a/src/libmach/coff32/coff32write.c
+++ b/src/libmach/coff32/coff32write.c
@@ -231,7 +231,7 @@
 
 	if (hdr->f_opthdr == 0)
 		return 1;
-	pack_aout(ORDER(obj->type), buf, coff->aout);
+	pack_aout(ORDER(obj->type), buf, &coff->aout);
 
 	return fread(buf, AOUTSZ, 1, fp) != 1;
 }
--- /dev/null
+++ b/src/libmach/getsym.c
@@ -1,0 +1,9 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+int
+getsym(Obj *obj, long *index, Symbol *sym)
+{
+	return (*obj->ops->getsym)(obj, index, sym);
+}
--- a/src/libmach/libmach.h
+++ b/src/libmach/libmach.h
@@ -26,7 +26,7 @@
 /* common functions */
 extern int pack(int order, unsigned char *dst, char *fmt, ...);
 extern int unpack(int order, unsigned char *src, char *fmt, ...);
-extern void objdel(Obj *obj);
+extern int objpos(Obj *obj, FILE *fp, long pos);
 
 /* globals */
 extern Objops *objops[];
--- a/src/libmach/objaddseg.c
+++ /dev/null
@@ -1,9 +1,0 @@
-#include <stdio.h>
-
-#include <scc/mach.h>
-
-int
-objaddseg(Obj *obj, void *seg)
-{
-	return 0;
-}
--- a/src/libmach/objdel.c
+++ /dev/null
@@ -1,18 +1,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <scc/mach.h>
-
-#include "libmach.h"
-
-void
-objdel(Obj *obj)
-{
-	free(obj->secs);
-	free(obj->syms);
-
-	obj->syms = NULL;
-	obj->secs = NULL;
-	memset(obj->htab, 0, sizeof(obj->htab));
-}
--- a/src/libmach/objlookup.c
+++ /dev/null
@@ -1,35 +1,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <scc/mach.h>
-#include <scc/scc.h>
-
-Objsym *
-objlookup(Obj *obj, char *name, int install)
-{
-	unsigned h;
-	Objsym *sym;
-
-	h = genhash(name) % NR_SYMHASH;
-	for (sym = obj->htab[h]; sym; sym = sym->hash) {
-		if (!strcmp(name, sym->name))
-			return sym;
-	}
-	if (!install)
-		return NULL;
-
-	if ((sym = malloc(sizeof(*sym))) == NULL)
-		return NULL;
-
-	sym->name = name;
-	sym->type = 'U';
-	sym->size = 0;
-	sym->value = 0;
-	sym->hash = obj->htab[h];
-	obj->htab[h] = sym;
-	sym->next = obj->syms;
-	obj->syms = sym;
-
-	return sym;
-}
--- a/src/libmach/objnew.c
+++ b/src/libmach/objnew.c
@@ -21,12 +21,6 @@
 		return NULL;
 
 	obj->type = type;
-	obj->syms = NULL;
-	obj->secs = NULL;
-	obj->nsyms = 0;
-	obj->nsecs = 0;
-	memset(obj->htab, 0, sizeof(obj->htab));
-
 	ops = objops[fmt];
 	obj->ops = ops;
 
--- a/src/libmach/objtype.c
+++ b/src/libmach/objtype.c
@@ -22,7 +22,7 @@
 	for (opsp = objops; ops = *opsp; ++opsp) {
 		if ((*ops->probe)(buf, name) < 0)
 			continue;
-		return n;
+		return opsp - objops;
 	}
 
 	return -1;
--- /dev/null
+++ b/src/libmach/readobj.c
@@ -1,0 +1,15 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+int
+readobj(Obj *obj, FILE *fp)
+{
+	long off;
+
+	if ((off = ftell(fp)) == EOF)
+		return -1;
+	obj->pos = off;
+
+	return (*obj->ops->read)(obj, fp);
+}
--- a/tests/nm/execute/Makefile
+++ b/tests/nm/execute/Makefile
@@ -1,13 +1,12 @@
 .POSIX:
+ROOT=../../..
 
-ROOT=$(PROJECTDIR)/root
-
 OUT = z80.out
 
 all: tests
 
 tests: $(OUT)
-	@PATH=$(ROOT)/bin:$$PATH chktest.sh
+	@PATH=$(ROOT)/bin:$$PATH:. chktest.sh
 
 z80.out: master.s
 	z80-unknown-coff-as -o $@ master.s