mirror of
https://github.com/netwide-assembler/nasm.git
synced 2024-11-27 08:10:07 +08:00
190 lines
5.1 KiB
C
190 lines
5.1 KiB
C
/* rdf2ihx: 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 "rdoff.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("rdf2bin: required parameter missing");
|
|
return -1;
|
|
}
|
|
m = rdfload(*argv);
|
|
|
|
if (!m) {
|
|
rdfperror("rdf2bin",*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;
|
|
}
|
|
|