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