NASM 0.98.22
[nasm.git] / rdoff / rdf2ihx.c
blobed91537022f30a86707bace37204906106b26540
1 /* rdf2ihx: convert an RDOFF object file to Intel Hex format. This is based
2 on rdf2bin. Note that this program only writes 16-bit HEX. */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
8 #include "rdfload.h"
9 #include "rdoff.h"
10 #include "nasmlib.h"
11 #include "symtab.h"
13 long origin = 0;
14 int align = 16;
16 /* This function writes a single n-byte data record to of. Maximum value
17 for n is 255. */
18 static int write_data_record(FILE *of, int ofs, int nbytes,
19 unsigned char *data)
21 int i, iofs;
22 unsigned int checksum;
24 iofs = ofs;
25 fprintf(of, ":%02X%04X00", nbytes, ofs);
26 checksum = 0;
27 for (i=0; i<nbytes; i++) {
28 fprintf(of, "%02X", data[i]);
29 ofs++;
30 checksum += data[i];
32 checksum = checksum + /* current checksum */
33 nbytes + /* RECLEN (one byte) */
34 ((iofs >> 8) & 0xff) + /* high byte of load offset */
35 (iofs & 0xff); /* low byte of load offset */
36 checksum = ~checksum + 1;
37 fprintf(of, "%02X\n", checksum&0xff);
38 return(ofs);
41 int main(int argc, char **argv)
43 rdfmodule *m;
44 int tmp;
45 FILE *of;
46 char *padding;
47 unsigned char *segbin[2];
48 int pad[2], segn, ofs, i;
49 long segaddr;
50 unsigned int checksum;
51 symtabEnt *s;
53 if (argc < 2) {
54 puts("Usage: rdf2ihx [-o relocation-origin] [-p segment-alignment] "
55 "input-file output-file");
56 return(1);
59 argv++, argc--;
61 while (argc > 2) {
62 if (strcmp(*argv,"-o") == 0) {
63 argv++, argc--;
64 origin = readnum(*argv, &tmp);
65 if (tmp) {
66 fprintf(stderr,"rdf2ihx: invalid parameter: %s\n",*argv);
67 return 1;
69 } else if (strcmp(*argv,"-p") == 0) {
70 argv++, argc--;
71 align = readnum(*argv, &tmp);
72 if (tmp) {
73 fprintf(stderr,"rdf2ihx: invalid parameter: %s\n",*argv);
74 return 1;
76 } else
77 break;
78 argv++, argc--;
80 if (argc < 2) {
81 puts("rdf2ihx: required parameter missing");
82 return -1;
84 m = rdfload(*argv);
86 if (!m) {
87 rdfperror("rdf2ihx",*argv);
88 return 1;
90 printf("relocating %s: origin=%lx, align=%d\n",*argv, origin, align);
92 m->textrel = origin;
93 m->datarel = origin + m->f.seg[0].length;
94 if (m->datarel % align != 0) {
95 pad[0] = align - (m->datarel % align);
96 m->datarel += pad[0];
97 } else {
98 pad[0] = 0;
101 m->bssrel = m->datarel + m->f.seg[1].length;
102 if (m->bssrel % align != 0) {
103 pad[1] = align - (m->bssrel % align);
104 m->bssrel += pad[1];
105 } else {
106 pad[1] = 0;
109 printf("code: %08lx\ndata: %08lx\nbss: %08lx\n",
110 m->textrel, m->datarel, m->bssrel);
112 rdf_relocate(m);
114 argv++;
116 of = fopen(*argv,"w");
117 if (!of) {
118 fprintf(stderr,"rdf2ihx: could not open output file %s\n",*argv);
119 return(1);
122 padding = malloc(align);
123 if (!padding) {
124 fprintf(stderr,"rdf2ihx: out of memory\n");
125 return(1);
128 /* write extended segment address record */
129 fprintf(of, ":02000002"); /* Record mark, reclen, load offset & rectyp
130 fields for ext. seg. address record */
131 segaddr = ((origin >> 16) & 0xffff); /* segment address */
132 fprintf(of, "%04X", (unsigned int)(segaddr & 0xffff));
133 checksum = 0x02 + /* reclen */
134 0x0000 + /* Load Offset */
135 0x02 + /* Rectyp */
136 (segaddr & 0xff) + /* USBA low */
137 ((segaddr >> 8) & 0xff); /* USBA high */
138 checksum = ~checksum + 1; /* two's-complement the checksum */
139 fprintf(of, "%02X\n", checksum & 0xff);
141 /* See if there's a '_main' symbol in the symbol table */
142 if ((s=symtabFind(m->symtab, "_main")) == NULL) {
143 printf("No _main symbol found, no start segment address record added\n");
144 } else {
145 printf("_main symbol found at %04x:%04x\n", s->segment,
146 (unsigned int)(s->offset & 0xffff));
147 /* Create a start segment address record for the _main symbol. */
148 segaddr = ((s->segment & 0xffff) << 16) + ((s->offset) & 0xffff);
149 fprintf(of, ":04000003"); /* Record mark, reclen, load offset & rectyp
150 fields for start seg. addr. record */
151 fprintf(of, "%08lX", segaddr); /* CS/IP field */
152 checksum = 0x04 + /* reclen */
153 0x0000 + /* load offset */
154 0x03 + /* Rectyp */
155 (segaddr & 0xff) + /* low-low byte of segaddr */
156 ((segaddr >> 8) & 0xff) + /* low-high byte of segaddr */
157 ((segaddr >> 16) & 0xff) + /* high-low byte of segaddr */
158 ((segaddr >> 24) & 0xff); /* high-high byte of segaddr */
159 checksum = ~checksum + 1; /* two's complement */
160 fprintf(of, "%02X\n", checksum & 0xff);
163 /* Now it's time to write data records from the code and data segments in.
164 This current version doesn't check for segment overflow; proper behavior
165 should be to output a segment address record for the code and data
166 segments. Something to do. */
167 ofs = 0;
168 segbin[0] = m->t;
169 segbin[1] = m->d;
170 for (segn=0; segn<2; segn++) {
171 int mod, adr;
173 if (m->f.seg[segn].length == 0)
174 continue;
175 for (i=0; i+15<m->f.seg[segn].length; i+=16) {
176 ofs = write_data_record(of, ofs, 16, &segbin[segn][i]);
178 if ((mod=m->f.seg[segn].length & 0x000f) != 0) {
179 adr = m->f.seg[segn].length & 0xfff0;
180 ofs = write_data_record(of, ofs, mod, &segbin[segn][adr]);
183 /* output an end of file record */
184 fprintf(of, ":00000001FF\n");
186 fclose(of);
187 return 0;