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) {