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