Beginnings of a crude utility to dump the contents of an OMF file
[nasm/nasm.git] / rdoff / rdf2ihx.c
blobab6df8cda30c318e569cdd77be0dbdf2cba23388
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 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, Inc.,
10 * 51 Franklin St, Fifth Floor, Boston MA 02110-1301, USA; version 2.1,
11 * or, at your option, any later version, incorporated herein by
12 * reference.
14 * Patches submitted to this file are required to be dual licensed
15 * under the LGPL 2.1+ and the 2-clause BSD license:
17 * Copyright 1996-2009 the NASM Authors - All rights reserved.
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following
21 * conditions are met:
23 * * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above
26 * copyright notice, this list of conditions and the following
27 * disclaimer in the documentation and/or other materials provided
28 * with the distribution.
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
33 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
41 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
42 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 * ----------------------------------------------------------------------- */
47 * rdf2ihx.c - convert an RDOFF object file to Intel Hex format.
48 * This is based on rdf2bin.
49 * Note that this program only writes 16-bit HEX.
52 #include "compiler.h"
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <string.h>
58 #include "rdfload.h"
59 #include "nasmlib.h"
60 #include "symtab.h"
62 int32_t origin = 0;
63 int align = 16;
65 /* This function writes a single n-byte data record to of. Maximum value
66 for n is 255. */
67 static int write_data_record(FILE * of, int ofs, int nbytes,
68 uint8_t *data)
70 int i, iofs;
71 unsigned int checksum;
73 iofs = ofs;
74 fprintf(of, ":%02X%04X00", nbytes, ofs);
75 checksum = 0;
76 for (i = 0; i < nbytes; i++) {
77 fprintf(of, "%02X", data[i]);
78 ofs++;
79 checksum += data[i];
81 checksum = checksum + /* current checksum */
82 nbytes + /* RECLEN (one byte) */
83 ((iofs >> 8) & 0xff) + /* high byte of load offset */
84 (iofs & 0xff); /* low byte of load offset */
85 checksum = ~checksum + 1;
86 fprintf(of, "%02X\n", checksum & 0xff);
87 return (ofs);
90 int main(int argc, char **argv)
92 rdfmodule *m;
93 bool err;
94 FILE *of;
95 char *padding;
96 uint8_t *segbin[2];
97 int pad[2], segn, ofs, i;
98 int32_t segaddr;
99 unsigned int checksum;
100 symtabEnt *s;
102 if (argc < 2) {
103 puts("Usage: rdf2ihx [-o relocation-origin] [-p segment-alignment] " "input-file output-file");
104 return (1);
107 argv++, argc--;
109 while (argc > 2) {
110 if (strcmp(*argv, "-o") == 0) {
111 argv++, argc--;
112 origin = readnum(*argv, &err);
113 if (err) {
114 fprintf(stderr, "rdf2ihx: invalid parameter: %s\n", *argv);
115 return 1;
117 } else if (strcmp(*argv, "-p") == 0) {
118 argv++, argc--;
119 align = readnum(*argv, &err);
120 if (err) {
121 fprintf(stderr, "rdf2ihx: invalid parameter: %s\n", *argv);
122 return 1;
124 } else
125 break;
126 argv++, argc--;
128 if (argc < 2) {
129 puts("rdf2ihx: required parameter missing");
130 return -1;
132 m = rdfload(*argv);
134 if (!m) {
135 rdfperror("rdf2ihx", *argv);
136 return 1;
138 printf("relocating %s: origin=%"PRIx32", align=%d\n", *argv, origin, align);
140 m->textrel = origin;
141 m->datarel = origin + m->f.seg[0].length;
142 if (m->datarel % align != 0) {
143 pad[0] = align - (m->datarel % align);
144 m->datarel += pad[0];
145 } else {
146 pad[0] = 0;
149 m->bssrel = m->datarel + m->f.seg[1].length;
150 if (m->bssrel % align != 0) {
151 pad[1] = align - (m->bssrel % align);
152 m->bssrel += pad[1];
153 } else {
154 pad[1] = 0;
157 printf("code: %08"PRIx32"\ndata: %08"PRIx32"\nbss: %08"PRIx32"\n",
158 m->textrel, m->datarel, m->bssrel);
160 rdf_relocate(m);
162 argv++;
164 of = fopen(*argv, "w");
165 if (!of) {
166 fprintf(stderr, "rdf2ihx: could not open output file %s\n", *argv);
167 return (1);
170 padding = malloc(align);
171 if (!padding) {
172 fprintf(stderr, "rdf2ihx: out of memory\n");
173 return (1);
176 /* write extended segment address record */
177 fprintf(of, ":02000002"); /* Record mark, reclen, load offset & rectyp
178 fields for ext. seg. address record */
179 segaddr = ((origin >> 16) & 0xffff); /* segment address */
180 fprintf(of, "%04X", (unsigned int)(segaddr & 0xffff));
181 checksum = 0x02 + /* reclen */
182 0x0000 + /* Load Offset */
183 0x02 + /* Rectyp */
184 (segaddr & 0xff) + /* USBA low */
185 ((segaddr >> 8) & 0xff); /* USBA high */
186 checksum = ~checksum + 1; /* two's-complement the checksum */
187 fprintf(of, "%02X\n", checksum & 0xff);
189 /* See if there's a '_main' symbol in the symbol table */
190 if ((s = symtabFind(m->symtab, "_main")) == NULL) {
191 printf
192 ("No _main symbol found, no start segment address record added\n");
193 } else {
194 printf("_main symbol found at %04x:%04x\n", s->segment,
195 (unsigned int)(s->offset & 0xffff));
196 /* Create a start segment address record for the _main symbol. */
197 segaddr = ((s->segment & 0xffff) << 16) + ((s->offset) & 0xffff);
198 fprintf(of, ":04000003"); /* Record mark, reclen, load offset & rectyp
199 fields for start seg. addr. record */
200 fprintf(of, "%08"PRIX32"", segaddr); /* CS/IP field */
201 checksum = 0x04 + /* reclen */
202 0x0000 + /* load offset */
203 0x03 + /* Rectyp */
204 (segaddr & 0xff) + /* low-low byte of segaddr */
205 ((segaddr >> 8) & 0xff) + /* low-high byte of segaddr */
206 ((segaddr >> 16) & 0xff) + /* high-low byte of segaddr */
207 ((segaddr >> 24) & 0xff); /* high-high byte of segaddr */
208 checksum = ~checksum + 1; /* two's complement */
209 fprintf(of, "%02X\n", checksum & 0xff);
212 /* Now it's time to write data records from the code and data segments in.
213 This current version doesn't check for segment overflow; proper behavior
214 should be to output a segment address record for the code and data
215 segments. Something to do. */
216 ofs = 0;
217 segbin[0] = m->t;
218 segbin[1] = m->d;
219 for (segn = 0; segn < 2; segn++) {
220 int mod, adr;
222 if (m->f.seg[segn].length == 0)
223 continue;
224 for (i = 0; i + 15 < m->f.seg[segn].length; i += 16) {
225 ofs = write_data_record(of, ofs, 16, &segbin[segn][i]);
227 if ((mod = m->f.seg[segn].length & 0x000f) != 0) {
228 adr = m->f.seg[segn].length & 0xfff0;
229 ofs = write_data_record(of, ofs, mod, &segbin[segn][adr]);
232 /* output an end of file record */
233 fprintf(of, ":00000001FF\n");
235 fclose(of);
236 return 0;