commit ed9d3bc176b3f0318551d9214b1cec4e49197842 Author: Roland McGrath Date: Thu Jan 1 21:22:18 2009 -0800 Fill gaps and update bookkeeping between all sections, not only before a dirty one. --- libelf/ChangeLog | 7 ++ libelf/elf32_updatefile.c | 142 +++++++++++++++++++++++++++------------------ 2 files changed, 93 insertions(+), 56 deletions(-) diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 9578f8b..bb487b1 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,10 @@ +2009-01-01 Roland McGrath + + * elf32_updatefile.c (__elfw2(LIBELFBITS,updatemmap)): + Fill gaps and update bookkeeping between all sections, + not only before a dirty one. + (__elfw2(LIBELFBITS,updatefile)): Likewise. + 2008-12-11 Roland McGrath * elf32_updatefile.c (__elfw2(LIBELFBITS,updatemmap)): Handle diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c index e88f4a4..4e170cb 100644 --- a/libelf/elf32_updatefile.c +++ b/libelf/elf32_updatefile.c @@ -1,5 +1,5 @@ /* Write changed data structures. - Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. + Copyright (C) 2000,2001,2002,2004,2005,2006,2007,2008,2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2000. @@ -127,7 +127,6 @@ internal_function __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) { ElfW2(LIBELFBITS,Ehdr) *ehdr; - char *last_position; /* We need the ELF header several times. */ ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; @@ -204,10 +203,11 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) /* From now on we have to keep track of the last position to eventually fill the gaps with the prescribed fill byte. */ - last_position = ((char *) elf->map_address + elf->start_offset - + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), - ehdr->e_phoff) - + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum)); + char *last_position = ((char *) elf->map_address + elf->start_offset + + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), + ehdr->e_phoff) + + elf_typesize (LIBELFBITS, + ELF_T_PHDR, ehdr->e_phnum)); /* Write all the sections. Well, only those which are modified. */ if (shnum > 0) @@ -278,6 +278,35 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) } } + /* Prepare to write at START, and then update LAST_POSITION. + If LAST_POSITION was before START, fill in the gap. */ + inline void prepare_position (char *start) + { + if (start > last_position) + { + /* This code assumes that the data blocks for + a section are ordered by offset. */ + size_t written = 0; + + if (last_position < shdr_start) + { + written = MIN (start - last_position, + shdr_start - last_position); + + memset (last_position, __libelf_fill_byte, written); + } + + if (last_position + written != start && shdr_end < start) + memset (shdr_end, __libelf_fill_byte, start - shdr_end); + } + + /* Let it go backward if the sections use a bogus layout with + overlaps. We'll overwrite the stupid user's section data + with the latest one, rather than crashing. */ + + last_position = start; + } + /* Iterate over all the section in the order in which they appear in the output file. */ for (size_t cnt = 0; cnt < shnum; ++cnt) @@ -298,38 +327,10 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) assert (dl->data.d.d_size <= (shdr->sh_size - (GElf_Off) dl->data.d.d_off)); + prepare_position (scn_start + dl->data.d.d_off); + if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY) { - if (scn_start + dl->data.d.d_off > last_position) - { - /* This code assumes that the data blocks for - a section are ordered by offset. */ - size_t written = 0; - - if (last_position < shdr_start) - { - written = MIN (scn_start + dl->data.d.d_off - - last_position, - shdr_start - last_position); - - memset (last_position, __libelf_fill_byte, - written); - } - - if (last_position + written - != scn_start + dl->data.d.d_off - && shdr_end < scn_start + dl->data.d.d_off) - memset (shdr_end, __libelf_fill_byte, - scn_start + dl->data.d.d_off - shdr_end); - } - - /* Let it go backward if the sections use a bogus - layout with overlaps. We'll overwrite the stupid - user's section data with the latest one, rather than - crashing. */ - - last_position = scn_start + dl->data.d.d_off; - if (unlikely (change_bo)) { #if EV_NUM != 2 @@ -362,9 +363,19 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) dl = dl->next; } while (dl != NULL); - else if (shdr->sh_type != SHT_NOBITS && scn->index != 0) - /* We have to trust the existing section header information. */ - last_position += shdr->sh_size; + else if (shdr->sh_type != SHT_NOBITS && scn->index != 0 + && shdr->sh_size != 0) + { + /* We have to trust the existing section header information. + + If there are any contents at all, we must be sure we've + filled in any gap before them, even if it turns out we + aren't touching the contents after the gap. */ + + prepare_position (scn_start); + + last_position += shdr->sh_size; + } scn->flags &= ~ELF_F_DIRTY; } @@ -622,31 +633,39 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) off_t scn_start = elf->start_offset + shdr->sh_offset; Elf_Data_List *dl = &scn->data_list; + /* Prepare to write at START, and then update LAST_OFFSET. + If LAST_OFFSET was before START, fill in the gap. */ + inline bool prepare_offset (off_t start) + { + if (start > last_offset) + { + if (unlikely (fill (elf->fildes, last_offset, + start - last_offset, fillbuf, + &filled) != 0)) + return true; + } + + /* Let it go backward if the sections use a bogus layout with + overlaps. We'll overwrite the stupid user's section data + with the latest one, rather than crashing. */ + + last_offset = start; + + return false; + } + if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL && scn->index != 0) do { + if (unlikely (prepare_offset (scn_start + dl->data.d.d_off))) + return 1; + if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY) { char tmpbuf[MAX_TMPBUF]; void *buf = dl->data.d.d_buf; - if (scn_start + dl->data.d.d_off > last_offset) - { - if (unlikely (fill (elf->fildes, last_offset, - (scn_start + dl->data.d.d_off) - - last_offset, fillbuf, - &filled) != 0)) - return 1; - } - - /* Let it go backward if the sections use a bogus - layout with overlaps. We'll overwrite the stupid - user's section data with the latest one, rather than - crashing. */ - - last_offset = scn_start + dl->data.d.d_off; - if (unlikely (change_bo)) { #if EV_NUM != 2 @@ -696,7 +715,18 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) } while (dl != NULL); else if (shdr->sh_type != SHT_NOBITS && scn->index != 0) - last_offset = scn_start + shdr->sh_size; + { + /* We have to trust the existing section header information. + + If there are any contents at all, we must be sure we've + filled in any gap before them, even if it turns out we + aren't touching the contents after the gap. */ + + if (shdr->sh_size != 0 && unlikely (prepare_offset (scn_start))) + return 1; + + last_offset = scn_start + shdr->sh_size; + } /* Collect the section header table information. */ if (unlikely (change_bo))