gcc: newer gcc trip on -Wstringop-truncation for valid uses of strncpy()
[nasm.git] / rdoff / rdf2bin.c
blob1beb82451173511ffb0a5fb11bb1aec27e27c852
1 /* ----------------------------------------------------------------------- *
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 fwritezero(pad, f);
90 offset += pad;
92 if (fwrite(data, 1, bytes, f) != bytes)
93 return -1;
94 offset += bytes;
96 return 0;
99 static int write_ith_record(FILE *f, unsigned int len, uint16_t addr,
100 uint8_t type, void *data)
102 char buf[1+2+4+2+255*2+2+2];
103 char *p = buf;
104 uint8_t csum, *dptr = data;
105 unsigned int i;
107 if (len > 255) {
108 fprintf(stderr, "%s: internal error: invalid ith record size\n",
109 progname);
110 exit(1);
113 csum = len + addr + (addr >> 8) + type;
114 for (i = 0; i < len; i++)
115 csum += dptr[i];
116 csum = -csum;
118 p += sprintf(p, ":%02X%04X%02X", len, addr, type);
119 for (i = 0; i < len; i++)
120 p += sprintf(p, "%02X", dptr[i]);
121 p += sprintf(p, "%02X\n", csum);
123 if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf))
124 return -1;
126 return 0;
129 static int output_ith(FILE *f, void *data, uint32_t bytes, uint32_t where)
131 static uint32_t last = 0; /* Last address written */
132 uint8_t abuf[2];
133 uint8_t *dbuf = data;
134 uint32_t chunk;
136 while (bytes) {
137 if ((where ^ last) & ~0xffff) {
138 abuf[0] = where >> 24;
139 abuf[1] = where >> 16;
140 if (write_ith_record(f, 2, 0, 4, abuf))
141 return -1;
144 /* Output up to 32 bytes, but always end on an aligned boundary */
145 chunk = 32 - (where & 31);
146 if (bytes < chunk)
147 chunk = bytes;
149 if (write_ith_record(f, chunk, (uint16_t)where, 0, dbuf))
150 return -1;
152 dbuf += chunk;
153 last = where + chunk - 1;
154 where += chunk;
155 bytes -= chunk;
157 return 0;
160 static int fini_ith(FILE *f)
162 /* XXX: entry point? */
163 return write_ith_record(f, 0, 0, 1, NULL);
166 static int write_srecord(FILE *f, unsigned int len, unsigned int alen,
167 uint32_t addr, uint8_t type, void *data)
169 char buf[2+2+8+255*2+2+2];
170 char *p = buf;
171 uint8_t csum, *dptr = data;
172 unsigned int i;
174 if (len > 255) {
175 fprintf(stderr, "%s: internal error: invalid srec record size\n",
176 progname);
177 exit(1);
180 switch (alen) {
181 case 2:
182 addr &= 0xffff;
183 break;
184 case 3:
185 addr &= 0xffffff;
186 break;
187 case 4:
188 break;
189 default:
190 fprintf(stderr, "%s: internal error: invalid srec address length\n",
191 progname);
192 exit(1);
195 csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24);
196 for (i = 0; i < len; i++)
197 csum += dptr[i];
198 csum = 0xff-csum;
200 p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr);
201 for (i = 0; i < len; i++)
202 p += sprintf(p, "%02X", dptr[i]);
203 p += sprintf(p, "%02X\n", csum);
205 if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf))
206 return -1;
208 return 0;
211 static int init_srec(FILE *f)
213 return write_srecord(f, 0, 2, 0, '0', NULL);
216 static int fini_srec(FILE *f)
218 /* XXX: entry point? */
219 return write_srecord(f, 0, 4, 0, '7', NULL);
222 static int output_srec(FILE *f, void *data, uint32_t bytes, uint32_t where)
224 uint8_t *dbuf = data;
225 unsigned int chunk;
227 while (bytes) {
228 /* Output up to 32 bytes, but always end on an aligned boundary */
229 chunk = 32 - (where & 31);
230 if (bytes < chunk)
231 chunk = bytes;
233 if (write_srecord(f, chunk, 4, where, '3', dbuf))
234 return -1;
236 dbuf += chunk;
237 where += chunk;
238 bytes -= chunk;
240 return 0;
243 static struct output_format output_formats[] = {
244 { "bin", "wb", null_init_fini, output_bin, null_init_fini },
245 { "com", "wb", com_init, output_bin, null_init_fini },
246 { "ith", "wt", null_init_fini, output_ith, fini_ith },
247 { "ihx", "wt", null_init_fini, output_ith, fini_ith },
248 { "srec", "wt", init_srec, output_srec, fini_srec },
249 { NULL, NULL, NULL, NULL, NULL }
252 static const char *getformat(const char *pathname)
254 const char *p;
255 static char fmt_buf[16];
258 * Search backwards for the string "rdf2" followed by a string
259 * of alphanumeric characters. This should handle path prefixes,
260 * as well as extensions (e.g. C:\FOO\RDF2SREC.EXE).
262 for (p = strchr(pathname, '\0')-1 ; p >= pathname ; p--) {
263 if (!nasm_stricmp(p, "rdf2")) {
264 const char *q = p+4;
265 char *r = fmt_buf;
266 while (isalnum(*q) && r < fmt_buf+sizeof fmt_buf-1)
267 *r++ = *q++;
268 *r = '\0';
269 if (fmt_buf[0])
270 return fmt_buf;
273 return NULL;
276 static void usage(void)
278 fprintf(stderr,
279 "Usage: %s [options] input-file output-file\n"
280 "Options:\n"
281 " -o origin Specify the relocation origin\n"
282 " -p alignment Specify minimum segment alignment\n"
283 " -f format Select format (bin, com, ith, srec)\n"
284 " -q Run quiet\n"
285 " -v Run verbose\n",
286 progname);
289 int main(int argc, char **argv)
291 rdfmodule *m;
292 bool err;
293 FILE *of;
294 int codepad, datapad;
295 const char *format = NULL;
296 const struct output_format *fmt;
297 bool quiet = false;
299 progname = argv[0];
301 if (argc < 2) {
302 usage();
303 return 1;
306 rdoff_init();
308 argv++, argc--;
310 while (argc > 2) {
311 if (argv[0][0] == '-' && argv[0][1] && !argv[0][2]) {
312 switch (argv[0][1]) {
313 case 'o':
314 argv++, argc--;
315 origin = readnum(*argv, &err);
316 if (err) {
317 fprintf(stderr, "%s: invalid parameter: %s\n",
318 progname, *argv);
319 return 1;
321 origin_def = true;
322 break;
323 case 'p':
324 argv++, argc--;
325 align = readnum(*argv, &err);
326 if (err) {
327 fprintf(stderr, "%s: invalid parameter: %s\n",
328 progname, *argv);
329 return 1;
331 align_def = true;
332 break;
333 case 'f':
334 argv++, argc--;
335 format = *argv;
336 break;
337 case 'q':
338 quiet = true;
339 break;
340 case 'v':
341 quiet = false;
342 break;
343 case 'h':
344 usage();
345 return 0;
346 default:
347 fprintf(stderr, "%s: unknown option: %s\n",
348 progname, *argv);
349 return 1;
352 argv++, argc--;
355 if (argc < 2) {
356 usage();
357 return 1;
360 if (!format)
361 format = getformat(progname);
363 if (!format) {
364 fprintf(stderr, "%s: unable to determine desired output format\n",
365 progname);
366 return 1;
369 for (fmt = output_formats; fmt->name; fmt++) {
370 if (!nasm_stricmp(format, fmt->name))
371 break;
374 if (!fmt->name) {
375 fprintf(stderr, "%s: unknown output format: %s\n", progname, format);
376 return 1;
379 m = rdfload(*argv);
381 if (!m) {
382 rdfperror(progname, *argv);
383 return 1;
386 if (!quiet)
387 printf("relocating %s: origin=%"PRIx32", align=%d\n",
388 *argv, origin, align);
390 m->textrel = origin;
391 m->datarel = origin + m->f.seg[0].length;
392 if (m->datarel % align != 0) {
393 codepad = align - (m->datarel % align);
394 m->datarel += codepad;
395 } else
396 codepad = 0;
398 m->bssrel = m->datarel + m->f.seg[1].length;
399 if (m->bssrel % align != 0) {
400 datapad = align - (m->bssrel % align);
401 m->bssrel += datapad;
402 } else
403 datapad = 0;
405 if (!quiet)
406 printf("code: %08"PRIx32"\ndata: %08"PRIx32"\nbss: %08"PRIx32"\n",
407 m->textrel, m->datarel, m->bssrel);
409 rdf_relocate(m);
411 argv++;
413 of = fopen(*argv, fmt->mode);
414 if (!of) {
415 fprintf(stderr, "%s: could not open output file %s: %s\n",
416 progname, *argv, strerror(errno));
417 return 1;
420 if (fmt->init(of) ||
421 fmt->output(of, m->t, m->f.seg[0].length, m->textrel) ||
422 fmt->output(of, m->d, m->f.seg[1].length, m->datarel) ||
423 fmt->fini(of)) {
424 fprintf(stderr, "%s: error writing to %s: %s\n",
425 progname, *argv, strerror(errno));
426 return 1;
429 fclose(of);
430 return 0;