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