nasm/rdoff/rdf2ihx.c
Yuri Zaporogets e0c059ab4e outrdf2.c now uses the same definitions of RDOFF2 format that RDOFF utils.
Export/import/common label size is increased from 33 to 64. Fixed the bug
that caused wrong behavior of rdfgetheaderrec() if label length was 32.
Changed error codes from numeric values to symbolic constants.
Moved some routines from rdfdump.c to rdoff.c. They will be utilized also
by rdfdisasm, which is being developed.
2004-09-15 06:54:34 +00:00

190 lines
5.1 KiB
C

/*
* rdf2ihx.c - convert an RDOFF object file to Intel Hex format.
* This is based on rdf2bin.
* Note that this program only writes 16-bit HEX.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "rdfload.h"
#include "nasmlib.h"
#include "symtab.h"
long origin = 0;
int align = 16;
/* This function writes a single n-byte data record to of. Maximum value
for n is 255. */
static int write_data_record(FILE *of, int ofs, int nbytes,
unsigned char *data)
{
int i, iofs;
unsigned int checksum;
iofs = ofs;
fprintf(of, ":%02X%04X00", nbytes, ofs);
checksum = 0;
for (i=0; i<nbytes; i++) {
fprintf(of, "%02X", data[i]);
ofs++;
checksum += data[i];
}
checksum = checksum + /* current checksum */
nbytes + /* RECLEN (one byte) */
((iofs >> 8) & 0xff) + /* high byte of load offset */
(iofs & 0xff); /* low byte of load offset */
checksum = ~checksum + 1;
fprintf(of, "%02X\n", checksum&0xff);
return(ofs);
}
int main(int argc, char **argv)
{
rdfmodule *m;
int tmp;
FILE *of;
char *padding;
unsigned char *segbin[2];
int pad[2], segn, ofs, i;
long segaddr;
unsigned int checksum;
symtabEnt *s;
if (argc < 2) {
puts("Usage: rdf2ihx [-o relocation-origin] [-p segment-alignment] "
"input-file output-file");
return(1);
}
argv++, argc--;
while (argc > 2) {
if (strcmp(*argv,"-o") == 0) {
argv++, argc--;
origin = readnum(*argv, &tmp);
if (tmp) {
fprintf(stderr,"rdf2ihx: invalid parameter: %s\n",*argv);
return 1;
}
} else if (strcmp(*argv,"-p") == 0) {
argv++, argc--;
align = readnum(*argv, &tmp);
if (tmp) {
fprintf(stderr,"rdf2ihx: invalid parameter: %s\n",*argv);
return 1;
}
} else
break;
argv++, argc--;
}
if (argc < 2) {
puts("rdf2ihx: required parameter missing");
return -1;
}
m = rdfload(*argv);
if (!m) {
rdfperror("rdf2ihx",*argv);
return 1;
}
printf("relocating %s: origin=%lx, align=%d\n",*argv, origin, align);
m->textrel = origin;
m->datarel = origin + m->f.seg[0].length;
if (m->datarel % align != 0) {
pad[0] = align - (m->datarel % align);
m->datarel += pad[0];
} else {
pad[0] = 0;
}
m->bssrel = m->datarel + m->f.seg[1].length;
if (m->bssrel % align != 0) {
pad[1] = align - (m->bssrel % align);
m->bssrel += pad[1];
} else {
pad[1] = 0;
}
printf("code: %08lx\ndata: %08lx\nbss: %08lx\n",
m->textrel, m->datarel, m->bssrel);
rdf_relocate(m);
argv++;
of = fopen(*argv,"w");
if (!of) {
fprintf(stderr,"rdf2ihx: could not open output file %s\n",*argv);
return(1);
}
padding = malloc(align);
if (!padding) {
fprintf(stderr,"rdf2ihx: out of memory\n");
return(1);
}
/* write extended segment address record */
fprintf(of, ":02000002"); /* Record mark, reclen, load offset & rectyp
fields for ext. seg. address record */
segaddr = ((origin >> 16) & 0xffff); /* segment address */
fprintf(of, "%04X", (unsigned int)(segaddr & 0xffff));
checksum = 0x02 + /* reclen */
0x0000 + /* Load Offset */
0x02 + /* Rectyp */
(segaddr & 0xff) + /* USBA low */
((segaddr >> 8) & 0xff); /* USBA high */
checksum = ~checksum + 1; /* two's-complement the checksum */
fprintf(of, "%02X\n", checksum & 0xff);
/* See if there's a '_main' symbol in the symbol table */
if ((s=symtabFind(m->symtab, "_main")) == NULL) {
printf("No _main symbol found, no start segment address record added\n");
} else {
printf("_main symbol found at %04x:%04x\n", s->segment,
(unsigned int)(s->offset & 0xffff));
/* Create a start segment address record for the _main symbol. */
segaddr = ((s->segment & 0xffff) << 16) + ((s->offset) & 0xffff);
fprintf(of, ":04000003"); /* Record mark, reclen, load offset & rectyp
fields for start seg. addr. record */
fprintf(of, "%08lX", segaddr); /* CS/IP field */
checksum = 0x04 + /* reclen */
0x0000 + /* load offset */
0x03 + /* Rectyp */
(segaddr & 0xff) + /* low-low byte of segaddr */
((segaddr >> 8) & 0xff) + /* low-high byte of segaddr */
((segaddr >> 16) & 0xff) + /* high-low byte of segaddr */
((segaddr >> 24) & 0xff); /* high-high byte of segaddr */
checksum = ~checksum + 1; /* two's complement */
fprintf(of, "%02X\n", checksum & 0xff);
}
/* Now it's time to write data records from the code and data segments in.
This current version doesn't check for segment overflow; proper behavior
should be to output a segment address record for the code and data
segments. Something to do. */
ofs = 0;
segbin[0] = m->t;
segbin[1] = m->d;
for (segn=0; segn<2; segn++) {
int mod, adr;
if (m->f.seg[segn].length == 0)
continue;
for (i=0; i+15<m->f.seg[segn].length; i+=16) {
ofs = write_data_record(of, ofs, 16, &segbin[segn][i]);
}
if ((mod=m->f.seg[segn].length & 0x000f) != 0) {
adr = m->f.seg[segn].length & 0xfff0;
ofs = write_data_record(of, ofs, mod, &segbin[segn][adr]);
}
}
/* output an end of file record */
fprintf(of, ":00000001FF\n");
fclose(of);
return 0;
}