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