doc: Explain SECTALIGN
[nasm.git] / rdoff / rdf2bin.c
blob72e5104bd34a0ea3f1ab01037c3aa177ba88a3eb
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;
256 static char fmt_buf[16];
259 * Search backwards for the string "rdf2" followed by a string
260 * of alphanumeric characters. This should handle path prefixes,
261 * as well as extensions (e.g. C:\FOO\RDF2SREC.EXE).
263 for (p = strchr(pathname, '\0')-1 ; p >= pathname ; p--) {
264 if (!nasm_stricmp(p, "rdf2")) {
265 const char *q = p+4;
266 char *r = fmt_buf;
267 while (isalnum(*q) && r < fmt_buf+sizeof fmt_buf-1)
268 *r++ = *q++;
269 *r = '\0';
270 if (fmt_buf[0])
271 return fmt_buf;
274 return NULL;
277 static void usage(void)
279 fprintf(stderr,
280 "Usage: %s [options] input-file output-file\n"
281 "Options:\n"
282 " -o origin Specify the relocation origin\n"
283 " -p alignment Specify minimum segment alignment\n"
284 " -f format Select format (bin, com, ith, srec)\n"
285 " -q Run quiet\n"
286 " -v Run verbose\n",
287 progname);
290 int main(int argc, char **argv)
292 rdfmodule *m;
293 bool err;
294 FILE *of;
295 int codepad, datapad;
296 const char *format = NULL;
297 const struct output_format *fmt;
298 bool quiet = false;
300 progname = argv[0];
302 if (argc < 2) {
303 usage();
304 return 1;
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;