* 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
This commit is contained in:
Joerg Wunsch 2012-04-24 15:41:02 +00:00
parent 2343e419d3
commit 0bda6f26d1
2 changed files with 93 additions and 29 deletions

View File

@ -1,3 +1,13 @@
2012-04-24 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
* 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 <j.gnu@uriah.heep.sax.de>
bug #30756: When setting SUT to 64ms on XMEGA, avrdude doesn't

112
fileio.c
View File

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