1da0c48c4Sopenharmony_ci/* Write changed data structures.
2da0c48c4Sopenharmony_ci   Copyright (C) 2000-2010, 2014, 2015, 2016, 2018 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5da0c48c4Sopenharmony_ci
6da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
7da0c48c4Sopenharmony_ci   it under the terms of either
8da0c48c4Sopenharmony_ci
9da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
10da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
11da0c48c4Sopenharmony_ci       your option) any later version
12da0c48c4Sopenharmony_ci
13da0c48c4Sopenharmony_ci   or
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
16da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
17da0c48c4Sopenharmony_ci       your option) any later version
18da0c48c4Sopenharmony_ci
19da0c48c4Sopenharmony_ci   or both in parallel, as here.
20da0c48c4Sopenharmony_ci
21da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
22da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
23da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24da0c48c4Sopenharmony_ci   General Public License for more details.
25da0c48c4Sopenharmony_ci
26da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
27da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
28da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
29da0c48c4Sopenharmony_ci
30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
31da0c48c4Sopenharmony_ci# include <config.h>
32da0c48c4Sopenharmony_ci#endif
33da0c48c4Sopenharmony_ci
34da0c48c4Sopenharmony_ci#include <assert.h>
35da0c48c4Sopenharmony_ci#include <errno.h>
36da0c48c4Sopenharmony_ci#include <libelf.h>
37da0c48c4Sopenharmony_ci#include <stdbool.h>
38da0c48c4Sopenharmony_ci#include <stdlib.h>
39da0c48c4Sopenharmony_ci#include <string.h>
40da0c48c4Sopenharmony_ci
41da0c48c4Sopenharmony_ci#include "libelfP.h"
42da0c48c4Sopenharmony_ci
43da0c48c4Sopenharmony_ci
44da0c48c4Sopenharmony_ci#ifndef LIBELFBITS
45da0c48c4Sopenharmony_ci# define LIBELFBITS 32
46da0c48c4Sopenharmony_ci#endif
47da0c48c4Sopenharmony_ci
48da0c48c4Sopenharmony_ci
49da0c48c4Sopenharmony_cistatic int
50da0c48c4Sopenharmony_cicompare_sections (const void *a, const void *b)
51da0c48c4Sopenharmony_ci{
52da0c48c4Sopenharmony_ci  const Elf_Scn **scna = (const Elf_Scn **) a;
53da0c48c4Sopenharmony_ci  const Elf_Scn **scnb = (const Elf_Scn **) b;
54da0c48c4Sopenharmony_ci
55da0c48c4Sopenharmony_ci  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
56da0c48c4Sopenharmony_ci      < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
57da0c48c4Sopenharmony_ci    return -1;
58da0c48c4Sopenharmony_ci
59da0c48c4Sopenharmony_ci  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
60da0c48c4Sopenharmony_ci      > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
61da0c48c4Sopenharmony_ci    return 1;
62da0c48c4Sopenharmony_ci
63da0c48c4Sopenharmony_ci  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
64da0c48c4Sopenharmony_ci      < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
65da0c48c4Sopenharmony_ci    return -1;
66da0c48c4Sopenharmony_ci
67da0c48c4Sopenharmony_ci  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
68da0c48c4Sopenharmony_ci      > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
69da0c48c4Sopenharmony_ci    return 1;
70da0c48c4Sopenharmony_ci
71da0c48c4Sopenharmony_ci  if ((*scna)->index < (*scnb)->index)
72da0c48c4Sopenharmony_ci    return -1;
73da0c48c4Sopenharmony_ci
74da0c48c4Sopenharmony_ci  if ((*scna)->index > (*scnb)->index)
75da0c48c4Sopenharmony_ci    return 1;
76da0c48c4Sopenharmony_ci
77da0c48c4Sopenharmony_ci  return 0;
78da0c48c4Sopenharmony_ci}
79da0c48c4Sopenharmony_ci
80da0c48c4Sopenharmony_ci
81da0c48c4Sopenharmony_ci/* Insert the sections in the list into the provided array and sort
82da0c48c4Sopenharmony_ci   them according to their start offsets.  For sections with equal
83da0c48c4Sopenharmony_ci   start offsets, the size is used; for sections with equal start
84da0c48c4Sopenharmony_ci   offsets and sizes, the section index is used.  Sorting by size
85da0c48c4Sopenharmony_ci   ensures that zero-length sections are processed first, which
86da0c48c4Sopenharmony_ci   is what we want since they do not advance our file writing position.  */
87da0c48c4Sopenharmony_cistatic void
88da0c48c4Sopenharmony_cisort_sections (Elf_Scn **scns, Elf_ScnList *list)
89da0c48c4Sopenharmony_ci{
90da0c48c4Sopenharmony_ci  Elf_Scn **scnp = scns;
91da0c48c4Sopenharmony_ci  do
92da0c48c4Sopenharmony_ci    for (size_t cnt = 0; cnt < list->cnt; ++cnt)
93da0c48c4Sopenharmony_ci      *scnp++ = &list->data[cnt];
94da0c48c4Sopenharmony_ci  while ((list = list->next) != NULL);
95da0c48c4Sopenharmony_ci
96da0c48c4Sopenharmony_ci  qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
97da0c48c4Sopenharmony_ci}
98da0c48c4Sopenharmony_ci
99da0c48c4Sopenharmony_ci
100da0c48c4Sopenharmony_cistatic inline void
101da0c48c4Sopenharmony_cifill_mmap (size_t offset, char *last_position, char *scn_start,
102da0c48c4Sopenharmony_ci           char *const shdr_start, char *const shdr_end)
103da0c48c4Sopenharmony_ci{
104da0c48c4Sopenharmony_ci  size_t written = 0;
105da0c48c4Sopenharmony_ci
106da0c48c4Sopenharmony_ci  if (last_position < shdr_start)
107da0c48c4Sopenharmony_ci    {
108da0c48c4Sopenharmony_ci      written = MIN (scn_start + offset - last_position,
109da0c48c4Sopenharmony_ci                     shdr_start - last_position);
110da0c48c4Sopenharmony_ci
111da0c48c4Sopenharmony_ci      memset (last_position, __libelf_fill_byte, written);
112da0c48c4Sopenharmony_ci    }
113da0c48c4Sopenharmony_ci
114da0c48c4Sopenharmony_ci  if (last_position + written != scn_start + offset
115da0c48c4Sopenharmony_ci      && shdr_end < scn_start + offset)
116da0c48c4Sopenharmony_ci    {
117da0c48c4Sopenharmony_ci      char *fill_start = MAX (shdr_end, scn_start);
118da0c48c4Sopenharmony_ci      memset (fill_start, __libelf_fill_byte,
119da0c48c4Sopenharmony_ci              scn_start + offset - fill_start);
120da0c48c4Sopenharmony_ci    }
121da0c48c4Sopenharmony_ci}
122da0c48c4Sopenharmony_ci
123da0c48c4Sopenharmony_ciint
124da0c48c4Sopenharmony_ciinternal_function
125da0c48c4Sopenharmony_ci__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
126da0c48c4Sopenharmony_ci{
127da0c48c4Sopenharmony_ci  bool previous_scn_changed = false;
128da0c48c4Sopenharmony_ci
129da0c48c4Sopenharmony_ci  /* We need the ELF header several times.  */
130da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
131da0c48c4Sopenharmony_ci
132da0c48c4Sopenharmony_ci  /* Write out the ELF header.  */
133da0c48c4Sopenharmony_ci  if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
134da0c48c4Sopenharmony_ci    {
135da0c48c4Sopenharmony_ci      /* If the type sizes should be different at some time we have to
136da0c48c4Sopenharmony_ci	 rewrite this code.  */
137da0c48c4Sopenharmony_ci      assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
138da0c48c4Sopenharmony_ci	      == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
139da0c48c4Sopenharmony_ci
140da0c48c4Sopenharmony_ci      if (unlikely (change_bo))
141da0c48c4Sopenharmony_ci	{
142da0c48c4Sopenharmony_ci	  /* Today there is only one version of the ELF header.  */
143da0c48c4Sopenharmony_ci#undef fctp
144da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
145da0c48c4Sopenharmony_ci
146da0c48c4Sopenharmony_ci	  /* Do the real work.  */
147da0c48c4Sopenharmony_ci	  (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
148da0c48c4Sopenharmony_ci		   sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
149da0c48c4Sopenharmony_ci	}
150da0c48c4Sopenharmony_ci      else if (elf->map_address + elf->start_offset != ehdr)
151da0c48c4Sopenharmony_ci	memcpy (elf->map_address + elf->start_offset, ehdr,
152da0c48c4Sopenharmony_ci		sizeof (ElfW2(LIBELFBITS,Ehdr)));
153da0c48c4Sopenharmony_ci
154da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
155da0c48c4Sopenharmony_ci
156da0c48c4Sopenharmony_ci      /* We start writing sections after the ELF header only if there is
157da0c48c4Sopenharmony_ci	 no program header.  */
158da0c48c4Sopenharmony_ci      previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
159da0c48c4Sopenharmony_ci    }
160da0c48c4Sopenharmony_ci
161da0c48c4Sopenharmony_ci  size_t phnum;
162da0c48c4Sopenharmony_ci  if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
163da0c48c4Sopenharmony_ci    return -1;
164da0c48c4Sopenharmony_ci
165da0c48c4Sopenharmony_ci  /* Write out the program header table.  */
166da0c48c4Sopenharmony_ci  if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
167da0c48c4Sopenharmony_ci      && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
168da0c48c4Sopenharmony_ci	  & ELF_F_DIRTY))
169da0c48c4Sopenharmony_ci    {
170da0c48c4Sopenharmony_ci      /* If the type sizes should be different at some time we have to
171da0c48c4Sopenharmony_ci	 rewrite this code.  */
172da0c48c4Sopenharmony_ci      assert (sizeof (ElfW2(LIBELFBITS,Phdr))
173da0c48c4Sopenharmony_ci	      == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
174da0c48c4Sopenharmony_ci
175da0c48c4Sopenharmony_ci      /* Maybe the user wants a gap between the ELF header and the program
176da0c48c4Sopenharmony_ci	 header.  */
177da0c48c4Sopenharmony_ci      if (ehdr->e_phoff > ehdr->e_ehsize)
178da0c48c4Sopenharmony_ci	memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
179da0c48c4Sopenharmony_ci		__libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
180da0c48c4Sopenharmony_ci
181da0c48c4Sopenharmony_ci      if (unlikely (change_bo))
182da0c48c4Sopenharmony_ci	{
183da0c48c4Sopenharmony_ci	  /* Today there is only one version of the ELF header.  */
184da0c48c4Sopenharmony_ci#undef fctp
185da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
186da0c48c4Sopenharmony_ci
187da0c48c4Sopenharmony_ci	  /* Do the real work.  */
188da0c48c4Sopenharmony_ci	  (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
189da0c48c4Sopenharmony_ci		   elf->state.ELFW(elf,LIBELFBITS).phdr,
190da0c48c4Sopenharmony_ci		   sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
191da0c48c4Sopenharmony_ci	}
192da0c48c4Sopenharmony_ci      else
193da0c48c4Sopenharmony_ci	memmove (elf->map_address + elf->start_offset + ehdr->e_phoff,
194da0c48c4Sopenharmony_ci		elf->state.ELFW(elf,LIBELFBITS).phdr,
195da0c48c4Sopenharmony_ci		sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
196da0c48c4Sopenharmony_ci
197da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
198da0c48c4Sopenharmony_ci
199da0c48c4Sopenharmony_ci      /* We modified the program header.  Maybe this created a gap so
200da0c48c4Sopenharmony_ci	 we have to write fill bytes, if necessary.  */
201da0c48c4Sopenharmony_ci      previous_scn_changed = true;
202da0c48c4Sopenharmony_ci    }
203da0c48c4Sopenharmony_ci
204da0c48c4Sopenharmony_ci  /* From now on we have to keep track of the last position to eventually
205da0c48c4Sopenharmony_ci     fill the gaps with the prescribed fill byte.  */
206da0c48c4Sopenharmony_ci  char *last_position = ((char *) elf->map_address + elf->start_offset
207da0c48c4Sopenharmony_ci			 + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
208da0c48c4Sopenharmony_ci				ehdr->e_phoff)
209da0c48c4Sopenharmony_ci			 + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
210da0c48c4Sopenharmony_ci
211da0c48c4Sopenharmony_ci  /* Write all the sections.  Well, only those which are modified.  */
212da0c48c4Sopenharmony_ci  if (shnum > 0)
213da0c48c4Sopenharmony_ci    {
214da0c48c4Sopenharmony_ci      if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
215da0c48c4Sopenharmony_ci	return 1;
216da0c48c4Sopenharmony_ci
217da0c48c4Sopenharmony_ci      Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
218da0c48c4Sopenharmony_ci      Elf_Scn **scns = malloc (shnum * sizeof (Elf_Scn *));
219da0c48c4Sopenharmony_ci      if (unlikely (scns == NULL))
220da0c48c4Sopenharmony_ci	{
221da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_NOMEM);
222da0c48c4Sopenharmony_ci	  return -1;
223da0c48c4Sopenharmony_ci	}
224da0c48c4Sopenharmony_ci      char *const shdr_start = ((char *) elf->map_address + elf->start_offset
225da0c48c4Sopenharmony_ci				+ ehdr->e_shoff);
226da0c48c4Sopenharmony_ci      char *const shdr_end = shdr_start + shnum * ehdr->e_shentsize;
227da0c48c4Sopenharmony_ci
228da0c48c4Sopenharmony_ci#undef shdr_fctp
229da0c48c4Sopenharmony_ci#define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
230da0c48c4Sopenharmony_ci#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
231da0c48c4Sopenharmony_ci
232da0c48c4Sopenharmony_ci      /* Get all sections into the array and sort them.  */
233da0c48c4Sopenharmony_ci      sort_sections (scns, list);
234da0c48c4Sopenharmony_ci
235da0c48c4Sopenharmony_ci      /* We possibly have to copy the section header data because moving
236da0c48c4Sopenharmony_ci	 the sections might overwrite the data.  */
237da0c48c4Sopenharmony_ci      for (size_t cnt = 0; cnt < shnum; ++cnt)
238da0c48c4Sopenharmony_ci	{
239da0c48c4Sopenharmony_ci	  Elf_Scn *scn = scns[cnt];
240da0c48c4Sopenharmony_ci
241da0c48c4Sopenharmony_ci	  if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
242da0c48c4Sopenharmony_ci	      && (scn->shdr_flags & ELF_F_MALLOCED) == 0
243da0c48c4Sopenharmony_ci	      && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
244da0c48c4Sopenharmony_ci	    {
245da0c48c4Sopenharmony_ci	      assert ((char *) elf->map_address + elf->start_offset
246da0c48c4Sopenharmony_ci		      < (char *) scn->shdr.ELFW(e,LIBELFBITS));
247da0c48c4Sopenharmony_ci	      assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
248da0c48c4Sopenharmony_ci		      < ((char *) elf->map_address + elf->start_offset
249da0c48c4Sopenharmony_ci			 + elf->maximum_size));
250da0c48c4Sopenharmony_ci
251da0c48c4Sopenharmony_ci	      void *p = malloc (sizeof (ElfW2(LIBELFBITS,Shdr)));
252da0c48c4Sopenharmony_ci	      if (unlikely (p == NULL))
253da0c48c4Sopenharmony_ci		{
254da0c48c4Sopenharmony_ci		  free (scns);
255da0c48c4Sopenharmony_ci		  __libelf_seterrno (ELF_E_NOMEM);
256da0c48c4Sopenharmony_ci		  return -1;
257da0c48c4Sopenharmony_ci		}
258da0c48c4Sopenharmony_ci	      scn->shdr.ELFW(e,LIBELFBITS)
259da0c48c4Sopenharmony_ci		= memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
260da0c48c4Sopenharmony_ci			  sizeof (ElfW2(LIBELFBITS,Shdr)));
261da0c48c4Sopenharmony_ci	    }
262da0c48c4Sopenharmony_ci
263da0c48c4Sopenharmony_ci	  /* If the file is mmaped and the original position of the
264da0c48c4Sopenharmony_ci	     section in the file is lower than the new position we
265da0c48c4Sopenharmony_ci	     need to save the section content since otherwise it is
266da0c48c4Sopenharmony_ci	     overwritten before it can be copied.  If there are
267da0c48c4Sopenharmony_ci	     multiple data segments in the list only the first can be
268da0c48c4Sopenharmony_ci	     from the file.  */
269da0c48c4Sopenharmony_ci	  if (((char *) elf->map_address + elf->start_offset
270da0c48c4Sopenharmony_ci	       <= (char  *) scn->data_list.data.d.d_buf)
271da0c48c4Sopenharmony_ci	      && ((char *) scn->data_list.data.d.d_buf
272da0c48c4Sopenharmony_ci		  < ((char *) elf->map_address + elf->start_offset
273da0c48c4Sopenharmony_ci		     + elf->maximum_size))
274da0c48c4Sopenharmony_ci	      && (((char *) elf->map_address + elf->start_offset
275da0c48c4Sopenharmony_ci		   + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
276da0c48c4Sopenharmony_ci		  > (char *) scn->data_list.data.d.d_buf))
277da0c48c4Sopenharmony_ci	    {
278da0c48c4Sopenharmony_ci	      void *p = malloc (scn->data_list.data.d.d_size);
279da0c48c4Sopenharmony_ci	      if (unlikely (p == NULL))
280da0c48c4Sopenharmony_ci		{
281da0c48c4Sopenharmony_ci		  free (scns);
282da0c48c4Sopenharmony_ci		  __libelf_seterrno (ELF_E_NOMEM);
283da0c48c4Sopenharmony_ci		  return -1;
284da0c48c4Sopenharmony_ci		}
285da0c48c4Sopenharmony_ci	      scn->data_list.data.d.d_buf = scn->data_base
286da0c48c4Sopenharmony_ci		= memcpy (p, scn->data_list.data.d.d_buf,
287da0c48c4Sopenharmony_ci			  scn->data_list.data.d.d_size);
288da0c48c4Sopenharmony_ci	    }
289da0c48c4Sopenharmony_ci	}
290da0c48c4Sopenharmony_ci
291da0c48c4Sopenharmony_ci      /* Iterate over all the section in the order in which they
292da0c48c4Sopenharmony_ci	 appear in the output file.  */
293da0c48c4Sopenharmony_ci      for (size_t cnt = 0; cnt < shnum; ++cnt)
294da0c48c4Sopenharmony_ci	{
295da0c48c4Sopenharmony_ci	  Elf_Scn *scn = scns[cnt];
296da0c48c4Sopenharmony_ci	  if (scn->index == 0)
297da0c48c4Sopenharmony_ci	    {
298da0c48c4Sopenharmony_ci	      /* The dummy section header entry.  It should not be
299da0c48c4Sopenharmony_ci		 possible to mark this "section" as dirty.  */
300da0c48c4Sopenharmony_ci	      assert ((scn->flags & ELF_F_DIRTY) == 0);
301da0c48c4Sopenharmony_ci	      continue;
302da0c48c4Sopenharmony_ci	    }
303da0c48c4Sopenharmony_ci
304da0c48c4Sopenharmony_ci	  ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
305da0c48c4Sopenharmony_ci	  if (shdr->sh_type == SHT_NOBITS)
306da0c48c4Sopenharmony_ci	    goto next;
307da0c48c4Sopenharmony_ci
308da0c48c4Sopenharmony_ci	  char *scn_start = ((char *) elf->map_address
309da0c48c4Sopenharmony_ci			     + elf->start_offset + shdr->sh_offset);
310da0c48c4Sopenharmony_ci	  Elf_Data_List *dl = &scn->data_list;
311da0c48c4Sopenharmony_ci	  bool scn_changed = false;
312da0c48c4Sopenharmony_ci
313da0c48c4Sopenharmony_ci	  if (scn->data_list_rear != NULL)
314da0c48c4Sopenharmony_ci	    do
315da0c48c4Sopenharmony_ci	      {
316da0c48c4Sopenharmony_ci		assert (dl->data.d.d_off >= 0);
317da0c48c4Sopenharmony_ci		assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
318da0c48c4Sopenharmony_ci		assert (dl->data.d.d_size <= (shdr->sh_size
319da0c48c4Sopenharmony_ci					      - (GElf_Off) dl->data.d.d_off));
320da0c48c4Sopenharmony_ci
321da0c48c4Sopenharmony_ci		/* If there is a gap, fill it.  */
322da0c48c4Sopenharmony_ci		if (scn_start + dl->data.d.d_off > last_position
323da0c48c4Sopenharmony_ci		    && (dl->data.d.d_off == 0
324da0c48c4Sopenharmony_ci			|| ((scn->flags | dl->flags | elf->flags)
325da0c48c4Sopenharmony_ci			    & ELF_F_DIRTY) != 0))
326da0c48c4Sopenharmony_ci		  {
327da0c48c4Sopenharmony_ci		    fill_mmap (dl->data.d.d_off, last_position, scn_start,
328da0c48c4Sopenharmony_ci		               shdr_start, shdr_end);
329da0c48c4Sopenharmony_ci		  }
330da0c48c4Sopenharmony_ci
331da0c48c4Sopenharmony_ci		last_position = scn_start + dl->data.d.d_off;
332da0c48c4Sopenharmony_ci
333da0c48c4Sopenharmony_ci		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
334da0c48c4Sopenharmony_ci		  {
335da0c48c4Sopenharmony_ci		    /* Let it go backward if the sections use a bogus
336da0c48c4Sopenharmony_ci		       layout with overlaps.  We'll overwrite the stupid
337da0c48c4Sopenharmony_ci		       user's section data with the latest one, rather than
338da0c48c4Sopenharmony_ci		       crashing.  */
339da0c48c4Sopenharmony_ci
340da0c48c4Sopenharmony_ci		    if (unlikely (change_bo
341da0c48c4Sopenharmony_ci				  && dl->data.d.d_size != 0
342da0c48c4Sopenharmony_ci				  && dl->data.d.d_type != ELF_T_BYTE))
343da0c48c4Sopenharmony_ci		      {
344da0c48c4Sopenharmony_ci#undef fctp
345da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
346da0c48c4Sopenharmony_ci
347da0c48c4Sopenharmony_ci			size_t align;
348da0c48c4Sopenharmony_ci			align = __libelf_type_align (ELFW(ELFCLASS,LIBELFBITS),
349da0c48c4Sopenharmony_ci						     dl->data.d.d_type);
350da0c48c4Sopenharmony_ci			if ((((uintptr_t) last_position)
351da0c48c4Sopenharmony_ci			     & (uintptr_t) (align - 1)) == 0)
352da0c48c4Sopenharmony_ci			  {
353da0c48c4Sopenharmony_ci			    /* No need to copy, we can convert directly.  */
354da0c48c4Sopenharmony_ci			    (*fctp) (last_position, dl->data.d.d_buf,
355da0c48c4Sopenharmony_ci				     dl->data.d.d_size, 1);
356da0c48c4Sopenharmony_ci			  }
357da0c48c4Sopenharmony_ci			else
358da0c48c4Sopenharmony_ci			  {
359da0c48c4Sopenharmony_ci			    /* We have to do the conversion on properly
360da0c48c4Sopenharmony_ci			       aligned memory first.  align is a power of 2,
361da0c48c4Sopenharmony_ci			       but posix_memalign only works for alignments
362da0c48c4Sopenharmony_ci			       which are a multiple of sizeof (void *).
363da0c48c4Sopenharmony_ci			       So use normal malloc for smaller alignments.  */
364da0c48c4Sopenharmony_ci			    size_t size = dl->data.d.d_size;
365da0c48c4Sopenharmony_ci			    void *converted;
366da0c48c4Sopenharmony_ci			    if (align < sizeof (void *))
367da0c48c4Sopenharmony_ci			      converted = malloc (size);
368da0c48c4Sopenharmony_ci			    else
369da0c48c4Sopenharmony_ci			      {
370da0c48c4Sopenharmony_ci				int res;
371da0c48c4Sopenharmony_ci				res = posix_memalign (&converted, align, size);
372da0c48c4Sopenharmony_ci				if (res != 0)
373da0c48c4Sopenharmony_ci				  converted = NULL;
374da0c48c4Sopenharmony_ci			      }
375da0c48c4Sopenharmony_ci
376da0c48c4Sopenharmony_ci			    if (converted == NULL)
377da0c48c4Sopenharmony_ci			      {
378da0c48c4Sopenharmony_ci				free (scns);
379da0c48c4Sopenharmony_ci				__libelf_seterrno (ELF_E_NOMEM);
380da0c48c4Sopenharmony_ci				return 1;
381da0c48c4Sopenharmony_ci			      }
382da0c48c4Sopenharmony_ci
383da0c48c4Sopenharmony_ci			    (*fctp) (converted, dl->data.d.d_buf, size, 1);
384da0c48c4Sopenharmony_ci
385da0c48c4Sopenharmony_ci			    /* And then write it to the mmapped file.  */
386da0c48c4Sopenharmony_ci			    memcpy (last_position, converted, size);
387da0c48c4Sopenharmony_ci			    free (converted);
388da0c48c4Sopenharmony_ci			  }
389da0c48c4Sopenharmony_ci
390da0c48c4Sopenharmony_ci			last_position += dl->data.d.d_size;
391da0c48c4Sopenharmony_ci		      }
392da0c48c4Sopenharmony_ci		    else if (dl->data.d.d_size != 0)
393da0c48c4Sopenharmony_ci		      {
394da0c48c4Sopenharmony_ci			memmove (last_position, dl->data.d.d_buf,
395da0c48c4Sopenharmony_ci				 dl->data.d.d_size);
396da0c48c4Sopenharmony_ci			last_position += dl->data.d.d_size;
397da0c48c4Sopenharmony_ci		      }
398da0c48c4Sopenharmony_ci
399da0c48c4Sopenharmony_ci		    scn_changed = true;
400da0c48c4Sopenharmony_ci		  }
401da0c48c4Sopenharmony_ci		else
402da0c48c4Sopenharmony_ci		  last_position += dl->data.d.d_size;
403da0c48c4Sopenharmony_ci
404da0c48c4Sopenharmony_ci		assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
405da0c48c4Sopenharmony_ci			== last_position);
406da0c48c4Sopenharmony_ci
407da0c48c4Sopenharmony_ci		dl->flags &= ~ELF_F_DIRTY;
408da0c48c4Sopenharmony_ci
409da0c48c4Sopenharmony_ci		dl = dl->next;
410da0c48c4Sopenharmony_ci	      }
411da0c48c4Sopenharmony_ci	    while (dl != NULL);
412da0c48c4Sopenharmony_ci	  else
413da0c48c4Sopenharmony_ci	    {
414da0c48c4Sopenharmony_ci	      /* If the previous section (or the ELF/program
415da0c48c4Sopenharmony_ci		 header) changed we might have to fill the gap.  */
416da0c48c4Sopenharmony_ci	      if (scn_start > last_position && previous_scn_changed)
417da0c48c4Sopenharmony_ci		fill_mmap (0, last_position, scn_start,
418da0c48c4Sopenharmony_ci		           shdr_start, shdr_end);
419da0c48c4Sopenharmony_ci
420da0c48c4Sopenharmony_ci	      /* We have to trust the existing section header information.  */
421da0c48c4Sopenharmony_ci	      last_position = scn_start + shdr->sh_size;
422da0c48c4Sopenharmony_ci	    }
423da0c48c4Sopenharmony_ci
424da0c48c4Sopenharmony_ci
425da0c48c4Sopenharmony_ci	  previous_scn_changed = scn_changed;
426da0c48c4Sopenharmony_ci	next:
427da0c48c4Sopenharmony_ci	  scn->flags &= ~ELF_F_DIRTY;
428da0c48c4Sopenharmony_ci	}
429da0c48c4Sopenharmony_ci
430da0c48c4Sopenharmony_ci      /* Fill the gap between last section and section header table if
431da0c48c4Sopenharmony_ci	 necessary.  */
432da0c48c4Sopenharmony_ci      if ((elf->flags & ELF_F_DIRTY)
433da0c48c4Sopenharmony_ci	  && last_position < ((char *) elf->map_address + elf->start_offset
434da0c48c4Sopenharmony_ci			      + ehdr->e_shoff))
435da0c48c4Sopenharmony_ci	memset (last_position, __libelf_fill_byte,
436da0c48c4Sopenharmony_ci		(char *) elf->map_address + elf->start_offset + ehdr->e_shoff
437da0c48c4Sopenharmony_ci		- last_position);
438da0c48c4Sopenharmony_ci
439da0c48c4Sopenharmony_ci      /* Write the section header table entry if necessary.  */
440da0c48c4Sopenharmony_ci      for (size_t cnt = 0; cnt < shnum; ++cnt)
441da0c48c4Sopenharmony_ci	{
442da0c48c4Sopenharmony_ci	  Elf_Scn *scn = scns[cnt];
443da0c48c4Sopenharmony_ci
444da0c48c4Sopenharmony_ci	  if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
445da0c48c4Sopenharmony_ci	    {
446da0c48c4Sopenharmony_ci	      if (unlikely (change_bo))
447da0c48c4Sopenharmony_ci		(*shdr_fctp) (&shdr_dest[scn->index],
448da0c48c4Sopenharmony_ci			      scn->shdr.ELFW(e,LIBELFBITS),
449da0c48c4Sopenharmony_ci			      sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
450da0c48c4Sopenharmony_ci	      else
451da0c48c4Sopenharmony_ci		memcpy (&shdr_dest[scn->index],
452da0c48c4Sopenharmony_ci			scn->shdr.ELFW(e,LIBELFBITS),
453da0c48c4Sopenharmony_ci			sizeof (ElfW2(LIBELFBITS,Shdr)));
454da0c48c4Sopenharmony_ci
455da0c48c4Sopenharmony_ci	      /* If we previously made a copy of the section header
456da0c48c4Sopenharmony_ci		 entry we now have to adjust the pointer again so
457da0c48c4Sopenharmony_ci		 point to new place in the mapping.  */
458da0c48c4Sopenharmony_ci	      if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
459da0c48c4Sopenharmony_ci		  && (scn->shdr_flags & ELF_F_MALLOCED) == 0
460da0c48c4Sopenharmony_ci		  && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
461da0c48c4Sopenharmony_ci		{
462da0c48c4Sopenharmony_ci		  free (scn->shdr.ELFW(e,LIBELFBITS));
463da0c48c4Sopenharmony_ci		  scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
464da0c48c4Sopenharmony_ci		}
465da0c48c4Sopenharmony_ci
466da0c48c4Sopenharmony_ci	      scn->shdr_flags &= ~ELF_F_DIRTY;
467da0c48c4Sopenharmony_ci	    }
468da0c48c4Sopenharmony_ci	}
469da0c48c4Sopenharmony_ci      free (scns);
470da0c48c4Sopenharmony_ci    }
471da0c48c4Sopenharmony_ci
472da0c48c4Sopenharmony_ci  /* That was the last part.  Clear the overall flag.  */
473da0c48c4Sopenharmony_ci  elf->flags &= ~ELF_F_DIRTY;
474da0c48c4Sopenharmony_ci
475da0c48c4Sopenharmony_ci  /* Make sure the content hits the disk.  */
476da0c48c4Sopenharmony_ci  char *msync_start = ((char *) elf->map_address
477da0c48c4Sopenharmony_ci		       + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
478da0c48c4Sopenharmony_ci  char *msync_end = ((char *) elf->map_address
479da0c48c4Sopenharmony_ci		     + elf->start_offset + ehdr->e_shoff
480da0c48c4Sopenharmony_ci		     + ehdr->e_shentsize * shnum);
481da0c48c4Sopenharmony_ci  (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
482da0c48c4Sopenharmony_ci
483da0c48c4Sopenharmony_ci  return 0;
484da0c48c4Sopenharmony_ci}
485da0c48c4Sopenharmony_ci
486da0c48c4Sopenharmony_ci
487da0c48c4Sopenharmony_ci/* Size of the buffer we use to generate the blocks of fill bytes.  */
488da0c48c4Sopenharmony_ci#define FILLBUFSIZE	4096
489da0c48c4Sopenharmony_ci
490da0c48c4Sopenharmony_ci/* If we have to convert the section buffer contents we have to use
491da0c48c4Sopenharmony_ci   temporary buffer.  Only buffers up to MAX_TMPBUF bytes are allocated
492da0c48c4Sopenharmony_ci   on the stack.  */
493da0c48c4Sopenharmony_ci#define MAX_TMPBUF	32768
494da0c48c4Sopenharmony_ci
495da0c48c4Sopenharmony_ci
496da0c48c4Sopenharmony_ci/* Helper function to write out fill bytes.  */
497da0c48c4Sopenharmony_cistatic int
498da0c48c4Sopenharmony_cifill (int fd, int64_t pos, size_t len, char *fillbuf, size_t *filledp)
499da0c48c4Sopenharmony_ci{
500da0c48c4Sopenharmony_ci  size_t filled = *filledp;
501da0c48c4Sopenharmony_ci  size_t fill_len = MIN (len, FILLBUFSIZE);
502da0c48c4Sopenharmony_ci
503da0c48c4Sopenharmony_ci  if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
504da0c48c4Sopenharmony_ci    {
505da0c48c4Sopenharmony_ci      /* Initialize a few more bytes.  */
506da0c48c4Sopenharmony_ci      memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
507da0c48c4Sopenharmony_ci      *filledp = filled = fill_len;
508da0c48c4Sopenharmony_ci    }
509da0c48c4Sopenharmony_ci
510da0c48c4Sopenharmony_ci  do
511da0c48c4Sopenharmony_ci    {
512da0c48c4Sopenharmony_ci      /* This many bytes we want to write in this round.  */
513da0c48c4Sopenharmony_ci      size_t n = MIN (filled, len);
514da0c48c4Sopenharmony_ci
515da0c48c4Sopenharmony_ci      if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
516da0c48c4Sopenharmony_ci	{
517da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_WRITE_ERROR);
518da0c48c4Sopenharmony_ci	  return 1;
519da0c48c4Sopenharmony_ci	}
520da0c48c4Sopenharmony_ci
521da0c48c4Sopenharmony_ci      pos += n;
522da0c48c4Sopenharmony_ci      len -= n;
523da0c48c4Sopenharmony_ci    }
524da0c48c4Sopenharmony_ci  while (len > 0);
525da0c48c4Sopenharmony_ci
526da0c48c4Sopenharmony_ci  return 0;
527da0c48c4Sopenharmony_ci}
528da0c48c4Sopenharmony_ci
529da0c48c4Sopenharmony_ci
530da0c48c4Sopenharmony_ciint
531da0c48c4Sopenharmony_ciinternal_function
532da0c48c4Sopenharmony_ci__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
533da0c48c4Sopenharmony_ci{
534da0c48c4Sopenharmony_ci  char fillbuf[FILLBUFSIZE];
535da0c48c4Sopenharmony_ci  size_t filled = 0;
536da0c48c4Sopenharmony_ci  bool previous_scn_changed = false;
537da0c48c4Sopenharmony_ci
538da0c48c4Sopenharmony_ci  /* We need the ELF header several times.  */
539da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
540da0c48c4Sopenharmony_ci
541da0c48c4Sopenharmony_ci  /* Write out the ELF header.  */
542da0c48c4Sopenharmony_ci  if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
543da0c48c4Sopenharmony_ci    {
544da0c48c4Sopenharmony_ci      ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
545da0c48c4Sopenharmony_ci      ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
546da0c48c4Sopenharmony_ci
547da0c48c4Sopenharmony_ci      /* If the type sizes should be different at some time we have to
548da0c48c4Sopenharmony_ci	 rewrite this code.  */
549da0c48c4Sopenharmony_ci      assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
550da0c48c4Sopenharmony_ci	      == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
551da0c48c4Sopenharmony_ci
552da0c48c4Sopenharmony_ci      if (unlikely (change_bo))
553da0c48c4Sopenharmony_ci	{
554da0c48c4Sopenharmony_ci	  /* Today there is only one version of the ELF header.  */
555da0c48c4Sopenharmony_ci#undef fctp
556da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
557da0c48c4Sopenharmony_ci
558da0c48c4Sopenharmony_ci	  /* Write the converted ELF header in a temporary buffer.  */
559da0c48c4Sopenharmony_ci	  (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
560da0c48c4Sopenharmony_ci
561da0c48c4Sopenharmony_ci	  /* This is the buffer we want to write.  */
562da0c48c4Sopenharmony_ci	  out_ehdr = &tmp_ehdr;
563da0c48c4Sopenharmony_ci	}
564da0c48c4Sopenharmony_ci
565da0c48c4Sopenharmony_ci      /* Write out the ELF header.  */
566da0c48c4Sopenharmony_ci      if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
567da0c48c4Sopenharmony_ci				  sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
568da0c48c4Sopenharmony_ci		    != sizeof (ElfW2(LIBELFBITS,Ehdr))))
569da0c48c4Sopenharmony_ci	{
570da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_WRITE_ERROR);
571da0c48c4Sopenharmony_ci	  return 1;
572da0c48c4Sopenharmony_ci	}
573da0c48c4Sopenharmony_ci
574da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
575da0c48c4Sopenharmony_ci
576da0c48c4Sopenharmony_ci      /* We start writing sections after the ELF header only if there is
577da0c48c4Sopenharmony_ci	 no program header.  */
578da0c48c4Sopenharmony_ci      previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
579da0c48c4Sopenharmony_ci    }
580da0c48c4Sopenharmony_ci
581da0c48c4Sopenharmony_ci  /* If the type sizes should be different at some time we have to
582da0c48c4Sopenharmony_ci     rewrite this code.  */
583da0c48c4Sopenharmony_ci  assert (sizeof (ElfW2(LIBELFBITS,Phdr))
584da0c48c4Sopenharmony_ci	  == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
585da0c48c4Sopenharmony_ci
586da0c48c4Sopenharmony_ci  size_t phnum;
587da0c48c4Sopenharmony_ci  if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
588da0c48c4Sopenharmony_ci    return -1;
589da0c48c4Sopenharmony_ci
590da0c48c4Sopenharmony_ci  /* Write out the program header table.  */
591da0c48c4Sopenharmony_ci  if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
592da0c48c4Sopenharmony_ci      && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
593da0c48c4Sopenharmony_ci	  & ELF_F_DIRTY))
594da0c48c4Sopenharmony_ci    {
595da0c48c4Sopenharmony_ci      ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
596da0c48c4Sopenharmony_ci      ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
597da0c48c4Sopenharmony_ci
598da0c48c4Sopenharmony_ci      /* Maybe the user wants a gap between the ELF header and the program
599da0c48c4Sopenharmony_ci	 header.  */
600da0c48c4Sopenharmony_ci      if (ehdr->e_phoff > ehdr->e_ehsize
601da0c48c4Sopenharmony_ci	  && unlikely (fill (elf->fildes, ehdr->e_ehsize,
602da0c48c4Sopenharmony_ci			     ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
603da0c48c4Sopenharmony_ci		       != 0))
604da0c48c4Sopenharmony_ci	return 1;
605da0c48c4Sopenharmony_ci
606da0c48c4Sopenharmony_ci      if (unlikely (change_bo))
607da0c48c4Sopenharmony_ci	{
608da0c48c4Sopenharmony_ci	  /* Today there is only one version of the ELF header.  */
609da0c48c4Sopenharmony_ci#undef fctp
610da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
611da0c48c4Sopenharmony_ci
612da0c48c4Sopenharmony_ci	  /* Allocate sufficient memory.  */
613da0c48c4Sopenharmony_ci	  tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
614da0c48c4Sopenharmony_ci	    malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
615da0c48c4Sopenharmony_ci	  if (unlikely (tmp_phdr == NULL))
616da0c48c4Sopenharmony_ci	    {
617da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_NOMEM);
618da0c48c4Sopenharmony_ci	      return 1;
619da0c48c4Sopenharmony_ci	    }
620da0c48c4Sopenharmony_ci
621da0c48c4Sopenharmony_ci	  /* Write the converted ELF header in a temporary buffer.  */
622da0c48c4Sopenharmony_ci	  (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
623da0c48c4Sopenharmony_ci		   sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
624da0c48c4Sopenharmony_ci
625da0c48c4Sopenharmony_ci	  /* This is the buffer we want to write.  */
626da0c48c4Sopenharmony_ci	  out_phdr = tmp_phdr;
627da0c48c4Sopenharmony_ci	}
628da0c48c4Sopenharmony_ci
629da0c48c4Sopenharmony_ci      /* Write out the ELF header.  */
630da0c48c4Sopenharmony_ci      size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
631da0c48c4Sopenharmony_ci      if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
632da0c48c4Sopenharmony_ci					   phdr_size, ehdr->e_phoff)
633da0c48c4Sopenharmony_ci		    != phdr_size))
634da0c48c4Sopenharmony_ci	{
635da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_WRITE_ERROR);
636da0c48c4Sopenharmony_ci	  return 1;
637da0c48c4Sopenharmony_ci	}
638da0c48c4Sopenharmony_ci
639da0c48c4Sopenharmony_ci      /* This is a no-op we we have not allocated any memory.  */
640da0c48c4Sopenharmony_ci      free (tmp_phdr);
641da0c48c4Sopenharmony_ci
642da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
643da0c48c4Sopenharmony_ci
644da0c48c4Sopenharmony_ci      /* We modified the program header.  Maybe this created a gap so
645da0c48c4Sopenharmony_ci	 we have to write fill bytes, if necessary.  */
646da0c48c4Sopenharmony_ci      previous_scn_changed = true;
647da0c48c4Sopenharmony_ci    }
648da0c48c4Sopenharmony_ci
649da0c48c4Sopenharmony_ci  /* From now on we have to keep track of the last position to eventually
650da0c48c4Sopenharmony_ci     fill the gaps with the prescribed fill byte.  */
651da0c48c4Sopenharmony_ci  int64_t last_offset;
652da0c48c4Sopenharmony_ci  if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
653da0c48c4Sopenharmony_ci    last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
654da0c48c4Sopenharmony_ci  else
655da0c48c4Sopenharmony_ci    last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
656da0c48c4Sopenharmony_ci
657da0c48c4Sopenharmony_ci  /* Write all the sections.  Well, only those which are modified.  */
658da0c48c4Sopenharmony_ci  if (shnum > 0)
659da0c48c4Sopenharmony_ci    {
660da0c48c4Sopenharmony_ci      if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
661da0c48c4Sopenharmony_ci					+ sizeof (ElfW2(LIBELFBITS,Shdr)))))
662da0c48c4Sopenharmony_ci	return 1;
663da0c48c4Sopenharmony_ci
664da0c48c4Sopenharmony_ci      int64_t shdr_offset = elf->start_offset + ehdr->e_shoff;
665da0c48c4Sopenharmony_ci#undef shdr_fctp
666da0c48c4Sopenharmony_ci#define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
667da0c48c4Sopenharmony_ci
668da0c48c4Sopenharmony_ci      ElfW2(LIBELFBITS,Shdr) *shdr_data;
669da0c48c4Sopenharmony_ci      ElfW2(LIBELFBITS,Shdr) *shdr_data_mem = NULL;
670da0c48c4Sopenharmony_ci      if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
671da0c48c4Sopenharmony_ci	  || (elf->flags & ELF_F_DIRTY))
672da0c48c4Sopenharmony_ci	{
673da0c48c4Sopenharmony_ci	  shdr_data_mem = (ElfW2(LIBELFBITS,Shdr) *)
674da0c48c4Sopenharmony_ci	    malloc (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
675da0c48c4Sopenharmony_ci	  if (unlikely (shdr_data_mem == NULL))
676da0c48c4Sopenharmony_ci	    {
677da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_NOMEM);
678da0c48c4Sopenharmony_ci	      return -1;
679da0c48c4Sopenharmony_ci	    }
680da0c48c4Sopenharmony_ci	  shdr_data = shdr_data_mem;
681da0c48c4Sopenharmony_ci	}
682da0c48c4Sopenharmony_ci      else
683da0c48c4Sopenharmony_ci	shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
684da0c48c4Sopenharmony_ci      int shdr_flags = elf->flags;
685da0c48c4Sopenharmony_ci
686da0c48c4Sopenharmony_ci      /* Get all sections into the array and sort them.  */
687da0c48c4Sopenharmony_ci      Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
688da0c48c4Sopenharmony_ci      Elf_Scn **scns = malloc (shnum * sizeof (Elf_Scn *));
689da0c48c4Sopenharmony_ci      if (unlikely (scns == NULL))
690da0c48c4Sopenharmony_ci	{
691da0c48c4Sopenharmony_ci	  free (shdr_data_mem);
692da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_NOMEM);
693da0c48c4Sopenharmony_ci	  return -1;
694da0c48c4Sopenharmony_ci	}
695da0c48c4Sopenharmony_ci      sort_sections (scns, list);
696da0c48c4Sopenharmony_ci
697da0c48c4Sopenharmony_ci      for (size_t cnt = 0; cnt < shnum; ++cnt)
698da0c48c4Sopenharmony_ci	{
699da0c48c4Sopenharmony_ci	  Elf_Scn *scn = scns[cnt];
700da0c48c4Sopenharmony_ci	  if (scn->index == 0)
701da0c48c4Sopenharmony_ci	    {
702da0c48c4Sopenharmony_ci	      /* The dummy section header entry.  It should not be
703da0c48c4Sopenharmony_ci		 possible to mark this "section" as dirty.  */
704da0c48c4Sopenharmony_ci	      assert ((scn->flags & ELF_F_DIRTY) == 0);
705da0c48c4Sopenharmony_ci	      goto next;
706da0c48c4Sopenharmony_ci	    }
707da0c48c4Sopenharmony_ci
708da0c48c4Sopenharmony_ci	  ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
709da0c48c4Sopenharmony_ci	  if (shdr->sh_type == SHT_NOBITS)
710da0c48c4Sopenharmony_ci	    goto next;
711da0c48c4Sopenharmony_ci
712da0c48c4Sopenharmony_ci	  int64_t scn_start = elf->start_offset + shdr->sh_offset;
713da0c48c4Sopenharmony_ci	  Elf_Data_List *dl = &scn->data_list;
714da0c48c4Sopenharmony_ci	  bool scn_changed = false;
715da0c48c4Sopenharmony_ci
716da0c48c4Sopenharmony_ci	  if (scn->data_list_rear != NULL)
717da0c48c4Sopenharmony_ci	    do
718da0c48c4Sopenharmony_ci	      {
719da0c48c4Sopenharmony_ci		/* If there is a gap, fill it.  */
720da0c48c4Sopenharmony_ci		if (scn_start + dl->data.d.d_off > last_offset
721da0c48c4Sopenharmony_ci		    && ((previous_scn_changed && dl->data.d.d_off == 0)
722da0c48c4Sopenharmony_ci			|| ((scn->flags | dl->flags | elf->flags)
723da0c48c4Sopenharmony_ci			    & ELF_F_DIRTY) != 0))
724da0c48c4Sopenharmony_ci		  {
725da0c48c4Sopenharmony_ci		    if (unlikely (fill (elf->fildes, last_offset,
726da0c48c4Sopenharmony_ci					(scn_start + dl->data.d.d_off)
727da0c48c4Sopenharmony_ci					- last_offset, fillbuf,
728da0c48c4Sopenharmony_ci					&filled) != 0))
729da0c48c4Sopenharmony_ci		      {
730da0c48c4Sopenharmony_ci		      fail_free:
731da0c48c4Sopenharmony_ci			free (shdr_data_mem);
732da0c48c4Sopenharmony_ci			free (scns);
733da0c48c4Sopenharmony_ci			return 1;
734da0c48c4Sopenharmony_ci		      }
735da0c48c4Sopenharmony_ci		  }
736da0c48c4Sopenharmony_ci
737da0c48c4Sopenharmony_ci		last_offset = scn_start + dl->data.d.d_off;
738da0c48c4Sopenharmony_ci
739da0c48c4Sopenharmony_ci		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
740da0c48c4Sopenharmony_ci		  {
741da0c48c4Sopenharmony_ci		    char tmpbuf[MAX_TMPBUF];
742da0c48c4Sopenharmony_ci		    void *buf = dl->data.d.d_buf;
743da0c48c4Sopenharmony_ci
744da0c48c4Sopenharmony_ci		    /* Let it go backward if the sections use a bogus
745da0c48c4Sopenharmony_ci		       layout with overlaps.  We'll overwrite the stupid
746da0c48c4Sopenharmony_ci		       user's section data with the latest one, rather than
747da0c48c4Sopenharmony_ci		       crashing.  */
748da0c48c4Sopenharmony_ci
749da0c48c4Sopenharmony_ci		    if (unlikely (change_bo))
750da0c48c4Sopenharmony_ci		      {
751da0c48c4Sopenharmony_ci#undef fctp
752da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
753da0c48c4Sopenharmony_ci
754da0c48c4Sopenharmony_ci			buf = tmpbuf;
755da0c48c4Sopenharmony_ci			if (dl->data.d.d_size > MAX_TMPBUF)
756da0c48c4Sopenharmony_ci			  {
757da0c48c4Sopenharmony_ci			    buf = malloc (dl->data.d.d_size);
758da0c48c4Sopenharmony_ci			    if (unlikely (buf == NULL))
759da0c48c4Sopenharmony_ci			      {
760da0c48c4Sopenharmony_ci				__libelf_seterrno (ELF_E_NOMEM);
761da0c48c4Sopenharmony_ci				goto fail_free;
762da0c48c4Sopenharmony_ci			      }
763da0c48c4Sopenharmony_ci			  }
764da0c48c4Sopenharmony_ci
765da0c48c4Sopenharmony_ci			/* Do the real work.  */
766da0c48c4Sopenharmony_ci			(*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
767da0c48c4Sopenharmony_ci		      }
768da0c48c4Sopenharmony_ci
769da0c48c4Sopenharmony_ci		    ssize_t n = pwrite_retry (elf->fildes, buf,
770da0c48c4Sopenharmony_ci					      dl->data.d.d_size,
771da0c48c4Sopenharmony_ci					      last_offset);
772da0c48c4Sopenharmony_ci		    if (unlikely ((size_t) n != dl->data.d.d_size))
773da0c48c4Sopenharmony_ci		      {
774da0c48c4Sopenharmony_ci			if (buf != dl->data.d.d_buf && buf != tmpbuf)
775da0c48c4Sopenharmony_ci			  free (buf);
776da0c48c4Sopenharmony_ci
777da0c48c4Sopenharmony_ci			__libelf_seterrno (ELF_E_WRITE_ERROR);
778da0c48c4Sopenharmony_ci			goto fail_free;
779da0c48c4Sopenharmony_ci		      }
780da0c48c4Sopenharmony_ci
781da0c48c4Sopenharmony_ci		    if (buf != dl->data.d.d_buf && buf != tmpbuf)
782da0c48c4Sopenharmony_ci		      free (buf);
783da0c48c4Sopenharmony_ci
784da0c48c4Sopenharmony_ci		    scn_changed = true;
785da0c48c4Sopenharmony_ci		  }
786da0c48c4Sopenharmony_ci
787da0c48c4Sopenharmony_ci		last_offset += dl->data.d.d_size;
788da0c48c4Sopenharmony_ci
789da0c48c4Sopenharmony_ci		dl->flags &= ~ELF_F_DIRTY;
790da0c48c4Sopenharmony_ci
791da0c48c4Sopenharmony_ci		dl = dl->next;
792da0c48c4Sopenharmony_ci	      }
793da0c48c4Sopenharmony_ci	    while (dl != NULL);
794da0c48c4Sopenharmony_ci	  else
795da0c48c4Sopenharmony_ci	    {
796da0c48c4Sopenharmony_ci	      /* If the previous section (or the ELF/program
797da0c48c4Sopenharmony_ci		 header) changed we might have to fill the gap.  */
798da0c48c4Sopenharmony_ci	      if (scn_start > last_offset && previous_scn_changed)
799da0c48c4Sopenharmony_ci		{
800da0c48c4Sopenharmony_ci		  if (unlikely (fill (elf->fildes, last_offset,
801da0c48c4Sopenharmony_ci				      scn_start - last_offset, fillbuf,
802da0c48c4Sopenharmony_ci				      &filled) != 0))
803da0c48c4Sopenharmony_ci		    goto fail_free;
804da0c48c4Sopenharmony_ci		}
805da0c48c4Sopenharmony_ci
806da0c48c4Sopenharmony_ci	      last_offset = scn_start + shdr->sh_size;
807da0c48c4Sopenharmony_ci	    }
808da0c48c4Sopenharmony_ci
809da0c48c4Sopenharmony_ci	  previous_scn_changed = scn_changed;
810da0c48c4Sopenharmony_ci	next:
811da0c48c4Sopenharmony_ci	  /* Collect the section header table information.  */
812da0c48c4Sopenharmony_ci	  if (unlikely (change_bo))
813da0c48c4Sopenharmony_ci	    (*shdr_fctp) (&shdr_data[scn->index],
814da0c48c4Sopenharmony_ci			  scn->shdr.ELFW(e,LIBELFBITS),
815da0c48c4Sopenharmony_ci			  sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
816da0c48c4Sopenharmony_ci	  else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
817da0c48c4Sopenharmony_ci		   || (elf->flags & ELF_F_DIRTY))
818da0c48c4Sopenharmony_ci	    memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
819da0c48c4Sopenharmony_ci		    sizeof (ElfW2(LIBELFBITS,Shdr)));
820da0c48c4Sopenharmony_ci
821da0c48c4Sopenharmony_ci	  shdr_flags |= scn->shdr_flags;
822da0c48c4Sopenharmony_ci	  scn->shdr_flags &= ~ELF_F_DIRTY;
823da0c48c4Sopenharmony_ci	}
824da0c48c4Sopenharmony_ci
825da0c48c4Sopenharmony_ci      /* Fill the gap between last section and section header table if
826da0c48c4Sopenharmony_ci	 necessary.  */
827da0c48c4Sopenharmony_ci      if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
828da0c48c4Sopenharmony_ci	  && unlikely (fill (elf->fildes, last_offset,
829da0c48c4Sopenharmony_ci			     shdr_offset - last_offset,
830da0c48c4Sopenharmony_ci			     fillbuf, &filled) != 0))
831da0c48c4Sopenharmony_ci	goto fail_free;
832da0c48c4Sopenharmony_ci
833da0c48c4Sopenharmony_ci      /* Write out the section header table.  */
834da0c48c4Sopenharmony_ci      if (shdr_flags & ELF_F_DIRTY
835da0c48c4Sopenharmony_ci	  && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
836da0c48c4Sopenharmony_ci					      sizeof (ElfW2(LIBELFBITS,Shdr))
837da0c48c4Sopenharmony_ci					      * shnum, shdr_offset)
838da0c48c4Sopenharmony_ci		       != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
839da0c48c4Sopenharmony_ci	{
840da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_WRITE_ERROR);
841da0c48c4Sopenharmony_ci	  goto fail_free;
842da0c48c4Sopenharmony_ci	}
843da0c48c4Sopenharmony_ci
844da0c48c4Sopenharmony_ci      free (shdr_data_mem);
845da0c48c4Sopenharmony_ci      free (scns);
846da0c48c4Sopenharmony_ci    }
847da0c48c4Sopenharmony_ci
848da0c48c4Sopenharmony_ci  /* That was the last part.  Clear the overall flag.  */
849da0c48c4Sopenharmony_ci  elf->flags &= ~ELF_F_DIRTY;
850da0c48c4Sopenharmony_ci
851da0c48c4Sopenharmony_ci  return 0;
852da0c48c4Sopenharmony_ci}
853