rdf2bin: revamp so it can output bin, ith, or srec
[nasm/sigaren-mirror.git] / rdoff / rdf2bin.c
blob22820634e3f114f2f2707cf831b875a5ccb4a85f
1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2009 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * rdf2bin.c - convert an RDOFF object file to flat binary
38 #include "compiler.h"
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <errno.h>
46 #include "rdfload.h"
47 #include "nasmlib.h"
49 const char *progname;
51 static uint32_t origin = 0;
52 static bool origin_def = false;
53 static uint32_t align = 16;
54 static bool align_def = false;
56 struct output_format {
57 const char *name;
58 const char *mode;
59 int (*init)(FILE *f);
60 int (*output)(FILE *f, void *data, uint32_t bytes, uint32_t where);
61 int (*fini)(FILE *f);
64 static int null_init_fini(FILE *f)
66 (void)f;
67 return 0;
70 static int com_init(FILE *f)
72 (void)f;
73 if (!origin_def)
74 origin = 0x100;
75 return 0;
78 static int output_bin(FILE *f, void *data, uint32_t bytes, uint32_t where)
80 static uint32_t offset = 0; /* Current file offset, if applicable */
81 size_t pad;
83 if (where-origin < offset) {
84 fprintf(stderr, "%s: internal error: backwards movement\n", progname);
85 exit(1);
88 pad = (where-origin) - offset;
89 if (fwritezero(pad, f) != pad)
90 return -1;
91 offset += pad;
93 if (fwrite(data, 1, bytes, f) != bytes)
94 return -1;
95 offset += bytes;
97 return 0;
100 static int write_ith_record(FILE *f, unsigned int len, uint16_t addr,
101 uint8_t type, void *data)
103 char buf[1+2+4+2+255*2+2+2];
104 char *p = buf;
105 uint8_t csum, *dptr = data;
106 unsigned int i;
108 if (len > 255) {
109 fprintf(stderr, "%s: internal error: invalid ith record size\n",
110 progname);
111 exit(1);
114 csum = len + addr + (addr >> 8) + type;
115 for (i = 0; i < len; i++)
116 csum += dptr[i];
117 csum = -csum;
119 p += sprintf(p, ":%02X%04X%02X", len, addr, type);
120 for (i = 0; i < len; i++)
121 p += sprintf(p, "%02X", dptr[i]);
122 p += sprintf(p, "%02X\n", csum);
124 if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf))
125 return -1;
127 return 0;
130 static int output_ith(FILE *f, void *data, uint32_t bytes, uint32_t where)
132 static uint32_t last = 0; /* Last address written */
133 uint8_t abuf[2];
134 uint8_t *dbuf = data;
135 uint32_t chunk;
137 while (bytes) {
138 if ((where ^ last) & ~0xffff) {
139 abuf[0] = where >> 24;
140 abuf[1] = where >> 16;
141 if (write_ith_record(f, 2, 0, 4, abuf))
142 return -1;
145 /* Output up to 32 bytes, but always end on an aligned boundary */
146 chunk = 32 - (where & 31);
147 if (bytes < chunk)
148 chunk = bytes;
150 if (write_ith_record(f, chunk, (uint16_t)where, 0, dbuf))
151 return -1;
153 dbuf += chunk;
154 last = where + chunk - 1;
155 where += chunk;
156 bytes -= chunk;
158 return 0;
161 static int fini_ith(FILE *f)
163 /* XXX: entry point? */
164 return write_ith_record(f, 0, 0, 1, NULL);
167 static int write_srecord(FILE *f, unsigned int len, unsigned int alen,
168 uint32_t addr, uint8_t type, void *data)
170 char buf[2+2+8+255*2+2+2];
171 char *p = buf;
172 uint8_t csum, *dptr = data;
173 unsigned int i;
175 if (len > 255) {
176 fprintf(stderr, "%s: internal error: invalid srec record size\n",
177 progname);
178 exit(1);
181 switch (alen) {
182 case 2:
183 addr &= 0xffff;
184 break;
185 case 3:
186 addr &= 0xffffff;
187 break;
188 case 4:
189 break;
190 default:
191 fprintf(stderr, "%s: internal error: invalid srec address length\n",
192 progname);
193 exit(1);
196 csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24);
197 for (i = 0; i < len; i++)
198 csum += dptr[i];
199 csum = 0xff-csum;
201 p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr);
202 for (i = 0; i < len; i++)
203 p += sprintf(p, "%02X", dptr[i]);
204 p += sprintf(p, "%02X\n", csum);
206 if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf))
207 return -1;
209 return 0;
212 static int init_srec(FILE *f)
214 return write_srecord(f, 0, 2, 0, '0', NULL);
217 static int fini_srec(FILE *f)
219 /* XXX: entry point? */
220 return write_srecord(f, 0, 4, 0, '7', NULL);
223 static int output_srec(FILE *f, void *data, uint32_t bytes, uint32_t where)
225 uint8_t *dbuf = data;
226 unsigned int chunk;
228 while (bytes) {
229 /* Output up to 32 bytes, but always end on an aligned boundary */
230 chunk = 32 - (where & 31);
231 if (bytes < chunk)
232 chunk = bytes;
234 if (write_srecord(f, chunk, 4, where, '3', dbuf))
235 return -1;
237 dbuf += chunk;
238 where += chunk;
239 bytes -= chunk;
241 return 0;
244 static struct output_format output_formats[] = {
245 { "bin", "wb", null_init_fini, output_bin, null_init_fini },
246 { "com", "wb", com_init, output_bin, null_init_fini },
247 { "ith", "wt", null_init_fini, output_ith, fini_ith },
248 { "ihx", "wt", null_init_fini, output_ith, fini_ith },
249 { "srec", "wt", init_srec, output_srec, fini_srec },
250 { NULL, NULL, NULL, NULL, NULL }
253 static const char *getformat(const char *pathname)
255 const char *p;
257 /* Search backwards for the first non-alphabetic character */
259 for (p = strchr(pathname, '\0')-1 ; p >= pathname ; p--) {
260 if (!isalpha(*p))
261 break;
263 return p+1;
266 static void usage(void)
268 fprintf(stderr,
269 "Usage: %s [options] input-file output-file\n"
270 "Options:\n"
271 " -o origin Specify the relocation origin\n"
272 " -p alignment Specify minimum segment alignment\n"
273 " -f format Select format (bin, com, ith, srec)\n"
274 " -q Run quiet\n"
275 " -v Run verbose\n",
276 progname);
279 int main(int argc, char **argv)
281 rdfmodule *m;
282 bool err;
283 FILE *of;
284 int codepad, datapad;
285 const char *format = NULL;
286 const struct output_format *fmt;
287 bool quiet = false;
289 progname = argv[0];
291 if (argc < 2) {
292 usage();
293 return 1;
296 argv++, argc--;
298 while (argc > 2) {
299 if (argv[0][0] == '-' && argv[0][1] && !argv[0][2]) {
300 switch (argv[0][1]) {
301 case 'o':
302 argv++, argc--;
303 origin = readnum(*argv, &err);
304 if (err) {
305 fprintf(stderr, "%s: invalid parameter: %s\n",
306 progname, *argv);
307 return 1;
309 origin_def = true;
310 break;
311 case 'p':
312 argv++, argc--;
313 align = readnum(*argv, &err);
314 if (err) {
315 fprintf(stderr, "%s: invalid parameter: %s\n",
316 progname, *argv);
317 return 1;
319 align_def = true;
320 break;
321 case 'f':
322 argv++, argc--;
323 format = *argv;
324 break;
325 case 'q':
326 quiet = true;
327 break;
328 case 'v':
329 quiet = false;
330 break;
331 case 'h':
332 usage();
333 return 0;
334 default:
335 fprintf(stderr, "%s: unknown option: %s\n",
336 progname, *argv);
337 return 1;
340 argv++, argc--;
343 if (argc < 2) {
344 usage();
345 return 1;
348 if (!format)
349 format = getformat(progname);
350 for (fmt = output_formats; fmt->name; fmt++) {
351 if (!nasm_stricmp(format, fmt->name))
352 break;
354 if (!fmt->name) {
355 fprintf(stderr, "%s: unknown output format: %s\n", progname, format);
356 return -1;
359 m = rdfload(*argv);
361 if (!m) {
362 rdfperror(progname, *argv);
363 return 1;
366 if (!quiet)
367 printf("relocating %s: origin=%"PRIx32", align=%d\n",
368 *argv, origin, align);
370 m->textrel = origin;
371 m->datarel = origin + m->f.seg[0].length;
372 if (m->datarel % align != 0) {
373 codepad = align - (m->datarel % align);
374 m->datarel += codepad;
375 } else
376 codepad = 0;
378 m->bssrel = m->datarel + m->f.seg[1].length;
379 if (m->bssrel % align != 0) {
380 datapad = align - (m->bssrel % align);
381 m->bssrel += datapad;
382 } else
383 datapad = 0;
385 if (!quiet)
386 printf("code: %08"PRIx32"\ndata: %08"PRIx32"\nbss: %08"PRIx32"\n",
387 m->textrel, m->datarel, m->bssrel);
389 rdf_relocate(m);
391 argv++;
393 of = fopen(*argv, fmt->mode);
394 if (!of) {
395 fprintf(stderr, "%s: could not open output file %s: %s\n",
396 progname, *argv, strerror(errno));
397 return 1;
400 if (fmt->init(of) ||
401 fmt->output(of, m->t, m->f.seg[0].length, m->textrel) ||
402 fmt->output(of, m->d, m->f.seg[1].length, m->datarel) ||
403 fmt->fini(of)) {
404 fprintf(stderr, "%s: error writing to %s: %s\n",
405 progname, *argv, strerror(errno));
406 return 1;
409 fclose(of);
410 return 0;