From 0bda6f26d19ed0a0a34e254906e9de07e8756266 Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Tue, 24 Apr 2012 15:41:02 +0000 Subject: [PATCH] * fileio.c: Rework the way ELF file sections are considered: while scanning the program header table, the offsets from a program header entry must never be used directly when checking the bounds of the current AVR memory region. Instead, they must always be checked based on the corresponding section's entry. That way, Xmega devices now properly take into account whether the segment fits into any of the application/apptable/boot memory region. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1085 81a1dc3b-b13d-400b-aceb-764788c761c2 --- ChangeLog | 10 +++++ fileio.c | 112 ++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8a1819d7..a7df3aea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2012-04-24 Joerg Wunsch + + * fileio.c: Rework the way ELF file sections are considered: while + scanning the program header table, the offsets from a program + header entry must never be used directly when checking the bounds + of the current AVR memory region. Instead, they must always be + checked based on the corresponding section's entry. That way, + Xmega devices now properly take into account whether the segment + fits into any of the application/apptable/boot memory region. + 2012-04-20 Joerg Wunsch bug #30756: When setting SUT to 64ms on XMEGA, avrdude doesn't diff --git a/fileio.c b/fileio.c index f625543e..1680128d 100644 --- a/fileio.c +++ b/fileio.c @@ -766,7 +766,10 @@ static int elf_mem_limits(AVRMEM *mem, struct avrpart * p, rv = -1; } } else { - if (strcmp(mem->desc, "flash") == 0) { + if (strcmp(mem->desc, "flash") == 0 || + strcmp(mem->desc, "boot") == 0 || + strcmp(mem->desc, "application") == 0 || + strcmp(mem->desc, "apptable") == 0) { *lowbound = 0; *highbound = 0x7ffff; /* max 8 MiB */ *fileoff = 0; @@ -820,6 +823,30 @@ static int elf2b(char * infile, FILE * inf, return -1; } + /* + * The Xmega memory regions for "boot", "application", and + * "apptable" are actually sub-regions of "flash". Refine the + * applicable limits. This allows to select only the appropriate + * sections out of an ELF file that contains section data for more + * than one sub-segment. + */ + if ((p->flags & AVRPART_HAS_PDI) != 0 && + (strcmp(mem->desc, "boot") == 0 || + strcmp(mem->desc, "application") == 0 || + strcmp(mem->desc, "apptable") == 0)) { + AVRMEM *flashmem = avr_locate_mem(p, "flash"); + if (flashmem == NULL) { + fprintf(stderr, + "%s: ERROR: No \"flash\" memory region found, " + "cannot compute bounds of \"%s\" sub-region.\n", + progname, mem->desc); + return -1; + } + /* The config file offsets are PDI offsets, rebase to 0. */ + low = mem->offset - flashmem->offset; + high = low + mem->size - 1; + } + if (elf_version(EV_CURRENT) == EV_NONE) { fprintf(stderr, "%s: ERROR: ELF library initialization failed: %s\n", @@ -913,6 +940,14 @@ static int elf2b(char * infile, FILE * inf, goto done; } + size_t sndx; + if (elf_getshstrndx(e, &sndx) != 0) { + fprintf(stderr, + "%s: ERROR: Error obtaining section name string table: %s\n", + progname, elf_errmsg(-1)); + sndx = 0; + } + /* * Walk the program header table, pick up entries that are of type * PT_LOAD, and have a non-zero p_filesz. @@ -928,33 +963,6 @@ static int elf2b(char * infile, FILE * inf, " p_vaddr 0x%x, p_paddr 0x%x, p_filesz %d\n", progname, i, ph[i].p_vaddr, ph[i].p_paddr, ph[i].p_filesz); } - if (ph[i].p_paddr >= low && - ph[i].p_paddr < high) { - /* OK */ - } else { - if (verbose >= 2) { - fprintf(stderr, - " => skipping, inappropriate for \"%s\" memory region\n", - mem->desc); - } - continue; - } - /* - * 1-byte sized memory regions are special: they are used for fuse - * bits, where multiple regions (in the config file) map to a - * single, larger region in the ELF file (e.g. "lfuse", "hfuse", - * and "efuse" all map to ".fuse"). We silently accept a larger - * ELF file region for these, and extract the actual byte to write - * from it, using the "foff" offset obtained above. - */ - if (mem->size != 1 && - ph[i].p_paddr - low + ph[i].p_filesz > mem->size) { - fprintf(stderr, - "%s: ERROR: program header entry #%d does not fit into \"%s\" memory:\n" - " 0x%x + %u > %u\n", - progname, i, mem->desc, ph[i].p_paddr, ph[i].p_filesz, mem->size); - continue; - } Elf32_Shdr *sh; Elf_Scn *s = elf_get_scn(e, ph + i, &sh); @@ -962,6 +970,52 @@ static int elf2b(char * infile, FILE * inf, continue; if ((sh->sh_flags & SHF_ALLOC) && sh->sh_size) { + const char *sname; + + if (sndx != 0) { + sname = elf_strptr(e, sndx, sh->sh_name); + } else { + sname = "*unknown*"; + } + + unsigned int lma; + lma = ph[i].p_paddr + sh->sh_offset - ph[i].p_offset; + + if (verbose >= 2) { + fprintf(stderr, + "%s: Found section \"%s\", LMA 0x%x, sh_size %u\n", + progname, sname, lma, sh->sh_size); + } + + if (lma >= low && + lma + sh->sh_size < high) { + /* OK */ + } else { + if (verbose >= 2) { + fprintf(stderr, + " => skipping, inappropriate for \"%s\" memory region\n", + mem->desc); + } + continue; + } + /* + * 1-byte sized memory regions are special: they are used for fuse + * bits, where multiple regions (in the config file) map to a + * single, larger region in the ELF file (e.g. "lfuse", "hfuse", + * and "efuse" all map to ".fuse"). We silently accept a larger + * ELF file region for these, and extract the actual byte to write + * from it, using the "foff" offset obtained above. + */ + if (mem->size != 1 && + sh->sh_size > mem->size) { + fprintf(stderr, + "%s: ERROR: section \"%s\" does not fit into \"%s\" memory:\n" + " 0x%x + %u > %u\n", + progname, sname, mem->desc, + lma, sh->sh_size, mem->size); + continue; + } + Elf_Data *d = NULL; while ((d = elf_getdata(s, d)) != NULL) { if (verbose >= 2) { @@ -991,7 +1045,7 @@ static int elf2b(char * infile, FILE * inf, } else { unsigned int idx; - idx = ph[i].p_paddr - low + d->d_off; + idx = lma - low + d->d_off; if ((int)(idx + d->d_size) > rv) rv = idx + d->d_size; if (verbose >= 3) {