rbtree: add rb_search_exact()
[nasm.git] / rdoff / rdf2bin.c
blob2c58e606f433118f91a603eb58575588bde699fd
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 <ctype.h>
43 #include <errno.h>
45 #include "rdfload.h"
46 #include "nasmlib.h"
48 const char *progname;
50 static uint32_t origin = 0;
51 static bool origin_def = false;
52 static uint32_t align = 16;
53 static bool align_def = false;
55 struct output_format {
56 const char *name;
57 const char *mode;
58 int (*init)(FILE *f);
59 int (*output)(FILE *f, void *data, uint32_t bytes, uint32_t where);
60 int (*fini)(FILE *f);
63 static int null_init_fini(FILE *f)
65 (void)f;
66 return 0;
69 static int com_init(FILE *f)
71 (void)f;
72 if (!origin_def)
73 origin = 0x100;
74 return 0;
77 static int output_bin(FILE *f, void *data, uint32_t bytes, uint32_t where)
79 static uint32_t offset = 0; /* Current file offset, if applicable */
80 size_t pad;
82 if (where-origin < offset) {
83 fprintf(stderr, "%s: internal error: backwards movement\n", progname);
84 exit(1);
87 pad = (where-origin) - offset;
88 fwritezero(pad, f);
89 offset += pad;
91 if (fwrite(data, 1, bytes, f) != bytes)
92 return -1;
93 offset += bytes;
95 return 0;
98 static int write_ith_record(FILE *f, unsigned int len, uint16_t addr,
99 uint8_t type, void *data)
101 char buf[1+2+4+2+255*2+2+2];
102 char *p = buf;
103 uint8_t csum, *dptr = data;
104 unsigned int i;
106 if (len > 255) {
107 fprintf(stderr, "%s: internal error: invalid ith record size\n",
108 progname);
109 exit(1);
112 csum = len + addr + (addr >> 8) + type;
113 for (i = 0; i < len; i++)
114 csum += dptr[i];
115 csum = -csum;
117 p += sprintf(p, ":%02X%04X%02X", len, addr, type);
118 for (i = 0; i < len; i++)
119 p += sprintf(p, "%02X", dptr[i]);
120 p += sprintf(p, "%02X\n", csum);
122 if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf))
123 return -1;
125 return 0;
128 static int output_ith(FILE *f, void *data, uint32_t bytes, uint32_t where)
130 static uint32_t last = 0; /* Last address written */
131 uint8_t abuf[2];
132 uint8_t *dbuf = data;
133 uint32_t chunk;
135 while (bytes) {
136 if ((where ^ last) & ~0xffff) {
137 abuf[0] = where >> 24;
138 abuf[1] = where >> 16;
139 if (write_ith_record(f, 2, 0, 4, abuf))
140 return -1;
143 /* Output up to 32 bytes, but always end on an aligned boundary */
144 chunk = 32 - (where & 31);
145 if (bytes < chunk)
146 chunk = bytes;
148 if (write_ith_record(f, chunk, (uint16_t)where, 0, dbuf))
149 return -1;
151 dbuf += chunk;
152 last = where + chunk - 1;
153 where += chunk;
154 bytes -= chunk;
156 return 0;
159 static int fini_ith(FILE *f)
161 /* XXX: entry point? */
162 return write_ith_record(f, 0, 0, 1, NULL);
165 static int write_srecord(FILE *f, unsigned int len, unsigned int alen,
166 uint32_t addr, uint8_t type, void *data)
168 char buf[2+2+8+255*2+2+2];
169 char *p = buf;
170 uint8_t csum, *dptr = data;
171 unsigned int i;
173 if (len > 255) {
174 fprintf(stderr, "%s: internal error: invalid srec record size\n",
175 progname);
176 exit(1);
179 switch (alen) {
180 case 2:
181 addr &= 0xffff;
182 break;
183 case 3:
184 addr &= 0xffffff;
185 break;
186 case 4:
187 break;
188 default:
189 fprintf(stderr, "%s: internal error: invalid srec address length\n",
190 progname);
191 exit(1);
194 csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24);
195 for (i = 0; i < len; i++)
196 csum += dptr[i];
197 csum = 0xff-csum;
199 p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr);
200 for (i = 0; i < len; i++)
201 p += sprintf(p, "%02X", dptr[i]);
202 p += sprintf(p, "%02X\n", csum);
204 if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf))
205 return -1;
207 return 0;
210 static int init_srec(FILE *f)
212 return write_srecord(f, 0, 2, 0, '0', NULL);
215 static int fini_srec(FILE *f)
217 /* XXX: entry point? */
218 return write_srecord(f, 0, 4, 0, '7', NULL);
221 static int output_srec(FILE *f, void *data, uint32_t bytes, uint32_t where)
223 uint8_t *dbuf = data;
224 unsigned int chunk;
226 while (bytes) {
227 /* Output up to 32 bytes, but always end on an aligned boundary */
228 chunk = 32 - (where & 31);
229 if (bytes < chunk)
230 chunk = bytes;
232 if (write_srecord(f, chunk, 4, where, '3', dbuf))
233 return -1;
235 dbuf += chunk;
236 where += chunk;
237 bytes -= chunk;
239 return 0;
242 static struct output_format output_formats[] = {
243 { "bin", "wb", null_init_fini, output_bin, null_init_fini },
244 { "com", "wb", com_init, output_bin, null_init_fini },
245 { "ith", "wt", null_init_fini, output_ith, fini_ith },
246 { "ihx", "wt", null_init_fini, output_ith, fini_ith },
247 { "srec", "wt", init_srec, output_srec, fini_srec },
248 { NULL, NULL, NULL, NULL, NULL }
251 static const char *getformat(const char *pathname)
253 const char *p;
254 static char fmt_buf[16];
257 * Search backwards for the string "rdf2" followed by a string
258 * of alphanumeric characters. This should handle path prefixes,
259 * as well as extensions (e.g. C:\FOO\RDF2SREC.EXE).
261 for (p = strchr(pathname, '\0')-1 ; p >= pathname ; p--) {
262 if (!nasm_stricmp(p, "rdf2")) {
263 const char *q = p+4;
264 char *r = fmt_buf;
265 while (isalnum(*q) && r < fmt_buf+sizeof fmt_buf-1)
266 *r++ = *q++;
267 *r = '\0';
268 if (fmt_buf[0])
269 return fmt_buf;
272 return NULL;
275 static void usage(void)
277 fprintf(stderr,
278 "Usage: %s [options] input-file output-file\n"
279 "Options:\n"
280 " -o origin Specify the relocation origin\n"
281 " -p alignment Specify minimum segment alignment\n"
282 " -f format Select format (bin, com, ith, srec)\n"
283 " -q Run quiet\n"
284 " -v Run verbose\n",
285 progname);
288 int main(int argc, char **argv)
290 rdfmodule *m;
291 bool err;
292 FILE *of;
293 int codepad, datapad;
294 const char *format = NULL;
295 const struct output_format *fmt;
296 bool quiet = false;
298 progname = argv[0];
300 if (argc < 2) {
301 usage();
302 return 1;
305 rdoff_init();
307 argv++, argc--;
309 while (argc > 2) {
310 if (argv[0][0] == '-' && argv[0][1] && !argv[0][2]) {
311 switch (argv[0][1]) {
312 case 'o':
313 argv++, argc--;
314 origin = readnum(*argv, &err);
315 if (err) {
316 fprintf(stderr, "%s: invalid parameter: %s\n",
317 progname, *argv);
318 return 1;
320 origin_def = true;
321 break;
322 case 'p':
323 argv++, argc--;
324 align = readnum(*argv, &err);
325 if (err) {
326 fprintf(stderr, "%s: invalid parameter: %s\n",
327 progname, *argv);
328 return 1;
330 align_def = true;
331 break;
332 case 'f':
333 argv++, argc--;
334 format = *argv;
335 break;
336 case 'q':
337 quiet = true;
338 break;
339 case 'v':
340 quiet = false;
341 break;
342 case 'h':
343 usage();
344 return 0;
345 default:
346 fprintf(stderr, "%s: unknown option: %s\n",
347 progname, *argv);
348 return 1;
351 argv++, argc--;
354 if (argc < 2) {
355 usage();
356 return 1;
359 if (!format)
360 format = getformat(progname);
362 if (!format) {
363 fprintf(stderr, "%s: unable to determine desired output format\n",
364 progname);
365 return 1;
368 for (fmt = output_formats; fmt->name; fmt++) {
369 if (!nasm_stricmp(format, fmt->name))
370 break;
373 if (!fmt->name) {
374 fprintf(stderr, "%s: unknown output format: %s\n", progname, format);
375 return 1;
378 m = rdfload(*argv);
380 if (!m) {
381 rdfperror(progname, *argv);
382 return 1;
385 if (!quiet)
386 printf("relocating %s: origin=%"PRIx32", align=%d\n",
387 *argv, origin, align);
389 m->textrel = origin;
390 m->datarel = origin + m->f.seg[0].length;
391 if (m->datarel % align != 0) {
392 codepad = align - (m->datarel % align);
393 m->datarel += codepad;
394 } else
395 codepad = 0;
397 m->bssrel = m->datarel + m->f.seg[1].length;
398 if (m->bssrel % align != 0) {
399 datapad = align - (m->bssrel % align);
400 m->bssrel += datapad;
401 } else
402 datapad = 0;
404 if (!quiet)
405 printf("code: %08"PRIx32"\ndata: %08"PRIx32"\nbss: %08"PRIx32"\n",
406 m->textrel, m->datarel, m->bssrel);
408 rdf_relocate(m);
410 argv++;
412 of = fopen(*argv, fmt->mode);
413 if (!of) {
414 fprintf(stderr, "%s: could not open output file %s: %s\n",
415 progname, *argv, strerror(errno));
416 return 1;
419 if (fmt->init(of) ||
420 fmt->output(of, m->t, m->f.seg[0].length, m->textrel) ||
421 fmt->output(of, m->d, m->f.seg[1].length, m->datarel) ||
422 fmt->fini(of)) {
423 fprintf(stderr, "%s: error writing to %s: %s\n",
424 progname, *argv, strerror(errno));
425 return 1;
428 fclose(of);
429 return 0;