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.
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.
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.
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.
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.
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>. */
63 #include <sys/param.h>
70 # define LIBELFBITS 32
75 compare_sections (const void *a, const void *b)
77 const Elf_Scn **scna = (const Elf_Scn **) a;
78 const Elf_Scn **scnb = (const Elf_Scn **) b;
80 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
81 < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
84 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
85 > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
88 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
89 < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
92 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
93 > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
96 if ((*scna)->index < (*scnb)->index)
99 if ((*scna)->index > (*scnb)->index)
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. */
113 sort_sections (Elf_Scn **scns, Elf_ScnList *list)
115 Elf_Scn **scnp = scns;
117 for (size_t cnt = 0; cnt < list->cnt; ++cnt)
118 *scnp++ = &list->data[cnt];
119 while ((list = list->next) != NULL);
121 qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
127 __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
129 bool previous_scn_changed = false;
131 /* We need the ELF header several times. */
132 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
134 /* Write out the ELF header. */
135 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
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));
142 if (unlikely (change_bo))
144 /* Today there is only one version of the ELF header. */
147 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
150 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
153 /* Do the real work. */
154 (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
155 sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
158 memcpy (elf->map_address + elf->start_offset, ehdr,
159 sizeof (ElfW2(LIBELFBITS,Ehdr)));
161 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
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;
169 if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
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)
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));
182 /* Maybe the user wants a gap between the ELF header and the program
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);
188 if (unlikely (change_bo))
190 /* Today there is only one version of the ELF header. */
193 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
196 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
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);
205 memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
206 elf->state.ELFW(elf,LIBELFBITS).phdr,
207 sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
209 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
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;
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),
221 + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
223 /* Write all the sections. Well, only those which are modified. */
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
230 char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
233 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
236 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
238 #define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
240 /* Get all sections into the array and sort them. */
241 sort_sections (scns, list);
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)
247 Elf_Scn *scn = scns[cnt];
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])
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));
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)));
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
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))
280 void *p = malloc (scn->data_list.data.d.d_size);
283 __libelf_seterrno (ELF_E_NOMEM);
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);
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)
296 Elf_Scn *scn = scns[cnt];
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);
305 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
306 if (shdr->sh_type == SHT_NOBITS)
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;
314 void fill_mmap (size_t offset)
318 if (last_position < shdr_start)
320 written = MIN (scn_start + offset - last_position,
321 shdr_start - last_position);
323 memset (last_position, __libelf_fill_byte, written);
326 if (last_position + written != scn_start + offset
327 && shdr_end < scn_start + offset)
329 char *fill_start = MAX (shdr_end, scn_start);
330 memset (fill_start, __libelf_fill_byte,
331 scn_start + offset - fill_start);
335 if (scn->data_list_rear != NULL)
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));
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))
349 fill_mmap (dl->data.d.d_off);
350 last_position = scn_start + dl->data.d.d_off;
353 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
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
360 last_position = scn_start + dl->data.d.d_off;
362 if (unlikely (change_bo))
366 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
369 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
372 /* Do the real work. */
373 (*fctp) (last_position, dl->data.d.d_buf,
374 dl->data.d.d_size, 1);
376 last_position += dl->data.d.d_size;
379 last_position = mempcpy (last_position,
386 last_position += dl->data.d.d_size;
388 assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
391 dl->flags &= ~ELF_F_DIRTY;
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)
403 /* We have to trust the existing section header information. */
404 last_position = scn_start + shdr->sh_size;
408 previous_scn_changed = scn_changed;
410 scn->flags &= ~ELF_F_DIRTY;
413 /* Fill the gap between last section and section header table if
415 if ((elf->flags & ELF_F_DIRTY)
416 && last_position < ((char *) elf->map_address + elf->start_offset
418 memset (last_position, __libelf_fill_byte,
419 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
422 /* Write the section header table entry if necessary. */
423 for (size_t cnt = 0; cnt < shnum; ++cnt)
425 Elf_Scn *scn = scns[cnt];
427 if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
429 if (unlikely (change_bo))
430 (*shdr_fctp) (&shdr_dest[scn->index],
431 scn->shdr.ELFW(e,LIBELFBITS),
432 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
434 memcpy (&shdr_dest[scn->index],
435 scn->shdr.ELFW(e,LIBELFBITS),
436 sizeof (ElfW2(LIBELFBITS,Shdr)));
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];
445 scn->shdr_flags &= ~ELF_F_DIRTY;
450 /* That was the last part. Clear the overall flag. */
451 elf->flags &= ~ELF_F_DIRTY;
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);
465 /* Size of the buffer we use to generate the blocks of fill bytes. */
466 #define FILLBUFSIZE 4096
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
471 #define MAX_TMPBUF 32768
474 /* Helper function to write out fill bytes. */
476 fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
478 size_t filled = *filledp;
479 size_t fill_len = MIN (len, FILLBUFSIZE);
481 if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
483 /* Initialize a few more bytes. */
484 memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
485 *filledp = filled = fill_len;
490 /* This many bytes we want to write in this round. */
491 size_t n = MIN (filled, len);
493 if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
495 __libelf_seterrno (ELF_E_WRITE_ERROR);
510 __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
512 char fillbuf[FILLBUFSIZE];
514 bool previous_scn_changed = false;
516 /* We need the ELF header several times. */
517 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
519 /* Write out the ELF header. */
520 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
522 ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
523 ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
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));
530 if (unlikely (change_bo))
532 /* Today there is only one version of the ELF header. */
535 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
538 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
541 /* Write the converted ELF header in a temporary buffer. */
542 (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
544 /* This is the buffer we want to write. */
545 out_ehdr = &tmp_ehdr;
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))))
553 __libelf_seterrno (ELF_E_WRITE_ERROR);
557 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
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;
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));
570 if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
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)
578 ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
579 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
581 /* Maybe the user wants a gap between the ELF header and the program
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)
589 if (unlikely (change_bo))
591 /* Today there is only one version of the ELF header. */
594 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
597 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
600 /* Allocate sufficient memory. */
601 tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
602 malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
603 if (tmp_phdr == NULL)
605 __libelf_seterrno (ELF_E_NOMEM);
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);
613 /* This is the buffer we want to write. */
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)
623 __libelf_seterrno (ELF_E_WRITE_ERROR);
627 /* This is a no-op we we have not allocated any memory. */
630 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
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;
637 /* From now on we have to keep track of the last position to eventually
638 fill the gaps with the prescribed fill byte. */
640 if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
641 last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
643 last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
645 /* Write all the sections. Well, only those which are modified. */
648 off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
650 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
653 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
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)));
661 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
662 int shdr_flags = elf->flags;
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);
669 for (size_t cnt = 0; cnt < shnum; ++cnt)
671 Elf_Scn *scn = scns[cnt];
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);
680 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
681 if (shdr->sh_type == SHT_NOBITS)
684 off_t scn_start = elf->start_offset + shdr->sh_offset;
685 Elf_Data_List *dl = &scn->data_list;
686 bool scn_changed = false;
688 if (scn->data_list_rear != NULL)
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))
697 if (unlikely (fill (elf->fildes, last_offset,
698 (scn_start + dl->data.d.d_off)
699 - last_offset, fillbuf,
704 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
706 char tmpbuf[MAX_TMPBUF];
707 void *buf = dl->data.d.d_buf;
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
714 last_offset = scn_start + dl->data.d.d_off;
716 if (unlikely (change_bo))
720 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
723 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
727 if (dl->data.d.d_size > MAX_TMPBUF)
729 buf = malloc (dl->data.d.d_size);
732 __libelf_seterrno (ELF_E_NOMEM);
737 /* Do the real work. */
738 (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
741 ssize_t n = pwrite_retry (elf->fildes, buf,
744 if (unlikely ((size_t) n != dl->data.d.d_size))
746 if (buf != dl->data.d.d_buf && buf != tmpbuf)
749 __libelf_seterrno (ELF_E_WRITE_ERROR);
753 if (buf != dl->data.d.d_buf && buf != tmpbuf)
759 last_offset += dl->data.d.d_size;
761 dl->flags &= ~ELF_F_DIRTY;
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)
772 if (unlikely (fill (elf->fildes, last_offset,
773 scn_start - last_offset, fillbuf,
778 last_offset = scn_start + shdr->sh_size;
781 previous_scn_changed = scn_changed;
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)));
792 shdr_flags |= scn->shdr_flags;
793 scn->shdr_flags &= ~ELF_F_DIRTY;
796 /* Fill the gap between last section and section header table if
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))
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))
811 __libelf_seterrno (ELF_E_WRITE_ERROR);
816 /* That was the last part. Clear the overall flag. */
817 elf->flags &= ~ELF_F_DIRTY;