blob: 14893defc1ffdebc468a2ebdb821b46f29eb5028 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Write changed data structures.
2 Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 2.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <assert.h>
23#include <libelf.h>
24#include <stdbool.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28#include <sys/param.h>
29
30#include "libelfP.h"
31
32
33#ifndef LIBELFBITS
34# define LIBELFBITS 32
35#endif
36
37
38static int
39compare_sections (const void *a, const void *b)
40{
41 const Elf_Scn **scna = (const Elf_Scn **) a;
42 const Elf_Scn **scnb = (const Elf_Scn **) b;
43
44 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
45 < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
46 return -1;
47
48 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
49 > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
50 return 1;
51
52 if ((*scna)->index < (*scnb)->index)
53 return -1;
54
55 if ((*scna)->index > (*scnb)->index)
56 return 1;
57
58 return 0;
59}
60
61
62/* Insert the sections in the list into the provided array and sort
63 them according to their start offsets. For sections with equal
64 start offsets the section index is used. */
65static void
66sort_sections (Elf_Scn **scns, Elf_ScnList *list)
67{
68 Elf_Scn **scnp = scns;
69 do
70 for (size_t cnt = 0; cnt < list->cnt; ++cnt)
71 *scnp++ = &list->data[cnt];
72 while ((list = list->next) != NULL);
73
74 qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
75}
76
77
78int
79internal_function_def
80__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
81{
82 ElfW2(LIBELFBITS,Ehdr) *ehdr;
83 xfct_t fctp;
84 char *last_position;
85
86 /* We need the ELF header several times. */
87 ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
88
89 /* Write out the ELF header. */
90 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
91 {
92 /* If the type sizes should be different at some time we have to
93 rewrite this code. */
94 assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
95 == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
96
97 if (unlikely (change_bo))
98 {
99 /* Today there is only one version of the ELF header. */
100#if EV_NUM != 2
101 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
102#else
103# undef fctp
104# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
105#endif
106
107 /* Do the real work. */
108 (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
109 sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
110 }
111 else
112 memcpy (elf->map_address + elf->start_offset, ehdr,
113 sizeof (ElfW2(LIBELFBITS,Ehdr)));
114
115 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
116 }
117
118 /* Write out the program header table. */
119 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
120 && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
121 & ELF_F_DIRTY))
122 {
123 /* If the type sizes should be different at some time we have to
124 rewrite this code. */
125 assert (sizeof (ElfW2(LIBELFBITS,Phdr))
126 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
127
128 /* Maybe the user wants a gap between the ELF header and the program
129 header. */
130 if (ehdr->e_phoff > ehdr->e_ehsize)
131 memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
132 __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
133
134 if (unlikely (change_bo))
135 {
136 /* Today there is only one version of the ELF header. */
137#if EV_NUM != 2
138 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
139#else
140# undef fctp
141# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
142#endif
143
144 /* Do the real work. */
145 (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
146 elf->state.ELFW(elf,LIBELFBITS).phdr,
147 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum, 1);
148 }
149 else
150 memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
151 elf->state.ELFW(elf,LIBELFBITS).phdr,
152 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
153
154 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
155 }
156
157 /* From now on we have to keep track of the last position to eventually
158 fill the gaps with the prescribed fill byte. */
159 last_position = ((char *) elf->map_address + elf->start_offset
160 + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
161 ehdr->e_phoff)
162 + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
163
164 /* Write all the sections. Well, only those which are modified. */
165 if (shnum > 0)
166 {
167 ElfW2(LIBELFBITS,Shdr) *shdr_dest;
168 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
169 Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
170 char *shdr_start = ((char *) elf->map_address + elf->start_offset
171 + ehdr->e_shoff);
172 char *shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
173
174#if EV_NUM != 2
175 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
176#else
177# undef shdr_fctp
178# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
179#endif
180 shdr_dest = (ElfW2(LIBELFBITS,Shdr) *)
181 ((char *) elf->map_address + elf->start_offset + ehdr->e_shoff);
182
183 /* Get all sections into the array and sort them. */
184 sort_sections (scns, list);
185
186 /* Iterate over all the section in the order in which they
187 appear in the output file. */
188 for (size_t cnt = 0; cnt < shnum; ++cnt)
189 {
190 Elf_Scn *scn = scns[cnt];
191 ElfW2(LIBELFBITS,Shdr) *shdr;
192 char *scn_start;
193 Elf_Data_List *dl;
194
195 shdr = scn->shdr.ELFW(e,LIBELFBITS);
196
197 scn_start = ((char *) elf->map_address
198 + elf->start_offset + shdr->sh_offset);
199 dl = &scn->data_list;
200
201 if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL)
202 do
203 {
204 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
205 {
206 if (scn_start + dl->data.d.d_off != last_position)
207 {
208 if (scn_start + dl->data.d.d_off > last_position)
209 {
210 /* This code assumes that the data blocks for
211 a section are ordered by offset. */
212 size_t written = 0;
213
214 if (last_position < shdr_start)
215 {
216 written = MIN (scn_start + dl->data.d.d_off
217 - last_position,
218 shdr_start - last_position);
219
220 memset (last_position, __libelf_fill_byte,
221 written);
222 }
223
224 if (last_position + written
225 != scn_start + dl->data.d.d_off
226 && shdr_end < scn_start + dl->data.d.d_off)
227 memset (shdr_end, __libelf_fill_byte,
228 scn_start + dl->data.d.d_off - shdr_end);
229
230 last_position = scn_start + dl->data.d.d_off;
231 }
232 }
233
234 if (unlikely (change_bo))
235 {
236#if EV_NUM != 2
237 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
238#else
239# undef fctp
240 fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
241#endif
242
243 /* Do the real work. */
244 (*fctp) (last_position, dl->data.d.d_buf,
245 dl->data.d.d_size, 1);
246
247 last_position += dl->data.d.d_size;
248 }
249 else
250 last_position = mempcpy (last_position,
251 dl->data.d.d_buf,
252 dl->data.d.d_size);
253 }
254 else
255 last_position += dl->data.d.d_size;
256
257 dl->flags &= ~ELF_F_DIRTY;
258
259 dl = dl->next;
260 }
261 while (dl != NULL);
262 else if (shdr->sh_type != SHT_NOBITS && scn->index != 0)
263 /* We have to trust the existing section header information. */
264 last_position += shdr->sh_size;
265
266 /* Write the section header table entry if necessary. */
267 if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
268 {
269 if (unlikely (change_bo))
270 (*shdr_fctp) (&shdr_dest[scn->index],
271 scn->shdr.ELFW(e,LIBELFBITS),
272 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
273 else
274 memcpy (&shdr_dest[scn->index],
275 scn->shdr.ELFW(e,LIBELFBITS),
276 sizeof (ElfW2(LIBELFBITS,Shdr)));
277
278 scn->shdr_flags &= ~ELF_F_DIRTY;
279 }
280
281 scn->flags &= ~ELF_F_DIRTY;
282 }
283
284 /* Fill the gap between last section and section header table if
285 necessary. */
286 if ((elf->flags & ELF_F_DIRTY)
287 && last_position < ((char *) elf->map_address + elf->start_offset
288 + ehdr->e_shoff))
289 memset (last_position, __libelf_fill_byte,
290 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
291 - last_position);
292 }
293
294 /* That was the last part. Clear the overall flag. */
295 elf->flags &= ~ELF_F_DIRTY;
296
297 return 0;
298}
299
300
301/* Size of the buffer we use to generate the blocks of fill bytes. */
302#define FILLBUFSIZE 4096
303
304/* If we have to convert the section buffer contents we have to use
305 temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated
306 on the stack. */
307#define MAX_TMPBUF 32768
308
309
310/* Helper function to write out fill bytes. */
311static int
312fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
313{
314 size_t filled = *filledp;
315 size_t fill_len = MIN (len, FILLBUFSIZE);
316
317 if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
318 {
319 /* Initialize a few more bytes. */
320 memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
321 *filledp = filled = fill_len;
322 }
323
324 do
325 {
326 /* This many bytes we want to write in this round. */
327 size_t n = MIN (filled, len);
328
329 if (unlikely ((size_t) pwrite (fd, fillbuf, n, pos) != n))
330 {
331 __libelf_seterrno (ELF_E_WRITE_ERROR);
332 return 1;
333 }
334
335 pos += n;
336 len -= n;
337 }
338 while (len > 0);
339
340 return 0;
341}
342
343
344int
345internal_function_def
346__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
347{
348 char fillbuf[FILLBUFSIZE];
349 size_t filled = 0;
350 xfct_t fctp;
351
352 /* We need the ELF header several times. */
353 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
354
355 /* Write out the ELF header. */
356 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
357 {
358 ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
359 ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
360
361 /* If the type sizes should be different at some time we have to
362 rewrite this code. */
363 assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
364 == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
365
366 if (unlikely (change_bo))
367 {
368 /* Today there is only one version of the ELF header. */
369#if EV_NUM != 2
370 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
371#else
372# undef fctp
373# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
374#endif
375
376 /* Write the converted ELF header in a temporary buffer. */
377 (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
378
379 /* This is the buffer we want to write. */
380 out_ehdr = &tmp_ehdr;
381 }
382
383 /* Write out the ELF header. */
384 if (unlikely (pwrite (elf->fildes, out_ehdr,
385 sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
386 != sizeof (ElfW2(LIBELFBITS,Ehdr))))
387 {
388 __libelf_seterrno (ELF_E_WRITE_ERROR);
389 return 1;
390 }
391
392 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
393 }
394
395 /* If the type sizes should be different at some time we have to
396 rewrite this code. */
397 assert (sizeof (ElfW2(LIBELFBITS,Phdr))
398 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
399
400 /* Write out the program header table. */
401 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
402 && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
403 & ELF_F_DIRTY))
404 {
405 ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
406 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
407
408 /* Maybe the user wants a gap between the ELF header and the program
409 header. */
410 if (ehdr->e_phoff > ehdr->e_ehsize
411 && unlikely (fill (elf->fildes, ehdr->e_ehsize,
412 ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
413 != 0))
414 return 1;
415
416 if (unlikely (change_bo))
417 {
418 /* Today there is only one version of the ELF header. */
419#if EV_NUM != 2
420 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
421#else
422# undef fctp
423# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
424#endif
425
426 /* Allocate sufficient memory. */
427 tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
428 malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
429 if (tmp_phdr == NULL)
430 {
431 __libelf_seterrno (ELF_E_NOMEM);
432 return 1;
433 }
434
435 /* Write the converted ELF header in a temporary buffer. */
436 (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
437 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum, 1);
438
439 /* This is the buffer we want to write. */
440 out_phdr = tmp_phdr;
441 }
442
443 /* Write out the ELF header. */
444 if (unlikely ((size_t) pwrite (elf->fildes, out_phdr,
445 sizeof (ElfW2(LIBELFBITS,Phdr))
446 * ehdr->e_phnum, ehdr->e_phoff)
447 != sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum))
448 {
449 __libelf_seterrno (ELF_E_WRITE_ERROR);
450 return 1;
451 }
452
453 /* This is a no-op we we have not allocated any memory. */
454 free (tmp_phdr);
455
456 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
457 }
458
459 /* From now on we have to keep track of the last position to eventually
460 fill the gaps with the prescribed fill byte. */
461 off_t last_offset;
462 if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
463 last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
464 else
465 last_offset = (ehdr->e_phoff
466 + sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
467
468 /* Write all the sections. Well, only those which are modified. */
469 if (shnum > 0)
470 {
471 off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
472#if EV_NUM != 2
473 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
474#else
475# undef shdr_fctp
476# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
477#endif
478
479 ElfW2(LIBELFBITS,Shdr) *shdr_data;
480 if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
481 shdr_data = (ElfW2(LIBELFBITS,Shdr) *)
482 alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
483 else
484 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
485 int shdr_flags = elf->flags;
486
487 /* Get all sections into the array and sort them. */
488 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
489 Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
490 sort_sections (scns, list);
491
492 for (size_t cnt = 0; cnt < shnum; ++cnt)
493 {
494 Elf_Scn *scn = scns[cnt];
495
496 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
497
498 off_t scn_start = elf->start_offset + shdr->sh_offset;
499 Elf_Data_List *dl = &scn->data_list;
500
501 if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL
502 && scn->index != 0)
503 do
504 {
505 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
506 {
507 char tmpbuf[MAX_TMPBUF];
508 void *buf = dl->data.d.d_buf;
509
510 if (scn_start + dl->data.d.d_off != last_offset)
511 {
512 assert (last_offset < scn_start + dl->data.d.d_off);
513
514 if (unlikely (fill (elf->fildes, last_offset,
515 (scn_start + dl->data.d.d_off)
516 - last_offset, fillbuf,
517 &filled) != 0))
518 return 1;
519
520 last_offset = scn_start + dl->data.d.d_off;
521 }
522
523 if (unlikely (change_bo))
524 {
525#if EV_NUM != 2
526 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
527#else
528# undef fctp
529 fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
530#endif
531
532 buf = tmpbuf;
533 if (dl->data.d.d_size > MAX_TMPBUF)
534 {
535 buf = malloc (dl->data.d.d_size);
536 if (buf == NULL)
537 {
538 __libelf_seterrno (ELF_E_NOMEM);
539 return 1;
540 }
541 }
542
543 /* Do the real work. */
544 (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
545 }
546
547 if (unlikely ((size_t) pwrite (elf->fildes, buf,
548 dl->data.d.d_size,
549 last_offset)
550 != dl->data.d.d_size))
551 {
552 if (buf != dl->data.d.d_buf && buf != tmpbuf)
553 free (buf);
554
555 __libelf_seterrno (ELF_E_WRITE_ERROR);
556 return 1;
557 }
558
559 if (buf != dl->data.d.d_buf && buf != tmpbuf)
560 free (buf);
561 }
562
563 last_offset += dl->data.d.d_size;
564
565 dl->flags &= ~ELF_F_DIRTY;
566
567 dl = dl->next;
568 }
569 while (dl != NULL);
570 else if (shdr->sh_type != SHT_NOBITS && scn->index != 0)
571 last_offset = scn_start + shdr->sh_size;
572
573 /* Collect the section header table information. */
574 if (unlikely (change_bo))
575 (*shdr_fctp) (&shdr_data[scn->index],
576 scn->shdr.ELFW(e,LIBELFBITS),
577 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
578 else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
579 memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
580 sizeof (ElfW2(LIBELFBITS,Shdr)));
581
582 shdr_flags |= scn->shdr_flags;
583 scn->shdr_flags &= ~ELF_F_DIRTY;
584 }
585
586 /* Fill the gap between last section and section header table if
587 necessary. */
588 if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
589 && unlikely (fill (elf->fildes, last_offset,
590 shdr_offset - last_offset,
591 fillbuf, &filled) != 0))
592 return 1;
593
594 /* Write out the section header table. */
595 if (shdr_flags & ELF_F_DIRTY
596 && unlikely ((size_t) pwrite (elf->fildes, shdr_data,
597 sizeof (ElfW2(LIBELFBITS,Shdr))
598 * shnum, shdr_offset)
599 != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
600 {
601 __libelf_seterrno (ELF_E_WRITE_ERROR);
602 return 1;
603 }
604 }
605
606 /* That was the last part. Clear the overall flag. */
607 elf->flags &= ~ELF_F_DIRTY;
608
609 return 0;
610}