scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

commit 34254b681ccacb54e48648f9137a6baffbb3807c
parent 5adb9664d4c43d1f155907fc8c7abdc50750b6f1
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Mon, 12 Mar 2018 11:53:45 +0100

[nm] Implement coff symbol listing

Diffstat:
Minc/coff32/filehdr.h | 3+++
Minc/coff32/scnhdr.h | 8+++-----
Minc/coff32/syms.h | 8++++++--
Minc/scc.h | 2++
Mnm/Makefile | 8++++++--
Dnm/coff.c | 21---------------------
Anm/coff32.c | 308+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mnm/formats.c | 5++---
Mnm/main.c | 41+++++++++++++++++++++++------------------
Mnm/nm.h | 6+++---
10 files changed, 356 insertions(+), 54 deletions(-)

diff --git a/inc/coff32/filehdr.h b/inc/coff32/filehdr.h @@ -18,5 +18,8 @@ struct filehdr { #define F_EXEC (1 << 1) #define F_LMNO (1 << 2) #define F_SYMS (1 << 3) +#define F_AR16WR (1 << 4) +#define F_AR32WR (1 << 5) +#define F_A32WR (1 << 6) #define COFF_Z80MAGIC 0x805a diff --git a/inc/coff32/scnhdr.h b/inc/coff32/scnhdr.h @@ -26,11 +26,9 @@ struct scnhdr { #define STYP_PAD (1 << 3) #define STYP_COPY (1 << 4) #define STYP_TEXT (1 << 5) -#define S_SHRSEG (1 << 6) -#define STYP_DATA (1 << 7) -#define STYP_BSS (1 << 8) -#define S_NEWFCN (1 << 9) -#define STYP_INFO (1 << 10) +#define STYP_DATA (1 << 6) +#define STYP_BSS (1 << 7) +#define STYP_INFO (1 << 9) #define STYP_OVER (1 << 11) #define STYP_LIB (1 << 12) #define STYP_MERGE (1 << 13) diff --git a/inc/coff32/syms.h b/inc/coff32/syms.h @@ -1,6 +1,8 @@ /* This file is inspired in the book "Understanding and using COFF" */ +#define E_SYMNMLEN 8 + struct syment { union { char _n_name[8]; /* symbol name */ @@ -8,7 +10,6 @@ struct syment { long _n_zeroes; /* if _n_name[0-3] == 0 */ long _n_offset; /* offset into string table */ } _n_n; - char _n_ptr[2]; /* allows for overlaying */ } _n; long n_value; /* value of symbol */ short n_scnum; /* section number */ @@ -17,8 +18,10 @@ struct syment { char n_numaux; /* number of aux. entries */ }; +#define SYMENT struct syment +#define SYMESZ 18 + #define n_name _n._n_name -#define n_nptr _n._n_nptr[1] #define n_zeroes _n._n_n._n_zeroes #define n_offset _n._n_n._n_offset @@ -26,6 +29,7 @@ struct syment { #define N_DEBUG -2 #define N_ABS -1 #define N_UNDEF 0 +#define N_SCNUM(x) ((x) > 0) /* basic types */ #define T_NULL 0 diff --git a/inc/scc.h b/inc/scc.h @@ -37,3 +37,5 @@ extern void delete(Alloc *allocp, void *p); extern int casecmp(const char *s1, const char *s2); extern int lpack(unsigned char *dst, char *fmt, ...); extern int lunpack(unsigned char *src, char *fmt, ...); +extern int bpack(unsigned char *dst, char *fmt, ...); +extern int bunpack(unsigned char *src, char *fmt, ...); diff --git a/nm/Makefile b/nm/Makefile @@ -5,12 +5,16 @@ LIBDIR = $(PROJECTDIR)/lib/scc include $(PROJECTDIR)/rules.mk include $(LIBDIR)/libdep.mk -OBJ = main.o coff.o formats.o +OBJ = main.o coff32.o formats.o all: nm main.o: $(INCDIR)/scc.h $(INCDIR)/ar.h $(INCDIR)/arg.h nm.h -coff.o: nm.h +coff32.o: nm.h +coff32.o: ../inc/coff32/filehdr.h +coff32.o: ../inc/coff32/scnhdr.h +coff32.o: ../inc/coff32/syms.h +coff32.o: ../inc/scc.h formats.o: nm.h nm: $(OBJ) $(LIBDIR)/libscc.a diff --git a/nm/coff.c b/nm/coff.c @@ -1,21 +0,0 @@ - -static char sccsid[] = "@(#) ./nm/coff.c"; - -#include <stdio.h> - -#include "nm.h" - -static void -nm(char *fname, FILE *fp) -{ -} - -static int -probe(FILE *fp) -{ -} - -struct objfile coff = { - .probe = probe, - .nm = nm, -}; diff --git a/nm/coff32.c b/nm/coff32.c @@ -0,0 +1,308 @@ + +static char sccsid[] = "@(#) ./nm/coff.c"; + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../inc/coff32/filehdr.h" +#include "../inc/coff32/scnhdr.h" +#include "../inc/coff32/syms.h" +#include "../inc/scc.h" +#include "nm.h" + +static int (*unpack)(unsigned char *, char *, ...); +static long stringtbl; +static SCNHDR *sections; +static struct symbol *syms; +static size_t nsect, nsyms; + +static char +typeof(SYMENT *ent) +{ + SCNHDR *sec; + int c; + long flags; + char **bp; + + switch (ent->n_scnum) { + case N_DEBUG: + c = '?'; + break; + case N_ABS: + c = 'A'; + break; + case N_UNDEF: + c = 'U'; + break; + default: + if (ent->n_scnum > nsect) + die("nm:incorrect section index"); + sec = &sections[ent->n_scnum-1]; + flags = sec->s_flags; + if (flags & STYP_TEXT) + c = 't'; + else if (flags & STYP_DATA) + c = 'd'; + else if (flags & STYP_BSS) + c = 'b'; + else + c = '?'; + + if (ent->n_sclass == C_EXT) + c = toupper(c); + + break; + } + return c; +} + +static char * +getsname(FILE *fp, SYMENT *ent) +{ + int c; + size_t len; + char *s; + fpos_t pos; + + if (ent->n_zeroes != 0) { + for (len = 0; len < E_SYMNMLEN && ent->n_name[len]; ++len) + ; + s = xmalloc(len+1); + s[len] = '\0'; + return memcpy(s, ent->n_name, len); + } + + + fgetpos(fp, &pos); + fseek(fp, stringtbl, SEEK_SET); + fseek(fp, ent->n_offset, SEEK_CUR); + + if (ferror(fp)) + goto error; + + s = xmalloc(1); + for (len = 0; (c = getc(fp)) != '\0'; len++) { + if (c == EOF) + goto error; + s = xrealloc(s, len+1); + s[len] = c; + } + s[len] = '\0'; + fsetpos(fp, &pos); + return s; + +error: + fprintf(stderr, + "nm::%s\n", + (ferror(fp)) ? strerror(errno) : "broken string table"); + exit(1); +} + +static void +getfsym(unsigned char *buff, SYMENT *ent) +{ + int n; + + n = (*unpack)(buff, + "'8lsscc", + &ent->n_name, + &ent->n_value, + &ent->n_scnum, + &ent->n_type, + &ent->n_sclass, + &ent->n_numaux); + assert(n == SYMESZ); +} + +static void +getsymbol(FILE *fp, unsigned char *buff, SYMENT *ent, struct symbol *sym) +{ + char *nam; + + getfsym(buff, ent); + nam = ent->n_name; + if (nam[0] == 0 && nam[1] == 0 && nam[2] == 0 && nam[3] == 0) { + long zero, offset; + + (*unpack)(nam, "ll", &zero, &offset); + ent->n_zeroes = zero; + ent->n_offset = offset; + } + sym->name = getsname(fp, ent); + sym->type = typeof(ent); + sym->value = ent->n_value; +} + +static void +getsyms(char *fname, char *member, FILE *fp, FILHDR *hdr) +{ + size_t n, i; + unsigned aux; + unsigned char buff[SYMESZ]; + SYMENT ent; + + if (hdr->f_nsyms > SIZE_MAX) + die("nm:%s:Too many symbols\n", member); + + n = hdr->f_nsyms; + syms = xcalloc(sizeof(*syms), n); + + if (fseek(fp, hdr->f_symptr, SEEK_SET) == EOF) + die("nm:%s:%s", member, strerror(errno)); + + aux = nsyms = 0; + for (i = 0; i < n; i++) { + if (fread(buff, SYMESZ, 1, fp) != 1) + break; + if (aux > 0) { + aux--; + continue; + } + getsymbol(fp, buff, &ent, &syms[nsyms++]); + aux = ent.n_numaux; + } + if (n != i) { + die("nm:%s:%s", + member, + (ferror(fp)) ? strerror(errno) : "EOF before reading symbols"); + } +} + +static void +getfsec(unsigned char *buff, SCNHDR *sec) +{ + int n; + + n = (*unpack)(buff, + "'8llllllssl", + sec->s_name, + &sec->s_paddr, + &sec->s_vaddr, + &sec->s_size, + &sec->s_scnptr, + &sec->s_relptr, + &sec->s_lnnoptr, + &sec->s_nrelloc, + &sec->s_nlnno, + &sec->s_flags); + assert(n == SCNHSZ); +} + +static void +getsects(char *fname, char *member, FILE *fp, FILHDR *hdr) +{ + size_t i; + char buff[SCNHSZ]; + + nsect = hdr->f_nscns; + if (nsect == 0) + return; + + if (nsect > SIZE_MAX) + die("nm:%s:Too many sections\n", member); + + if (fseek(fp, FILHSZ + hdr->f_opthdr, SEEK_SET) == EOF) + die("nm:%s:%s", member, strerror(errno)); + + sections = xcalloc(sizeof(*sections), nsect); + for (i = 0; i < nsect; i++) { + if (fread(buff, SCNHSZ, 1, fp) != 1) + break; + getfsec(buff, &sections[i]); + } + if (i != nsect) { + fprintf(stderr, + "nm:%s:%s\n", + member, + (ferror(fp)) ? strerror(errno) : "EOF before reading sections"); + exit(1); + } +} + +static void +getfhdr(unsigned char *buff, FILHDR *hdr) +{ + int n; + + n = (*unpack)(buff, + "sslllss", + &hdr->f_magic, + &hdr->f_nscns, + &hdr->f_timdat, + &hdr->f_symptr, + &hdr->f_nsyms, + &hdr->f_opthdr, + &hdr->f_flags); + assert(n == FILHSZ); +} + +static void +nm(char *fname, char *member, FILE *fp) +{ + unsigned char buff[FILHSZ]; + FILHDR hdr; + unsigned magic; + + if (fread(buff, FILHSZ, 1, fp) != 1) + return; + + magic = buff[0] | buff[1] << 8; + + switch (magic) { + case COFF_Z80MAGIC: + unpack = lunpack; + break; + default: + abort(); + } + + getfhdr(buff, &hdr); + if ((hdr.f_flags & F_SYMS) != 0 || hdr.f_nsyms == 0) { + fprintf(stderr, "nm: %s: no symbols\n", member); + return; + } + + stringtbl = hdr.f_symptr + hdr.f_nsyms* SYMESZ; + + getsects(fname, member, fp, &hdr); + getsyms(fname, member, fp, &hdr); + printsyms(fname, member, syms, nsyms); + + free(sections); + free(syms); +} + +static int +probe(FILE *fp) +{ + int c; + int c1, c2; + fpos_t pos; + static unsigned short magic; + + fgetpos(fp, &pos); + c1 = getc(fp); + c2 = getc(fp); + fsetpos(fp, &pos); + + if (c1 == EOF || c2 == EOF) + return 0; + magic = c1 | c2 << 8; + + switch (magic) { + case COFF_Z80MAGIC: + return 1; + default: + return 0; + } +} + +struct objfile coff32 = { + .probe = probe, + .nm = nm, +}; diff --git a/nm/formats.c b/nm/formats.c @@ -5,11 +5,10 @@ static char sccsid[] = "@(#) ./nm/probe.c"; #include "nm.h" -struct objfile coff; - /* TODO: Autogenerate this file */ +struct objfile coff32; struct objfile *formats[] = { - &coff, + &coff32, NULL, }; diff --git a/nm/main.c b/nm/main.c @@ -23,16 +23,20 @@ static int uflag; static int arflag; int -object(char *fname, FILE *fp) +object(char *fname, char *member, FILE *fp) { - extern struct objfile formats[]; - struct objfile *p; + extern struct objfile *formats[]; + struct objfile **p, *obj; + void *data; - for (p = formats; p->probe && (*p->probe)(fp); ++p) - ; - if (!p->probe) + for (p = formats; *p; ++p) { + obj = *p; + if ((*obj->probe)(fp)) + break; + } + if (*p == NULL) return 0; - (*p->nm)(fname, fp); + (*obj->nm)(fname, member, fp); return 1; } @@ -65,7 +69,7 @@ ar(char *fname, FILE *fp) while (fread(&hdr, sizeof(hdr), 1, fp) == 1) { pos = ftell(fp); - if (strncmp(hdr.ar_fmag, ARFMAG, strlen(ARFMAG))) + if (strncmp(hdr.ar_fmag, ARFMAG, SARMAG)) goto corrupted; siz = 0; @@ -84,7 +88,7 @@ ar(char *fname, FILE *fp) pos += siz; getfname(&hdr, member); - if (!object(member, fp)) { + if (!object(member, member, fp)) { fprintf(stderr, "nm: skipping member %s in archive %s\n", member, fname); @@ -108,22 +112,23 @@ archive(char *fname, FILE *fp) fread(magic, SARMAG, 1, fp); fsetpos(fp, &pos); - if (ferror(fp)) { - perror("nm"); - exit(1); - } + if (ferror(fp)) + return 0; if (strncmp(magic, ARMAG, SARMAG) != 0) return 0; + ar(fname, fp); return 1; } -void +static void print(char *file, char *member, struct symbol *sym) { char *fmt; int type = sym->type; + if (type == '?') + return; if (uflag && type != 'U') return; if (gflag && type != 'A' && type != 'B' && type != 'D') @@ -140,7 +145,7 @@ print(char *file, char *member, struct symbol *sym) fmt = "%llu %llu"; else fmt = "%llx %llx"; - printf(fmt, sym->off, sym->size); + printf(fmt, sym->value, sym->size); } } else { if (type == 'U') @@ -151,7 +156,7 @@ print(char *file, char *member, struct symbol *sym) fmt = "%016.16lld"; else fmt = "%016.16llx"; - printf(fmt, sym->off); + printf(fmt, sym->value); printf(" %c %s", sym->type, sym->name); } putchar('\n'); @@ -163,7 +168,7 @@ cmp(const void *p1, const void *p2) const struct symbol *s1 = p1, *s2 = p2; if (vflag) - return s1->off - s2->off; + return s1->value - s2->value; else return strcmp(s1->name, s2->name); } @@ -188,7 +193,7 @@ doit(char *fname) exit(1); } - if (!object(fname, fp) && !archive(fname, fp)) + if (!object(fname, fname, fp) && !archive(fname, fp)) fprintf(stderr, "nm: %s: File format not recognized\n", fname); if (ferror(fp) || fclose(fp) == EOF) { diff --git a/nm/nm.h b/nm/nm.h @@ -2,14 +2,14 @@ struct symbol { char *name; int type; - unsigned long long off; + unsigned long long value; unsigned long size; }; struct objfile { int (*probe)(FILE *fp); - void (*nm)(char *fname, FILE *fp); + void (*nm)(char *fname, char *member, FILE *fp); }; /* main.c */ -extern void print(char *file, char *member, struct symbol *sym); +extern void printsyms(char *, char *, struct symbol *, size_t );