From 1e5b102109356a96b3c81187101d3858989ebf59 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 3 Jul 2009 15:30:48 -0700 Subject: [PATCH] rdf2bin: revamp so it can output bin, ith, or srec Revamp rdf2bin so it can output binary, Intel hex, or Motorola S-records. Signed-off-by: H. Peter Anvin --- rdoff/Makefile.in | 10 +- rdoff/rdf2bin.c | 370 ++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 313 insertions(+), 67 deletions(-) diff --git a/rdoff/Makefile.in b/rdoff/Makefile.in index 2ceb9548..78483fa7 100644 --- a/rdoff/Makefile.in +++ b/rdoff/Makefile.in @@ -37,7 +37,7 @@ O = @OBJEXT@ X = @EXEEXT@ PROGRAMS = rdfdump$(X) ldrdf$(X) rdx$(X) rdflib$(X) \ - rdf2bin$(X) rdf2com$(X) rdf2ihx$(X) + rdf2bin$(X) rdf2com$(X) rdf2ith$(X) rdf2ihx$(X) rdf2srec$(X) .SUFFIXES: .c .i .s .$(O) .1 .man @@ -58,8 +58,12 @@ rdf2bin$(X): rdf2bin.$(O) $(RDXLIBS) nasmlib.$(O) $(CC) $(LDFLAGS) -o rdf2bin$(X) rdf2bin.$(O) $(RDXLIBS) nasmlib.$(O) rdf2com$(X): rm -f rdf2com$(X) && $(LN_S) rdf2bin$(X) rdf2com$(X) -rdf2ihx$(X): rdf2ihx.$(O) $(RDXLIBS) nasmlib.$(O) - $(CC) $(LDFLAGS) -o rdf2ihx$(X) rdf2ihx.$(O) $(RDXLIBS) nasmlib.$(O) +rdf2ith$(X): + rm -f rdf2ith$(X) && $(LN_S) rdf2bin$(X) rdf2ith$(X) +rdf2ihx$(X): + rm -f rdf2ihx$(X) && $(LN_S) rdf2bin$(X) rdf2ith$(X) +rdf2srec$(X): + rm -f rdf2ihx$(X) && $(LN_S) rdf2bin$(X) rdf2srec$(X) rdf2ihx.$(O): rdf2ihx.c rdf2bin.$(O): rdf2bin.c diff --git a/rdoff/rdf2bin.c b/rdoff/rdf2bin.c index e01b36d5..22820634 100644 --- a/rdoff/rdf2bin.c +++ b/rdoff/rdf2bin.c @@ -40,24 +40,240 @@ #include #include #include +#include +#include #include "rdfload.h" #include "nasmlib.h" -int32_t origin = 0; -int align = 16; +const char *progname; -char *getfilename(char *pathname) +static uint32_t origin = 0; +static bool origin_def = false; +static uint32_t align = 16; +static bool align_def = false; + +struct output_format { + const char *name; + const char *mode; + int (*init)(FILE *f); + int (*output)(FILE *f, void *data, uint32_t bytes, uint32_t where); + int (*fini)(FILE *f); +}; + +static int null_init_fini(FILE *f) +{ + (void)f; + return 0; +} + +static int com_init(FILE *f) +{ + (void)f; + if (!origin_def) + origin = 0x100; + return 0; +} + +static int output_bin(FILE *f, void *data, uint32_t bytes, uint32_t where) +{ + static uint32_t offset = 0; /* Current file offset, if applicable */ + size_t pad; + + if (where-origin < offset) { + fprintf(stderr, "%s: internal error: backwards movement\n", progname); + exit(1); + } + + pad = (where-origin) - offset; + if (fwritezero(pad, f) != pad) + return -1; + offset += pad; + + if (fwrite(data, 1, bytes, f) != bytes) + return -1; + offset += bytes; + + return 0; +} + +static int write_ith_record(FILE *f, unsigned int len, uint16_t addr, + uint8_t type, void *data) +{ + char buf[1+2+4+2+255*2+2+2]; + char *p = buf; + uint8_t csum, *dptr = data; + unsigned int i; + + if (len > 255) { + fprintf(stderr, "%s: internal error: invalid ith record size\n", + progname); + exit(1); + } + + csum = len + addr + (addr >> 8) + type; + for (i = 0; i < len; i++) + csum += dptr[i]; + csum = -csum; + + p += sprintf(p, ":%02X%04X%02X", len, addr, type); + for (i = 0; i < len; i++) + p += sprintf(p, "%02X", dptr[i]); + p += sprintf(p, "%02X\n", csum); + + if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf)) + return -1; + + return 0; +} + +static int output_ith(FILE *f, void *data, uint32_t bytes, uint32_t where) { - char *lastslash = pathname - 1; - char *i = pathname; + static uint32_t last = 0; /* Last address written */ + uint8_t abuf[2]; + uint8_t *dbuf = data; + uint32_t chunk; + + while (bytes) { + if ((where ^ last) & ~0xffff) { + abuf[0] = where >> 24; + abuf[1] = where >> 16; + if (write_ith_record(f, 2, 0, 4, abuf)) + return -1; + } + + /* Output up to 32 bytes, but always end on an aligned boundary */ + chunk = 32 - (where & 31); + if (bytes < chunk) + chunk = bytes; - while (*i) { - if (*i == '/') - lastslash = i; - i++; + if (write_ith_record(f, chunk, (uint16_t)where, 0, dbuf)) + return -1; + + dbuf += chunk; + last = where + chunk - 1; + where += chunk; + bytes -= chunk; } - return lastslash + 1; + return 0; +} + +static int fini_ith(FILE *f) +{ + /* XXX: entry point? */ + return write_ith_record(f, 0, 0, 1, NULL); +} + +static int write_srecord(FILE *f, unsigned int len, unsigned int alen, + uint32_t addr, uint8_t type, void *data) +{ + char buf[2+2+8+255*2+2+2]; + char *p = buf; + uint8_t csum, *dptr = data; + unsigned int i; + + if (len > 255) { + fprintf(stderr, "%s: internal error: invalid srec record size\n", + progname); + exit(1); + } + + switch (alen) { + case 2: + addr &= 0xffff; + break; + case 3: + addr &= 0xffffff; + break; + case 4: + break; + default: + fprintf(stderr, "%s: internal error: invalid srec address length\n", + progname); + exit(1); + } + + csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24); + for (i = 0; i < len; i++) + csum += dptr[i]; + csum = 0xff-csum; + + p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr); + for (i = 0; i < len; i++) + p += sprintf(p, "%02X", dptr[i]); + p += sprintf(p, "%02X\n", csum); + + if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf)) + return -1; + + return 0; +} + +static int init_srec(FILE *f) +{ + return write_srecord(f, 0, 2, 0, '0', NULL); +} + +static int fini_srec(FILE *f) +{ + /* XXX: entry point? */ + return write_srecord(f, 0, 4, 0, '7', NULL); +} + +static int output_srec(FILE *f, void *data, uint32_t bytes, uint32_t where) +{ + uint8_t *dbuf = data; + unsigned int chunk; + + while (bytes) { + /* Output up to 32 bytes, but always end on an aligned boundary */ + chunk = 32 - (where & 31); + if (bytes < chunk) + chunk = bytes; + + if (write_srecord(f, chunk, 4, where, '3', dbuf)) + return -1; + + dbuf += chunk; + where += chunk; + bytes -= chunk; + } + return 0; +} + +static struct output_format output_formats[] = { + { "bin", "wb", null_init_fini, output_bin, null_init_fini }, + { "com", "wb", com_init, output_bin, null_init_fini }, + { "ith", "wt", null_init_fini, output_ith, fini_ith }, + { "ihx", "wt", null_init_fini, output_ith, fini_ith }, + { "srec", "wt", init_srec, output_srec, fini_srec }, + { NULL, NULL, NULL, NULL, NULL } +}; + +static const char *getformat(const char *pathname) +{ + const char *p; + + /* Search backwards for the first non-alphabetic character */ + + for (p = strchr(pathname, '\0')-1 ; p >= pathname ; p--) { + if (!isalpha(*p)) + break; + } + return p+1; +} + +static void usage(void) +{ + fprintf(stderr, + "Usage: %s [options] input-file output-file\n" + "Options:\n" + " -o origin Specify the relocation origin\n" + " -p alignment Specify minimum segment alignment\n" + " -f format Select format (bin, com, ith, srec)\n" + " -q Run quiet\n" + " -v Run verbose\n", + progname); } int main(int argc, char **argv) @@ -65,58 +281,91 @@ int main(int argc, char **argv) rdfmodule *m; bool err; FILE *of; - char *padding; - int codepad, datapad, bsspad = 0; + int codepad, datapad; + const char *format = NULL; + const struct output_format *fmt; + bool quiet = false; + + progname = argv[0]; if (argc < 2) { - puts("Usage: rdf2bin [-o relocation-origin] [-p segment-alignment] " "input-file output-file"); - puts(" rdf2com [-p segment-alignment] input-file output-file"); + usage(); return 1; } - if (!nasm_stricmp(getfilename(*argv), "rdf2com")) { - origin = 0x100; - } argv++, argc--; while (argc > 2) { - if (!strcmp(*argv, "-o")) { - argv++, argc--; - origin = readnum(*argv, &err); - if (err) { - fprintf(stderr, "rdf2bin: invalid parameter: %s\n", *argv); - return 1; - } - } else if (!strcmp(*argv, "-p")) { - argv++, argc--; - align = readnum(*argv, &err); - if (err) { - fprintf(stderr, "rdf2bin: invalid parameter: %s\n", *argv); - return 1; - } - } else if (!strcmp(*argv, "-b")) { - argv++, argc--; - bsspad = readnum(*argv, &err); - if (err) { - fprintf(stderr, "rdf2bin: invalid parameter: %s\n", *argv); - return 1; - } - } else - break; - + if (argv[0][0] == '-' && argv[0][1] && !argv[0][2]) { + switch (argv[0][1]) { + case 'o': + argv++, argc--; + origin = readnum(*argv, &err); + if (err) { + fprintf(stderr, "%s: invalid parameter: %s\n", + progname, *argv); + return 1; + } + origin_def = true; + break; + case 'p': + argv++, argc--; + align = readnum(*argv, &err); + if (err) { + fprintf(stderr, "%s: invalid parameter: %s\n", + progname, *argv); + return 1; + } + align_def = true; + break; + case 'f': + argv++, argc--; + format = *argv; + break; + case 'q': + quiet = true; + break; + case 'v': + quiet = false; + break; + case 'h': + usage(); + return 0; + default: + fprintf(stderr, "%s: unknown option: %s\n", + progname, *argv); + return 1; + } + } argv++, argc--; } + if (argc < 2) { - puts("rdf2bin: required parameter missing"); - return -1; + usage(); + return 1; } + + if (!format) + format = getformat(progname); + for (fmt = output_formats; fmt->name; fmt++) { + if (!nasm_stricmp(format, fmt->name)) + break; + } + if (!fmt->name) { + fprintf(stderr, "%s: unknown output format: %s\n", progname, format); + return -1; + } + m = rdfload(*argv); if (!m) { - rdfperror("rdf2bin", *argv); + rdfperror(progname, *argv); return 1; } - printf("relocating %s: origin=%"PRIx32", align=%d\n", *argv, origin, align); + + if (!quiet) + printf("relocating %s: origin=%"PRIx32", align=%d\n", + *argv, origin, align); m->textrel = origin; m->datarel = origin + m->f.seg[0].length; @@ -133,37 +382,30 @@ int main(int argc, char **argv) } else datapad = 0; - printf("code: %08"PRIx32"\ndata: %08"PRIx32"\nbss: %08"PRIx32"\n", - m->textrel, m->datarel, m->bssrel); + if (!quiet) + printf("code: %08"PRIx32"\ndata: %08"PRIx32"\nbss: %08"PRIx32"\n", + m->textrel, m->datarel, m->bssrel); rdf_relocate(m); argv++; - of = fopen(*argv, "wb"); + of = fopen(*argv, fmt->mode); if (!of) { - fprintf(stderr, "rdf2bin: could not open output file %s\n", *argv); + fprintf(stderr, "%s: could not open output file %s: %s\n", + progname, *argv, strerror(errno)); return 1; } - padding = malloc(align); - if (!padding) { - fprintf(stderr, "rdf2bin: out of memory\n"); + if (fmt->init(of) || + fmt->output(of, m->t, m->f.seg[0].length, m->textrel) || + fmt->output(of, m->d, m->f.seg[1].length, m->datarel) || + fmt->fini(of)) { + fprintf(stderr, "%s: error writing to %s: %s\n", + progname, *argv, strerror(errno)); return 1; } - if (fwrite(m->t, 1, m->f.seg[0].length, of) != (size_t)m->f.seg[0].length || - fwrite(padding, 1, codepad, of) != (size_t)codepad || - fwrite(m->d, 1, m->f.seg[1].length, of) != (size_t)m->f.seg[1].length) { - fprintf(stderr, "rdf2bin: error writing to %s\n", *argv); - return 1; - } - - if (bsspad) { - void *p = calloc(bsspad -= (m->bssrel - origin), 1); - fwrite(p, 1, bsspad, of); - } - fclose(of); return 0; } -- 2.11.4.GIT