diff options
Diffstat (limited to 'rdoff/rdf2bin.c')
-rw-r--r-- | rdoff/rdf2bin.c | 430 |
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; +} |