blob: 898cf1abb6ad7c434350c3ad1ec84d7c5c1ef846 [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001/* 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
74static int
75compare_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. */
112static void
113sort_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
125int
126internal_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. */
475static int
476fill (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
508int
509internal_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}