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