mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-03-13 17:57:12 +08:00
outbin: add support for Intel hex and Motorola S-records
Add support for directly generating Intel hex or Motorola S-records. These formats are commonly used with ROM burners. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
parent
0cba107579
commit
4660a2b4a0
@ -4565,6 +4565,32 @@ or \c{symbols} may be specified. Output may be directed to \c{stdout}
|
|||||||
brackets must be used.
|
brackets must be used.
|
||||||
|
|
||||||
|
|
||||||
|
\H{ithfmt} \i\c{ith}: \i{Intel Hex} Output
|
||||||
|
|
||||||
|
The \c{ith} file format produces Intel Hex-format files. Just as the
|
||||||
|
\c{bin} format, this is a flat memory image format with no support for
|
||||||
|
relocation or linking. It is usually used with ROM programmers and
|
||||||
|
similar utilities.
|
||||||
|
|
||||||
|
All options supported by the \c{bin} file format is also supported by
|
||||||
|
the \c{ith} file format.
|
||||||
|
|
||||||
|
\c{ith} provides a default output file-name extension of \c{.ith}.
|
||||||
|
|
||||||
|
|
||||||
|
\H{srecfmt} \i\c{srec}: \i{Motorola S-Record} Output
|
||||||
|
|
||||||
|
The \c{srec} file format produces Intel Hex-format files. Just as the
|
||||||
|
\c{bin} format, this is a flat memory image format with no support for
|
||||||
|
relocation or linking. It is usually used with ROM programmers and
|
||||||
|
similar utilities.
|
||||||
|
|
||||||
|
All options supported by the \c{bin} file format is also supported by
|
||||||
|
the \c{srec} file format.
|
||||||
|
|
||||||
|
\c{srec} provides a default output file-name extension of \c{.srec}.
|
||||||
|
|
||||||
|
|
||||||
\H{objfmt} \i\c{obj}: \i{Microsoft OMF}\I{OMF} Object Files
|
\H{objfmt} \i\c{obj}: \i{Microsoft OMF}\I{OMF} Object Files
|
||||||
|
|
||||||
The \c{obj} file format (NASM calls it \c{obj} rather than \c{omf}
|
The \c{obj} file format (NASM calls it \c{obj} rather than \c{omf}
|
||||||
|
318
output/outbin.c
318
output/outbin.c
@ -92,10 +92,10 @@
|
|||||||
|
|
||||||
#ifdef OF_BIN
|
#ifdef OF_BIN
|
||||||
|
|
||||||
struct ofmt *bin_get_ofmt(); /* Prototype goes here since no header file. */
|
|
||||||
|
|
||||||
static FILE *fp, *rf = NULL;
|
static FILE *fp, *rf = NULL;
|
||||||
static efunc error;
|
static efunc error;
|
||||||
|
static struct ofmt *my_ofmt;
|
||||||
|
static void (*do_output)(void);
|
||||||
|
|
||||||
/* Section flags keep track of which attributes the user has defined. */
|
/* Section flags keep track of which attributes the user has defined. */
|
||||||
#define START_DEFINED 0x001
|
#define START_DEFINED 0x001
|
||||||
@ -592,26 +592,8 @@ static void bin_cleanup(int debuginfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Step 6: Write the section data to the output file. */
|
/* Step 6: Write the section data to the output file. */
|
||||||
|
do_output();
|
||||||
/* Write the progbits sections to the output file. */
|
fclose(fp); /* Done with the output file */
|
||||||
pend = origin;
|
|
||||||
for (s = sections; s; s = s->next) {
|
|
||||||
/* Skip non-progbits sections */
|
|
||||||
if (!(s->flags & TYPE_PROGBITS))
|
|
||||||
continue;
|
|
||||||
/* Skip zero-length sections */
|
|
||||||
if (s->length == 0)
|
|
||||||
continue;
|
|
||||||
/* Pad the space between sections. */
|
|
||||||
for (h = s->start - pend; h; h--)
|
|
||||||
fputc('\0', fp);
|
|
||||||
/* Write the section to the output file. */
|
|
||||||
if (s->length > 0)
|
|
||||||
saa_fpwrite(s->contents, fp);
|
|
||||||
pend = s->start + s->length;
|
|
||||||
}
|
|
||||||
/* Done writing the file, so close it. */
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
/* Step 7: Generate the map file. */
|
/* Step 7: Generate the map file. */
|
||||||
|
|
||||||
@ -1227,12 +1209,12 @@ static void bin_define_section_labels(void)
|
|||||||
/* section.<name>.start */
|
/* section.<name>.start */
|
||||||
strcpy(label_name + base_len, ".start");
|
strcpy(label_name + base_len, ".start");
|
||||||
define_label(label_name, sec->start_index, 0L,
|
define_label(label_name, sec->start_index, 0L,
|
||||||
NULL, 0, 0, bin_get_ofmt(), error);
|
NULL, 0, 0, my_ofmt, error);
|
||||||
|
|
||||||
/* section.<name>.vstart */
|
/* section.<name>.vstart */
|
||||||
strcpy(label_name + base_len, ".vstart");
|
strcpy(label_name + base_len, ".vstart");
|
||||||
define_label(label_name, sec->vstart_index, 0L,
|
define_label(label_name, sec->vstart_index, 0L,
|
||||||
NULL, 0, 0, bin_get_ofmt(), error);
|
NULL, 0, 0, my_ofmt, error);
|
||||||
|
|
||||||
nasm_free(label_name);
|
nasm_free(label_name);
|
||||||
}
|
}
|
||||||
@ -1394,6 +1376,20 @@ static void bin_filename(char *inname, char *outname, efunc error)
|
|||||||
outfile = outname;
|
outfile = outname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ith_filename(char *inname, char *outname, efunc error)
|
||||||
|
{
|
||||||
|
standard_extension(inname, outname, ".ith", error);
|
||||||
|
infile = inname;
|
||||||
|
outfile = outname;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void srec_filename(char *inname, char *outname, efunc error)
|
||||||
|
{
|
||||||
|
standard_extension(inname, outname, ".srec", error);
|
||||||
|
infile = inname;
|
||||||
|
outfile = outname;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t bin_segbase(int32_t segment)
|
static int32_t bin_segbase(int32_t segment)
|
||||||
{
|
{
|
||||||
return segment;
|
return segment;
|
||||||
@ -1406,7 +1402,34 @@ static int bin_set_info(enum geninfo type, char **val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void binfmt_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval);
|
||||||
|
struct ofmt of_bin, of_ith, of_srec;
|
||||||
|
static void do_output_bin(void);
|
||||||
|
static void do_output_ith(void);
|
||||||
|
static void do_output_srec(void);
|
||||||
|
|
||||||
static void bin_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
|
static void bin_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
|
||||||
|
{
|
||||||
|
my_ofmt = &of_bin;
|
||||||
|
do_output = do_output_bin;
|
||||||
|
binfmt_init(afp, errfunc, ldef, eval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ith_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
|
||||||
|
{
|
||||||
|
my_ofmt = &of_ith;
|
||||||
|
do_output = do_output_ith;
|
||||||
|
binfmt_init(afp, errfunc, ldef, eval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void srec_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
|
||||||
|
{
|
||||||
|
my_ofmt = &of_srec;
|
||||||
|
do_output = do_output_srec;
|
||||||
|
binfmt_init(afp, errfunc, ldef, eval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void binfmt_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
|
||||||
{
|
{
|
||||||
fp = afp;
|
fp = afp;
|
||||||
error = errfunc;
|
error = errfunc;
|
||||||
@ -1438,6 +1461,213 @@ static void bin_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
|
|||||||
last_section->vstart_index = current_section = seg_alloc();
|
last_section->vstart_index = current_section = seg_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generate binary file output */
|
||||||
|
static void do_output_bin(void)
|
||||||
|
{
|
||||||
|
struct Section *s;
|
||||||
|
uint64_t addr = origin;
|
||||||
|
|
||||||
|
/* Write the progbits sections to the output file. */
|
||||||
|
for (s = sections; s; s = s->next) {
|
||||||
|
/* Skip non-progbits sections */
|
||||||
|
if (!(s->flags & TYPE_PROGBITS))
|
||||||
|
continue;
|
||||||
|
/* Skip zero-length sections */
|
||||||
|
if (s->length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Pad the space between sections. */
|
||||||
|
fwritezero(s->start - addr, fp);
|
||||||
|
|
||||||
|
/* Write the section to the output file. */
|
||||||
|
saa_fpwrite(s->contents, fp);
|
||||||
|
|
||||||
|
/* Keep track of the current file position */
|
||||||
|
addr = s->start + s->length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate Intel hex file output */
|
||||||
|
static int write_ith_record(unsigned int len, uint16_t addr,
|
||||||
|
uint8_t type, void *data)
|
||||||
|
{
|
||||||
|
char buf[1+2+4+2+255*2+2+2];
|
||||||
|
char *p = buf;
|
||||||
|
uint8_t csum, *dptr = data;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
nasm_assert(len <= 255);
|
||||||
|
|
||||||
|
csum = len + addr + (addr >> 8) + type;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
csum += dptr[i];
|
||||||
|
csum = -csum;
|
||||||
|
|
||||||
|
p += sprintf(p, ":%02X%04X%02X", len, addr, type);
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
p += sprintf(p, "%02X", dptr[i]);
|
||||||
|
p += sprintf(p, "%02X\n", csum);
|
||||||
|
|
||||||
|
if (fwrite(buf, 1, p-buf, fp) != (size_t)(p-buf))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_output_ith(void)
|
||||||
|
{
|
||||||
|
uint8_t buf[32];
|
||||||
|
struct Section *s;
|
||||||
|
uint64_t addr, last;
|
||||||
|
uint64_t length;
|
||||||
|
unsigned int chunk;
|
||||||
|
|
||||||
|
/* Write the progbits sections to the output file. */
|
||||||
|
last = 0;
|
||||||
|
for (s = sections; s; s = s->next) {
|
||||||
|
/* Skip non-progbits sections */
|
||||||
|
if (!(s->flags & TYPE_PROGBITS))
|
||||||
|
continue;
|
||||||
|
/* Skip zero-length sections */
|
||||||
|
if (s->length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
addr = s->start;
|
||||||
|
length = s->length;
|
||||||
|
|
||||||
|
while (length) {
|
||||||
|
if ((addr^last) & 0xffff0000) {
|
||||||
|
buf[0] = addr >> 24;
|
||||||
|
buf[1] = addr >> 16;
|
||||||
|
write_ith_record(2, 0, 4, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = 32 - (addr & 31);
|
||||||
|
if (length < chunk)
|
||||||
|
chunk = length;
|
||||||
|
|
||||||
|
saa_rnbytes(s->contents, buf, chunk);
|
||||||
|
write_ith_record(chunk, (uint16_t)addr, 0, buf);
|
||||||
|
|
||||||
|
last = addr + chunk - 1;
|
||||||
|
addr += chunk;
|
||||||
|
length -= chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write closing record */
|
||||||
|
write_ith_record(0, 0, 1, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate Motorola S-records */
|
||||||
|
static int write_srecord(unsigned int len, unsigned int alen,
|
||||||
|
uint32_t addr, uint8_t type, void *data)
|
||||||
|
{
|
||||||
|
char buf[2+2+8+255*2+2+2];
|
||||||
|
char *p = buf;
|
||||||
|
uint8_t csum, *dptr = data;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
nasm_assert(len <= 255);
|
||||||
|
|
||||||
|
switch (alen) {
|
||||||
|
case 2:
|
||||||
|
addr &= 0xffff;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
addr &= 0xffffff;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nasm_assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24);
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
csum += dptr[i];
|
||||||
|
csum = 0xff-csum;
|
||||||
|
|
||||||
|
p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr);
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
p += sprintf(p, "%02X", dptr[i]);
|
||||||
|
p += sprintf(p, "%02X\n", csum);
|
||||||
|
|
||||||
|
if (fwrite(buf, 1, p-buf, fp) != (size_t)(p-buf))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_output_srec(void)
|
||||||
|
{
|
||||||
|
uint8_t buf[32];
|
||||||
|
struct Section *s;
|
||||||
|
uint64_t addr, maxaddr;
|
||||||
|
uint64_t length;
|
||||||
|
int alen;
|
||||||
|
unsigned int chunk;
|
||||||
|
char dtype, etype;
|
||||||
|
|
||||||
|
maxaddr = 0;
|
||||||
|
for (s = sections; s; s = s->next) {
|
||||||
|
/* Skip non-progbits sections */
|
||||||
|
if (!(s->flags & TYPE_PROGBITS))
|
||||||
|
continue;
|
||||||
|
/* Skip zero-length sections */
|
||||||
|
if (s->length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
addr = s->start + s->length - 1;
|
||||||
|
if (addr > maxaddr)
|
||||||
|
maxaddr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxaddr <= 0xffff) {
|
||||||
|
alen = 2;
|
||||||
|
dtype = '1'; /* S1 = 16-bit data */
|
||||||
|
etype = '9'; /* S9 = 16-bit end */
|
||||||
|
} else if (maxaddr <= 0xffffff) {
|
||||||
|
alen = 3;
|
||||||
|
dtype = '2'; /* S2 = 24-bit data */
|
||||||
|
etype = '8'; /* S8 = 24-bit end */
|
||||||
|
} else {
|
||||||
|
alen = 4;
|
||||||
|
dtype = '3'; /* S3 = 32-bit data */
|
||||||
|
etype = '7'; /* S7 = 32-bit end */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the progbits sections to the output file. */
|
||||||
|
for (s = sections; s; s = s->next) {
|
||||||
|
/* Skip non-progbits sections */
|
||||||
|
if (!(s->flags & TYPE_PROGBITS))
|
||||||
|
continue;
|
||||||
|
/* Skip zero-length sections */
|
||||||
|
if (s->length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
addr = s->start;
|
||||||
|
length = s->length;
|
||||||
|
|
||||||
|
while (length) {
|
||||||
|
chunk = 32 - (addr & 31);
|
||||||
|
if (length < chunk)
|
||||||
|
chunk = length;
|
||||||
|
|
||||||
|
saa_rnbytes(s->contents, buf, chunk);
|
||||||
|
write_srecord(chunk, alen, (uint32_t)addr, dtype, buf);
|
||||||
|
|
||||||
|
addr += chunk;
|
||||||
|
length -= chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write closing record */
|
||||||
|
write_srecord(0, alen, 0, etype, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct ofmt of_bin = {
|
struct ofmt of_bin = {
|
||||||
"flat-form binary files (e.g. DOS .COM, .SYS)",
|
"flat-form binary files (e.g. DOS .COM, .SYS)",
|
||||||
"bin",
|
"bin",
|
||||||
@ -1456,10 +1686,40 @@ struct ofmt of_bin = {
|
|||||||
bin_cleanup
|
bin_cleanup
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is needed for bin_define_section_labels() */
|
struct ofmt of_ith = {
|
||||||
struct ofmt *bin_get_ofmt(void)
|
"Intel Hex",
|
||||||
{
|
"ith",
|
||||||
return &of_bin;
|
OFMT_TEXT,
|
||||||
}
|
null_debug_arr,
|
||||||
|
&null_debug_form,
|
||||||
|
bin_stdmac,
|
||||||
|
ith_init,
|
||||||
|
bin_set_info,
|
||||||
|
bin_out,
|
||||||
|
bin_deflabel,
|
||||||
|
bin_secname,
|
||||||
|
bin_segbase,
|
||||||
|
bin_directive,
|
||||||
|
ith_filename,
|
||||||
|
bin_cleanup
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ofmt of_srec = {
|
||||||
|
"Motorola S-records",
|
||||||
|
"srec",
|
||||||
|
0,
|
||||||
|
null_debug_arr,
|
||||||
|
&null_debug_form,
|
||||||
|
bin_stdmac,
|
||||||
|
srec_init,
|
||||||
|
bin_set_info,
|
||||||
|
bin_out,
|
||||||
|
bin_deflabel,
|
||||||
|
bin_secname,
|
||||||
|
bin_segbase,
|
||||||
|
bin_directive,
|
||||||
|
srec_filename,
|
||||||
|
bin_cleanup
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* #ifdef OF_BIN */
|
#endif /* #ifdef OF_BIN */
|
||||||
|
@ -250,6 +250,8 @@
|
|||||||
* array based on the above defines */
|
* array based on the above defines */
|
||||||
|
|
||||||
extern struct ofmt of_bin;
|
extern struct ofmt of_bin;
|
||||||
|
extern struct ofmt of_ith;
|
||||||
|
extern struct ofmt of_srec;
|
||||||
extern struct ofmt of_aout;
|
extern struct ofmt of_aout;
|
||||||
extern struct ofmt of_aoutb;
|
extern struct ofmt of_aoutb;
|
||||||
extern struct ofmt of_coff;
|
extern struct ofmt of_coff;
|
||||||
@ -268,6 +270,8 @@ extern struct ofmt of_dbg;
|
|||||||
struct ofmt *drivers[] = {
|
struct ofmt *drivers[] = {
|
||||||
#ifdef OF_BIN
|
#ifdef OF_BIN
|
||||||
&of_bin,
|
&of_bin,
|
||||||
|
&of_ith,
|
||||||
|
&of_srec,
|
||||||
#endif
|
#endif
|
||||||
#ifdef OF_AOUT
|
#ifdef OF_AOUT
|
||||||
&of_aout,
|
&of_aout,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user