Home | History | Annotate | Download | only in libelf
      1 /* Write changed data structures.
      2    Copyright (C) 2000-2010, 2014, 2015 Red Hat, Inc.
      3    This file is part of elfutils.
      4    Written by Ulrich Drepper <drepper (at) redhat.com>, 2000.
      5 
      6    This file is free software; you can redistribute it and/or modify
      7    it under the terms of either
      8 
      9      * the GNU Lesser General Public License as published by the Free
     10        Software Foundation; either version 3 of the License, or (at
     11        your option) any later version
     12 
     13    or
     14 
     15      * the GNU General Public License as published by the Free
     16        Software Foundation; either version 2 of the License, or (at
     17        your option) any later version
     18 
     19    or both in parallel, as here.
     20 
     21    elfutils is distributed in the hope that it will be useful, but
     22    WITHOUT ANY WARRANTY; without even the implied warranty of
     23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     24    General Public License for more details.
     25 
     26    You should have received copies of the GNU General Public License and
     27    the GNU Lesser General Public License along with this program.  If
     28    not, see <http://www.gnu.org/licenses/>.  */
     29 
     30 #ifdef HAVE_CONFIG_H
     31 # include <config.h>
     32 #endif
     33 
     34 #include <assert.h>
     35 #include <errno.h>
     36 #include <libelf.h>
     37 #include <stdbool.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <unistd.h>
     41 #include <sys/mman.h>
     42 #include <sys/param.h>
     43 
     44 #include <system.h>
     45 #include "libelfP.h"
     46 
     47 
     48 #ifndef LIBELFBITS
     49 # define LIBELFBITS 32
     50 #endif
     51 
     52 
     53 static int
     54 compare_sections (const void *a, const void *b)
     55 {
     56   const Elf_Scn **scna = (const Elf_Scn **) a;
     57   const Elf_Scn **scnb = (const Elf_Scn **) b;
     58 
     59   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
     60       < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
     61     return -1;
     62 
     63   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
     64       > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
     65     return 1;
     66 
     67   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
     68       < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
     69     return -1;
     70 
     71   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
     72       > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
     73     return 1;
     74 
     75   if ((*scna)->index < (*scnb)->index)
     76     return -1;
     77 
     78   if ((*scna)->index > (*scnb)->index)
     79     return 1;
     80 
     81   return 0;
     82 }
     83 
     84 
     85 /* Insert the sections in the list into the provided array and sort
     86    them according to their start offsets.  For sections with equal
     87    start offsets, the size is used; for sections with equal start
     88    offsets and sizes, the section index is used.  Sorting by size
     89    ensures that zero-length sections are processed first, which
     90    is what we want since they do not advance our file writing position.  */
     91 static void
     92 sort_sections (Elf_Scn **scns, Elf_ScnList *list)
     93 {
     94   Elf_Scn **scnp = scns;
     95   do
     96     for (size_t cnt = 0; cnt < list->cnt; ++cnt)
     97       *scnp++ = &list->data[cnt];
     98   while ((list = list->next) != NULL);
     99 
    100   qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
    101 }
    102 
    103 
    104 static inline void
    105 fill_mmap (size_t offset, char *last_position, char *scn_start,
    106            char *const shdr_start, char *const shdr_end)
    107 {
    108   size_t written = 0;
    109 
    110   if (last_position < shdr_start)
    111     {
    112       written = MIN (scn_start + offset - last_position,
    113                      shdr_start - last_position);
    114 
    115       memset (last_position, __libelf_fill_byte, written);
    116     }
    117 
    118   if (last_position + written != scn_start + offset
    119       && shdr_end < scn_start + offset)
    120     {
    121       char *fill_start = MAX (shdr_end, scn_start);
    122       memset (fill_start, __libelf_fill_byte,
    123               scn_start + offset - fill_start);
    124     }
    125 }
    126 
    127 int
    128 internal_function
    129 __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
    130 {
    131   bool previous_scn_changed = false;
    132 
    133   /* We need the ELF header several times.  */
    134   ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
    135 
    136   /* Write out the ELF header.  */
    137   if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
    138     {
    139       /* If the type sizes should be different at some time we have to
    140 	 rewrite this code.  */
    141       assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
    142 	      == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
    143 
    144       if (unlikely (change_bo))
    145 	{
    146 	  /* Today there is only one version of the ELF header.  */
    147 #if EV_NUM != 2
    148 	  xfct_t fctp;
    149 	  fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
    150 #else
    151 # undef fctp
    152 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
    153 #endif
    154 
    155 	  /* Do the real work.  */
    156 	  (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
    157 		   sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
    158 	}
    159       else if (elf->map_address + elf->start_offset != ehdr)
    160 	memcpy (elf->map_address + elf->start_offset, ehdr,
    161 		sizeof (ElfW2(LIBELFBITS,Ehdr)));
    162 
    163       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
    164 
    165       /* We start writing sections after the ELF header only if there is
    166 	 no program header.  */
    167       previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
    168     }
    169 
    170   size_t phnum;
    171   if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
    172     return -1;
    173 
    174   /* Write out the program header table.  */
    175   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
    176       && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
    177 	  & ELF_F_DIRTY))
    178     {
    179       /* If the type sizes should be different at some time we have to
    180 	 rewrite this code.  */
    181       assert (sizeof (ElfW2(LIBELFBITS,Phdr))
    182 	      == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
    183 
    184       /* Maybe the user wants a gap between the ELF header and the program
    185 	 header.  */
    186       if (ehdr->e_phoff > ehdr->e_ehsize)
    187 	memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
    188 		__libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
    189 
    190       if (unlikely (change_bo))
    191 	{
    192 	  /* Today there is only one version of the ELF header.  */
    193 #if EV_NUM != 2
    194 	  xfct_t fctp;
    195 	  fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
    196 #else
    197 # undef fctp
    198 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
    199 #endif
    200 
    201 	  /* Do the real work.  */
    202 	  (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
    203 		   elf->state.ELFW(elf,LIBELFBITS).phdr,
    204 		   sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
    205 	}
    206       else
    207 	memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
    208 		elf->state.ELFW(elf,LIBELFBITS).phdr,
    209 		sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
    210 
    211       elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
    212 
    213       /* We modified the program header.  Maybe this created a gap so
    214 	 we have to write fill bytes, if necessary.  */
    215       previous_scn_changed = true;
    216     }
    217 
    218   /* From now on we have to keep track of the last position to eventually
    219      fill the gaps with the prescribed fill byte.  */
    220   char *last_position = ((char *) elf->map_address + elf->start_offset
    221 			 + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
    222 				ehdr->e_phoff)
    223 			 + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
    224 
    225   /* Write all the sections.  Well, only those which are modified.  */
    226   if (shnum > 0)
    227     {
    228       if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
    229 	return 1;
    230 
    231       Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
    232       Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
    233       if (unlikely (scns == NULL))
    234 	{
    235 	  __libelf_seterrno (ELF_E_NOMEM);
    236 	  return -1;
    237 	}
    238       char *const shdr_start = ((char *) elf->map_address + elf->start_offset
    239 				+ ehdr->e_shoff);
    240       char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
    241 
    242 #if EV_NUM != 2
    243       xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
    244 #else
    245 # undef shdr_fctp
    246 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
    247 #endif
    248 #define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
    249 
    250       /* Get all sections into the array and sort them.  */
    251       sort_sections (scns, list);
    252 
    253       /* We possibly have to copy the section header data because moving
    254 	 the sections might overwrite the data.  */
    255       for (size_t cnt = 0; cnt < shnum; ++cnt)
    256 	{
    257 	  Elf_Scn *scn = scns[cnt];
    258 
    259 	  if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
    260 	      && (scn->shdr_flags & ELF_F_MALLOCED) == 0
    261 	      && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
    262 	    {
    263 	      assert ((char *) elf->map_address + elf->start_offset
    264 		      < (char *) scn->shdr.ELFW(e,LIBELFBITS));
    265 	      assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
    266 		      < ((char *) elf->map_address + elf->start_offset
    267 			 + elf->maximum_size));
    268 
    269 	      void *p = malloc (sizeof (ElfW2(LIBELFBITS,Shdr)));
    270 	      if (unlikely (p == NULL))
    271 		{
    272 		  __libelf_seterrno (ELF_E_NOMEM);
    273 		  return -1;
    274 		}
    275 	      scn->shdr.ELFW(e,LIBELFBITS)
    276 		= memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
    277 			  sizeof (ElfW2(LIBELFBITS,Shdr)));
    278 	    }
    279 
    280 	  /* If the file is mmaped and the original position of the
    281 	     section in the file is lower than the new position we
    282 	     need to save the section content since otherwise it is
    283 	     overwritten before it can be copied.  If there are
    284 	     multiple data segments in the list only the first can be
    285 	     from the file.  */
    286 	  if (((char *) elf->map_address + elf->start_offset
    287 	       <= (char  *) scn->data_list.data.d.d_buf)
    288 	      && ((char *) scn->data_list.data.d.d_buf
    289 		  < ((char *) elf->map_address + elf->start_offset
    290 		     + elf->maximum_size))
    291 	      && (((char *) elf->map_address + elf->start_offset
    292 		   + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
    293 		  > (char *) scn->data_list.data.d.d_buf))
    294 	    {
    295 	      void *p = malloc (scn->data_list.data.d.d_size);
    296 	      if (unlikely (p == NULL))
    297 		{
    298 		  __libelf_seterrno (ELF_E_NOMEM);
    299 		  return -1;
    300 		}
    301 	      scn->data_list.data.d.d_buf = scn->data_base
    302 		= memcpy (p, scn->data_list.data.d.d_buf,
    303 			  scn->data_list.data.d.d_size);
    304 	    }
    305 	}
    306 
    307       /* Iterate over all the section in the order in which they
    308 	 appear in the output file.  */
    309       for (size_t cnt = 0; cnt < shnum; ++cnt)
    310 	{
    311 	  Elf_Scn *scn = scns[cnt];
    312 	  if (scn->index == 0)
    313 	    {
    314 	      /* The dummy section header entry.  It should not be
    315 		 possible to mark this "section" as dirty.  */
    316 	      assert ((scn->flags & ELF_F_DIRTY) == 0);
    317 	      continue;
    318 	    }
    319 
    320 	  ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
    321 	  if (shdr->sh_type == SHT_NOBITS)
    322 	    goto next;
    323 
    324 	  char *scn_start = ((char *) elf->map_address
    325 			     + elf->start_offset + shdr->sh_offset);
    326 	  Elf_Data_List *dl = &scn->data_list;
    327 	  bool scn_changed = false;
    328 
    329 	  if (scn->data_list_rear != NULL)
    330 	    do
    331 	      {
    332 		assert (dl->data.d.d_off >= 0);
    333 		assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
    334 		assert (dl->data.d.d_size <= (shdr->sh_size
    335 					      - (GElf_Off) dl->data.d.d_off));
    336 
    337 		/* If there is a gap, fill it.  */
    338 		if (scn_start + dl->data.d.d_off > last_position
    339 		    && (dl->data.d.d_off == 0
    340 			|| ((scn->flags | dl->flags | elf->flags)
    341 			    & ELF_F_DIRTY) != 0))
    342 		  {
    343 		    fill_mmap (dl->data.d.d_off, last_position, scn_start,
    344 		               shdr_start, shdr_end);
    345 		    last_position = scn_start + dl->data.d.d_off;
    346 		  }
    347 
    348 		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
    349 		  {
    350 		    /* Let it go backward if the sections use a bogus
    351 		       layout with overlaps.  We'll overwrite the stupid
    352 		       user's section data with the latest one, rather than
    353 		       crashing.  */
    354 
    355 		    last_position = scn_start + dl->data.d.d_off;
    356 
    357 		    if (unlikely (change_bo))
    358 		      {
    359 #if EV_NUM != 2
    360 			xfct_t fctp;
    361 			fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
    362 #else
    363 # undef fctp
    364 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
    365 #endif
    366 
    367 			/* Do the real work.  */
    368 			(*fctp) (last_position, dl->data.d.d_buf,
    369 				 dl->data.d.d_size, 1);
    370 
    371 			last_position += dl->data.d.d_size;
    372 		      }
    373 		    else if (dl->data.d.d_size != 0)
    374 		      last_position = mempcpy (last_position,
    375 					       dl->data.d.d_buf,
    376 					       dl->data.d.d_size);
    377 
    378 		    scn_changed = true;
    379 		  }
    380 		else
    381 		  last_position += dl->data.d.d_size;
    382 
    383 		assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
    384 			== last_position);
    385 
    386 		dl->flags &= ~ELF_F_DIRTY;
    387 
    388 		dl = dl->next;
    389 	      }
    390 	    while (dl != NULL);
    391 	  else
    392 	    {
    393 	      /* If the previous section (or the ELF/program
    394 		 header) changed we might have to fill the gap.  */
    395 	      if (scn_start > last_position && previous_scn_changed)
    396 		fill_mmap (0, last_position, scn_start,
    397 		           shdr_start, shdr_end);
    398 
    399 	      /* We have to trust the existing section header information.  */
    400 	      last_position = scn_start + shdr->sh_size;
    401 	    }
    402 
    403 
    404 	  previous_scn_changed = scn_changed;
    405 	next:
    406 	  scn->flags &= ~ELF_F_DIRTY;
    407 	}
    408 
    409       /* Fill the gap between last section and section header table if
    410 	 necessary.  */
    411       if ((elf->flags & ELF_F_DIRTY)
    412 	  && last_position < ((char *) elf->map_address + elf->start_offset
    413 			      + ehdr->e_shoff))
    414 	memset (last_position, __libelf_fill_byte,
    415 		(char *) elf->map_address + elf->start_offset + ehdr->e_shoff
    416 		- last_position);
    417 
    418       /* Write the section header table entry if necessary.  */
    419       for (size_t cnt = 0; cnt < shnum; ++cnt)
    420 	{
    421 	  Elf_Scn *scn = scns[cnt];
    422 
    423 	  if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
    424 	    {
    425 	      if (unlikely (change_bo))
    426 		(*shdr_fctp) (&shdr_dest[scn->index],
    427 			      scn->shdr.ELFW(e,LIBELFBITS),
    428 			      sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
    429 	      else
    430 		memcpy (&shdr_dest[scn->index],
    431 			scn->shdr.ELFW(e,LIBELFBITS),
    432 			sizeof (ElfW2(LIBELFBITS,Shdr)));
    433 
    434 	      /* If we previously made a copy of the section header
    435 		 entry we now have to adjust the pointer again so
    436 		 point to new place in the mapping.  */
    437 	      if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
    438 		  && (scn->shdr_flags & ELF_F_MALLOCED) == 0
    439 		  && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
    440 		{
    441 		  free (scn->shdr.ELFW(e,LIBELFBITS));
    442 		  scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
    443 		}
    444 
    445 	      scn->shdr_flags &= ~ELF_F_DIRTY;
    446 	    }
    447 	}
    448       free (scns);
    449     }
    450 
    451   /* That was the last part.  Clear the overall flag.  */
    452   elf->flags &= ~ELF_F_DIRTY;
    453 
    454   /* Make sure the content hits the disk.  */
    455   char *msync_start = ((char *) elf->map_address
    456 		       + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
    457   char *msync_end = ((char *) elf->map_address
    458 		     + elf->start_offset + ehdr->e_shoff
    459 		     + ehdr->e_shentsize * shnum);
    460   (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
    461 
    462   return 0;
    463 }
    464 
    465 
    466 /* Size of the buffer we use to generate the blocks of fill bytes.  */
    467 #define FILLBUFSIZE	4096
    468 
    469 /* If we have to convert the section buffer contents we have to use
    470    temporary buffer.  Only buffers up to MAX_TMPBUF bytes are allocated
    471    on the stack.  */
    472 #define MAX_TMPBUF	32768
    473 
    474 
    475 /* Helper function to write out fill bytes.  */
    476 static int
    477 fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
    478 {
    479   size_t filled = *filledp;
    480   size_t fill_len = MIN (len, FILLBUFSIZE);
    481 
    482   if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
    483     {
    484       /* Initialize a few more bytes.  */
    485       memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
    486       *filledp = filled = fill_len;
    487     }
    488 
    489   do
    490     {
    491       /* This many bytes we want to write in this round.  */
    492       size_t n = MIN (filled, len);
    493 
    494       if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
    495 	{
    496 	  __libelf_seterrno (ELF_E_WRITE_ERROR);
    497 	  return 1;
    498 	}
    499 
    500       pos += n;
    501       len -= n;
    502     }
    503   while (len > 0);
    504 
    505   return 0;
    506 }
    507 
    508 
    509 int
    510 internal_function
    511 __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
    512 {
    513   char fillbuf[FILLBUFSIZE];
    514   size_t filled = 0;
    515   bool previous_scn_changed = false;
    516 
    517   /* We need the ELF header several times.  */
    518   ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
    519 
    520   /* Write out the ELF header.  */
    521   if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
    522     {
    523       ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
    524       ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
    525 
    526       /* If the type sizes should be different at some time we have to
    527 	 rewrite this code.  */
    528       assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
    529 	      == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
    530 
    531       if (unlikely (change_bo))
    532 	{
    533 	  /* Today there is only one version of the ELF header.  */
    534 #if EV_NUM != 2
    535 	  xfct_t fctp;
    536 	  fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
    537 #else
    538 # undef fctp
    539 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
    540 #endif
    541 
    542 	  /* Write the converted ELF header in a temporary buffer.  */
    543 	  (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
    544 
    545 	  /* This is the buffer we want to write.  */
    546 	  out_ehdr = &tmp_ehdr;
    547 	}
    548 
    549       /* Write out the ELF header.  */
    550       if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
    551 				  sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
    552 		    != sizeof (ElfW2(LIBELFBITS,Ehdr))))
    553 	{
    554 	  __libelf_seterrno (ELF_E_WRITE_ERROR);
    555 	  return 1;
    556 	}
    557 
    558       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
    559 
    560       /* We start writing sections after the ELF header only if there is
    561 	 no program header.  */
    562       previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
    563     }
    564 
    565   /* If the type sizes should be different at some time we have to
    566      rewrite this code.  */
    567   assert (sizeof (ElfW2(LIBELFBITS,Phdr))
    568 	  == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
    569 
    570   size_t phnum;
    571   if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
    572     return -1;
    573 
    574   /* Write out the program header table.  */
    575   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
    576       && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
    577 	  & ELF_F_DIRTY))
    578     {
    579       ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
    580       ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
    581 
    582       /* Maybe the user wants a gap between the ELF header and the program
    583 	 header.  */
    584       if (ehdr->e_phoff > ehdr->e_ehsize
    585 	  && unlikely (fill (elf->fildes, ehdr->e_ehsize,
    586 			     ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
    587 		       != 0))
    588 	return 1;
    589 
    590       if (unlikely (change_bo))
    591 	{
    592 	  /* Today there is only one version of the ELF header.  */
    593 #if EV_NUM != 2
    594 	  xfct_t fctp;
    595 	  fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
    596 #else
    597 # undef fctp
    598 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
    599 #endif
    600 
    601 	  /* Allocate sufficient memory.  */
    602 	  tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
    603 	    malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
    604 	  if (unlikely (tmp_phdr == NULL))
    605 	    {
    606 	      __libelf_seterrno (ELF_E_NOMEM);
    607 	      return 1;
    608 	    }
    609 
    610 	  /* Write the converted ELF header in a temporary buffer.  */
    611 	  (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
    612 		   sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
    613 
    614 	  /* This is the buffer we want to write.  */
    615 	  out_phdr = tmp_phdr;
    616 	}
    617 
    618       /* Write out the ELF header.  */
    619       size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
    620       if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
    621 					   phdr_size, ehdr->e_phoff)
    622 		    != phdr_size))
    623 	{
    624 	  __libelf_seterrno (ELF_E_WRITE_ERROR);
    625 	  return 1;
    626 	}
    627 
    628       /* This is a no-op we we have not allocated any memory.  */
    629       free (tmp_phdr);
    630 
    631       elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
    632 
    633       /* We modified the program header.  Maybe this created a gap so
    634 	 we have to write fill bytes, if necessary.  */
    635       previous_scn_changed = true;
    636     }
    637 
    638   /* From now on we have to keep track of the last position to eventually
    639      fill the gaps with the prescribed fill byte.  */
    640   off_t last_offset;
    641   if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
    642     last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
    643   else
    644     last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
    645 
    646   /* Write all the sections.  Well, only those which are modified.  */
    647   if (shnum > 0)
    648     {
    649       if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
    650 					+ sizeof (ElfW2(LIBELFBITS,Shdr)))))
    651 	return 1;
    652 
    653       off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
    654 #if EV_NUM != 2
    655       xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
    656 #else
    657 # undef shdr_fctp
    658 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
    659 #endif
    660 
    661       ElfW2(LIBELFBITS,Shdr) *shdr_data;
    662       ElfW2(LIBELFBITS,Shdr) *shdr_data_mem = NULL;
    663       if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
    664 	  || (elf->flags & ELF_F_DIRTY))
    665 	{
    666 	  shdr_data_mem = (ElfW2(LIBELFBITS,Shdr) *)
    667 	    malloc (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
    668 	  if (unlikely (shdr_data_mem == NULL))
    669 	    {
    670 	      __libelf_seterrno (ELF_E_NOMEM);
    671 	      return -1;
    672 	    }
    673 	  shdr_data = shdr_data_mem;
    674 	}
    675       else
    676 	shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
    677       int shdr_flags = elf->flags;
    678 
    679       /* Get all sections into the array and sort them.  */
    680       Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
    681       Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
    682       if (unlikely (scns == NULL))
    683 	{
    684 	  free (shdr_data_mem);
    685 	  __libelf_seterrno (ELF_E_NOMEM);
    686 	  return -1;
    687 	}
    688       sort_sections (scns, list);
    689 
    690       for (size_t cnt = 0; cnt < shnum; ++cnt)
    691 	{
    692 	  Elf_Scn *scn = scns[cnt];
    693 	  if (scn->index == 0)
    694 	    {
    695 	      /* The dummy section header entry.  It should not be
    696 		 possible to mark this "section" as dirty.  */
    697 	      assert ((scn->flags & ELF_F_DIRTY) == 0);
    698 	      goto next;
    699 	    }
    700 
    701 	  ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
    702 	  if (shdr->sh_type == SHT_NOBITS)
    703 	    goto next;
    704 
    705 	  off_t scn_start = elf->start_offset + shdr->sh_offset;
    706 	  Elf_Data_List *dl = &scn->data_list;
    707 	  bool scn_changed = false;
    708 
    709 	  if (scn->data_list_rear != NULL)
    710 	    do
    711 	      {
    712 		/* If there is a gap, fill it.  */
    713 		if (scn_start + dl->data.d.d_off > last_offset
    714 		    && ((previous_scn_changed && dl->data.d.d_off == 0)
    715 			|| ((scn->flags | dl->flags | elf->flags)
    716 			    & ELF_F_DIRTY) != 0))
    717 		  {
    718 		    if (unlikely (fill (elf->fildes, last_offset,
    719 					(scn_start + dl->data.d.d_off)
    720 					- last_offset, fillbuf,
    721 					&filled) != 0))
    722 		      {
    723 		      fail_free:
    724 			free (shdr_data_mem);
    725 			free (scns);
    726 			return 1;
    727 		      }
    728 		  }
    729 
    730 		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
    731 		  {
    732 		    char tmpbuf[MAX_TMPBUF];
    733 		    void *buf = dl->data.d.d_buf;
    734 
    735 		    /* Let it go backward if the sections use a bogus
    736 		       layout with overlaps.  We'll overwrite the stupid
    737 		       user's section data with the latest one, rather than
    738 		       crashing.  */
    739 
    740 		    last_offset = scn_start + dl->data.d.d_off;
    741 
    742 		    if (unlikely (change_bo))
    743 		      {
    744 #if EV_NUM != 2
    745 			xfct_t fctp;
    746 			fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
    747 #else
    748 # undef fctp
    749 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
    750 #endif
    751 
    752 			buf = tmpbuf;
    753 			if (dl->data.d.d_size > MAX_TMPBUF)
    754 			  {
    755 			    buf = malloc (dl->data.d.d_size);
    756 			    if (unlikely (buf == NULL))
    757 			      {
    758 				__libelf_seterrno (ELF_E_NOMEM);
    759 				goto fail_free;
    760 			      }
    761 			  }
    762 
    763 			/* Do the real work.  */
    764 			(*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
    765 		      }
    766 
    767 		    ssize_t n = pwrite_retry (elf->fildes, buf,
    768 					      dl->data.d.d_size,
    769 					      last_offset);
    770 		    if (unlikely ((size_t) n != dl->data.d.d_size))
    771 		      {
    772 			if (buf != dl->data.d.d_buf && buf != tmpbuf)
    773 			  free (buf);
    774 
    775 			__libelf_seterrno (ELF_E_WRITE_ERROR);
    776 			goto fail_free;
    777 		      }
    778 
    779 		    if (buf != dl->data.d.d_buf && buf != tmpbuf)
    780 		      free (buf);
    781 
    782 		    scn_changed = true;
    783 		  }
    784 
    785 		last_offset += dl->data.d.d_size;
    786 
    787 		dl->flags &= ~ELF_F_DIRTY;
    788 
    789 		dl = dl->next;
    790 	      }
    791 	    while (dl != NULL);
    792 	  else
    793 	    {
    794 	      /* If the previous section (or the ELF/program
    795 		 header) changed we might have to fill the gap.  */
    796 	      if (scn_start > last_offset && previous_scn_changed)
    797 		{
    798 		  if (unlikely (fill (elf->fildes, last_offset,
    799 				      scn_start - last_offset, fillbuf,
    800 				      &filled) != 0))
    801 		    goto fail_free;
    802 		}
    803 
    804 	      last_offset = scn_start + shdr->sh_size;
    805 	    }
    806 
    807 	  previous_scn_changed = scn_changed;
    808 	next:
    809 	  /* Collect the section header table information.  */
    810 	  if (unlikely (change_bo))
    811 	    (*shdr_fctp) (&shdr_data[scn->index],
    812 			  scn->shdr.ELFW(e,LIBELFBITS),
    813 			  sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
    814 	  else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
    815 		   || (elf->flags & ELF_F_DIRTY))
    816 	    memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
    817 		    sizeof (ElfW2(LIBELFBITS,Shdr)));
    818 
    819 	  shdr_flags |= scn->shdr_flags;
    820 	  scn->shdr_flags &= ~ELF_F_DIRTY;
    821 	}
    822 
    823       /* Fill the gap between last section and section header table if
    824 	 necessary.  */
    825       if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
    826 	  && unlikely (fill (elf->fildes, last_offset,
    827 			     shdr_offset - last_offset,
    828 			     fillbuf, &filled) != 0))
    829 	goto fail_free;
    830 
    831       /* Write out the section header table.  */
    832       if (shdr_flags & ELF_F_DIRTY
    833 	  && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
    834 					      sizeof (ElfW2(LIBELFBITS,Shdr))
    835 					      * shnum, shdr_offset)
    836 		       != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
    837 	{
    838 	  __libelf_seterrno (ELF_E_WRITE_ERROR);
    839 	  goto fail_free;
    840 	}
    841 
    842       free (shdr_data_mem);
    843       free (scns);
    844     }
    845 
    846   /* That was the last part.  Clear the overall flag.  */
    847   elf->flags &= ~ELF_F_DIRTY;
    848 
    849   return 0;
    850 }
    851