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.
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);
136 else if (elf->map_address + elf->start_offset != ehdr)
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 if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
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
212 char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
215 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
218 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
220 #define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
222 /* Get all sections into the array and sort them. */
223 sort_sections (scns, list);
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)
229 Elf_Scn *scn = scns[cnt];
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])
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));
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)));
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
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))
262 void *p = malloc (scn->data_list.data.d.d_size);
265 __libelf_seterrno (ELF_E_NOMEM);
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);
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)
278 Elf_Scn *scn = scns[cnt];
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);
287 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
288 if (shdr->sh_type == SHT_NOBITS)
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;
296 void fill_mmap (size_t offset)
300 if (last_position < shdr_start)
302 written = MIN (scn_start + offset - last_position,
303 shdr_start - last_position);
305 memset (last_position, __libelf_fill_byte, written);
308 if (last_position + written != scn_start + offset
309 && shdr_end < scn_start + offset)
311 char *fill_start = MAX (shdr_end, scn_start);
312 memset (fill_start, __libelf_fill_byte,
313 scn_start + offset - fill_start);
317 if (scn->data_list_rear != NULL)
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));
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))
331 fill_mmap (dl->data.d.d_off);
332 last_position = scn_start + dl->data.d.d_off;
335 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
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
342 last_position = scn_start + dl->data.d.d_off;
344 if (unlikely (change_bo))
348 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
351 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
354 /* Do the real work. */
355 (*fctp) (last_position, dl->data.d.d_buf,
356 dl->data.d.d_size, 1);
358 last_position += dl->data.d.d_size;
361 last_position = mempcpy (last_position,
368 last_position += dl->data.d.d_size;
370 assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
373 dl->flags &= ~ELF_F_DIRTY;
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)
385 /* We have to trust the existing section header information. */
386 last_position = scn_start + shdr->sh_size;
390 previous_scn_changed = scn_changed;
392 scn->flags &= ~ELF_F_DIRTY;
395 /* Fill the gap between last section and section header table if
397 if ((elf->flags & ELF_F_DIRTY)
398 && last_position < ((char *) elf->map_address + elf->start_offset
400 memset (last_position, __libelf_fill_byte,
401 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
404 /* Write the section header table entry if necessary. */
405 for (size_t cnt = 0; cnt < shnum; ++cnt)
407 Elf_Scn *scn = scns[cnt];
409 if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
411 if (unlikely (change_bo))
412 (*shdr_fctp) (&shdr_dest[scn->index],
413 scn->shdr.ELFW(e,LIBELFBITS),
414 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
416 memcpy (&shdr_dest[scn->index],
417 scn->shdr.ELFW(e,LIBELFBITS),
418 sizeof (ElfW2(LIBELFBITS,Shdr)));
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];
427 scn->shdr_flags &= ~ELF_F_DIRTY;
432 /* That was the last part. Clear the overall flag. */
433 elf->flags &= ~ELF_F_DIRTY;
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);
447 /* Size of the buffer we use to generate the blocks of fill bytes. */
448 #define FILLBUFSIZE 4096
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
453 #define MAX_TMPBUF 32768
456 /* Helper function to write out fill bytes. */
458 fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
460 size_t filled = *filledp;
461 size_t fill_len = MIN (len, FILLBUFSIZE);
463 if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
465 /* Initialize a few more bytes. */
466 memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
467 *filledp = filled = fill_len;
472 /* This many bytes we want to write in this round. */
473 size_t n = MIN (filled, len);
475 if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
477 __libelf_seterrno (ELF_E_WRITE_ERROR);
492 __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
494 char fillbuf[FILLBUFSIZE];
496 bool previous_scn_changed = false;
498 /* We need the ELF header several times. */
499 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
501 /* Write out the ELF header. */
502 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
504 ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
505 ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
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));
512 if (unlikely (change_bo))
514 /* Today there is only one version of the ELF header. */
517 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
520 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
523 /* Write the converted ELF header in a temporary buffer. */
524 (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
526 /* This is the buffer we want to write. */
527 out_ehdr = &tmp_ehdr;
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))))
535 __libelf_seterrno (ELF_E_WRITE_ERROR);
539 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
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;
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));
552 if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
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)
560 ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
561 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
563 /* Maybe the user wants a gap between the ELF header and the program
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)
571 if (unlikely (change_bo))
573 /* Today there is only one version of the ELF header. */
576 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
579 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
582 /* Allocate sufficient memory. */
583 tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
584 malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
585 if (tmp_phdr == NULL)
587 __libelf_seterrno (ELF_E_NOMEM);
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);
595 /* This is the buffer we want to write. */
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)
605 __libelf_seterrno (ELF_E_WRITE_ERROR);
609 /* This is a no-op we we have not allocated any memory. */
612 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
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;
619 /* From now on we have to keep track of the last position to eventually
620 fill the gaps with the prescribed fill byte. */
622 if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
623 last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
625 last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
627 /* Write all the sections. Well, only those which are modified. */
630 if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
631 + sizeof (ElfW2(LIBELFBITS,Shdr)))))
634 off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
636 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
639 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
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)));
648 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
649 int shdr_flags = elf->flags;
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);
656 for (size_t cnt = 0; cnt < shnum; ++cnt)
658 Elf_Scn *scn = scns[cnt];
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);
667 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
668 if (shdr->sh_type == SHT_NOBITS)
671 off_t scn_start = elf->start_offset + shdr->sh_offset;
672 Elf_Data_List *dl = &scn->data_list;
673 bool scn_changed = false;
675 if (scn->data_list_rear != NULL)
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))
684 if (unlikely (fill (elf->fildes, last_offset,
685 (scn_start + dl->data.d.d_off)
686 - last_offset, fillbuf,
691 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
693 char tmpbuf[MAX_TMPBUF];
694 void *buf = dl->data.d.d_buf;
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
701 last_offset = scn_start + dl->data.d.d_off;
703 if (unlikely (change_bo))
707 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
710 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
714 if (dl->data.d.d_size > MAX_TMPBUF)
716 buf = malloc (dl->data.d.d_size);
719 __libelf_seterrno (ELF_E_NOMEM);
724 /* Do the real work. */
725 (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
728 ssize_t n = pwrite_retry (elf->fildes, buf,
731 if (unlikely ((size_t) n != dl->data.d.d_size))
733 if (buf != dl->data.d.d_buf && buf != tmpbuf)
736 __libelf_seterrno (ELF_E_WRITE_ERROR);
740 if (buf != dl->data.d.d_buf && buf != tmpbuf)
746 last_offset += dl->data.d.d_size;
748 dl->flags &= ~ELF_F_DIRTY;
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)
759 if (unlikely (fill (elf->fildes, last_offset,
760 scn_start - last_offset, fillbuf,
765 last_offset = scn_start + shdr->sh_size;
768 previous_scn_changed = scn_changed;
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)));
780 shdr_flags |= scn->shdr_flags;
781 scn->shdr_flags &= ~ELF_F_DIRTY;
784 /* Fill the gap between last section and section header table if
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))
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))
799 __libelf_seterrno (ELF_E_WRITE_ERROR);
804 /* That was the last part. Clear the overall flag. */
805 elf->flags &= ~ELF_F_DIRTY;