From: Ulrich Drepper Date: Fri, 23 Jan 2009 00:32:15 +0000 (-0800) Subject: When writing ELF files in libelf, fill the gap between sections even if only X-Git-Tag: elfutils-0.139~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5ece80960dac84eae27270f73ecbb6fba17a666c;p=thirdparty%2Felfutils.git When writing ELF files in libelf, fill the gap between sections even if only the section at the start of the gap has been changed. --- diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 2f8ff2be6..119fa5b1e 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,10 +1,17 @@ +2009-01-22 Ulrich Drepper + + * elf32_updatefile.c (__elfXX_updatemmap): Fill the gap between + sections even if only the section at the start of the gap has been + changed. + (__elfXX_updatefile): Likewise. + 2009-01-21 Ulrich Drepper - * elf32_updatefile.c (elfXX_updatemmap): Skip most of the loop to + * elf32_updatefile.c (__elfXX_updatemmap): Skip most of the loop to handle sections for NOBITS sections. (elfXX_updatefile): Likewise. - * elf32_updatefile.c (elfXX_updatemmap): When skipping non-NOBITS + * elf32_updatefile.c (__elfXX_updatemmap): When skipping non-NOBITS sections we haven't loaded, update last_position based on scn_start, not based on old value. Don't run the loop for the dummy section 0. (elfXX_updatefile): Don't run the loop for the dummy section 0. diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c index f23035a52..def4c09a7 100644 --- a/libelf/elf32_updatefile.c +++ b/libelf/elf32_updatefile.c @@ -126,11 +126,10 @@ int internal_function __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) { - ElfW2(LIBELFBITS,Ehdr) *ehdr; - char *last_position; + bool previous_scn_changed = false; /* We need the ELF header several times. */ - ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; /* Write out the ELF header. */ if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY) @@ -160,6 +159,10 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) sizeof (ElfW2(LIBELFBITS,Ehdr))); elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY; + + /* We start writing sections after the ELF header only if there is + no program header. */ + previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL; } /* Write out the program header table. */ @@ -200,14 +203,19 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum); elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY; + + /* We modified the program header. Maybe this created a gap so + we have to write fill bytes, if necessary. */ + previous_scn_changed = true; } /* 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) @@ -286,7 +294,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) if (scn->index == 0) { /* The dummy section header entry. It should not be - possible to make this "section" as dirty. */ + possible to mark this "section" as dirty. */ assert ((scn->flags & ELF_F_DIRTY) == 0); continue; } @@ -298,6 +306,25 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) char *scn_start = ((char *) elf->map_address + elf->start_offset + shdr->sh_offset); Elf_Data_List *dl = &scn->data_list; + bool scn_changed = false; + + void fill_mmap (size_t offset) + { + size_t written = 0; + + if (last_position < shdr_start) + { + written = MIN (scn_start + offset - last_position, + shdr_start - last_position); + + memset (last_position, __libelf_fill_byte, written); + } + + if (last_position + written != scn_start + offset + && shdr_end < scn_start + offset) + memset (shdr_end, __libelf_fill_byte, + scn_start + offset - shdr_end); + } if (scn->data_list_rear != NULL) do @@ -307,31 +334,15 @@ __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)); + /* If there is a gap, fill it. */ + if (scn_start + dl->data.d.d_off > last_position + && ((previous_scn_changed && dl->data.d.d_off == 0) + || ((scn->flags | dl->flags | elf->flags) + & ELF_F_DIRTY) != 0)) + fill_mmap (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 @@ -359,6 +370,8 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) last_position = mempcpy (last_position, dl->data.d.d_buf, dl->data.d.d_size); + + scn_changed = true; } else last_position += dl->data.d.d_size; @@ -372,9 +385,18 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) } while (dl != NULL); else - /* We have to trust the existing section header information. */ - last_position = scn_start + shdr->sh_size; + { + /* If the previous section (or the ELF/program + header) changed we might have to fill the gap. */ + if (scn_start > last_position && previous_scn_changed) + fill_mmap (0); + + /* We have to trust the existing section header information. */ + last_position = scn_start + shdr->sh_size; + } + + previous_scn_changed = scn_changed; next: scn->flags &= ~ELF_F_DIRTY; } @@ -480,6 +502,7 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) { char fillbuf[FILLBUFSIZE]; size_t filled = 0; + bool previous_scn_changed = false; /* We need the ELF header several times. */ ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; @@ -523,6 +546,10 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) } elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY; + + /* We start writing sections after the ELF header only if there is + no program header. */ + previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL; } /* If the type sizes should be different at some time we have to @@ -588,6 +615,10 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) free (tmp_phdr); elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY; + + /* We modified the program header. Maybe this created a gap so + we have to write fill bytes, if necessary. */ + previous_scn_changed = true; } /* From now on we have to keep track of the last position to eventually @@ -629,7 +660,7 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) if (scn->index == 0) { /* The dummy section header entry. It should not be - possible to make this "section" as dirty. */ + possible to mark this "section" as dirty. */ assert ((scn->flags & ELF_F_DIRTY) == 0); continue; } @@ -640,24 +671,29 @@ __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; + bool scn_changed = false; if (scn->data_list_rear != NULL) do { + /* If there is a gap, fill it. */ + if (scn_start + dl->data.d.d_off > last_offset + && ((previous_scn_changed && dl->data.d.d_off == 0) + || ((scn->flags | dl->flags | elf->flags) + & ELF_F_DIRTY) != 0)) + { + if (unlikely (fill (elf->fildes, last_offset, + (scn_start + dl->data.d.d_off) + - last_offset, fillbuf, + &filled) != 0)) + 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 @@ -704,6 +740,8 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) if (buf != dl->data.d.d_buf && buf != tmpbuf) free (buf); + + scn_changed = true; } last_offset += dl->data.d.d_size; @@ -714,8 +752,21 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) } while (dl != NULL); else - last_offset = scn_start + shdr->sh_size; + { + /* If the previous section (or the ELF/program + header) changed we might have to fill the gap. */ + if (scn_start > last_offset && previous_scn_changed) + { + if (unlikely (fill (elf->fildes, last_offset, + scn_start - last_offset, fillbuf, + &filled) != 0)) + return 1; + } + + last_offset = scn_start + shdr->sh_size; + } + previous_scn_changed = scn_changed; next: /* Collect the section header table information. */ if (unlikely (change_bo))