1da0c48c4Sopenharmony_ci/* Update data structures for changes.
2da0c48c4Sopenharmony_ci   Copyright (C) 2000-2010, 2015, 2016 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 <libelf.h>
36da0c48c4Sopenharmony_ci#include <stdbool.h>
37da0c48c4Sopenharmony_ci#include <string.h>
38da0c48c4Sopenharmony_ci
39da0c48c4Sopenharmony_ci#include "libelfP.h"
40da0c48c4Sopenharmony_ci#include "elf-knowledge.h"
41da0c48c4Sopenharmony_ci
42da0c48c4Sopenharmony_ci#ifndef LIBELFBITS
43da0c48c4Sopenharmony_ci# define LIBELFBITS 32
44da0c48c4Sopenharmony_ci#endif
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_ci/* Some fields contain 32/64 sizes.  We cannot use Elf32/64_Word for those,
47da0c48c4Sopenharmony_ci   since those are both 32bits.  Elf32/64_Xword is always 64bits.  */
48da0c48c4Sopenharmony_ci#define Elf32_SizeWord Elf32_Word
49da0c48c4Sopenharmony_ci#define Elf64_SizeWord Elf64_Xword
50da0c48c4Sopenharmony_ci
51da0c48c4Sopenharmony_ci
52da0c48c4Sopenharmony_cistatic int
53da0c48c4Sopenharmony_ciELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
54da0c48c4Sopenharmony_ci			       size_t shnum, int *change_bop)
55da0c48c4Sopenharmony_ci{
56da0c48c4Sopenharmony_ci  /* Always write the magic bytes.  */
57da0c48c4Sopenharmony_ci  if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
58da0c48c4Sopenharmony_ci    {
59da0c48c4Sopenharmony_ci      memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
60da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
61da0c48c4Sopenharmony_ci    }
62da0c48c4Sopenharmony_ci
63da0c48c4Sopenharmony_ci  /* Always set the file class.  */
64da0c48c4Sopenharmony_ci  update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
65da0c48c4Sopenharmony_ci		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
66da0c48c4Sopenharmony_ci
67da0c48c4Sopenharmony_ci  /* Set the data encoding if necessary.  */
68da0c48c4Sopenharmony_ci  if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
69da0c48c4Sopenharmony_ci    {
70da0c48c4Sopenharmony_ci      ehdr->e_ident[EI_DATA] =
71da0c48c4Sopenharmony_ci	BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
72da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
73da0c48c4Sopenharmony_ci    }
74da0c48c4Sopenharmony_ci  else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
75da0c48c4Sopenharmony_ci    {
76da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_DATA_ENCODING);
77da0c48c4Sopenharmony_ci      return 1;
78da0c48c4Sopenharmony_ci    }
79da0c48c4Sopenharmony_ci  else
80da0c48c4Sopenharmony_ci    *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
81da0c48c4Sopenharmony_ci		    && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
82da0c48c4Sopenharmony_ci		   || (BYTE_ORDER == BIG_ENDIAN
83da0c48c4Sopenharmony_ci		       && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
84da0c48c4Sopenharmony_ci
85da0c48c4Sopenharmony_ci  /* Unconditionally overwrite the ELF version.  */
86da0c48c4Sopenharmony_ci  update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
87da0c48c4Sopenharmony_ci		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
88da0c48c4Sopenharmony_ci
89da0c48c4Sopenharmony_ci  if (unlikely (ehdr->e_version == EV_NONE))
90da0c48c4Sopenharmony_ci    {
91da0c48c4Sopenharmony_ci      ehdr->e_version = EV_CURRENT;
92da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
93da0c48c4Sopenharmony_ci    }
94da0c48c4Sopenharmony_ci  else if (unlikely (ehdr->e_version != EV_CURRENT))
95da0c48c4Sopenharmony_ci    {
96da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
97da0c48c4Sopenharmony_ci      return 1;
98da0c48c4Sopenharmony_ci    }
99da0c48c4Sopenharmony_ci
100da0c48c4Sopenharmony_ci  if (unlikely (shnum >= SHN_LORESERVE))
101da0c48c4Sopenharmony_ci    {
102da0c48c4Sopenharmony_ci      update_if_changed (ehdr->e_shnum, 0,
103da0c48c4Sopenharmony_ci			 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
104da0c48c4Sopenharmony_ci    }
105da0c48c4Sopenharmony_ci  else
106da0c48c4Sopenharmony_ci    update_if_changed (ehdr->e_shnum, shnum,
107da0c48c4Sopenharmony_ci		       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
108da0c48c4Sopenharmony_ci
109da0c48c4Sopenharmony_ci  if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
110da0c48c4Sopenharmony_ci    {
111da0c48c4Sopenharmony_ci      ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
112da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
113da0c48c4Sopenharmony_ci    }
114da0c48c4Sopenharmony_ci
115da0c48c4Sopenharmony_ci  /* If phnum is zero make sure e_phoff is also zero and not some random
116da0c48c4Sopenharmony_ci     value.  That would cause trouble in update_file.  */
117da0c48c4Sopenharmony_ci  if (ehdr->e_phnum == 0 && ehdr->e_phoff != 0)
118da0c48c4Sopenharmony_ci    {
119da0c48c4Sopenharmony_ci      ehdr->e_phoff = 0;
120da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
121da0c48c4Sopenharmony_ci    }
122da0c48c4Sopenharmony_ci
123da0c48c4Sopenharmony_ci  return 0;
124da0c48c4Sopenharmony_ci}
125da0c48c4Sopenharmony_ci
126da0c48c4Sopenharmony_ci
127da0c48c4Sopenharmony_ciint64_t
128da0c48c4Sopenharmony_ciinternal_function
129da0c48c4Sopenharmony_ci__elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
130da0c48c4Sopenharmony_ci{
131da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Ehdr) *ehdr;
132da0c48c4Sopenharmony_ci  int changed = 0;
133da0c48c4Sopenharmony_ci  int ehdr_flags = 0;
134da0c48c4Sopenharmony_ci
135da0c48c4Sopenharmony_ci  ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
136da0c48c4Sopenharmony_ci
137da0c48c4Sopenharmony_ci  /* Set the default values.  */
138da0c48c4Sopenharmony_ci  if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
139da0c48c4Sopenharmony_ci    return -1;
140da0c48c4Sopenharmony_ci
141da0c48c4Sopenharmony_ci  /* At least the ELF header is there.  */
142da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,SizeWord) size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
143da0c48c4Sopenharmony_ci
144da0c48c4Sopenharmony_ci  /* Set the program header position.  */
145da0c48c4Sopenharmony_ci  if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
146da0c48c4Sopenharmony_ci    (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
147da0c48c4Sopenharmony_ci  if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
148da0c48c4Sopenharmony_ci    {
149da0c48c4Sopenharmony_ci      size_t phnum;
150da0c48c4Sopenharmony_ci      if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
151da0c48c4Sopenharmony_ci	return -1;
152da0c48c4Sopenharmony_ci
153da0c48c4Sopenharmony_ci      if (elf->flags & ELF_F_LAYOUT)
154da0c48c4Sopenharmony_ci	{
155da0c48c4Sopenharmony_ci	  /* The user is supposed to fill out e_phoff.  Use it and
156da0c48c4Sopenharmony_ci	     e_phnum to determine the maximum extend.  */
157da0c48c4Sopenharmony_ci	  size = MAX (size,
158da0c48c4Sopenharmony_ci		      ehdr->e_phoff
159da0c48c4Sopenharmony_ci		      + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
160da0c48c4Sopenharmony_ci	}
161da0c48c4Sopenharmony_ci      else
162da0c48c4Sopenharmony_ci	{
163da0c48c4Sopenharmony_ci	  update_if_changed (ehdr->e_phoff,
164da0c48c4Sopenharmony_ci			     elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
165da0c48c4Sopenharmony_ci			     ehdr_flags);
166da0c48c4Sopenharmony_ci
167da0c48c4Sopenharmony_ci	  /* We need no alignment here.  */
168da0c48c4Sopenharmony_ci	  size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum);
169da0c48c4Sopenharmony_ci	}
170da0c48c4Sopenharmony_ci    }
171da0c48c4Sopenharmony_ci
172da0c48c4Sopenharmony_ci  if (shnum > 0)
173da0c48c4Sopenharmony_ci    {
174da0c48c4Sopenharmony_ci      struct Elf_Scn *scn1 = NULL;
175da0c48c4Sopenharmony_ci      Elf_ScnList *list;
176da0c48c4Sopenharmony_ci      bool first = true;
177da0c48c4Sopenharmony_ci
178da0c48c4Sopenharmony_ci      assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
179da0c48c4Sopenharmony_ci
180da0c48c4Sopenharmony_ci      if (shnum >= SHN_LORESERVE)
181da0c48c4Sopenharmony_ci	{
182da0c48c4Sopenharmony_ci	  /* We have to  fill in the number of sections in the header
183da0c48c4Sopenharmony_ci	     of the zeroth section.  */
184da0c48c4Sopenharmony_ci	  Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
185da0c48c4Sopenharmony_ci
186da0c48c4Sopenharmony_ci	  update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size,
187da0c48c4Sopenharmony_ci			     shnum, scn0->shdr_flags);
188da0c48c4Sopenharmony_ci	}
189da0c48c4Sopenharmony_ci
190da0c48c4Sopenharmony_ci      /* Go over all sections and find out how large they are.  */
191da0c48c4Sopenharmony_ci      list = &elf->state.ELFW(elf,LIBELFBITS).scns;
192da0c48c4Sopenharmony_ci
193da0c48c4Sopenharmony_ci      /* Find the first section. */
194da0c48c4Sopenharmony_ci      if (list->cnt > 1)
195da0c48c4Sopenharmony_ci	scn1 = &list->data[1];
196da0c48c4Sopenharmony_ci      else if (list->next != NULL)
197da0c48c4Sopenharmony_ci	scn1 = &list->next->data[0];
198da0c48c4Sopenharmony_ci
199da0c48c4Sopenharmony_ci      /* Load the section headers if necessary.  This loads the
200da0c48c4Sopenharmony_ci	 headers for all sections.  */
201da0c48c4Sopenharmony_ci      if (scn1 != NULL && scn1->shdr.ELFW(e,LIBELFBITS) == NULL)
202da0c48c4Sopenharmony_ci	(void) __elfw2(LIBELFBITS,getshdr_wrlock) (scn1);
203da0c48c4Sopenharmony_ci
204da0c48c4Sopenharmony_ci      do
205da0c48c4Sopenharmony_ci	{
206da0c48c4Sopenharmony_ci	  for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
207da0c48c4Sopenharmony_ci	    {
208da0c48c4Sopenharmony_ci	      Elf_Scn *scn = &list->data[cnt];
209da0c48c4Sopenharmony_ci	      ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
210da0c48c4Sopenharmony_ci	      int64_t offset = 0;
211da0c48c4Sopenharmony_ci
212da0c48c4Sopenharmony_ci	      assert (shdr != NULL);
213da0c48c4Sopenharmony_ci	      ElfW2(LIBELFBITS,SizeWord) sh_entsize = shdr->sh_entsize;
214da0c48c4Sopenharmony_ci	      ElfW2(LIBELFBITS,SizeWord) sh_align = shdr->sh_addralign ?: 1;
215da0c48c4Sopenharmony_ci	      if (unlikely (! powerof2 (sh_align)))
216da0c48c4Sopenharmony_ci		{
217da0c48c4Sopenharmony_ci		  __libelf_seterrno (ELF_E_INVALID_ALIGN);
218da0c48c4Sopenharmony_ci		  return -1;
219da0c48c4Sopenharmony_ci		}
220da0c48c4Sopenharmony_ci
221da0c48c4Sopenharmony_ci	      /* Set the sh_entsize value if we can reliably detect it.  */
222da0c48c4Sopenharmony_ci	      switch (shdr->sh_type)
223da0c48c4Sopenharmony_ci		{
224da0c48c4Sopenharmony_ci		case SHT_SYMTAB:
225da0c48c4Sopenharmony_ci		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
226da0c48c4Sopenharmony_ci		  break;
227da0c48c4Sopenharmony_ci		case SHT_RELA:
228da0c48c4Sopenharmony_ci		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
229da0c48c4Sopenharmony_ci		  break;
230da0c48c4Sopenharmony_ci		case SHT_GROUP:
231da0c48c4Sopenharmony_ci		  /* Only relocatable files can contain section groups.  */
232da0c48c4Sopenharmony_ci		  if (ehdr->e_type != ET_REL)
233da0c48c4Sopenharmony_ci		    {
234da0c48c4Sopenharmony_ci		      __libelf_seterrno (ELF_E_GROUP_NOT_REL);
235da0c48c4Sopenharmony_ci		      return -1;
236da0c48c4Sopenharmony_ci		    }
237da0c48c4Sopenharmony_ci		  FALLTHROUGH;
238da0c48c4Sopenharmony_ci		case SHT_SYMTAB_SHNDX:
239da0c48c4Sopenharmony_ci		  sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
240da0c48c4Sopenharmony_ci		  break;
241da0c48c4Sopenharmony_ci		case SHT_HASH:
242da0c48c4Sopenharmony_ci		  sh_entsize = SH_ENTSIZE_HASH (ehdr);
243da0c48c4Sopenharmony_ci		  break;
244da0c48c4Sopenharmony_ci		case SHT_DYNAMIC:
245da0c48c4Sopenharmony_ci		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
246da0c48c4Sopenharmony_ci		  break;
247da0c48c4Sopenharmony_ci		case SHT_REL:
248da0c48c4Sopenharmony_ci		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
249da0c48c4Sopenharmony_ci		  break;
250da0c48c4Sopenharmony_ci		case SHT_DYNSYM:
251da0c48c4Sopenharmony_ci		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
252da0c48c4Sopenharmony_ci		  break;
253da0c48c4Sopenharmony_ci		case SHT_SUNW_move:
254da0c48c4Sopenharmony_ci		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
255da0c48c4Sopenharmony_ci		  break;
256da0c48c4Sopenharmony_ci		case SHT_SUNW_syminfo:
257da0c48c4Sopenharmony_ci		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
258da0c48c4Sopenharmony_ci		  break;
259da0c48c4Sopenharmony_ci		default:
260da0c48c4Sopenharmony_ci		  break;
261da0c48c4Sopenharmony_ci		}
262da0c48c4Sopenharmony_ci
263da0c48c4Sopenharmony_ci	      /* If the section header contained the wrong entry size
264da0c48c4Sopenharmony_ci		 correct it and mark the header as modified.  */
265da0c48c4Sopenharmony_ci	      update_if_changed (shdr->sh_entsize, sh_entsize,
266da0c48c4Sopenharmony_ci				 scn->shdr_flags);
267da0c48c4Sopenharmony_ci
268da0c48c4Sopenharmony_ci	      /* Likewise for the alignment of a compressed section.
269da0c48c4Sopenharmony_ci	         For a SHF_COMPRESSED section set the correct
270da0c48c4Sopenharmony_ci	         sh_addralign value, which must match the d_align of
271da0c48c4Sopenharmony_ci	         the data (see __libelf_set_rawdata in elf_getdata.c).  */
272da0c48c4Sopenharmony_ci	      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
273da0c48c4Sopenharmony_ci		{
274da0c48c4Sopenharmony_ci		  sh_align = __libelf_type_align (ELFW(ELFCLASS,LIBELFBITS),
275da0c48c4Sopenharmony_ci						  ELF_T_CHDR);
276da0c48c4Sopenharmony_ci		  update_if_changed (shdr->sh_addralign, sh_align,
277da0c48c4Sopenharmony_ci				     scn->shdr_flags);
278da0c48c4Sopenharmony_ci		}
279da0c48c4Sopenharmony_ci
280da0c48c4Sopenharmony_ci	      if (scn->data_read == 0
281da0c48c4Sopenharmony_ci		  && __libelf_set_rawdata_wrlock (scn) != 0)
282da0c48c4Sopenharmony_ci		/* Something went wrong.  The error value is already set.  */
283da0c48c4Sopenharmony_ci		return -1;
284da0c48c4Sopenharmony_ci
285da0c48c4Sopenharmony_ci	      /* Iterate over all data blocks.  */
286da0c48c4Sopenharmony_ci	      if (list->data[cnt].data_list_rear != NULL)
287da0c48c4Sopenharmony_ci		{
288da0c48c4Sopenharmony_ci		  Elf_Data_List *dl = &scn->data_list;
289da0c48c4Sopenharmony_ci
290da0c48c4Sopenharmony_ci		  while (dl != NULL)
291da0c48c4Sopenharmony_ci		    {
292da0c48c4Sopenharmony_ci		      Elf_Data *data = &dl->data.d;
293da0c48c4Sopenharmony_ci		      if (dl == &scn->data_list && data->d_buf == NULL
294da0c48c4Sopenharmony_ci			  && scn->rawdata.d.d_buf != NULL)
295da0c48c4Sopenharmony_ci			data = &scn->rawdata.d;
296da0c48c4Sopenharmony_ci
297da0c48c4Sopenharmony_ci		      if (unlikely (data->d_version != EV_CURRENT))
298da0c48c4Sopenharmony_ci			{
299da0c48c4Sopenharmony_ci			  __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
300da0c48c4Sopenharmony_ci			  return -1;
301da0c48c4Sopenharmony_ci			}
302da0c48c4Sopenharmony_ci
303da0c48c4Sopenharmony_ci		      if (unlikely (! powerof2 (data->d_align)))
304da0c48c4Sopenharmony_ci			{
305da0c48c4Sopenharmony_ci			  __libelf_seterrno (ELF_E_INVALID_ALIGN);
306da0c48c4Sopenharmony_ci			  return -1;
307da0c48c4Sopenharmony_ci			}
308da0c48c4Sopenharmony_ci
309da0c48c4Sopenharmony_ci		      sh_align = MAX (sh_align, data->d_align);
310da0c48c4Sopenharmony_ci
311da0c48c4Sopenharmony_ci		      if (elf->flags & ELF_F_LAYOUT)
312da0c48c4Sopenharmony_ci			{
313da0c48c4Sopenharmony_ci			  /* The user specified the offset and the size.
314da0c48c4Sopenharmony_ci			     All we have to do is check whether this block
315da0c48c4Sopenharmony_ci			     fits in the size specified for the section.  */
316da0c48c4Sopenharmony_ci			  if (unlikely ((ElfW2(LIBELFBITS,SizeWord))
317da0c48c4Sopenharmony_ci					(data->d_off + data->d_size)
318da0c48c4Sopenharmony_ci					> shdr->sh_size))
319da0c48c4Sopenharmony_ci			    {
320da0c48c4Sopenharmony_ci			      __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
321da0c48c4Sopenharmony_ci			      return -1;
322da0c48c4Sopenharmony_ci			    }
323da0c48c4Sopenharmony_ci			}
324da0c48c4Sopenharmony_ci		      else
325da0c48c4Sopenharmony_ci			{
326da0c48c4Sopenharmony_ci			  /* Determine the padding.  */
327da0c48c4Sopenharmony_ci			  offset = ((offset + data->d_align - 1)
328da0c48c4Sopenharmony_ci				    & ~(data->d_align - 1));
329da0c48c4Sopenharmony_ci
330da0c48c4Sopenharmony_ci			  update_if_changed (data->d_off, offset, changed);
331da0c48c4Sopenharmony_ci
332da0c48c4Sopenharmony_ci			  offset += data->d_size;
333da0c48c4Sopenharmony_ci			}
334da0c48c4Sopenharmony_ci
335da0c48c4Sopenharmony_ci		      /* Next data block.  */
336da0c48c4Sopenharmony_ci		      dl = dl->next;
337da0c48c4Sopenharmony_ci		    }
338da0c48c4Sopenharmony_ci		}
339da0c48c4Sopenharmony_ci	      else
340da0c48c4Sopenharmony_ci		/* Get the size of the section from the raw data.  If
341da0c48c4Sopenharmony_ci		   none is available the value is zero.  */
342da0c48c4Sopenharmony_ci		offset += scn->rawdata.d.d_size;
343da0c48c4Sopenharmony_ci
344da0c48c4Sopenharmony_ci	      if (elf->flags & ELF_F_LAYOUT)
345da0c48c4Sopenharmony_ci		{
346da0c48c4Sopenharmony_ci		  size = MAX (size,
347da0c48c4Sopenharmony_ci			      (shdr->sh_type != SHT_NOBITS
348da0c48c4Sopenharmony_ci			       ? shdr->sh_offset + shdr->sh_size : 0));
349da0c48c4Sopenharmony_ci
350da0c48c4Sopenharmony_ci		  /* The alignment must be a power of two.  This is a
351da0c48c4Sopenharmony_ci		     requirement from the ELF specification.  Additionally
352da0c48c4Sopenharmony_ci		     we test for the alignment of the section being large
353da0c48c4Sopenharmony_ci		     enough for the largest alignment required by a data
354da0c48c4Sopenharmony_ci		     block.  */
355da0c48c4Sopenharmony_ci		  if (unlikely (! powerof2 (shdr->sh_addralign))
356da0c48c4Sopenharmony_ci		      || unlikely ((shdr->sh_addralign ?: 1) < sh_align))
357da0c48c4Sopenharmony_ci		    {
358da0c48c4Sopenharmony_ci		      __libelf_seterrno (ELF_E_INVALID_ALIGN);
359da0c48c4Sopenharmony_ci		      return -1;
360da0c48c4Sopenharmony_ci		    }
361da0c48c4Sopenharmony_ci		}
362da0c48c4Sopenharmony_ci	      else
363da0c48c4Sopenharmony_ci		{
364da0c48c4Sopenharmony_ci		  /* How much alignment do we need for this section.  */
365da0c48c4Sopenharmony_ci		  update_if_changed (shdr->sh_addralign, sh_align,
366da0c48c4Sopenharmony_ci				     scn->shdr_flags);
367da0c48c4Sopenharmony_ci
368da0c48c4Sopenharmony_ci		  size = (size + sh_align - 1) & ~(sh_align - 1);
369da0c48c4Sopenharmony_ci		  int offset_changed = 0;
370da0c48c4Sopenharmony_ci		  update_if_changed (shdr->sh_offset, size, offset_changed);
371da0c48c4Sopenharmony_ci		  changed |= offset_changed;
372da0c48c4Sopenharmony_ci
373da0c48c4Sopenharmony_ci		  if (offset_changed && scn->data_list_rear == NULL)
374da0c48c4Sopenharmony_ci		    {
375da0c48c4Sopenharmony_ci		      /* The position of the section in the file
376da0c48c4Sopenharmony_ci			 changed.  Create the section data list.  */
377da0c48c4Sopenharmony_ci		      if (__elf_getdata_rdlock (scn, NULL) == NULL)
378da0c48c4Sopenharmony_ci			return -1;
379da0c48c4Sopenharmony_ci		    }
380da0c48c4Sopenharmony_ci
381da0c48c4Sopenharmony_ci		  /* See whether the section size is correct.  */
382da0c48c4Sopenharmony_ci		  int size_changed = 0;
383da0c48c4Sopenharmony_ci		  update_if_changed (shdr->sh_size,
384da0c48c4Sopenharmony_ci				     (ElfW2(LIBELFBITS,SizeWord)) offset,
385da0c48c4Sopenharmony_ci				     size_changed);
386da0c48c4Sopenharmony_ci		  changed |= size_changed;
387da0c48c4Sopenharmony_ci
388da0c48c4Sopenharmony_ci		  if (shdr->sh_type != SHT_NOBITS)
389da0c48c4Sopenharmony_ci		    size += offset;
390da0c48c4Sopenharmony_ci
391da0c48c4Sopenharmony_ci		  scn->shdr_flags |= (offset_changed | size_changed);
392da0c48c4Sopenharmony_ci		  scn->flags |= changed;
393da0c48c4Sopenharmony_ci		}
394da0c48c4Sopenharmony_ci
395da0c48c4Sopenharmony_ci	      /* Check that the section size is actually a multiple of
396da0c48c4Sopenharmony_ci		 the entry size.  */
397da0c48c4Sopenharmony_ci	      if (shdr->sh_entsize != 0 && shdr->sh_entsize != 1
398da0c48c4Sopenharmony_ci		  && (elf->flags & ELF_F_PERMISSIVE) == 0)
399da0c48c4Sopenharmony_ci		{
400da0c48c4Sopenharmony_ci		  /* For compressed sections check the uncompressed size.  */
401da0c48c4Sopenharmony_ci		  ElfW2(LIBELFBITS,SizeWord) sh_size;
402da0c48c4Sopenharmony_ci		  if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
403da0c48c4Sopenharmony_ci		    sh_size = shdr->sh_size;
404da0c48c4Sopenharmony_ci		  else
405da0c48c4Sopenharmony_ci		    {
406da0c48c4Sopenharmony_ci		      ElfW2(LIBELFBITS,Chdr) *chdr;
407da0c48c4Sopenharmony_ci		      chdr = elfw2(LIBELFBITS,getchdr) (scn);
408da0c48c4Sopenharmony_ci		      if (unlikely (chdr == NULL))
409da0c48c4Sopenharmony_ci			return -1;
410da0c48c4Sopenharmony_ci		      sh_size = chdr->ch_size;
411da0c48c4Sopenharmony_ci		    }
412da0c48c4Sopenharmony_ci
413da0c48c4Sopenharmony_ci		  if (unlikely (sh_size % shdr->sh_entsize != 0))
414da0c48c4Sopenharmony_ci		    {
415da0c48c4Sopenharmony_ci		      __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
416da0c48c4Sopenharmony_ci		      return -1;
417da0c48c4Sopenharmony_ci		    }
418da0c48c4Sopenharmony_ci		}
419da0c48c4Sopenharmony_ci	    }
420da0c48c4Sopenharmony_ci
421da0c48c4Sopenharmony_ci	  assert (list->next == NULL || list->cnt == list->max);
422da0c48c4Sopenharmony_ci
423da0c48c4Sopenharmony_ci	  first = false;
424da0c48c4Sopenharmony_ci	}
425da0c48c4Sopenharmony_ci      while ((list = list->next) != NULL);
426da0c48c4Sopenharmony_ci
427da0c48c4Sopenharmony_ci      /* Store section information.  */
428da0c48c4Sopenharmony_ci      update_if_changed (ehdr->e_shentsize,
429da0c48c4Sopenharmony_ci			 elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), ehdr_flags);
430da0c48c4Sopenharmony_ci      if (elf->flags & ELF_F_LAYOUT)
431da0c48c4Sopenharmony_ci	{
432da0c48c4Sopenharmony_ci	  /* The user is supposed to fill out e_shoff.  Use it and
433da0c48c4Sopenharmony_ci	     e_shnum (or sh_size of the dummy, first section header)
434da0c48c4Sopenharmony_ci	     to determine the maximum extend.  */
435da0c48c4Sopenharmony_ci	  size = MAX (size,
436da0c48c4Sopenharmony_ci		      (ehdr->e_shoff
437da0c48c4Sopenharmony_ci		       + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
438da0c48c4Sopenharmony_ci	}
439da0c48c4Sopenharmony_ci      else
440da0c48c4Sopenharmony_ci	{
441da0c48c4Sopenharmony_ci	  /* Align for section header table.
442da0c48c4Sopenharmony_ci
443da0c48c4Sopenharmony_ci	     Yes, we use `sizeof' and not `__alignof__' since we do not
444da0c48c4Sopenharmony_ci	     want to be surprised by architectures with less strict
445da0c48c4Sopenharmony_ci	     alignment rules.  */
446da0c48c4Sopenharmony_ci#define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
447da0c48c4Sopenharmony_ci	  size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
448da0c48c4Sopenharmony_ci
449da0c48c4Sopenharmony_ci	  update_if_changed (ehdr->e_shoff, size, elf->flags);
450da0c48c4Sopenharmony_ci
451da0c48c4Sopenharmony_ci	  /* Account for the section header size.  */
452da0c48c4Sopenharmony_ci	  size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
453da0c48c4Sopenharmony_ci	}
454da0c48c4Sopenharmony_ci    }
455da0c48c4Sopenharmony_ci
456da0c48c4Sopenharmony_ci  elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
457da0c48c4Sopenharmony_ci
458da0c48c4Sopenharmony_ci  return size;
459da0c48c4Sopenharmony_ci}
460