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