blob: 153e377f67dddd473edf6c8ae25432704d3c10db [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001/* Write changed data structures.
Elliott Hughes03333822015-02-18 22:19:45 -08002 Copyright (C) 2000-2010, 2014 Red Hat, Inc.
3 This file is part of elfutils.
Ben Cheng25b3c042013-11-20 14:45:36 -08004 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
Elliott Hughes03333822015-02-18 22:19:45 -08006 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
Ben Cheng25b3c042013-11-20 14:45:36 -08008
Elliott Hughes03333822015-02-18 22:19:45 -08009 * 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
12
13 or
14
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
18
19 or both in parallel, as here.
20
21 elfutils is distributed in the hope that it will be useful, but
Ben Cheng25b3c042013-11-20 14:45:36 -080022 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.
25
Elliott Hughes03333822015-02-18 22:19:45 -080026 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/>. */
Ben Cheng25b3c042013-11-20 14:45:36 -080029
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
34#include <assert.h>
35#include <errno.h>
36#include <libelf.h>
37#include <stdbool.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41#include <sys/mman.h>
42#include <sys/param.h>
43
44#include <system.h>
45#include "libelfP.h"
46
47
48#ifndef LIBELFBITS
49# define LIBELFBITS 32
50#endif
51
52
53static int
54compare_sections (const void *a, const void *b)
55{
56 const Elf_Scn **scna = (const Elf_Scn **) a;
57 const Elf_Scn **scnb = (const Elf_Scn **) b;
58
59 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
60 < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
61 return -1;
62
63 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
64 > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
65 return 1;
66
67 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
68 < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
69 return -1;
70
71 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
72 > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
73 return 1;
74
75 if ((*scna)->index < (*scnb)->index)
76 return -1;
77
78 if ((*scna)->index > (*scnb)->index)
79 return 1;
80
81 return 0;
82}
83
84
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. */
91static void
92sort_sections (Elf_Scn **scns, Elf_ScnList *list)
93{
94 Elf_Scn **scnp = scns;
95 do
96 for (size_t cnt = 0; cnt < list->cnt; ++cnt)
97 *scnp++ = &list->data[cnt];
98 while ((list = list->next) != NULL);
99
100 qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
101}
102
103
104int
105internal_function
106__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
107{
108 bool previous_scn_changed = false;
109
110 /* We need the ELF header several times. */
111 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
112
113 /* Write out the ELF header. */
114 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
115 {
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));
120
121 if (unlikely (change_bo))
122 {
123 /* Today there is only one version of the ELF header. */
124#if EV_NUM != 2
125 xfct_t fctp;
126 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
127#else
128# undef fctp
129# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
130#endif
131
132 /* Do the real work. */
133 (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
134 sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
135 }
Elliott Hughes03333822015-02-18 22:19:45 -0800136 else if (elf->map_address + elf->start_offset != ehdr)
Ben Cheng25b3c042013-11-20 14:45:36 -0800137 memcpy (elf->map_address + elf->start_offset, ehdr,
138 sizeof (ElfW2(LIBELFBITS,Ehdr)));
139
140 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
141
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;
145 }
146
147 size_t phnum;
148 if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
149 return -1;
150
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)
154 & ELF_F_DIRTY))
155 {
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));
160
161 /* Maybe the user wants a gap between the ELF header and the program
162 header. */
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);
166
167 if (unlikely (change_bo))
168 {
169 /* Today there is only one version of the ELF header. */
170#if EV_NUM != 2
171 xfct_t fctp;
172 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
173#else
174# undef fctp
175# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
176#endif
177
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);
182 }
183 else
184 memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
185 elf->state.ELFW(elf,LIBELFBITS).phdr,
186 sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
187
188 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
189
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;
193 }
194
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),
199 ehdr->e_phoff)
200 + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
201
202 /* Write all the sections. Well, only those which are modified. */
203 if (shnum > 0)
204 {
Elliott Hughes03333822015-02-18 22:19:45 -0800205 if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
206 return 1;
207
Ben Cheng25b3c042013-11-20 14:45:36 -0800208 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
211 + ehdr->e_shoff);
212 char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
213
214#if EV_NUM != 2
215 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
216#else
217# undef shdr_fctp
218# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
219#endif
220#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
221
222 /* Get all sections into the array and sort them. */
223 sort_sections (scns, list);
224
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)
228 {
229 Elf_Scn *scn = scns[cnt];
230
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])
234 {
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));
240
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)));
245 }
246
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
252 from the file. */
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))
261 {
262 void *p = malloc (scn->data_list.data.d.d_size);
263 if (p == NULL)
264 {
265 __libelf_seterrno (ELF_E_NOMEM);
266 return -1;
267 }
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);
271 }
272 }
273
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)
277 {
278 Elf_Scn *scn = scns[cnt];
279 if (scn->index == 0)
280 {
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);
284 continue;
285 }
286
287 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
288 if (shdr->sh_type == SHT_NOBITS)
289 goto next;
290
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;
295
296 void fill_mmap (size_t offset)
297 {
298 size_t written = 0;
299
300 if (last_position < shdr_start)
301 {
302 written = MIN (scn_start + offset - last_position,
303 shdr_start - last_position);
304
305 memset (last_position, __libelf_fill_byte, written);
306 }
307
308 if (last_position + written != scn_start + offset
309 && shdr_end < scn_start + offset)
310 {
311 char *fill_start = MAX (shdr_end, scn_start);
312 memset (fill_start, __libelf_fill_byte,
313 scn_start + offset - fill_start);
314 }
315 }
316
317 if (scn->data_list_rear != NULL)
318 do
319 {
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));
324
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))
330 {
331 fill_mmap (dl->data.d.d_off);
332 last_position = scn_start + dl->data.d.d_off;
333 }
334
335 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
336 {
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
340 crashing. */
341
342 last_position = scn_start + dl->data.d.d_off;
343
344 if (unlikely (change_bo))
345 {
346#if EV_NUM != 2
347 xfct_t fctp;
348 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
349#else
350# undef fctp
351# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
352#endif
353
354 /* Do the real work. */
355 (*fctp) (last_position, dl->data.d.d_buf,
356 dl->data.d.d_size, 1);
357
358 last_position += dl->data.d.d_size;
359 }
360 else
361 last_position = mempcpy (last_position,
362 dl->data.d.d_buf,
363 dl->data.d.d_size);
364
365 scn_changed = true;
366 }
367 else
368 last_position += dl->data.d.d_size;
369
370 assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
371 == last_position);
372
373 dl->flags &= ~ELF_F_DIRTY;
374
375 dl = dl->next;
376 }
377 while (dl != NULL);
378 else
379 {
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)
383 fill_mmap (0);
384
385 /* We have to trust the existing section header information. */
386 last_position = scn_start + shdr->sh_size;
387 }
388
389
390 previous_scn_changed = scn_changed;
391 next:
392 scn->flags &= ~ELF_F_DIRTY;
393 }
394
395 /* Fill the gap between last section and section header table if
396 necessary. */
397 if ((elf->flags & ELF_F_DIRTY)
398 && last_position < ((char *) elf->map_address + elf->start_offset
399 + ehdr->e_shoff))
400 memset (last_position, __libelf_fill_byte,
401 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
402 - last_position);
403
404 /* Write the section header table entry if necessary. */
405 for (size_t cnt = 0; cnt < shnum; ++cnt)
406 {
407 Elf_Scn *scn = scns[cnt];
408
409 if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
410 {
411 if (unlikely (change_bo))
412 (*shdr_fctp) (&shdr_dest[scn->index],
413 scn->shdr.ELFW(e,LIBELFBITS),
414 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
415 else
416 memcpy (&shdr_dest[scn->index],
417 scn->shdr.ELFW(e,LIBELFBITS),
418 sizeof (ElfW2(LIBELFBITS,Shdr)));
419
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];
426
427 scn->shdr_flags &= ~ELF_F_DIRTY;
428 }
429 }
430 }
431
432 /* That was the last part. Clear the overall flag. */
433 elf->flags &= ~ELF_F_DIRTY;
434
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);
442
443 return 0;
444}
445
446
447/* Size of the buffer we use to generate the blocks of fill bytes. */
448#define FILLBUFSIZE 4096
449
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
452 on the stack. */
453#define MAX_TMPBUF 32768
454
455
456/* Helper function to write out fill bytes. */
457static int
458fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
459{
460 size_t filled = *filledp;
461 size_t fill_len = MIN (len, FILLBUFSIZE);
462
463 if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
464 {
465 /* Initialize a few more bytes. */
466 memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
467 *filledp = filled = fill_len;
468 }
469
470 do
471 {
472 /* This many bytes we want to write in this round. */
473 size_t n = MIN (filled, len);
474
475 if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
476 {
477 __libelf_seterrno (ELF_E_WRITE_ERROR);
478 return 1;
479 }
480
481 pos += n;
482 len -= n;
483 }
484 while (len > 0);
485
486 return 0;
487}
488
489
490int
491internal_function
492__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
493{
494 char fillbuf[FILLBUFSIZE];
495 size_t filled = 0;
496 bool previous_scn_changed = false;
497
498 /* We need the ELF header several times. */
499 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
500
501 /* Write out the ELF header. */
502 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
503 {
504 ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
505 ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
506
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));
511
512 if (unlikely (change_bo))
513 {
514 /* Today there is only one version of the ELF header. */
515#if EV_NUM != 2
516 xfct_t fctp;
517 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
518#else
519# undef fctp
520# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
521#endif
522
523 /* Write the converted ELF header in a temporary buffer. */
524 (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
525
526 /* This is the buffer we want to write. */
527 out_ehdr = &tmp_ehdr;
528 }
529
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))))
534 {
535 __libelf_seterrno (ELF_E_WRITE_ERROR);
536 return 1;
537 }
538
539 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
540
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;
544 }
545
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));
550
551 size_t phnum;
552 if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
553 return -1;
554
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)
558 & ELF_F_DIRTY))
559 {
560 ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
561 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
562
563 /* Maybe the user wants a gap between the ELF header and the program
564 header. */
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)
568 != 0))
569 return 1;
570
571 if (unlikely (change_bo))
572 {
573 /* Today there is only one version of the ELF header. */
574#if EV_NUM != 2
575 xfct_t fctp;
576 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
577#else
578# undef fctp
579# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
580#endif
581
582 /* Allocate sufficient memory. */
583 tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
584 malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
585 if (tmp_phdr == NULL)
586 {
587 __libelf_seterrno (ELF_E_NOMEM);
588 return 1;
589 }
590
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);
594
595 /* This is the buffer we want to write. */
596 out_phdr = tmp_phdr;
597 }
598
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)
603 != phdr_size))
604 {
605 __libelf_seterrno (ELF_E_WRITE_ERROR);
606 return 1;
607 }
608
609 /* This is a no-op we we have not allocated any memory. */
610 free (tmp_phdr);
611
612 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
613
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;
617 }
618
619 /* From now on we have to keep track of the last position to eventually
620 fill the gaps with the prescribed fill byte. */
621 off_t last_offset;
622 if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
623 last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
624 else
625 last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
626
627 /* Write all the sections. Well, only those which are modified. */
628 if (shnum > 0)
629 {
Elliott Hughes03333822015-02-18 22:19:45 -0800630 if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
631 + sizeof (ElfW2(LIBELFBITS,Shdr)))))
632 return 1;
633
Ben Cheng25b3c042013-11-20 14:45:36 -0800634 off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
635#if EV_NUM != 2
636 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
637#else
638# undef shdr_fctp
639# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
640#endif
641
642 ElfW2(LIBELFBITS,Shdr) *shdr_data;
Elliott Hughes03333822015-02-18 22:19:45 -0800643 if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
644 || (elf->flags & ELF_F_DIRTY))
Ben Cheng25b3c042013-11-20 14:45:36 -0800645 shdr_data = (ElfW2(LIBELFBITS,Shdr) *)
646 alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
647 else
648 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
649 int shdr_flags = elf->flags;
650
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);
655
656 for (size_t cnt = 0; cnt < shnum; ++cnt)
657 {
658 Elf_Scn *scn = scns[cnt];
659 if (scn->index == 0)
660 {
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);
664 goto next;
665 }
666
667 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
668 if (shdr->sh_type == SHT_NOBITS)
669 goto next;
670
671 off_t scn_start = elf->start_offset + shdr->sh_offset;
672 Elf_Data_List *dl = &scn->data_list;
673 bool scn_changed = false;
674
675 if (scn->data_list_rear != NULL)
676 do
677 {
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))
683 {
684 if (unlikely (fill (elf->fildes, last_offset,
685 (scn_start + dl->data.d.d_off)
686 - last_offset, fillbuf,
687 &filled) != 0))
688 return 1;
689 }
690
691 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
692 {
693 char tmpbuf[MAX_TMPBUF];
694 void *buf = dl->data.d.d_buf;
695
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
699 crashing. */
700
701 last_offset = scn_start + dl->data.d.d_off;
702
703 if (unlikely (change_bo))
704 {
705#if EV_NUM != 2
706 xfct_t fctp;
707 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
708#else
709# undef fctp
710# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
711#endif
712
713 buf = tmpbuf;
714 if (dl->data.d.d_size > MAX_TMPBUF)
715 {
716 buf = malloc (dl->data.d.d_size);
717 if (buf == NULL)
718 {
719 __libelf_seterrno (ELF_E_NOMEM);
720 return 1;
721 }
722 }
723
724 /* Do the real work. */
725 (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
726 }
727
728 ssize_t n = pwrite_retry (elf->fildes, buf,
729 dl->data.d.d_size,
730 last_offset);
731 if (unlikely ((size_t) n != dl->data.d.d_size))
732 {
733 if (buf != dl->data.d.d_buf && buf != tmpbuf)
734 free (buf);
735
736 __libelf_seterrno (ELF_E_WRITE_ERROR);
737 return 1;
738 }
739
740 if (buf != dl->data.d.d_buf && buf != tmpbuf)
741 free (buf);
742
743 scn_changed = true;
744 }
745
746 last_offset += dl->data.d.d_size;
747
748 dl->flags &= ~ELF_F_DIRTY;
749
750 dl = dl->next;
751 }
752 while (dl != NULL);
753 else
754 {
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)
758 {
759 if (unlikely (fill (elf->fildes, last_offset,
760 scn_start - last_offset, fillbuf,
761 &filled) != 0))
762 return 1;
763 }
764
765 last_offset = scn_start + shdr->sh_size;
766 }
767
768 previous_scn_changed = scn_changed;
769 next:
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);
Elliott Hughes03333822015-02-18 22:19:45 -0800775 else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
776 || (elf->flags & ELF_F_DIRTY))
Ben Cheng25b3c042013-11-20 14:45:36 -0800777 memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
778 sizeof (ElfW2(LIBELFBITS,Shdr)));
779
780 shdr_flags |= scn->shdr_flags;
781 scn->shdr_flags &= ~ELF_F_DIRTY;
782 }
783
784 /* Fill the gap between last section and section header table if
785 necessary. */
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))
790 return 1;
791
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))
798 {
799 __libelf_seterrno (ELF_E_WRITE_ERROR);
800 return 1;
801 }
802 }
803
804 /* That was the last part. Clear the overall flag. */
805 elf->flags &= ~ELF_F_DIRTY;
806
807 return 0;
808}