summaryrefslogtreecommitdiff
path: root/rdoff/rdf2bin.c
diff options
context:
space:
mode:
Diffstat (limited to 'rdoff/rdf2bin.c')
-rw-r--r--rdoff/rdf2bin.c430
1 files changed, 430 insertions, 0 deletions
diff --git a/rdoff/rdf2bin.c b/rdoff/rdf2bin.c
new file mode 100644
index 0000000..72e5104
--- /dev/null
+++ b/rdoff/rdf2bin.c
@@ -0,0 +1,430 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2009 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * rdf2bin.c - convert an RDOFF object file to flat binary
+ */
+
+#include "compiler.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "rdfload.h"
+#include "nasmlib.h"
+
+const char *progname;
+
+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)
+{
+ 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;
+
+ if (write_ith_record(f, chunk, (uint16_t)where, 0, dbuf))
+ return -1;
+
+ dbuf += chunk;
+ last = where + chunk - 1;
+ where += chunk;
+ bytes -= chunk;
+ }
+ 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;
+ static char fmt_buf[16];
+
+ /*
+ * Search backwards for the string "rdf2" followed by a string
+ * of alphanumeric characters. This should handle path prefixes,
+ * as well as extensions (e.g. C:\FOO\RDF2SREC.EXE).
+ */
+ for (p = strchr(pathname, '\0')-1 ; p >= pathname ; p--) {
+ if (!nasm_stricmp(p, "rdf2")) {
+ const char *q = p+4;
+ char *r = fmt_buf;
+ while (isalnum(*q) && r < fmt_buf+sizeof fmt_buf-1)
+ *r++ = *q++;
+ *r = '\0';
+ if (fmt_buf[0])
+ return fmt_buf;
+ }
+ }
+ return NULL;
+}
+
+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)
+{
+ rdfmodule *m;
+ bool err;
+ FILE *of;
+ int codepad, datapad;
+ const char *format = NULL;
+ const struct output_format *fmt;
+ bool quiet = false;
+
+ progname = argv[0];
+
+ if (argc < 2) {
+ usage();
+ return 1;
+ }
+
+ argv++, argc--;
+
+ while (argc > 2) {
+ 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) {
+ usage();
+ return 1;
+ }
+
+ if (!format)
+ format = getformat(progname);
+
+ if (!format) {
+ fprintf(stderr, "%s: unable to determine desired output format\n",
+ progname);
+ return 1;
+ }
+
+ 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(progname, *argv);
+ return 1;
+ }
+
+ if (!quiet)
+ printf("relocating %s: origin=%"PRIx32", align=%d\n",
+ *argv, origin, align);
+
+ m->textrel = origin;
+ m->datarel = origin + m->f.seg[0].length;
+ if (m->datarel % align != 0) {
+ codepad = align - (m->datarel % align);
+ m->datarel += codepad;
+ } else
+ codepad = 0;
+
+ m->bssrel = m->datarel + m->f.seg[1].length;
+ if (m->bssrel % align != 0) {
+ datapad = align - (m->bssrel % align);
+ m->bssrel += datapad;
+ } else
+ datapad = 0;
+
+ 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, fmt->mode);
+ if (!of) {
+ fprintf(stderr, "%s: could not open output file %s: %s\n",
+ progname, *argv, strerror(errno));
+ return 1;
+ }
+
+ 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;
+ }
+
+ fclose(of);
+ return 0;
+}