scc

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

commit b7d29202339db11f3eb18a7a3d358e3f5a273ec7
parent acdc058a5a9605d42390a749966413ee3427f517
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Fri, 17 Jan 2025 15:58:10 +0100

libmach/coff32: Add support to read/write aux entries

Until this moment we were dealing aux entries like normal symbols,
assuming many, many things and it worked for the majority of the cases,
but it could be broken easily and it didn't allow new objects created
from scratch because we need a mechanism to define the correct value
of the different aux entries.

Diffstat:
Msrc/libmach/coff32/coff32.h | 22+++++++++++++++++++++-
Msrc/libmach/coff32/coff32getsym.c | 7++++++-
Msrc/libmach/coff32/coff32read.c | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/libmach/coff32/coff32setsym.c | 10++++++----
Msrc/libmach/coff32/coff32write.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
5 files changed, 399 insertions(+), 37 deletions(-)

diff --git a/src/libmach/coff32/coff32.h b/src/libmach/coff32/coff32.h @@ -6,13 +6,33 @@ #include <scc/coff32/linenum.h> #include <scc/coff32/storclass.h> +enum { + SYM_ENT, + SYM_AUX_UNK, + SYM_AUX_SYM, + SYM_AUX_FILE, + SYM_AUX_SCN, + SYM_AUX_FUN, + SYM_AUX_ARY, +}; + typedef struct coff32 Coff32; +typedef struct entry Entry; + +struct entry { + char type; + union { + SYMENT sym; + AUXENT aux; + unsigned char buf[AUXESZ]; + } u; +}; struct coff32 { FILHDR hdr; AOUTHDR aout; SCNHDR *scns; - SYMENT *ents; + Entry *ents; RELOC **rels; LINENO **lines; char *strtbl; diff --git a/src/libmach/coff32/coff32getsym.c b/src/libmach/coff32/coff32getsym.c @@ -67,6 +67,7 @@ Symbol * coff32getsym(Obj *obj, int *idx, Symbol *sym) { int n = *idx; + Entry *ep; SYMENT *ent; Coff32 *coff = obj->data; FILHDR *hdr = &coff->hdr; @@ -74,7 +75,11 @@ coff32getsym(Obj *obj, int *idx, Symbol *sym) if ((hdr->f_flags & F_LSYMS) != 0 || n >= coff->hdr.f_nsyms) return NULL; - ent = &coff->ents[n]; + ep = &coff->ents[n]; + if (ep->type != SYM_ENT) + return NULL; + ent = &ep->u.sym; + sym->name = symname(coff, ent); sym->type = typeof(coff, ent); sym->stype = SYMOBJECT; diff --git a/src/libmach/coff32/coff32read.c b/src/libmach/coff32/coff32read.c @@ -118,6 +118,96 @@ unpack_aout(int order, unsigned char *buf, AOUTHDR *aout) assert(n == AOUTSZ); } +static void +unpack_aux_file(int order, unsigned char *buf, AUXENT *aux) +{ + int n; + char *s; + + n = unpack(order, + buf, + "'18", + aux->x_fname); + assert(n == AUXESZ); + + s = aux->x_fname; + if (!s[0] && !s[1] && !s[2] && !s[3]) + unpack(order, buf, "ll", &aux->x_zeroes, &aux->x_offset); +} + +static void +unpack_aux_scn(int order, unsigned char *buf, AUXENT *aux) +{ + char dummy1, dummy2, dummy3; + int n; + + n = unpack(order, + buf, + "lsslscccc", + &aux->x_scnlen, + &aux->x_nreloc, + &aux->x_nlinno, + &aux->x_checksum, + &aux->x_associated, + &aux->x_comdat, + &dummy1, + &dummy2, + &dummy3); + assert(n == AUXESZ); +} + +static void +unpack_aux_fun(int order, unsigned char *buf, AUXENT *aux) +{ + int n; + + n = unpack(order, + buf, + "lllls", + &aux->x_tagndx, + &aux->x_fsize, + &aux->x_lnnoptr, + &aux->x_endndx, + &aux->x_tvndx); + assert(n == AUXESZ); +} + +static void +unpack_aux_ary(int order, unsigned char *buf, AUXENT *aux) +{ + int n; + + n = unpack(order, + buf, + "lssssss", + &aux->x_tagndx, + &aux->x_lnno, + &aux->x_size, + &aux->x_dimen[0], + &aux->x_dimen[1], + &aux->x_dimen[2], + &aux->x_dimen[3], + &aux->x_tvndx); + assert(n == AUXESZ); +} + +static void +unpack_aux_sym(int order, unsigned char *buf, AUXENT *aux) +{ + int n; + + n = unpack(order, + buf, + "lsslls", + &aux->x_tagndx, + &aux->x_lnno, + &aux->x_size, + &aux->x_lnnoptr, + &aux->x_endndx, + &aux->x_tvndx); + assert(n == AUXESZ); +} + static int readhdr(Obj *obj, FILE *fp) { @@ -132,6 +222,9 @@ readhdr(Obj *obj, FILE *fp) return 0; unpack_hdr(ORDER(obj->type), buf, hdr); + if (hdr->f_nsyms < 0 || hdr->f_nscns < 0) + return 0; + return 1; } @@ -217,12 +310,68 @@ readreloc(Obj *obj, FILE *fp) } static int -readents(Obj *obj, FILE *fp) +readauxs(Obj *obj, FILE *fp, SYMENT *ent, long pos) { + int i, n, typ, d1; + Entry *ep; FILHDR *hdr; struct coff32 *coff; - SYMENT *ent; + unsigned char buf[AUXESZ]; + + if ((n = ent->n_numaux) == 0) + return 1; + if (fread(buf, sizeof(buf), 1, fp) != 1) + return 0; + + coff = obj->data; + ep = &coff->ents[pos+1]; + typ = ent->n_type & 15; + d1 = (ent->n_type >> 4) & 15; + + switch (ent->n_sclass) { + case C_FILE: + ep->type = SYM_AUX_FILE; + unpack_aux_file(ORDER(obj->type), buf, &ep->u.aux); + break; + case C_STAT: + if (d1 == DT_NON && typ == T_NULL) { + ep->type = SYM_AUX_SCN; + unpack_aux_scn(ORDER(obj->type), buf, &ep->u.aux); + break; + } + default: + switch (d1) { + case DT_FCN: + ep->type = SYM_AUX_FUN; + unpack_aux_fun(ORDER(obj->type), buf, &ep->u.aux); + break; + case DT_ARY: + ep->type = SYM_AUX_ARY; + unpack_aux_ary(ORDER(obj->type), buf, &ep->u.aux); + break; + default: + ep->type = SYM_AUX_SYM; + unpack_aux_sym(ORDER(obj->type), buf, &ep->u.aux); + } + } + + for (++ep; --n > 0; ++ep) { + ep->type = SYM_AUX_UNK; + if (fread(ep->u.buf, AUXESZ, 1, fp) != 1) + return 0; + } + + return 1; +} + +static int +readents(Obj *obj, FILE *fp) +{ + int n; long i; + Entry *ep; + FILHDR *hdr; + struct coff32 *coff; unsigned char buf[SYMESZ]; coff = obj->data; @@ -231,19 +380,31 @@ readents(Obj *obj, FILE *fp) if (hdr->f_nsyms == 0) return 1; - ent = calloc(hdr->f_nsyms, sizeof(*ent)); - if (!ent) + ep = calloc(hdr->f_nsyms, sizeof(*ep)); + if (!ep) return 0; - coff->ents = ent; + coff->ents = ep; if (!objpos(obj, fp, hdr->f_symptr)) return 0; + for (i = 0; i < hdr->f_nsyms; i++) { + SYMENT *ent; + if (fread(buf, SYMESZ, 1, fp) != 1) return 0; - unpack_ent(ORDER(obj->type), buf, &ent[i]); + + ep = &coff->ents[i]; + ep->type = SYM_ENT; + ent = &ep->u.sym; + unpack_ent(ORDER(obj->type), buf, ent); if (ent->n_scnum > hdr->f_nscns) - return 0; + return 0; + + if (!readauxs(obj, fp, ent, i)) + return 0; + + i += ent->n_numaux; } return 1; @@ -341,13 +502,67 @@ readaout(Obj *obj, FILE *fp) return 1; } -int -coff32read(Obj *obj, FILE *fp) +static int +validate(Obj *obj) { - long i; + long i, n; + SYMENT *ent; struct coff32 *coff = obj->data; FILHDR *hdr = &coff->hdr; + ent = NULL; + for (i = 0; i < hdr->f_nsyms; i++) { + SCNHDR *scn; + AUXENT *aux; + Entry *ep = &coff->ents[i]; + + aux = &ep->u.aux; + switch (ep->type) { + case SYM_ENT: + ent = &ep->u.sym; + if (ent->n_zeroes != 0 && ent->n_offset > coff->strsiz) + return -1; + break; + case SYM_AUX_FILE: + if (aux->x_zeroes != 0 && aux->x_offset > coff->strsiz) + return -1; + break; + case SYM_AUX_SCN: + if (aux->x_scnlen < 0) + return -1; + n = ent->n_scnum; + if (n <= 0) + return -1; + scn = &coff->scns[n-1]; + if (scn->s_nrelloc != aux->x_nreloc) + return -1; + if (scn->s_nlnno != aux->x_nlinno) + return -1; + break; + case SYM_AUX_FUN: + case SYM_AUX_SYM: + if (aux->x_endndx < 0 || aux->x_endndx > hdr->f_nsyms) + return -1; + case SYM_AUX_ARY: + if (aux->x_tagndx < 0 || aux->x_tagndx > hdr->f_nsyms) + return -1; + if (aux->x_tvndx < 0 || aux->x_tvndx > hdr->f_nsyms) + return -1; + break; + case SYM_AUX_UNK: + break; + default: + return -1; + } + } + + return 0; +} + +int +coff32read(Obj *obj, FILE *fp) +{ + if (!readhdr(obj, fp)) return -1; if (!readaout(obj, fp)) @@ -363,11 +578,5 @@ coff32read(Obj *obj, FILE *fp) if (!readlines(obj, fp)) return -1; - 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; - } - - return 0; + return validate(obj); } diff --git a/src/libmach/coff32/coff32setsym.c b/src/libmach/coff32/coff32setsym.c @@ -78,7 +78,8 @@ Symbol * coff32setsym(Obj *obj, int *idx, Symbol *sym) { int n = *idx; - SYMENT *ent, *p; + Entry *ep; + SYMENT *ent; Coff32 *coff = obj->data; FILHDR *hdr = &coff->hdr; @@ -86,12 +87,13 @@ coff32setsym(Obj *obj, int *idx, Symbol *sym) if (n >= coff->hdr.f_nsyms) { if (n > LONG_MAX-1) return NULL; - if ((p = realloc(coff->ents, (n+1) * sizeof(*p))) == NULL) + if ((ep = realloc(coff->ents, (n+1) * sizeof(*ep))) == NULL) return NULL; - coff->ents = p; + coff->ents = ep; coff->hdr.f_nsyms = n+1; } - ent = &coff->ents[n]; + ep = &coff->ents[n]; + ent = &ep->u.sym; if (!symname(coff, ent, sym)) return NULL; diff --git a/src/libmach/coff32/coff32write.c b/src/libmach/coff32/coff32write.c @@ -74,6 +74,87 @@ pack_ent(int order, unsigned char *buf, SYMENT *ent) } static void +pack_aux_file(int order, unsigned char *buf, AUXENT *aux) +{ + + if (aux->x_zeroes == 0) { + memset(buf, 0, sizeof(AUXESZ)); + pack(order, buf, "ll", aux->x_zeroes, aux->x_offset); + } else { + memcpy(buf, aux->x_fname, E_FILNMLEN); + } +} + +static void +pack_aux_scn(int order, unsigned char *buf, AUXENT *aux) +{ + int n; + + n = pack(order, + buf, + "lsslsc", + aux->x_scnlen, + aux->x_nreloc, + aux->x_nlinno, + aux->x_checksum, + aux->x_associated, + aux->x_comdat); + assert(n == AUXESZ); +} + +static void +pack_aux_fun(int order, unsigned char *buf, AUXENT *aux) +{ + int n; + + n = pack(order, + buf, + "lllls", + aux->x_tagndx, + aux->x_fsize, + aux->x_lnnoptr, + aux->x_endndx, + aux->x_tvndx); + assert(n == AUXESZ); +} + +static void +pack_aux_ary(int order, unsigned char *buf, AUXENT *aux) +{ + int n; + + n = pack(order, + buf, + "lssssss", + aux->x_tagndx, + aux->x_lnno, + aux->x_size, + aux->x_dimen[0], + aux->x_dimen[1], + aux->x_dimen[2], + aux->x_dimen[3], + aux->x_tvndx); + assert(n == AUXESZ); +} + +static void +pack_aux_sym(int order, unsigned char *buf, AUXENT *aux) +{ + int n; + + n = pack(order, + buf, + "lsslls", + aux->x_tagndx, + aux->x_lnno, + aux->x_size, + aux->x_lnnoptr, + aux->x_endndx, + aux->x_tvndx); + assert(n == AUXESZ); +} + +static void pack_aout(int order, unsigned char *buf, AOUTHDR *aout) { int n; @@ -160,6 +241,29 @@ writescns(Obj *obj, FILE *fp) } static int +allocstring(struct coff32 *coff, long off, char **tbl, long *psiz) +{ + char *s, *name; + long len, siz; + + siz = *psiz; + name = &coff->strtbl[off]; + len = strlen(name) + 1; + if (len > siz - LONG_MAX) + return 0; + + s = realloc(*tbl, siz + len); + if (!s) + return 0; + memcpy(s + siz, name, len); + + *tbl = s; + *psiz += len; + + return 1; +} + +static int writeents(Obj *obj, FILE *fp) { long i, len, strsiz; @@ -178,22 +282,44 @@ writeents(Obj *obj, FILE *fp) strsiz = 0; for (i = 0; i < hdr->f_nsyms; i++) { - SYMENT *ent = &coff->ents[i]; - - if (ent->n_zeroes == 0) { - name = &coff->strtbl[ent->n_offset]; - len = strlen(name) + 1; - if (len > strsiz - LONG_MAX) - goto err; - s = realloc(strtbl, strsiz + len); - if (!s) - goto err; - memcpy(s + strsiz, name, len); - strtbl = s; - strsiz += len; + SYMENT *ent; + AUXENT *aux; + Entry *ep = &coff->ents[i]; + + aux = &ep->u.aux; + switch (ep->type) { + case SYM_ENT: + ent = &ep->u.sym; + if (ent->n_zeroes == 0) { + if (!allocstring(coff, ent->n_offset, &strtbl, &strsiz)) + goto err; + } + pack_ent(ORDER(obj->type), buf, ent); + break; + case SYM_AUX_UNK: + memcpy(buf, ep->u.buf, AUXESZ); + break; + case SYM_AUX_SYM: + pack_aux_file(ORDER(obj->type), buf, aux); + break; + case SYM_AUX_FILE: + if (aux->x_zeroes == 0) { + if (!allocstring(coff, aux->x_offset, &strtbl, &strsiz)) + goto err; + } + pack_aux_file(ORDER(obj->type), buf, aux); + break; + case SYM_AUX_SCN: + pack_aux_scn(ORDER(obj->type), buf, aux); + break; + case SYM_AUX_FUN: + pack_aux_fun(ORDER(obj->type), buf, aux); + break; + case SYM_AUX_ARY: + pack_aux_ary(ORDER(obj->type), buf, aux); + break; } - pack_ent(ORDER(obj->type), buf, ent); if (fwrite(buf, SYMESZ, 1, fp) != 1) return 0; }