/* ----------------------------------------------------------------------- * * * 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 #include #include #include #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; fwritezero(pad, f); 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; } rdoff_init(); 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; }