doc: Add NASMENV to the index (BR 1917084)
[nasm/autotest.git] / rdoff / rdf2ihx.c
blob5e9fba0baf8ea3aef818125e35ea45ddbf0ad91b
1 /*
2 * rdf2ihx.c - convert an RDOFF object file to Intel Hex format.
3 * This is based on rdf2bin.
4 * Note that this program only writes 16-bit HEX.
5 */
7 #include "compiler.h"
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
13 #include "rdfload.h"
14 #include "nasmlib.h"
15 #include "symtab.h"
17 int32_t origin = 0;
18 int align = 16;
20 /* This function writes a single n-byte data record to of. Maximum value
21 for n is 255. */
22 static int write_data_record(FILE * of, int ofs, int nbytes,
23 uint8_t *data)
25 int i, iofs;
26 unsigned int checksum;
28 iofs = ofs;
29 fprintf(of, ":%02X%04X00", nbytes, ofs);
30 checksum = 0;
31 for (i = 0; i < nbytes; i++) {
32 fprintf(of, "%02X", data[i]);
33 ofs++;
34 checksum += data[i];
36 checksum = checksum + /* current checksum */
37 nbytes + /* RECLEN (one byte) */
38 ((iofs >> 8) & 0xff) + /* high byte of load offset */
39 (iofs & 0xff); /* low byte of load offset */
40 checksum = ~checksum + 1;
41 fprintf(of, "%02X\n", checksum & 0xff);
42 return (ofs);
45 int main(int argc, char **argv)
47 rdfmodule *m;
48 bool err;
49 FILE *of;
50 char *padding;
51 uint8_t *segbin[2];
52 int pad[2], segn, ofs, i;
53 int32_t segaddr;
54 unsigned int checksum;
55 symtabEnt *s;
57 if (argc < 2) {
58 puts("Usage: rdf2ihx [-o relocation-origin] [-p segment-alignment] " "input-file output-file");
59 return (1);
62 argv++, argc--;
64 while (argc > 2) {
65 if (strcmp(*argv, "-o") == 0) {
66 argv++, argc--;
67 origin = readnum(*argv, &err);
68 if (err) {
69 fprintf(stderr, "rdf2ihx: invalid parameter: %s\n", *argv);
70 return 1;
72 } else if (strcmp(*argv, "-p") == 0) {
73 argv++, argc--;
74 align = readnum(*argv, &err);
75 if (err) {
76 fprintf(stderr, "rdf2ihx: invalid parameter: %s\n", *argv);
77 return 1;
79 } else
80 break;
81 argv++, argc--;
83 if (argc < 2) {
84 puts("rdf2ihx: required parameter missing");
85 return -1;
87 m = rdfload(*argv);
89 if (!m) {
90 rdfperror("rdf2ihx", *argv);
91 return 1;
93 printf("relocating %s: origin=%"PRIx32", align=%d\n", *argv, origin, align);
95 m->textrel = origin;
96 m->datarel = origin + m->f.seg[0].length;
97 if (m->datarel % align != 0) {
98 pad[0] = align - (m->datarel % align);
99 m->datarel += pad[0];
100 } else {
101 pad[0] = 0;
104 m->bssrel = m->datarel + m->f.seg[1].length;
105 if (m->bssrel % align != 0) {
106 pad[1] = align - (m->bssrel % align);
107 m->bssrel += pad[1];
108 } else {
109 pad[1] = 0;
112 printf("code: %08"PRIx32"\ndata: %08"PRIx32"\nbss: %08"PRIx32"\n",
113 m->textrel, m->datarel, m->bssrel);
115 rdf_relocate(m);
117 argv++;
119 of = fopen(*argv, "w");
120 if (!of) {
121 fprintf(stderr, "rdf2ihx: could not open output file %s\n", *argv);
122 return (1);
125 padding = malloc(align);
126 if (!padding) {
127 fprintf(stderr, "rdf2ihx: out of memory\n");
128 return (1);
131 /* write extended segment address record */
132 fprintf(of, ":02000002"); /* Record mark, reclen, load offset & rectyp
133 fields for ext. seg. address record */
134 segaddr = ((origin >> 16) & 0xffff); /* segment address */
135 fprintf(of, "%04X", (unsigned int)(segaddr & 0xffff));
136 checksum = 0x02 + /* reclen */
137 0x0000 + /* Load Offset */
138 0x02 + /* Rectyp */
139 (segaddr & 0xff) + /* USBA low */
140 ((segaddr >> 8) & 0xff); /* USBA high */
141 checksum = ~checksum + 1; /* two's-complement the checksum */
142 fprintf(of, "%02X\n", checksum & 0xff);
144 /* See if there's a '_main' symbol in the symbol table */
145 if ((s = symtabFind(m->symtab, "_main")) == NULL) {
146 printf
147 ("No _main symbol found, no start segment address record added\n");
148 } else {
149 printf("_main symbol found at %04x:%04x\n", s->segment,
150 (unsigned int)(s->offset & 0xffff));
151 /* Create a start segment address record for the _main symbol. */
152 segaddr = ((s->segment & 0xffff) << 16) + ((s->offset) & 0xffff);
153 fprintf(of, ":04000003"); /* Record mark, reclen, load offset & rectyp
154 fields for start seg. addr. record */
155 fprintf(of, "%08"PRIX32"", segaddr); /* CS/IP field */
156 checksum = 0x04 + /* reclen */
157 0x0000 + /* load offset */
158 0x03 + /* Rectyp */
159 (segaddr & 0xff) + /* low-low byte of segaddr */
160 ((segaddr >> 8) & 0xff) + /* low-high byte of segaddr */
161 ((segaddr >> 16) & 0xff) + /* high-low byte of segaddr */
162 ((segaddr >> 24) & 0xff); /* high-high byte of segaddr */
163 checksum = ~checksum + 1; /* two's complement */
164 fprintf(of, "%02X\n", checksum & 0xff);
167 /* Now it's time to write data records from the code and data segments in.
168 This current version doesn't check for segment overflow; proper behavior
169 should be to output a segment address record for the code and data
170 segments. Something to do. */
171 ofs = 0;
172 segbin[0] = m->t;
173 segbin[1] = m->d;
174 for (segn = 0; segn < 2; segn++) {
175 int mod, adr;
177 if (m->f.seg[segn].length == 0)
178 continue;
179 for (i = 0; i + 15 < m->f.seg[segn].length; i += 16) {
180 ofs = write_data_record(of, ofs, 16, &segbin[segn][i]);
182 if ((mod = m->f.seg[segn].length & 0x000f) != 0) {
183 adr = m->f.seg[segn].length & 0xfff0;
184 ofs = write_data_record(of, ofs, mod, &segbin[segn][adr]);
187 /* output an end of file record */
188 fprintf(of, ":00000001FF\n");
190 fclose(of);
191 return 0;