]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
When writing ELF files in libelf, fill the gap between sections even if only
authorUlrich Drepper <drepper@redhat.com>
Fri, 23 Jan 2009 00:32:15 +0000 (16:32 -0800)
committerUlrich Drepper <drepper@redhat.com>
Fri, 23 Jan 2009 00:32:15 +0000 (16:32 -0800)
the section at the start of the gap has been changed.

libelf/ChangeLog
libelf/elf32_updatefile.c

index 2f8ff2be68f67654976fbbc6cf63113b107ddf56..119fa5b1e1e3dd51765c648f61fd68fe8ba92739 100644 (file)
@@ -1,10 +1,17 @@
+2009-01-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * 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  <drepper@redhat.com>
 
-       * 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.
index f23035a52c4f7f0a045e2aed85e83048af8e2e59..def4c09a7ab669d777f5e344431761b1adc7d6ce 100644 (file)
@@ -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))