ref: 8b7b6ff1b717db376f32510ac62b89a822015050
dir: /ld/coff32.c/
static char sccsid[] = "@(#) ./ld/coff32.c"; #include <assert.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 "ld.h" static int (*unpack)(unsigned char *, char *, ...); static FILHDR * 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); return hdr; } static int readstr(Obj *obj, long off) { unsigned char buff[4]; char *str; size_t siz; if (fseek(obj->fp, off, SEEK_SET) == EOF) return -1; if (fread(buff, 4, 1, obj->fp) != 1) return -1; (*unpack)(buff, "l", &siz); if (siz > SIZE_MAX || (str = malloc(siz)) == NULL) outmem(); if (fread(str, siz, 1, obj->fp) != 1) return -1; obj->strtbl = str; return 0; } static SCNHDR * getscn(unsigned char *buff, SCNHDR *scn) { int n; n = (*unpack)(buff, "'8llllllssl", scn->s_name, &scn->s_paddr, &scn->s_vaddr, &scn->s_size, &scn->s_scnptr, &scn->s_relptr, &scn->s_lnnoptr, &scn->s_nrelloc, &scn->s_nlnno, &scn->s_flags); assert(n == SCNHSZ); return scn; } static int readsects(Obj *obj, long off) { unsigned nsec, i; unsigned char buff[SCNHSZ]; SCNHDR *scn; FILHDR *hdr; hdr = obj->filhdr; nsec = hdr->f_nscns; if (nsec > SIZE_MAX / sizeof(*scn)) return -1; if ((scn = malloc(nsec * sizeof(*scn))) == NULL) return -1; if (fseek(obj->fp, off, SEEK_SET) == EOF) return -1; for (i = 0; i < nsec; i++) { if (fread(buff, SCNHSZ, 1, obj->fp) != 1) return -1; getscn(buff, &scn[i]); } obj->scnhdr = scn; return 0; } static void getsym(unsigned char *buff, SYMENT *ent) { int n; long off, zero; char *name; 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); name = ent->n_name; if (!name[0] && !name[1] && !name[2] && !name[3]) (*unpack)(buff, "ll", &ent->n_zeroes, &ent->n_offset); } static int readsyms(Obj *obj, long off) { unsigned i, nsym; unsigned char buff[SYMESZ]; SYMENT *ent; FILHDR *hdr; hdr = obj->filhdr; nsym = hdr->f_nsyms; if (nsym > SIZE_MAX / sizeof(*ent)) return -1; if ((ent = malloc(nsym * sizeof(*ent))) == NULL) outmem(); if (fseek(obj->fp, off, SEEK_SET) == EOF) return -1; for (i = 0; i < nsym; i++) { if (fread(buff, SYMESZ, 1, obj->fp) != 1) return -1; getsym(buff, &ent[i]); } obj->enthdr = ent; return 0; } static void readobj(Obj *obj) { unsigned char buff[FILHSZ]; FILHDR *hdr; char *strtbl; long symoff, secoff, stroff, pos; pos = ftell(obj->fp); if (fread(buff, FILHSZ, 1, obj->fp) != 1) goto bad_file; if ((hdr = malloc(sizeof(*hdr))) == NULL) outmem(); getfhdr(buff, hdr); obj->filhdr = hdr; /* TODO: Check overflow */ stroff = pos + hdr->f_symptr + hdr->f_nsyms*SYMESZ; symoff = pos + hdr->f_symptr; secoff = pos + FILHSZ + hdr->f_opthdr; if (readstr(obj, stroff) < 0) goto bad_file; if (readsyms(obj, symoff) < 0) goto bad_file; if (readsects(obj, secoff) < 0) goto bad_file; return; bad_file: if (ferror(obj->fp)) die("ld: %s: %s", obj->fname, strerror(errno)); die("ld: %s: corrupted file", obj->fname); } static void pass1(char *fname, char *member, FILE *fp) { Obj *obj; obj = newobj(fname, member); obj->fp = fp; readobj(obj); } static void pass2(char *fname, char *member, FILE *fp) { } static int probe(char *fname, char *member, FILE *fp) { int c; int c1, c2; fpos_t pos; unsigned short magic; fgetpos(fp, &pos); c1 = getc(fp); c2 = getc(fp); fsetpos(fp, &pos); if (ferror(fp)) die("ld: %s: %s", fname, strerror(errno)); 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, .pass1 = pass1, .pass2 = pass2, };