237 lines
7.8 KiB
Diff
237 lines
7.8 KiB
Diff
commit ed9d3bc176b3f0318551d9214b1cec4e49197842
|
|
Author: Roland McGrath <roland@redhat.com>
|
|
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 <roland@redhat.com>
|
|
+
|
|
+ * 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 <roland@redhat.com>
|
|
|
|
* 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 <drepper@redhat.com>, 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))
|