diff options
| author | Keith Packard <keithp@keithp.com> | 2013-11-28 09:31:02 -0800 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2013-11-28 09:31:02 -0800 | 
| commit | 14204e3d147ad99cc249ad8de254809180fe5c38 (patch) | |
| tree | da6dfb4b4d5ea02af596a83748af27080f0dfec7 | |
| parent | ee07f1a0f8e431bebb3b948f6249f5f33413e966 (diff) | |
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 <keithp@keithp.com>
| -rw-r--r-- | ao-tools/Makefile.am | 2 | ||||
| -rw-r--r-- | ao-tools/ao-elftohex/Makefile.am | 18 | ||||
| -rw-r--r-- | ao-tools/ao-elftohex/ao-elftohex.1 | 38 | ||||
| -rw-r--r-- | ao-tools/ao-elftohex/ao-elftohex.c | 102 | ||||
| -rw-r--r-- | ao-tools/ao-stmload/ao-stmload.c | 39 | ||||
| -rw-r--r-- | ao-tools/ao-stmload/ao-stmload.h | 2 | ||||
| -rw-r--r-- | ao-tools/lib/Makefile.am | 4 | ||||
| -rw-r--r-- | ao-tools/lib/ao-elf.c | 94 | ||||
| -rw-r--r-- | ao-tools/lib/ao-elf.h | 13 | ||||
| -rw-r--r-- | ao-tools/lib/ao-hex.c | 286 | ||||
| -rw-r--r-- | ao-tools/lib/ao-hex.h | 16 | ||||
| -rw-r--r-- | configure.ac | 1 | 
12 files changed, 540 insertions, 75 deletions
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 <keithp@keithp.com> +.\" +.\" 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 <keithp@keithp.com> + * + * 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 <getopt.h> +#include <stdlib.h> +#include <string.h> +#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=<level>] [--output=<output.ihx>] <input.elf>\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 : "<stdout>"); +		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 <unistd.h>  #include <getopt.h>  #include <string.h> +#include <stdbool.h>  #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 <fcntl.h>  #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 <gelf.h>  #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 <ctype.h>  #include <stdio.h>  #include <stdlib.h> +#include <unistd.h>  #include <string.h>  #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 <stdint.h> +#include <stdbool.h> +#include <stdio.h>  #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  ])  | 
