• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
74 static int
compare_sections(const void * a,const void * b)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
sort_sections(Elf_Scn ** scns,Elf_ScnList * list)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
__elfw2(LIBELFBITS,updatemmap)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.  */
475 static int
fill(int fd,off_t pos,size_t len,char * fillbuf,size_t * filledp)476 fill (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 
508 int
509 internal_function
__elfw2(LIBELFBITS,updatefile)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