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