Imported Upstream version 0.153
[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 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
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
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
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
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
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 }