Home | History | Annotate | Download | only in libelf
      1 /* Write changed data structures.
      2    Copyright (C) 2000, 2001, 2002, 2004 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) 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
     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
     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
     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
    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
    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