From 14204e3d147ad99cc249ad8de254809180fe5c38 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Nov 2013 09:31:02 -0800 Subject: [PATCH] ao-tools: Add ao-elftohex and .ihx symbol support ao-elftohex converts an elf file into a hex file so that we can load it with java. Signed-off-by: Keith Packard --- ao-tools/Makefile.am | 2 +- ao-tools/ao-elftohex/Makefile.am | 18 ++ ao-tools/ao-elftohex/ao-elftohex.1 | 38 ++++ ao-tools/ao-elftohex/ao-elftohex.c | 102 ++++++++++ ao-tools/ao-stmload/ao-stmload.c | 39 +++- ao-tools/ao-stmload/ao-stmload.h | 2 +- ao-tools/lib/Makefile.am | 4 +- ao-tools/lib/ao-elf.c | 94 ++++++---- ao-tools/lib/ao-elf.h | 13 +- ao-tools/lib/ao-hex.c | 286 ++++++++++++++++++++++++++--- ao-tools/lib/ao-hex.h | 16 +- configure.ac | 1 + 12 files changed, 540 insertions(+), 75 deletions(-) create mode 100644 ao-tools/ao-elftohex/Makefile.am create mode 100644 ao-tools/ao-elftohex/ao-elftohex.1 create mode 100644 ao-tools/ao-elftohex/ao-elftohex.c diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am index 4600f1d6..9c382739 100644 --- a/ao-tools/Makefile.am +++ b/ao-tools/Makefile.am @@ -1,3 +1,3 @@ SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list \ ao-load ao-telem ao-stmload ao-send-telem ao-sky-flash \ - ao-dumpflash ao-edit-telem ao-dump-up + ao-dumpflash ao-edit-telem ao-dump-up ao-elftohex diff --git a/ao-tools/ao-elftohex/Makefile.am b/ao-tools/ao-elftohex/Makefile.am new file mode 100644 index 00000000..33c9923f --- /dev/null +++ b/ao-tools/ao-elftohex/Makefile.am @@ -0,0 +1,18 @@ +if LIBSTLINK + +bin_PROGRAMS=ao-elftohex + +LIBSTLINKDIR=/local/src/stlink + +AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS) +AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a + +ao_elftohex_DEPENDENCIES = $(AO_STMLOAD_LIBS) + +ao_elftohex_LDADD=$(AO_STMLOAD_LIBS) $(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf + +ao_elftohex_SOURCES=ao-elftohex.c + +man_MANS = ao-elftohex.1 + +endif diff --git a/ao-tools/ao-elftohex/ao-elftohex.1 b/ao-tools/ao-elftohex/ao-elftohex.1 new file mode 100644 index 00000000..e52e6f5a --- /dev/null +++ b/ao-tools/ao-elftohex/ao-elftohex.1 @@ -0,0 +1,38 @@ +.\" +.\" Copyright © 2013 Keith Packard +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, but +.\" WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +.\" General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License along +.\" with this program; if not, write to the Free Software Foundation, Inc., +.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +.\" +.\" +.TH AO-LOAD 1 "ao-elftohex" "" +.SH NAME +ao-elftohex \- convert a program to IHX format +.SH SYNOPSIS +.B "ao-elftohex" +[\--output-\fIoutput.ihx\fP] +[\--verbose] +\fIinput.elf\fP +.SH DESCRIPTION +.I ao-elftohex +reads the specified .elf file and writes out a .ihx version. +.SH OPTIONS +.TP +\--output=\fIoutput.ihx\fP +This specifies the output file (default is stdout) +.TP +\--verbose +Dumps some debug information. +.SH AUTHOR +Keith Packard diff --git a/ao-tools/ao-elftohex/ao-elftohex.c b/ao-tools/ao-elftohex/ao-elftohex.c new file mode 100644 index 00000000..db8f86f1 --- /dev/null +++ b/ao-tools/ao-elftohex/ao-elftohex.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include "ao-hex.h" +#include "ao-elf.h" +#include "ao-verbose.h" + +static const struct option options[] = { + { .name = "verbose", .has_arg = 1, .val = 'v' }, + { .name = "output", .has_arg = 1, .val = 'o' }, + { 0, 0, 0, 0}, +}; + +static void usage(char *program) +{ + fprintf(stderr, "usage: %s [--verbose=] [--output=] \n", program); + exit(1); +} + +static int +ends_with(char *whole, char *suffix) +{ + int whole_len = strlen(whole); + int suffix_len = strlen(suffix); + + if (suffix_len > whole_len) + return 0; + return strcmp(whole + whole_len - suffix_len, suffix) == 0; +} + +int +main (int argc, char **argv) +{ + char *input = NULL; + char *output = NULL; + struct ao_hex_image *image; + struct ao_sym *file_symbols; + int num_file_symbols; + FILE *file; + int c; + + while ((c = getopt_long(argc, argv, "v:o:", options, NULL)) != -1) { + switch (c) { + case 'o': + output = optarg; + break; + case 'v': + ao_verbose = (int) strtol(optarg, NULL, 0); + break; + default: + usage(argv[0]); + break; + } + } + + input = argv[optind]; + if (input == NULL) + usage(argv[0]); + + if (ends_with (input, ".ihx")) + image = ao_hex_load(input, &file_symbols, &num_file_symbols); + else + image = ao_load_elf(input, &file_symbols, &num_file_symbols); + + if (!image) + usage(argv[0]); + + if (!output) + file = stdout; + else { + file = fopen(output, "w"); + if (!file) { + perror(output); + exit(1); + } + } + + if (!ao_hex_save(file, image, file_symbols, num_file_symbols)) { + fprintf(stderr, "%s: failed to write hex file\n", output ? output : ""); + if (output) + unlink(output); + exit(1); + } + exit(0); +} diff --git a/ao-tools/ao-stmload/ao-stmload.c b/ao-tools/ao-stmload/ao-stmload.c index 6e3906fd..a11d93de 100644 --- a/ao-tools/ao-stmload/ao-stmload.c +++ b/ao-tools/ao-stmload/ao-stmload.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "stlink-common.h" #include "ao-elf.h" #include "ccdbg.h" @@ -34,7 +35,7 @@ #define AO_USB_DESC_STRING 3 -struct ao_elf_sym ao_symbols[] = { +struct ao_sym ao_symbols[] = { { 0, AO_BOOT_APPLICATION_BASE + 0x100, "ao_romconfig_version", 1 }, #define AO_ROMCONFIG_VERSION (ao_symbols[0].addr) @@ -218,6 +219,30 @@ check_flashed(stlink_t *sl, struct cc_usb *cc) return 1; } +/* + * Find the symbols needed to correctly load the program + */ + +static bool +find_symbols(struct ao_sym *file_symbols, int num_file_symbols, + struct ao_sym *symbols, int num_symbols) +{ + int f, s; + + for (f = 0; f < num_file_symbols; f++) { + for (s = 0; s < num_symbols; s++) { + if (strcmp(symbols[s].name, file_symbols[f].name) == 0) { + symbols[s].addr = file_symbols[f].addr; + symbols[s].found = true; + } + } + } + for (s = 0; s < num_symbols; s++) + if (!symbols[s].found && symbols[s].required) + return false; + return true; +} + static const struct option options[] = { { .name = "stlink", .has_arg = 0, .val = 'S' }, { .name = "tty", .has_arg = 1, .val = 'T' }, @@ -288,6 +313,8 @@ main (int argc, char **argv) char *tty = NULL; int success; int verbose = 0; + struct ao_sym *file_symbols; + int num_file_symbols; while ((c = getopt_long(argc, argv, "T:D:c:s:Sv", options, NULL)) != -1) { switch (c) { @@ -329,15 +356,15 @@ main (int argc, char **argv) usage(argv[0]); if (ends_with (filename, ".elf")) { - load = ao_load_elf(filename, ao_symbols, ao_num_symbols); + load = ao_load_elf(filename, &file_symbols, &num_file_symbols); } else if (ends_with (filename, ".ihx")) { - int i; - load = ao_hex_load(filename); - for (i = 0; i < ao_num_symbols; i++) - ao_symbols[i].addr = ao_symbols[i].default_addr; + load = ao_hex_load(filename, &file_symbols, &num_file_symbols); } else usage(argv[0]); + if (!find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols)) + fprintf(stderr, "Cannot find required symbols\n"); + if (use_stlink) { /* Connect to the programming dongle */ diff --git a/ao-tools/ao-stmload/ao-stmload.h b/ao-tools/ao-stmload/ao-stmload.h index 28c2dda4..744dfa75 100644 --- a/ao-tools/ao-stmload/ao-stmload.h +++ b/ao-tools/ao-stmload/ao-stmload.h @@ -22,7 +22,7 @@ #define AO_BOOT_APPLICATION_BASE 0x08001000 -extern struct ao_elf_sym ao_symbols[]; +extern struct ao_sym ao_symbols[]; extern int ao_num_symbols; extern int ao_num_required_symbols; diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index 868b64f1..ca32e121 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -43,4 +43,6 @@ libao_tools_a_SOURCES = \ ao-hex.c \ ao-hex.h \ ao-elf.c \ - ao-elf.h + ao-elf.h \ + ao-verbose.c \ + ao-verbose.h diff --git a/ao-tools/lib/ao-elf.c b/ao-tools/lib/ao-elf.c index 932dc853..99b37210 100644 --- a/ao-tools/lib/ao-elf.c +++ b/ao-tools/lib/ao-elf.c @@ -27,21 +27,26 @@ #include #include "ao-elf.h" #include "ao-hex.h" +#include "ao-verbose.h" /* * Look through the Elf file for symbols that can be adjusted before * the image is written to the device */ -static bool -find_symbols (Elf *e, struct ao_elf_sym *symbols, int num_symbols) +static struct ao_sym * +load_symbols (Elf *e, int *num_symbolsp) { Elf_Scn *scn; Elf_Data *symbol_data = NULL; GElf_Shdr shdr; GElf_Sym sym; - int i, symbol_count, s; + int i, symbol_count; char *symbol_name; size_t shstrndx; + struct ao_sym *symbols = NULL; + struct ao_sym *symbol; + int num_symbols = 0; + int size_symbols = 0; if (elf_getshdrstrndx(e, &shstrndx) < 0) return false; @@ -64,23 +69,46 @@ find_symbols (Elf *e, struct ao_elf_sym *symbols, int num_symbols) } if (!symbol_data) - return false; + return NULL; for (i = 0; i < symbol_count; i++) { gelf_getsym(symbol_data, i, &sym); symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name); + if (!symbol_name[0]) + continue; - for (s = 0; s < num_symbols; s++) - if (!strcmp (symbols[s].name, symbol_name)) { - symbols[s].addr = sym.st_value; - symbols[s].found = true; - } + if (num_symbols == size_symbols) { + struct ao_sym *new_symbols; + int new_size; + + if (!size_symbols) + new_size = 16; + else + new_size = size_symbols * 2; + new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym)); + if (!new_symbols) + goto bail; + + symbols = new_symbols; + size_symbols = new_size; + } + symbol = &symbols[num_symbols]; + memset(symbol, 0, sizeof (struct ao_sym)); + symbol->name = strdup(symbol_name); + if (!symbol->name) + goto bail; + symbol->addr = sym.st_value; + ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr); + num_symbols++; } - for (s = 0; s < num_symbols; s++) - if (symbols[s].required && !symbols[s].found) - return false; - return true; + *num_symbolsp = num_symbols; + return symbols; +bail: + for (i = 0; i < num_symbols; i++) + free(symbols[i].name); + free(symbols); + return NULL; } static uint32_t @@ -173,7 +201,9 @@ get_load(Elf *e) GElf_Phdr phdr; GElf_Addr sh_paddr; struct ao_hex_image *load = NULL; +#if 0 char *section_name; +#endif size_t nshdr; size_t s; @@ -201,27 +231,29 @@ get_load(Elf *e) /* Get the associated file section */ #if 0 - printf ("offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n", - (uint32_t) phdr.p_offset, - (uint32_t) phdr.p_vaddr, - (uint32_t) phdr.p_paddr, - (uint32_t) phdr.p_filesz, - (uint32_t) phdr.p_memsz); + fprintf (stderr, "offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n", + (uint32_t) phdr.p_offset, + (uint32_t) phdr.p_vaddr, + (uint32_t) phdr.p_paddr, + (uint32_t) phdr.p_filesz, + (uint32_t) phdr.p_memsz); #endif for (s = 0; s < nshdr; s++) { scn = elf_getscn(e, s); if (!scn) { - printf ("getscn failed\n"); + fprintf (stderr, "getscn failed\n"); abort(); } if (gelf_getshdr(scn, &shdr) != &shdr) { - printf ("gelf_getshdr failed\n"); + fprintf (stderr, "gelf_getshdr failed\n"); abort(); } +#if 0 section_name = elf_strptr(e, shstrndx, shdr.sh_name); +#endif if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) { @@ -230,11 +262,13 @@ get_load(Elf *e) sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset; - printf ("\tsize %08x rom %08x exec %08x %s\n", - (uint32_t) shdr.sh_size, - (uint32_t) sh_paddr, - (uint32_t) shdr.sh_addr, - section_name); +#if 0 + fprintf (stderr, "\tsize %08x rom %08x exec %08x %s\n", + (uint32_t) shdr.sh_size, + (uint32_t) sh_paddr, + (uint32_t) shdr.sh_addr, + section_name); +#endif data = elf_getdata(scn, NULL); @@ -252,7 +286,7 @@ get_load(Elf *e) */ struct ao_hex_image * -ao_load_elf(char *name, struct ao_elf_sym *symbols, int num_symbols) +ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols) { int fd; Elf *e; @@ -278,10 +312,8 @@ ao_load_elf(char *name, struct ao_elf_sym *symbols, int num_symbols) if (elf_getshdrstrndx(e, &shstrndx) != 0) return NULL; - if (!find_symbols(e, symbols, num_symbols)) { - fprintf (stderr, "Cannot find required symbols\n"); - return NULL; - } + if (symbols) + *symbols = load_symbols(e, num_symbols); image = get_load(e); if (!image) { diff --git a/ao-tools/lib/ao-elf.h b/ao-tools/lib/ao-elf.h index f3a2358c..0f79d142 100644 --- a/ao-tools/lib/ao-elf.h +++ b/ao-tools/lib/ao-elf.h @@ -22,18 +22,7 @@ #include #include "ao-hex.h" -struct ao_elf_sym { - unsigned addr; - unsigned default_addr; - char *name; - bool required; - bool found; -}; - struct ao_hex_image * -ao_load_elf(char *name, struct ao_elf_sym *symbols, int num_symbols); - -int -ao_elf_find_symbols (Elf *e, struct ao_elf_sym *symbols, int num_symbols); +ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols); #endif /* _AO_ELF_H_ */ diff --git a/ao-tools/lib/ao-hex.c b/ao-tools/lib/ao-hex.c index 85acc07f..5cfc63c1 100644 --- a/ao-tools/lib/ao-hex.c +++ b/ao-tools/lib/ao-hex.c @@ -20,8 +20,10 @@ #include #include #include +#include #include #include "ao-hex.h" +#include "ao-verbose.h" struct ao_hex_input { FILE *file; @@ -118,7 +120,7 @@ ao_hex_read_record(struct ao_hex_input *input) while (state != read_done) { c = getc(input->file); - if (c == EOF && state != read_white) { + if (c == EOF && state != read_white && state != read_marker) { ao_hex_error(input, "Unexpected EOF"); goto bail; } @@ -128,6 +130,8 @@ ao_hex_read_record(struct ao_hex_input *input) input->line++; switch (state) { case read_marker: + if (c == EOF) + return NULL; if (c != ':') { ao_hex_error(input, "Missing ':'"); goto bail; @@ -246,13 +250,20 @@ ao_hex_file_read(FILE *file, char *name) int done = 0; hex = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *), 1); + if (!hex) + return NULL; input.name = name; input.line = 1; input.file = file; while (!done) { record = ao_hex_read_record(&input); - if (!record) - goto bail; + if (!record) { + if (feof(input.file)) { + done = 1; + break; + } else + goto bail; + } if (hex->nrecord == srecord) { srecord *= 2; newhex = realloc(hex, @@ -263,8 +274,6 @@ ao_hex_file_read(FILE *file, char *name) hex = newhex; } hex->records[hex->nrecord++] = record; - if (record->type == AO_HEX_RECORD_EOF) - done = 1; } return hex; @@ -273,6 +282,92 @@ bail: return NULL; } +static struct ao_sym * +load_symbols(struct ao_hex_file *hex, + int *num_symbolsp) +{ + uint32_t extended_addr; + uint32_t addr; + int i; + struct ao_hex_record *record; + struct ao_sym *symbols = NULL; + struct ao_sym *symbol; + int num_symbols = 0; + int size_symbols = 0; + + extended_addr = 0; + for (i = 0; i < hex->nrecord; i++) { + record = hex->records[i]; + switch (record->type) { + case AO_HEX_RECORD_NORMAL: + addr = extended_addr + record->address; + break; + case AO_HEX_RECORD_EOF: + break; + case AO_HEX_RECORD_EXTENDED_ADDRESS_4: + if (record->length != 2) + goto bail; + extended_addr = ((record->data[0] << 8) | record->data[1]) << 4; + break; + case AO_HEX_RECORD_EXTENDED_ADDRESS_8: + if (record->length != 2) + goto bail; + extended_addr = (record->data[0] << 24) | (record->data[1] << 16); + break; + case AO_HEX_RECORD_SYMBOL: + addr = extended_addr + record->address; + if (num_symbols == size_symbols) { + struct ao_sym *new_symbols; + int new_size; + + if (!size_symbols) + new_size = 16; + else + new_size = size_symbols * 2; + new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym)); + if (!new_symbols) + goto bail; + + symbols = new_symbols; + size_symbols = new_size; + } + symbol = &symbols[num_symbols]; + memset(symbol, 0, sizeof (struct ao_sym)); + symbol->name = calloc(record->length + 1, 1); + if (!symbol->name) + goto bail; + memcpy(symbol->name, record->data, record->length); + symbol->addr = addr; + ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr); + num_symbols++; + break; + } + } + *num_symbolsp = num_symbols; + return symbols; +bail: + for (i = 0; i < num_symbols; i++) + free(symbols[i].name); + free(symbols); + return NULL; +} + +static void +ao_hex_record_set_checksum(struct ao_hex_record *record) +{ + uint8_t cksum = 0; + int i; + + cksum += record->length; + cksum += record->address >> 8; + cksum += record->address; + cksum += record->type; + for (i = 0; i < record->length; i++) + cksum += record->data[i]; + + record->checksum = -cksum; +} + struct ao_hex_image * ao_hex_image_create(struct ao_hex_file *hex) { @@ -286,6 +381,8 @@ ao_hex_image_create(struct ao_hex_file *hex) int length; + /* Find the address bounds of the file + */ base = 0xffffffff; bound = 0x0; extended_addr = 0; @@ -293,7 +390,7 @@ ao_hex_image_create(struct ao_hex_file *hex) uint32_t r_bound; record = hex->records[i]; switch (record->type) { - case 0: + case AO_HEX_RECORD_NORMAL: addr = extended_addr + record->address; r_bound = addr + record->length; if (addr < base) @@ -301,20 +398,21 @@ ao_hex_image_create(struct ao_hex_file *hex) if (r_bound > bound) bound = r_bound; break; - case 1: + case AO_HEX_RECORD_EOF: break; - case 2: + case AO_HEX_RECORD_EXTENDED_ADDRESS_4: if (record->length != 2) return NULL; extended_addr = ((record->data[0] << 8) | record->data[1]) << 4; break; - case 4: + case AO_HEX_RECORD_EXTENDED_ADDRESS_8: if (record->length != 2) return NULL; - extended_addr = ((record->data[0] << 8) | record->data[1]) << 16; + extended_addr = (record->data[0] << 24) | (record->data[1] << 16); + break; + case AO_HEX_RECORD_SYMBOL: break; } - } length = bound - base; image = calloc(sizeof(struct ao_hex_image) + length, 1); @@ -327,18 +425,20 @@ ao_hex_image_create(struct ao_hex_file *hex) for (i = 0; i < hex->nrecord; i++) { record = hex->records[i]; switch (record->type) { - case 0: + case AO_HEX_RECORD_NORMAL: addr = extended_addr + record->address; offset = addr - base; memcpy(image->data + offset, record->data, record->length); break; - case 1: + case AO_HEX_RECORD_EOF: break; - case 2: + case AO_HEX_RECORD_EXTENDED_ADDRESS_4: extended_addr = ((record->data[0] << 8) | record->data[1]) << 4; break; - case 4: - extended_addr = ((record->data[0] << 8) | record->data[1]) << 16; + case AO_HEX_RECORD_EXTENDED_ADDRESS_8: + extended_addr = (record->data[0] << 24) | (record->data[1] << 16); + break; + case AO_HEX_RECORD_SYMBOL: break; } } @@ -362,23 +462,165 @@ ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b) } struct ao_hex_image * -ao_hex_load(char *filename) +ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbolsp) { - FILE *file; + FILE *file; struct ao_hex_file *hex_file; - struct ao_hex_image *hex_image; + struct ao_hex_image *hex_image; file = fopen (filename, "r"); if (!file) - return 0; + return NULL; hex_file = ao_hex_file_read(file, filename); fclose(file); if (!hex_file) - return 0; + return NULL; hex_image = ao_hex_image_create(hex_file); if (!hex_image) - return 0; + return NULL; + + if (symbols) + *symbols = load_symbols(hex_file, num_symbolsp); + ao_hex_file_free(hex_file); return hex_image; } + +#define BYTES_PER_RECORD 32 + +static struct ao_hex_file * +ao_hex_file_create(struct ao_hex_image *image, struct ao_sym *symbols, int num_symbols) +{ + /* split data into n-byte-sized chunks */ + uint32_t data_records = (image->length + BYTES_PER_RECORD-1) / BYTES_PER_RECORD; + /* extended address and data for each block, EOF, address and data for each symbol */ + uint32_t total_records = data_records * 2 + 1 + num_symbols * 2; + uint32_t offset; + uint32_t address; + uint32_t length; + char *name; + struct ao_hex_file *hex_file; + int nrecord = 0; + int s; + struct ao_hex_record *record; + + hex_file = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *) * total_records, 1); + if (!hex_file) + return NULL; + + /* Add the data + */ + for (offset = 0; offset < image->length; offset += BYTES_PER_RECORD) { + uint32_t address = image->address + offset; + uint32_t length = image->length - offset; + + if (length > BYTES_PER_RECORD) + length = BYTES_PER_RECORD; + + record = calloc(sizeof (struct ao_hex_record) + 2, 1); + record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8; + record->address = 0; + record->length = 2; + record->data[0] = address >> 24; + record->data[1] = address >> 16; + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + + record = calloc(sizeof (struct ao_hex_record) + length, 1); + record->type = AO_HEX_RECORD_NORMAL; + record->address = address; + record->length = length; + memcpy(record->data, image->data + offset, length); + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + } + + /* Stick an EOF after the data + */ + record = calloc(sizeof (struct ao_hex_record), 1); + record->type = AO_HEX_RECORD_EOF; + record->address = 0; + record->length = 0; + record->data[0] = 0; + record->data[1] = 0; + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + + /* Add the symbols + */ + + for (s = 0; s < num_symbols; s++) { + + name = symbols[s].name; + address = symbols[s].addr; + length = strlen (name); + + record = calloc(sizeof (struct ao_hex_record) + 2, 1); + record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8; + record->address = 0; + record->length = 2; + record->data[0] = address >> 24; + record->data[1] = address >> 16; + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + + record = calloc(sizeof (struct ao_hex_record) + length, 1); + record->type = AO_HEX_RECORD_SYMBOL; + record->address = address; + record->length = length; + memcpy(record->data, name, length); + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + } + + hex_file->nrecord = nrecord; + return hex_file; +} + +static bool +ao_hex_write_record(FILE *file, struct ao_hex_record *record) +{ + int i; + + fputc(':', file); + fprintf(file, "%02x", record->length); + fprintf(file, "%04x", record->address); + fprintf(file, "%02x", record->type); + for (i = 0; i < record->length; i++) + fprintf(file, "%02x", record->data[i]); + fprintf(file, "%02x", record->checksum); + fputc('\n', file); + return true; +} + +bool +ao_hex_save(FILE *file, struct ao_hex_image *image, + struct ao_sym *symbols, int num_symbols) +{ + struct ao_hex_file *hex_file; + int i; + bool ret = false; + + hex_file = ao_hex_file_create(image, symbols, num_symbols); + if (!hex_file) + goto create_failed; + + for (i = 0; i < hex_file->nrecord; i++) { + if (!ao_hex_write_record(file, hex_file->records[i])) + goto write_failed; + } + ret = true; + + if (fflush(file) != 0) + ret = false; +write_failed: + ao_hex_file_free(hex_file); +create_failed: + return ret; +} diff --git a/ao-tools/lib/ao-hex.h b/ao-tools/lib/ao-hex.h index 8528eb45..98497460 100644 --- a/ao-tools/lib/ao-hex.h +++ b/ao-tools/lib/ao-hex.h @@ -19,6 +19,8 @@ #define _AO_HEX_H_ #include +#include +#include #define AO_HEX_RECORD_NORMAL 0x00 #define AO_HEX_RECORD_EOF 0x01 @@ -47,6 +49,14 @@ struct ao_hex_image { uint8_t data[0]; }; +struct ao_sym { + unsigned addr; + unsigned default_addr; + char *name; + bool required; + bool found; +}; + struct ao_hex_file * ao_hex_file_read(FILE *file, char *name); @@ -60,9 +70,13 @@ void ao_hex_image_free(struct ao_hex_image *image); struct ao_hex_image * -ao_hex_load(char *filename); +ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbols); int ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b); +bool +ao_hex_save(FILE *file, struct ao_hex_image *image, + struct ao_sym *symbols, int num_symbols); + #endif /* _AO_HEX_H_ */ diff --git a/configure.ac b/configure.ac index d1de21e6..bf801744 100644 --- a/configure.ac +++ b/configure.ac @@ -406,6 +406,7 @@ ao-tools/ao-sky-flash/Makefile ao-tools/ao-dumpflash/Makefile ao-tools/ao-edit-telem/Makefile ao-tools/ao-dump-up/Makefile +ao-tools/ao-elftohex/Makefile ao-utils/Makefile src/Version ]) -- 2.30.2