153e377f67dddd473edf6c8ae25432704d3c10db
[platform/upstream/elfutils.git] / libelf / elf32_updatefile.c
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
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 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
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
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 }