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.
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
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
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
19 or both in parallel, as here.
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.
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/>. */
42 #include <sys/param.h>
49 # define LIBELFBITS 32
54 compare_sections (const void *a, const void *b)
56 const Elf_Scn **scna = (const Elf_Scn **) a;
57 const Elf_Scn **scnb = (const Elf_Scn **) b;
59 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
60 < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
63 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
64 > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
67 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
68 < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
71 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
72 > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
75 if ((*scna)->index < (*scnb)->index)
78 if ((*scna)->index > (*scnb)->index)
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. */
92 sort_sections (Elf_Scn **scns, Elf_ScnList *list)
94 Elf_Scn **scnp = scns;
96 for (size_t cnt = 0; cnt < list->cnt; ++cnt)
97 *scnp++ = &list->data[cnt];
98 while ((list = list->next) != NULL);
100 qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
106 __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
108 bool previous_scn_changed = false;
110 /* We need the ELF header several times. */
111 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
113 /* Write out the ELF header. */
114 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
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));
121 if (unlikely (change_bo))
123 /* Today there is only one version of the ELF header. */
126 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
129 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
132 /* Do the real work. */
133 (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
134 sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
137 memcpy (elf->map_address + elf->start_offset, ehdr,
138 sizeof (ElfW2(LIBELFBITS,Ehdr)));
140 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
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;
148 if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
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)
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));
161 /* Maybe the user wants a gap between the ELF header and the program
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);
167 if (unlikely (change_bo))
169 /* Today there is only one version of the ELF header. */
172 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
175 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
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);
184 memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
185 elf->state.ELFW(elf,LIBELFBITS).phdr,
186 sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
188 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
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;
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),
200 + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
202 /* Write all the sections. Well, only those which are modified. */
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
209 char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
212 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
215 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
217 #define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
219 /* Get all sections into the array and sort them. */
220 sort_sections (scns, list);
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)
226 Elf_Scn *scn = scns[cnt];
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])
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));
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)));
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
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))
259 void *p = malloc (scn->data_list.data.d.d_size);
262 __libelf_seterrno (ELF_E_NOMEM);
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);
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)
275 Elf_Scn *scn = scns[cnt];
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);
284 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
285 if (shdr->sh_type == SHT_NOBITS)
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;
293 void fill_mmap (size_t offset)
297 if (last_position < shdr_start)
299 written = MIN (scn_start + offset - last_position,
300 shdr_start - last_position);
302 memset (last_position, __libelf_fill_byte, written);
305 if (last_position + written != scn_start + offset
306 && shdr_end < scn_start + offset)
308 char *fill_start = MAX (shdr_end, scn_start);
309 memset (fill_start, __libelf_fill_byte,
310 scn_start + offset - fill_start);
314 if (scn->data_list_rear != NULL)
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));
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))
328 fill_mmap (dl->data.d.d_off);
329 last_position = scn_start + dl->data.d.d_off;
332 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
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
339 last_position = scn_start + dl->data.d.d_off;
341 if (unlikely (change_bo))
345 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
348 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
351 /* Do the real work. */
352 (*fctp) (last_position, dl->data.d.d_buf,
353 dl->data.d.d_size, 1);
355 last_position += dl->data.d.d_size;
358 last_position = mempcpy (last_position,
365 last_position += dl->data.d.d_size;
367 assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
370 dl->flags &= ~ELF_F_DIRTY;
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)
382 /* We have to trust the existing section header information. */
383 last_position = scn_start + shdr->sh_size;
387 previous_scn_changed = scn_changed;
389 scn->flags &= ~ELF_F_DIRTY;
392 /* Fill the gap between last section and section header table if
394 if ((elf->flags & ELF_F_DIRTY)
395 && last_position < ((char *) elf->map_address + elf->start_offset
397 memset (last_position, __libelf_fill_byte,
398 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
401 /* Write the section header table entry if necessary. */
402 for (size_t cnt = 0; cnt < shnum; ++cnt)
404 Elf_Scn *scn = scns[cnt];
406 if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
408 if (unlikely (change_bo))
409 (*shdr_fctp) (&shdr_dest[scn->index],
410 scn->shdr.ELFW(e,LIBELFBITS),
411 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
413 memcpy (&shdr_dest[scn->index],
414 scn->shdr.ELFW(e,LIBELFBITS),
415 sizeof (ElfW2(LIBELFBITS,Shdr)));
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];
424 scn->shdr_flags &= ~ELF_F_DIRTY;
429 /* That was the last part. Clear the overall flag. */
430 elf->flags &= ~ELF_F_DIRTY;
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);
444 /* Size of the buffer we use to generate the blocks of fill bytes. */
445 #define FILLBUFSIZE 4096
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
450 #define MAX_TMPBUF 32768
453 /* Helper function to write out fill bytes. */
455 fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
457 size_t filled = *filledp;
458 size_t fill_len = MIN (len, FILLBUFSIZE);
460 if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
462 /* Initialize a few more bytes. */
463 memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
464 *filledp = filled = fill_len;
469 /* This many bytes we want to write in this round. */
470 size_t n = MIN (filled, len);
472 if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
474 __libelf_seterrno (ELF_E_WRITE_ERROR);
489 __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
491 char fillbuf[FILLBUFSIZE];
493 bool previous_scn_changed = false;
495 /* We need the ELF header several times. */
496 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
498 /* Write out the ELF header. */
499 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
501 ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
502 ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
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));
509 if (unlikely (change_bo))
511 /* Today there is only one version of the ELF header. */
514 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
517 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
520 /* Write the converted ELF header in a temporary buffer. */
521 (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
523 /* This is the buffer we want to write. */
524 out_ehdr = &tmp_ehdr;
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))))
532 __libelf_seterrno (ELF_E_WRITE_ERROR);
536 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
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;
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));
549 if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
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)
557 ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
558 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
560 /* Maybe the user wants a gap between the ELF header and the program
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)
568 if (unlikely (change_bo))
570 /* Today there is only one version of the ELF header. */
573 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
576 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
579 /* Allocate sufficient memory. */
580 tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
581 malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
582 if (tmp_phdr == NULL)
584 __libelf_seterrno (ELF_E_NOMEM);
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);
592 /* This is the buffer we want to write. */
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)
602 __libelf_seterrno (ELF_E_WRITE_ERROR);
606 /* This is a no-op we we have not allocated any memory. */
609 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
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;
616 /* From now on we have to keep track of the last position to eventually
617 fill the gaps with the prescribed fill byte. */
619 if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
620 last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
622 last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
624 /* Write all the sections. Well, only those which are modified. */
627 off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
629 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
632 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
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)));
640 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
641 int shdr_flags = elf->flags;
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);
648 for (size_t cnt = 0; cnt < shnum; ++cnt)
650 Elf_Scn *scn = scns[cnt];
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);
659 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
660 if (shdr->sh_type == SHT_NOBITS)
663 off_t scn_start = elf->start_offset + shdr->sh_offset;
664 Elf_Data_List *dl = &scn->data_list;
665 bool scn_changed = false;
667 if (scn->data_list_rear != NULL)
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))
676 if (unlikely (fill (elf->fildes, last_offset,
677 (scn_start + dl->data.d.d_off)
678 - last_offset, fillbuf,
683 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
685 char tmpbuf[MAX_TMPBUF];
686 void *buf = dl->data.d.d_buf;
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
693 last_offset = scn_start + dl->data.d.d_off;
695 if (unlikely (change_bo))
699 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
702 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
706 if (dl->data.d.d_size > MAX_TMPBUF)
708 buf = malloc (dl->data.d.d_size);
711 __libelf_seterrno (ELF_E_NOMEM);
716 /* Do the real work. */
717 (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
720 ssize_t n = pwrite_retry (elf->fildes, buf,
723 if (unlikely ((size_t) n != dl->data.d.d_size))
725 if (buf != dl->data.d.d_buf && buf != tmpbuf)
728 __libelf_seterrno (ELF_E_WRITE_ERROR);
732 if (buf != dl->data.d.d_buf && buf != tmpbuf)
738 last_offset += dl->data.d.d_size;
740 dl->flags &= ~ELF_F_DIRTY;
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)
751 if (unlikely (fill (elf->fildes, last_offset,
752 scn_start - last_offset, fillbuf,
757 last_offset = scn_start + shdr->sh_size;
760 previous_scn_changed = scn_changed;
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)));
771 shdr_flags |= scn->shdr_flags;
772 scn->shdr_flags &= ~ELF_F_DIRTY;
775 /* Fill the gap between last section and section header table if
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))
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))
790 __libelf_seterrno (ELF_E_WRITE_ERROR);
795 /* That was the last part. Clear the overall flag. */
796 elf->flags &= ~ELF_F_DIRTY;