Blame libelf/elf32_updatefile.c

Packit Service 97d2fb
/* Write changed data structures.
Packit Service 97d2fb
   Copyright (C) 2000-2010, 2014, 2015, 2016, 2018 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <errno.h>
Packit Service 97d2fb
#include <libelf.h>
Packit Service 97d2fb
#include <stdbool.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
#include <sys/mman.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include <system.h>
Packit Service 97d2fb
#include "libelfP.h"
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#ifndef LIBELFBITS
Packit Service 97d2fb
# define LIBELFBITS 32
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_sections (const void *a, const void *b)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const Elf_Scn **scna = (const Elf_Scn **) a;
Packit Service 97d2fb
  const Elf_Scn **scnb = (const Elf_Scn **) b;
Packit Service 97d2fb
Packit Service 97d2fb
  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
Packit Service 97d2fb
      < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
Packit Service 97d2fb
      > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
Packit Service 97d2fb
      < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
Packit Service 97d2fb
      > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  if ((*scna)->index < (*scnb)->index)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  if ((*scna)->index > (*scnb)->index)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Insert the sections in the list into the provided array and sort
Packit Service 97d2fb
   them according to their start offsets.  For sections with equal
Packit Service 97d2fb
   start offsets, the size is used; for sections with equal start
Packit Service 97d2fb
   offsets and sizes, the section index is used.  Sorting by size
Packit Service 97d2fb
   ensures that zero-length sections are processed first, which
Packit Service 97d2fb
   is what we want since they do not advance our file writing position.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
sort_sections (Elf_Scn **scns, Elf_ScnList *list)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf_Scn **scnp = scns;
Packit Service 97d2fb
  do
Packit Service 97d2fb
    for (size_t cnt = 0; cnt < list->cnt; ++cnt)
Packit Service 97d2fb
      *scnp++ = &list->data[cnt];
Packit Service 97d2fb
  while ((list = list->next) != NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static inline void
Packit Service 97d2fb
fill_mmap (size_t offset, char *last_position, char *scn_start,
Packit Service 97d2fb
           char *const shdr_start, char *const shdr_end)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t written = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  if (last_position < shdr_start)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      written = MIN (scn_start + offset - last_position,
Packit Service 97d2fb
                     shdr_start - last_position);
Packit Service 97d2fb
Packit Service 97d2fb
      memset (last_position, __libelf_fill_byte, written);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (last_position + written != scn_start + offset
Packit Service 97d2fb
      && shdr_end < scn_start + offset)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      char *fill_start = MAX (shdr_end, scn_start);
Packit Service 97d2fb
      memset (fill_start, __libelf_fill_byte,
Packit Service 97d2fb
              scn_start + offset - fill_start);
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
Packit Service 97d2fb
{
Packit Service 97d2fb
  bool previous_scn_changed = false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We need the ELF header several times.  */
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Write out the ELF header.  */
Packit Service 97d2fb
  if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* If the type sizes should be different at some time we have to
Packit Service 97d2fb
	 rewrite this code.  */
Packit Service 97d2fb
      assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
Packit Service 97d2fb
	      == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (change_bo))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Today there is only one version of the ELF header.  */
Packit Service 97d2fb
#undef fctp
Packit Service 97d2fb
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Do the real work.  */
Packit Service 97d2fb
	  (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
Packit Service 97d2fb
		   sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else if (elf->map_address + elf->start_offset != ehdr)
Packit Service 97d2fb
	memcpy (elf->map_address + elf->start_offset, ehdr,
Packit Service 97d2fb
		sizeof (ElfW2(LIBELFBITS,Ehdr)));
Packit Service 97d2fb
Packit Service 97d2fb
      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
      /* We start writing sections after the ELF header only if there is
Packit Service 97d2fb
	 no program header.  */
Packit Service 97d2fb
      previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  size_t phnum;
Packit Service 97d2fb
  if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Write out the program header table.  */
Packit Service 97d2fb
  if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
Packit Service 97d2fb
      && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
Packit Service 97d2fb
	  & ELF_F_DIRTY))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* If the type sizes should be different at some time we have to
Packit Service 97d2fb
	 rewrite this code.  */
Packit Service 97d2fb
      assert (sizeof (ElfW2(LIBELFBITS,Phdr))
Packit Service 97d2fb
	      == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
Packit Service 97d2fb
Packit Service 97d2fb
      /* Maybe the user wants a gap between the ELF header and the program
Packit Service 97d2fb
	 header.  */
Packit Service 97d2fb
      if (ehdr->e_phoff > ehdr->e_ehsize)
Packit Service 97d2fb
	memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
Packit Service 97d2fb
		__libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (change_bo))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Today there is only one version of the ELF header.  */
Packit Service 97d2fb
#undef fctp
Packit Service 97d2fb
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Do the real work.  */
Packit Service 97d2fb
	  (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
Packit Service 97d2fb
		   elf->state.ELFW(elf,LIBELFBITS).phdr,
Packit Service 97d2fb
		   sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	memmove (elf->map_address + elf->start_offset + ehdr->e_phoff,
Packit Service 97d2fb
		elf->state.ELFW(elf,LIBELFBITS).phdr,
Packit Service 97d2fb
		sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
Packit Service 97d2fb
Packit Service 97d2fb
      elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
      /* We modified the program header.  Maybe this created a gap so
Packit Service 97d2fb
	 we have to write fill bytes, if necessary.  */
Packit Service 97d2fb
      previous_scn_changed = true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* From now on we have to keep track of the last position to eventually
Packit Service 97d2fb
     fill the gaps with the prescribed fill byte.  */
Packit Service 97d2fb
  char *last_position = ((char *) elf->map_address + elf->start_offset
Packit Service 97d2fb
			 + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
Packit Service 97d2fb
				ehdr->e_phoff)
Packit Service 97d2fb
			 + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Write all the sections.  Well, only those which are modified.  */
Packit Service 97d2fb
  if (shnum > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
Packit Service 97d2fb
	return 1;
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
Packit Service 97d2fb
      Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
Packit Service 97d2fb
      if (unlikely (scns == NULL))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      char *const shdr_start = ((char *) elf->map_address + elf->start_offset
Packit Service 97d2fb
				+ ehdr->e_shoff);
Packit Service 97d2fb
      char *const shdr_end = shdr_start + shnum * ehdr->e_shentsize;
Packit Service 97d2fb
Packit Service 97d2fb
#undef shdr_fctp
Packit Service 97d2fb
#define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
Packit Service 97d2fb
#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
Packit Service 97d2fb
Packit Service 97d2fb
      /* Get all sections into the array and sort them.  */
Packit Service 97d2fb
      sort_sections (scns, list);
Packit Service 97d2fb
Packit Service 97d2fb
      /* We possibly have to copy the section header data because moving
Packit Service 97d2fb
	 the sections might overwrite the data.  */
Packit Service 97d2fb
      for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf_Scn *scn = scns[cnt];
Packit Service 97d2fb
Packit Service 97d2fb
	  if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
Packit Service 97d2fb
	      && (scn->shdr_flags & ELF_F_MALLOCED) == 0
Packit Service 97d2fb
	      && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      assert ((char *) elf->map_address + elf->start_offset
Packit Service 97d2fb
		      < (char *) scn->shdr.ELFW(e,LIBELFBITS));
Packit Service 97d2fb
	      assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
Packit Service 97d2fb
		      < ((char *) elf->map_address + elf->start_offset
Packit Service 97d2fb
			 + elf->maximum_size));
Packit Service 97d2fb
Packit Service 97d2fb
	      void *p = malloc (sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit Service 97d2fb
	      if (unlikely (p == NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  free (scns);
Packit Service 97d2fb
		  __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
		  return -1;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      scn->shdr.ELFW(e,LIBELFBITS)
Packit Service 97d2fb
		= memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
Packit Service 97d2fb
			  sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* If the file is mmaped and the original position of the
Packit Service 97d2fb
	     section in the file is lower than the new position we
Packit Service 97d2fb
	     need to save the section content since otherwise it is
Packit Service 97d2fb
	     overwritten before it can be copied.  If there are
Packit Service 97d2fb
	     multiple data segments in the list only the first can be
Packit Service 97d2fb
	     from the file.  */
Packit Service 97d2fb
	  if (((char *) elf->map_address + elf->start_offset
Packit Service 97d2fb
	       <= (char  *) scn->data_list.data.d.d_buf)
Packit Service 97d2fb
	      && ((char *) scn->data_list.data.d.d_buf
Packit Service 97d2fb
		  < ((char *) elf->map_address + elf->start_offset
Packit Service 97d2fb
		     + elf->maximum_size))
Packit Service 97d2fb
	      && (((char *) elf->map_address + elf->start_offset
Packit Service 97d2fb
		   + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
Packit Service 97d2fb
		  > (char *) scn->data_list.data.d.d_buf))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      void *p = malloc (scn->data_list.data.d.d_size);
Packit Service 97d2fb
	      if (unlikely (p == NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  free (scns);
Packit Service 97d2fb
		  __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
		  return -1;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      scn->data_list.data.d.d_buf = scn->data_base
Packit Service 97d2fb
		= memcpy (p, scn->data_list.data.d.d_buf,
Packit Service 97d2fb
			  scn->data_list.data.d.d_size);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Iterate over all the section in the order in which they
Packit Service 97d2fb
	 appear in the output file.  */
Packit Service 97d2fb
      for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf_Scn *scn = scns[cnt];
Packit Service 97d2fb
	  if (scn->index == 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* The dummy section header entry.  It should not be
Packit Service 97d2fb
		 possible to mark this "section" as dirty.  */
Packit Service 97d2fb
	      assert ((scn->flags & ELF_F_DIRTY) == 0);
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
Packit Service 97d2fb
	  if (shdr->sh_type == SHT_NOBITS)
Packit Service 97d2fb
	    goto next;
Packit Service 97d2fb
Packit Service 97d2fb
	  char *scn_start = ((char *) elf->map_address
Packit Service 97d2fb
			     + elf->start_offset + shdr->sh_offset);
Packit Service 97d2fb
	  Elf_Data_List *dl = &scn->data_list;
Packit Service 97d2fb
	  bool scn_changed = false;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (scn->data_list_rear != NULL)
Packit Service 97d2fb
	    do
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		assert (dl->data.d.d_off >= 0);
Packit Service 97d2fb
		assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
Packit Service 97d2fb
		assert (dl->data.d.d_size <= (shdr->sh_size
Packit Service 97d2fb
					      - (GElf_Off) dl->data.d.d_off));
Packit Service 97d2fb
Packit Service 97d2fb
		/* If there is a gap, fill it.  */
Packit Service 97d2fb
		if (scn_start + dl->data.d.d_off > last_position
Packit Service 97d2fb
		    && (dl->data.d.d_off == 0
Packit Service 97d2fb
			|| ((scn->flags | dl->flags | elf->flags)
Packit Service 97d2fb
			    & ELF_F_DIRTY) != 0))
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    fill_mmap (dl->data.d.d_off, last_position, scn_start,
Packit Service 97d2fb
		               shdr_start, shdr_end);
Packit Service 97d2fb
		  }
Packit Service 97d2fb
Packit Service 97d2fb
		last_position = scn_start + dl->data.d.d_off;
Packit Service 97d2fb
Packit Service 97d2fb
		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    /* Let it go backward if the sections use a bogus
Packit Service 97d2fb
		       layout with overlaps.  We'll overwrite the stupid
Packit Service 97d2fb
		       user's section data with the latest one, rather than
Packit Service 97d2fb
		       crashing.  */
Packit Service 97d2fb
Packit Service 97d2fb
		    if (unlikely (change_bo
Packit Service 97d2fb
				  && dl->data.d.d_size != 0
Packit Service 97d2fb
				  && dl->data.d.d_type != ELF_T_BYTE))
Packit Service 97d2fb
		      {
Packit Service 97d2fb
#undef fctp
Packit Service 97d2fb
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
Packit Service 97d2fb
Packit Service 97d2fb
			size_t align;
Packit Service 97d2fb
			align = __libelf_type_align (ELFW(ELFCLASS,LIBELFBITS),
Packit Service 97d2fb
						     dl->data.d.d_type);
Packit Service 97d2fb
			if ((((uintptr_t) last_position)
Packit Service 97d2fb
			     & (uintptr_t) (align - 1)) == 0)
Packit Service 97d2fb
			  {
Packit Service 97d2fb
			    /* No need to copy, we can convert directly.  */
Packit Service 97d2fb
			    (*fctp) (last_position, dl->data.d.d_buf,
Packit Service 97d2fb
				     dl->data.d.d_size, 1);
Packit Service 97d2fb
			  }
Packit Service 97d2fb
			else
Packit Service 97d2fb
			  {
Packit Service 97d2fb
			    /* We have to do the conversion on properly
Packit Service 97d2fb
			       aligned memory first.  align is a power of 2,
Packit Service 97d2fb
			       but posix_memalign only works for alignments
Packit Service 97d2fb
			       which are a multiple of sizeof (void *).
Packit Service 97d2fb
			       So use normal malloc for smaller alignments.  */
Packit Service 97d2fb
			    size_t size = dl->data.d.d_size;
Packit Service 97d2fb
			    void *converted;
Packit Service 97d2fb
			    if (align < sizeof (void *))
Packit Service 97d2fb
			      converted = malloc (size);
Packit Service 97d2fb
			    else
Packit Service 97d2fb
			      {
Packit Service 97d2fb
				int res;
Packit Service 97d2fb
				res = posix_memalign (&converted, align, size);
Packit Service 97d2fb
				if (res != 0)
Packit Service 97d2fb
				  converted = NULL;
Packit Service 97d2fb
			      }
Packit Service 97d2fb
Packit Service 97d2fb
			    if (converted == NULL)
Packit Service 97d2fb
			      {
Packit Service 97d2fb
				free (scns);
Packit Service 97d2fb
				__libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
				return 1;
Packit Service 97d2fb
			      }
Packit Service 97d2fb
Packit Service 97d2fb
			    (*fctp) (converted, dl->data.d.d_buf, size, 1);
Packit Service 97d2fb
Packit Service 97d2fb
			    /* And then write it to the mmapped file.  */
Packit Service 97d2fb
			    memcpy (last_position, converted, size);
Packit Service 97d2fb
			    free (converted);
Packit Service 97d2fb
			  }
Packit Service 97d2fb
Packit Service 97d2fb
			last_position += dl->data.d.d_size;
Packit Service 97d2fb
		      }
Packit Service 97d2fb
		    else if (dl->data.d.d_size != 0)
Packit Service 97d2fb
		      {
Packit Service 97d2fb
			memmove (last_position, dl->data.d.d_buf,
Packit Service 97d2fb
				 dl->data.d.d_size);
Packit Service 97d2fb
			last_position += dl->data.d.d_size;
Packit Service 97d2fb
		      }
Packit Service 97d2fb
Packit Service 97d2fb
		    scn_changed = true;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
		else
Packit Service 97d2fb
		  last_position += dl->data.d.d_size;
Packit Service 97d2fb
Packit Service 97d2fb
		assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
Packit Service 97d2fb
			== last_position);
Packit Service 97d2fb
Packit Service 97d2fb
		dl->flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
		dl = dl->next;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	    while (dl != NULL);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* If the previous section (or the ELF/program
Packit Service 97d2fb
		 header) changed we might have to fill the gap.  */
Packit Service 97d2fb
	      if (scn_start > last_position && previous_scn_changed)
Packit Service 97d2fb
		fill_mmap (0, last_position, scn_start,
Packit Service 97d2fb
		           shdr_start, shdr_end);
Packit Service 97d2fb
Packit Service 97d2fb
	      /* We have to trust the existing section header information.  */
Packit Service 97d2fb
	      last_position = scn_start + shdr->sh_size;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
	  previous_scn_changed = scn_changed;
Packit Service 97d2fb
	next:
Packit Service 97d2fb
	  scn->flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Fill the gap between last section and section header table if
Packit Service 97d2fb
	 necessary.  */
Packit Service 97d2fb
      if ((elf->flags & ELF_F_DIRTY)
Packit Service 97d2fb
	  && last_position < ((char *) elf->map_address + elf->start_offset
Packit Service 97d2fb
			      + ehdr->e_shoff))
Packit Service 97d2fb
	memset (last_position, __libelf_fill_byte,
Packit Service 97d2fb
		(char *) elf->map_address + elf->start_offset + ehdr->e_shoff
Packit Service 97d2fb
		- last_position);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Write the section header table entry if necessary.  */
Packit Service 97d2fb
      for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf_Scn *scn = scns[cnt];
Packit Service 97d2fb
Packit Service 97d2fb
	  if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (unlikely (change_bo))
Packit Service 97d2fb
		(*shdr_fctp) (&shdr_dest[scn->index],
Packit Service 97d2fb
			      scn->shdr.ELFW(e,LIBELFBITS),
Packit Service 97d2fb
			      sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		memcpy (&shdr_dest[scn->index],
Packit Service 97d2fb
			scn->shdr.ELFW(e,LIBELFBITS),
Packit Service 97d2fb
			sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit Service 97d2fb
Packit Service 97d2fb
	      /* If we previously made a copy of the section header
Packit Service 97d2fb
		 entry we now have to adjust the pointer again so
Packit Service 97d2fb
		 point to new place in the mapping.  */
Packit Service 97d2fb
	      if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
Packit Service 97d2fb
		  && (scn->shdr_flags & ELF_F_MALLOCED) == 0
Packit Service 97d2fb
		  && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  free (scn->shdr.ELFW(e,LIBELFBITS));
Packit Service 97d2fb
		  scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      scn->shdr_flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      free (scns);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* That was the last part.  Clear the overall flag.  */
Packit Service 97d2fb
  elf->flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make sure the content hits the disk.  */
Packit Service 97d2fb
  char *msync_start = ((char *) elf->map_address
Packit Service 97d2fb
		       + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
Packit Service 97d2fb
  char *msync_end = ((char *) elf->map_address
Packit Service 97d2fb
		     + elf->start_offset + ehdr->e_shoff
Packit Service 97d2fb
		     + ehdr->e_shentsize * shnum);
Packit Service 97d2fb
  (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Size of the buffer we use to generate the blocks of fill bytes.  */
Packit Service 97d2fb
#define FILLBUFSIZE	4096
Packit Service 97d2fb
Packit Service 97d2fb
/* If we have to convert the section buffer contents we have to use
Packit Service 97d2fb
   temporary buffer.  Only buffers up to MAX_TMPBUF bytes are allocated
Packit Service 97d2fb
   on the stack.  */
Packit Service 97d2fb
#define MAX_TMPBUF	32768
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Helper function to write out fill bytes.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
fill (int fd, int64_t pos, size_t len, char *fillbuf, size_t *filledp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t filled = *filledp;
Packit Service 97d2fb
  size_t fill_len = MIN (len, FILLBUFSIZE);
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Initialize a few more bytes.  */
Packit Service 97d2fb
      memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
Packit Service 97d2fb
      *filledp = filled = fill_len;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  do
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* This many bytes we want to write in this round.  */
Packit Service 97d2fb
      size_t n = MIN (filled, len);
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_WRITE_ERROR);
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      pos += n;
Packit Service 97d2fb
      len -= n;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  while (len > 0);
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
Packit Service 97d2fb
{
Packit Service 97d2fb
  char fillbuf[FILLBUFSIZE];
Packit Service 97d2fb
  size_t filled = 0;
Packit Service 97d2fb
  bool previous_scn_changed = false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We need the ELF header several times.  */
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Write out the ELF header.  */
Packit Service 97d2fb
  if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
Packit Service 97d2fb
      ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
Packit Service 97d2fb
Packit Service 97d2fb
      /* If the type sizes should be different at some time we have to
Packit Service 97d2fb
	 rewrite this code.  */
Packit Service 97d2fb
      assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
Packit Service 97d2fb
	      == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (change_bo))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Today there is only one version of the ELF header.  */
Packit Service 97d2fb
#undef fctp
Packit Service 97d2fb
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Write the converted ELF header in a temporary buffer.  */
Packit Service 97d2fb
	  (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* This is the buffer we want to write.  */
Packit Service 97d2fb
	  out_ehdr = &tmp_ehdr;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Write out the ELF header.  */
Packit Service 97d2fb
      if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
Packit Service 97d2fb
				  sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
Packit Service 97d2fb
		    != sizeof (ElfW2(LIBELFBITS,Ehdr))))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_WRITE_ERROR);
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
      /* We start writing sections after the ELF header only if there is
Packit Service 97d2fb
	 no program header.  */
Packit Service 97d2fb
      previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* If the type sizes should be different at some time we have to
Packit Service 97d2fb
     rewrite this code.  */
Packit Service 97d2fb
  assert (sizeof (ElfW2(LIBELFBITS,Phdr))
Packit Service 97d2fb
	  == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
Packit Service 97d2fb
Packit Service 97d2fb
  size_t phnum;
Packit Service 97d2fb
  if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Write out the program header table.  */
Packit Service 97d2fb
  if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
Packit Service 97d2fb
      && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
Packit Service 97d2fb
	  & ELF_F_DIRTY))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
Packit Service 97d2fb
      ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Maybe the user wants a gap between the ELF header and the program
Packit Service 97d2fb
	 header.  */
Packit Service 97d2fb
      if (ehdr->e_phoff > ehdr->e_ehsize
Packit Service 97d2fb
	  && unlikely (fill (elf->fildes, ehdr->e_ehsize,
Packit Service 97d2fb
			     ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
Packit Service 97d2fb
		       != 0))
Packit Service 97d2fb
	return 1;
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (change_bo))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Today there is only one version of the ELF header.  */
Packit Service 97d2fb
#undef fctp
Packit Service 97d2fb
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Allocate sufficient memory.  */
Packit Service 97d2fb
	  tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
Packit Service 97d2fb
	    malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
Packit Service 97d2fb
	  if (unlikely (tmp_phdr == NULL))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
	      return 1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Write the converted ELF header in a temporary buffer.  */
Packit Service 97d2fb
	  (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
Packit Service 97d2fb
		   sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* This is the buffer we want to write.  */
Packit Service 97d2fb
	  out_phdr = tmp_phdr;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Write out the ELF header.  */
Packit Service 97d2fb
      size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
Packit Service 97d2fb
      if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
Packit Service 97d2fb
					   phdr_size, ehdr->e_phoff)
Packit Service 97d2fb
		    != phdr_size))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_WRITE_ERROR);
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* This is a no-op we we have not allocated any memory.  */
Packit Service 97d2fb
      free (tmp_phdr);
Packit Service 97d2fb
Packit Service 97d2fb
      elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
      /* We modified the program header.  Maybe this created a gap so
Packit Service 97d2fb
	 we have to write fill bytes, if necessary.  */
Packit Service 97d2fb
      previous_scn_changed = true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* From now on we have to keep track of the last position to eventually
Packit Service 97d2fb
     fill the gaps with the prescribed fill byte.  */
Packit Service 97d2fb
  int64_t last_offset;
Packit Service 97d2fb
  if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
Packit Service 97d2fb
    last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
Packit Service 97d2fb
  else
Packit Service 97d2fb
    last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Write all the sections.  Well, only those which are modified.  */
Packit Service 97d2fb
  if (shnum > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
Packit Service 97d2fb
					+ sizeof (ElfW2(LIBELFBITS,Shdr)))))
Packit Service 97d2fb
	return 1;
Packit Service 97d2fb
Packit Service 97d2fb
      int64_t shdr_offset = elf->start_offset + ehdr->e_shoff;
Packit Service 97d2fb
#undef shdr_fctp
Packit Service 97d2fb
#define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
Packit Service 97d2fb
Packit Service 97d2fb
      ElfW2(LIBELFBITS,Shdr) *shdr_data;
Packit Service 97d2fb
      ElfW2(LIBELFBITS,Shdr) *shdr_data_mem = NULL;
Packit Service 97d2fb
      if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
Packit Service 97d2fb
	  || (elf->flags & ELF_F_DIRTY))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  shdr_data_mem = (ElfW2(LIBELFBITS,Shdr) *)
Packit Service 97d2fb
	    malloc (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit Service 97d2fb
	  if (unlikely (shdr_data_mem == NULL))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
	      return -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  shdr_data = shdr_data_mem;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
Packit Service 97d2fb
      int shdr_flags = elf->flags;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Get all sections into the array and sort them.  */
Packit Service 97d2fb
      Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
Packit Service 97d2fb
      Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
Packit Service 97d2fb
      if (unlikely (scns == NULL))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  free (shdr_data_mem);
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      sort_sections (scns, list);
Packit Service 97d2fb
Packit Service 97d2fb
      for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf_Scn *scn = scns[cnt];
Packit Service 97d2fb
	  if (scn->index == 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* The dummy section header entry.  It should not be
Packit Service 97d2fb
		 possible to mark this "section" as dirty.  */
Packit Service 97d2fb
	      assert ((scn->flags & ELF_F_DIRTY) == 0);
Packit Service 97d2fb
	      goto next;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
Packit Service 97d2fb
	  if (shdr->sh_type == SHT_NOBITS)
Packit Service 97d2fb
	    goto next;
Packit Service 97d2fb
Packit Service 97d2fb
	  int64_t scn_start = elf->start_offset + shdr->sh_offset;
Packit Service 97d2fb
	  Elf_Data_List *dl = &scn->data_list;
Packit Service 97d2fb
	  bool scn_changed = false;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (scn->data_list_rear != NULL)
Packit Service 97d2fb
	    do
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		/* If there is a gap, fill it.  */
Packit Service 97d2fb
		if (scn_start + dl->data.d.d_off > last_offset
Packit Service 97d2fb
		    && ((previous_scn_changed && dl->data.d.d_off == 0)
Packit Service 97d2fb
			|| ((scn->flags | dl->flags | elf->flags)
Packit Service 97d2fb
			    & ELF_F_DIRTY) != 0))
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (unlikely (fill (elf->fildes, last_offset,
Packit Service 97d2fb
					(scn_start + dl->data.d.d_off)
Packit Service 97d2fb
					- last_offset, fillbuf,
Packit Service 97d2fb
					&filled) != 0))
Packit Service 97d2fb
		      {
Packit Service 97d2fb
		      fail_free:
Packit Service 97d2fb
			free (shdr_data_mem);
Packit Service 97d2fb
			free (scns);
Packit Service 97d2fb
			return 1;
Packit Service 97d2fb
		      }
Packit Service 97d2fb
		  }
Packit Service 97d2fb
Packit Service 97d2fb
		last_offset = scn_start + dl->data.d.d_off;
Packit Service 97d2fb
Packit Service 97d2fb
		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    char tmpbuf[MAX_TMPBUF];
Packit Service 97d2fb
		    void *buf = dl->data.d.d_buf;
Packit Service 97d2fb
Packit Service 97d2fb
		    /* Let it go backward if the sections use a bogus
Packit Service 97d2fb
		       layout with overlaps.  We'll overwrite the stupid
Packit Service 97d2fb
		       user's section data with the latest one, rather than
Packit Service 97d2fb
		       crashing.  */
Packit Service 97d2fb
Packit Service 97d2fb
		    if (unlikely (change_bo))
Packit Service 97d2fb
		      {
Packit Service 97d2fb
#undef fctp
Packit Service 97d2fb
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
Packit Service 97d2fb
Packit Service 97d2fb
			buf = tmpbuf;
Packit Service 97d2fb
			if (dl->data.d.d_size > MAX_TMPBUF)
Packit Service 97d2fb
			  {
Packit Service 97d2fb
			    buf = malloc (dl->data.d.d_size);
Packit Service 97d2fb
			    if (unlikely (buf == NULL))
Packit Service 97d2fb
			      {
Packit Service 97d2fb
				__libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
				goto fail_free;
Packit Service 97d2fb
			      }
Packit Service 97d2fb
			  }
Packit Service 97d2fb
Packit Service 97d2fb
			/* Do the real work.  */
Packit Service 97d2fb
			(*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
Packit Service 97d2fb
		      }
Packit Service 97d2fb
Packit Service 97d2fb
		    ssize_t n = pwrite_retry (elf->fildes, buf,
Packit Service 97d2fb
					      dl->data.d.d_size,
Packit Service 97d2fb
					      last_offset);
Packit Service 97d2fb
		    if (unlikely ((size_t) n != dl->data.d.d_size))
Packit Service 97d2fb
		      {
Packit Service 97d2fb
			if (buf != dl->data.d.d_buf && buf != tmpbuf)
Packit Service 97d2fb
			  free (buf);
Packit Service 97d2fb
Packit Service 97d2fb
			__libelf_seterrno (ELF_E_WRITE_ERROR);
Packit Service 97d2fb
			goto fail_free;
Packit Service 97d2fb
		      }
Packit Service 97d2fb
Packit Service 97d2fb
		    if (buf != dl->data.d.d_buf && buf != tmpbuf)
Packit Service 97d2fb
		      free (buf);
Packit Service 97d2fb
Packit Service 97d2fb
		    scn_changed = true;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
Packit Service 97d2fb
		last_offset += dl->data.d.d_size;
Packit Service 97d2fb
Packit Service 97d2fb
		dl->flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
		dl = dl->next;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	    while (dl != NULL);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* If the previous section (or the ELF/program
Packit Service 97d2fb
		 header) changed we might have to fill the gap.  */
Packit Service 97d2fb
	      if (scn_start > last_offset && previous_scn_changed)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  if (unlikely (fill (elf->fildes, last_offset,
Packit Service 97d2fb
				      scn_start - last_offset, fillbuf,
Packit Service 97d2fb
				      &filled) != 0))
Packit Service 97d2fb
		    goto fail_free;
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      last_offset = scn_start + shdr->sh_size;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  previous_scn_changed = scn_changed;
Packit Service 97d2fb
	next:
Packit Service 97d2fb
	  /* Collect the section header table information.  */
Packit Service 97d2fb
	  if (unlikely (change_bo))
Packit Service 97d2fb
	    (*shdr_fctp) (&shdr_data[scn->index],
Packit Service 97d2fb
			  scn->shdr.ELFW(e,LIBELFBITS),
Packit Service 97d2fb
			  sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
Packit Service 97d2fb
	  else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
Packit Service 97d2fb
		   || (elf->flags & ELF_F_DIRTY))
Packit Service 97d2fb
	    memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
Packit Service 97d2fb
		    sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit Service 97d2fb
Packit Service 97d2fb
	  shdr_flags |= scn->shdr_flags;
Packit Service 97d2fb
	  scn->shdr_flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Fill the gap between last section and section header table if
Packit Service 97d2fb
	 necessary.  */
Packit Service 97d2fb
      if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
Packit Service 97d2fb
	  && unlikely (fill (elf->fildes, last_offset,
Packit Service 97d2fb
			     shdr_offset - last_offset,
Packit Service 97d2fb
			     fillbuf, &filled) != 0))
Packit Service 97d2fb
	goto fail_free;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Write out the section header table.  */
Packit Service 97d2fb
      if (shdr_flags & ELF_F_DIRTY
Packit Service 97d2fb
	  && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
Packit Service 97d2fb
					      sizeof (ElfW2(LIBELFBITS,Shdr))
Packit Service 97d2fb
					      * shnum, shdr_offset)
Packit Service 97d2fb
		       != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_WRITE_ERROR);
Packit Service 97d2fb
	  goto fail_free;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      free (shdr_data_mem);
Packit Service 97d2fb
      free (scns);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* That was the last part.  Clear the overall flag.  */
Packit Service 97d2fb
  elf->flags &= ~ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}