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@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
compare_sections(const void * a,const void * b)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
sort_sections(Elf_Scn ** scns,Elf_ScnList * list)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
__elfw2(LIBELFBITS,updatemmap)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
fill(int fd,off_t pos,size_t len,char * fillbuf,size_t * filledp)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
__elfw2(LIBELFBITS,updatefile)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