1da0c48c4Sopenharmony_ci/* Merge string sections.
2da0c48c4Sopenharmony_ci   Copyright (C) 2015, 2016 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of the GNU General Public License as published by
7da0c48c4Sopenharmony_ci   the Free Software Foundation; either version 3 of the License, or
8da0c48c4Sopenharmony_ci   (at your option) any later version.
9da0c48c4Sopenharmony_ci
10da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
11da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13da0c48c4Sopenharmony_ci   GNU General Public License for more details.
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci   You should have received a copy of the GNU General Public License
16da0c48c4Sopenharmony_ci   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci#include <config.h>
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci#include <assert.h>
21da0c48c4Sopenharmony_ci#include <errno.h>
22da0c48c4Sopenharmony_ci#include <stdlib.h>
23da0c48c4Sopenharmony_ci#include <string.h>
24da0c48c4Sopenharmony_ci#include <sys/types.h>
25da0c48c4Sopenharmony_ci#include <sys/stat.h>
26da0c48c4Sopenharmony_ci#include <fcntl.h>
27da0c48c4Sopenharmony_ci#include <stdio.h>
28da0c48c4Sopenharmony_ci#include <inttypes.h>
29da0c48c4Sopenharmony_ci#include <unistd.h>
30da0c48c4Sopenharmony_ci
31da0c48c4Sopenharmony_ci#include <system.h>
32da0c48c4Sopenharmony_ci#include <gelf.h>
33da0c48c4Sopenharmony_ci#include ELFUTILS_HEADER(dwelf)
34da0c48c4Sopenharmony_ci#include "elf-knowledge.h"
35da0c48c4Sopenharmony_ci
36da0c48c4Sopenharmony_ci/* The original ELF file.  */
37da0c48c4Sopenharmony_cistatic int fd = -1;
38da0c48c4Sopenharmony_cistatic Elf *elf = NULL;
39da0c48c4Sopenharmony_cistatic bool replace;
40da0c48c4Sopenharmony_ci
41da0c48c4Sopenharmony_ci/* The new ELF file.  */
42da0c48c4Sopenharmony_cistatic char *fnew = NULL;
43da0c48c4Sopenharmony_cistatic int fdnew = -1;
44da0c48c4Sopenharmony_cistatic Elf *elfnew = NULL;
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_ci/* The merged string table.  */
47da0c48c4Sopenharmony_cistatic Dwelf_Strtab *strings = NULL;
48da0c48c4Sopenharmony_ci
49da0c48c4Sopenharmony_ci/* Section name strents.  */
50da0c48c4Sopenharmony_cistatic Dwelf_Strent **scnstrents = NULL;
51da0c48c4Sopenharmony_ci
52da0c48c4Sopenharmony_ci/* Symbol name strends.  */
53da0c48c4Sopenharmony_cistatic Dwelf_Strent **symstrents = NULL;
54da0c48c4Sopenharmony_ci
55da0c48c4Sopenharmony_ci/* New ELF file buffers.  */
56da0c48c4Sopenharmony_cistatic Elf_Data newstrtabdata = { .d_buf = NULL };
57da0c48c4Sopenharmony_cistatic size_t newshnums = 0;
58da0c48c4Sopenharmony_cistatic void **newscnbufs = NULL;
59da0c48c4Sopenharmony_ci
60da0c48c4Sopenharmony_ci/* Release all files and resources allocated.  */
61da0c48c4Sopenharmony_cistatic void
62da0c48c4Sopenharmony_cirelease (void)
63da0c48c4Sopenharmony_ci{
64da0c48c4Sopenharmony_ci  /* The new string table.  */
65da0c48c4Sopenharmony_ci  if (strings != NULL)
66da0c48c4Sopenharmony_ci    dwelf_strtab_free (strings);
67da0c48c4Sopenharmony_ci
68da0c48c4Sopenharmony_ci  free (scnstrents);
69da0c48c4Sopenharmony_ci  free (symstrents);
70da0c48c4Sopenharmony_ci  free (newstrtabdata.d_buf);
71da0c48c4Sopenharmony_ci
72da0c48c4Sopenharmony_ci  /* Any new data buffers allocated.  */
73da0c48c4Sopenharmony_ci  for (size_t i = 0; i < newshnums; i++)
74da0c48c4Sopenharmony_ci    free (newscnbufs[i]);
75da0c48c4Sopenharmony_ci  free (newscnbufs);
76da0c48c4Sopenharmony_ci
77da0c48c4Sopenharmony_ci  /* The new ELF file.  */
78da0c48c4Sopenharmony_ci  if (fdnew != -1)
79da0c48c4Sopenharmony_ci    {
80da0c48c4Sopenharmony_ci      unlink (fnew);
81da0c48c4Sopenharmony_ci      elf_end (elfnew);
82da0c48c4Sopenharmony_ci      close (fdnew);
83da0c48c4Sopenharmony_ci    }
84da0c48c4Sopenharmony_ci  // Don't release, we might need it in the error message.
85da0c48c4Sopenharmony_ci  // if (replace)
86da0c48c4Sopenharmony_ci  //   free (fnew);
87da0c48c4Sopenharmony_ci
88da0c48c4Sopenharmony_ci  /* The original ELF file.  */
89da0c48c4Sopenharmony_ci  elf_end (elf);
90da0c48c4Sopenharmony_ci  close (fd);
91da0c48c4Sopenharmony_ci}
92da0c48c4Sopenharmony_ci
93da0c48c4Sopenharmony_ci/* The various ways we can fail... Cleanup and show some message to
94da0c48c4Sopenharmony_ci   the user.  The file name may be NULL.  */
95da0c48c4Sopenharmony_cistatic void __attribute__ ((noreturn))
96da0c48c4Sopenharmony_cifail (const char *msg, const char *fname)
97da0c48c4Sopenharmony_ci{
98da0c48c4Sopenharmony_ci  release ();
99da0c48c4Sopenharmony_ci  if (fname != NULL)
100da0c48c4Sopenharmony_ci    error (1, 0, "%s: %s", fname, msg);
101da0c48c4Sopenharmony_ci  else
102da0c48c4Sopenharmony_ci    error (1, 0, "%s", msg);
103da0c48c4Sopenharmony_ci  abort();
104da0c48c4Sopenharmony_ci}
105da0c48c4Sopenharmony_ci
106da0c48c4Sopenharmony_cistatic void __attribute__ ((noreturn))
107da0c48c4Sopenharmony_cifail_errno (const char *msg, const char *fname)
108da0c48c4Sopenharmony_ci{
109da0c48c4Sopenharmony_ci  release ();
110da0c48c4Sopenharmony_ci  if (fname != NULL)
111da0c48c4Sopenharmony_ci    error (1, errno, "%s: %s", fname, msg);
112da0c48c4Sopenharmony_ci  else
113da0c48c4Sopenharmony_ci    error (1, errno, "%s", msg);
114da0c48c4Sopenharmony_ci  abort();
115da0c48c4Sopenharmony_ci}
116da0c48c4Sopenharmony_ci
117da0c48c4Sopenharmony_cistatic void __attribute__ ((noreturn))
118da0c48c4Sopenharmony_cifail_idx (const char *msg, const char *fname, size_t idx)
119da0c48c4Sopenharmony_ci{
120da0c48c4Sopenharmony_ci  release ();
121da0c48c4Sopenharmony_ci  if (fname != NULL)
122da0c48c4Sopenharmony_ci    error (1, 0, "%s: %s %zd", fname, msg, idx);
123da0c48c4Sopenharmony_ci  else
124da0c48c4Sopenharmony_ci    error (1, 0, "%s %zd", msg, idx);
125da0c48c4Sopenharmony_ci  abort();
126da0c48c4Sopenharmony_ci}
127da0c48c4Sopenharmony_ci
128da0c48c4Sopenharmony_cistatic void __attribute__ ((noreturn))
129da0c48c4Sopenharmony_cifail_elf (const char *msg, const char *fname)
130da0c48c4Sopenharmony_ci{
131da0c48c4Sopenharmony_ci  release ();
132da0c48c4Sopenharmony_ci  if (fname != NULL)
133da0c48c4Sopenharmony_ci    error (1, 0, "%s: %s: %s", fname, msg, elf_errmsg (-1));
134da0c48c4Sopenharmony_ci  else
135da0c48c4Sopenharmony_ci    error (1, 0, "%s: %s", msg, elf_errmsg (-1));
136da0c48c4Sopenharmony_ci  abort();
137da0c48c4Sopenharmony_ci}
138da0c48c4Sopenharmony_ci
139da0c48c4Sopenharmony_cistatic void __attribute__ ((noreturn))
140da0c48c4Sopenharmony_cifail_elf_idx (const char *msg, const char *fname, size_t idx)
141da0c48c4Sopenharmony_ci{
142da0c48c4Sopenharmony_ci  release ();
143da0c48c4Sopenharmony_ci  if (fname != NULL)
144da0c48c4Sopenharmony_ci    error (1, 0, "%s: %s %zd: %s", fname, msg, idx, elf_errmsg (-1));
145da0c48c4Sopenharmony_ci  else
146da0c48c4Sopenharmony_ci    error (1, 0, "%s %zd: %s", msg, idx, elf_errmsg (-1));
147da0c48c4Sopenharmony_ci  abort();
148da0c48c4Sopenharmony_ci}
149da0c48c4Sopenharmony_ci
150da0c48c4Sopenharmony_ci/* section index mapping and sanity checking.  */
151da0c48c4Sopenharmony_cistatic size_t
152da0c48c4Sopenharmony_cinewsecndx (size_t secndx, size_t shdrstrndx, size_t shdrnum,
153da0c48c4Sopenharmony_ci	   const char *fname,
154da0c48c4Sopenharmony_ci	   const char *what, size_t widx,
155da0c48c4Sopenharmony_ci	   const char *member, size_t midx)
156da0c48c4Sopenharmony_ci{
157da0c48c4Sopenharmony_ci  if (unlikely (secndx == 0 || secndx == shdrstrndx || secndx >= shdrnum))
158da0c48c4Sopenharmony_ci    {
159da0c48c4Sopenharmony_ci      /* Don't use fail... too specialized messages.  Call release
160da0c48c4Sopenharmony_ci	 outselves and then error.  Ignores midx if widx is
161da0c48c4Sopenharmony_ci	 zero.  */
162da0c48c4Sopenharmony_ci      release ();
163da0c48c4Sopenharmony_ci      if (widx == 0)
164da0c48c4Sopenharmony_ci	error (1, 0, "%s: bad section index %zd in %s for %s",
165da0c48c4Sopenharmony_ci	       fname, secndx, what, member);
166da0c48c4Sopenharmony_ci      else if (midx == 0)
167da0c48c4Sopenharmony_ci	error (1, 0, "%s: bad section index %zd in %s %zd for %s",
168da0c48c4Sopenharmony_ci	       fname, secndx, what, widx, member);
169da0c48c4Sopenharmony_ci      else
170da0c48c4Sopenharmony_ci	error (1, 0, "%s: bad section index %zd in %s %zd for %s %zd",
171da0c48c4Sopenharmony_ci	       fname, secndx, what, widx, member, midx);
172da0c48c4Sopenharmony_ci    }
173da0c48c4Sopenharmony_ci
174da0c48c4Sopenharmony_ci  return secndx < shdrstrndx ? secndx : secndx - 1;
175da0c48c4Sopenharmony_ci}
176da0c48c4Sopenharmony_ci
177da0c48c4Sopenharmony_cistatic void
178da0c48c4Sopenharmony_cinew_data_buf (Elf_Data *d, const char *fname,
179da0c48c4Sopenharmony_ci	      size_t ndx, size_t shdrstrndx, size_t shdrnum)
180da0c48c4Sopenharmony_ci{
181da0c48c4Sopenharmony_ci  size_t s = d->d_size;
182da0c48c4Sopenharmony_ci  if (s == 0)
183da0c48c4Sopenharmony_ci    fail_idx ("Expected data in section", fname, ndx);
184da0c48c4Sopenharmony_ci  void *b = malloc (d->d_size);
185da0c48c4Sopenharmony_ci  if (b == NULL)
186da0c48c4Sopenharmony_ci    fail_idx ("Couldn't allocated buffer for section", NULL, ndx);
187da0c48c4Sopenharmony_ci  newscnbufs[newsecndx (ndx, shdrstrndx, shdrnum, fname,
188da0c48c4Sopenharmony_ci			"section", ndx, "d_buf", 0)] = d->d_buf = b;
189da0c48c4Sopenharmony_ci}
190da0c48c4Sopenharmony_ci
191da0c48c4Sopenharmony_ciint
192da0c48c4Sopenharmony_cimain (int argc, char **argv)
193da0c48c4Sopenharmony_ci{
194da0c48c4Sopenharmony_ci  elf_version (EV_CURRENT);
195da0c48c4Sopenharmony_ci
196da0c48c4Sopenharmony_ci  /* Basic command line handling.  Need to replace the input file?  */
197da0c48c4Sopenharmony_ci  if ((argc != 2 && argc != 4)
198da0c48c4Sopenharmony_ci      || (argc == 4 && strcmp (argv[1], "-o") != 0))
199da0c48c4Sopenharmony_ci    fail ("Usage argument: [-o <outputfile>] <inputfile>", NULL);
200da0c48c4Sopenharmony_ci  replace = argc == 2;
201da0c48c4Sopenharmony_ci
202da0c48c4Sopenharmony_ci  /* Get the ELF file.  */
203da0c48c4Sopenharmony_ci  const char *fname;
204da0c48c4Sopenharmony_ci  if (replace)
205da0c48c4Sopenharmony_ci    fname = argv[1];
206da0c48c4Sopenharmony_ci  else
207da0c48c4Sopenharmony_ci    fname = argv[3];
208da0c48c4Sopenharmony_ci  fd = open (fname, O_RDONLY);
209da0c48c4Sopenharmony_ci  if (fd < 0)
210da0c48c4Sopenharmony_ci    fail_errno ("couldn't open", fname);
211da0c48c4Sopenharmony_ci
212da0c48c4Sopenharmony_ci  elf = elf_begin (fd, ELF_C_READ, NULL);
213da0c48c4Sopenharmony_ci  if (elf == NULL)
214da0c48c4Sopenharmony_ci    fail_elf ("couldn't open ELF file for reading", fname);
215da0c48c4Sopenharmony_ci
216da0c48c4Sopenharmony_ci  GElf_Ehdr ehdr;
217da0c48c4Sopenharmony_ci  if (gelf_getehdr (elf, &ehdr) == NULL)
218da0c48c4Sopenharmony_ci    fail_elf ("Couldn't get ehdr", fname);
219da0c48c4Sopenharmony_ci
220da0c48c4Sopenharmony_ci  /* Get the section header string table.  */
221da0c48c4Sopenharmony_ci  size_t shdrstrndx;
222da0c48c4Sopenharmony_ci  if (elf_getshdrstrndx (elf, &shdrstrndx) != 0)
223da0c48c4Sopenharmony_ci    fail_elf ("couldn't get section header string table index", fname);
224da0c48c4Sopenharmony_ci
225da0c48c4Sopenharmony_ci  Elf_Scn *shdrstrscn = elf_getscn (elf, shdrstrndx);
226da0c48c4Sopenharmony_ci  GElf_Shdr shdrstrshdr_mem;
227da0c48c4Sopenharmony_ci  GElf_Shdr *shdrstrshdr = gelf_getshdr (shdrstrscn, &shdrstrshdr_mem);
228da0c48c4Sopenharmony_ci  if (shdrstrshdr == NULL)
229da0c48c4Sopenharmony_ci    fail_elf ("couldn't get section header string table section", fname);
230da0c48c4Sopenharmony_ci
231da0c48c4Sopenharmony_ci  if ((shdrstrshdr->sh_flags & SHF_ALLOC) != 0)
232da0c48c4Sopenharmony_ci    fail ("section header string table is an allocated section", fname);
233da0c48c4Sopenharmony_ci
234da0c48c4Sopenharmony_ci  /* Get the symtab section.  */
235da0c48c4Sopenharmony_ci  size_t symtabndx = 0;
236da0c48c4Sopenharmony_ci  Elf_Scn *symtabscn = NULL;
237da0c48c4Sopenharmony_ci  GElf_Shdr symtabshdr_mem;
238da0c48c4Sopenharmony_ci  GElf_Shdr *symtabshdr = NULL;
239da0c48c4Sopenharmony_ci  while ((symtabscn = elf_nextscn (elf, symtabscn)) != NULL)
240da0c48c4Sopenharmony_ci    {
241da0c48c4Sopenharmony_ci      symtabshdr = gelf_getshdr (symtabscn, &symtabshdr_mem);
242da0c48c4Sopenharmony_ci      if (symtabshdr == NULL)
243da0c48c4Sopenharmony_ci	fail_elf ("couldn't get shdr", fname);
244da0c48c4Sopenharmony_ci
245da0c48c4Sopenharmony_ci      if (symtabshdr->sh_type == SHT_SYMTAB)
246da0c48c4Sopenharmony_ci	{
247da0c48c4Sopenharmony_ci	  /* Just pick the first, we don't expect more than one. */
248da0c48c4Sopenharmony_ci	  symtabndx = elf_ndxscn (symtabscn);
249da0c48c4Sopenharmony_ci	  break;
250da0c48c4Sopenharmony_ci	}
251da0c48c4Sopenharmony_ci    }
252da0c48c4Sopenharmony_ci
253da0c48c4Sopenharmony_ci  if (symtabshdr == NULL)
254da0c48c4Sopenharmony_ci    fail ("No symtab found", fname);
255da0c48c4Sopenharmony_ci
256da0c48c4Sopenharmony_ci  if ((symtabshdr->sh_flags & SHF_ALLOC) != 0)
257da0c48c4Sopenharmony_ci    fail ("symtab is an allocated section", fname);
258da0c48c4Sopenharmony_ci
259da0c48c4Sopenharmony_ci  /* Get the strtab of the symtab.  */
260da0c48c4Sopenharmony_ci  size_t strtabndx = symtabshdr->sh_link;
261da0c48c4Sopenharmony_ci  Elf_Scn *strtabscn = elf_getscn (elf, strtabndx);
262da0c48c4Sopenharmony_ci  GElf_Shdr strtabshdr_mem;
263da0c48c4Sopenharmony_ci  GElf_Shdr *strtabshdr = gelf_getshdr (strtabscn, &strtabshdr_mem);
264da0c48c4Sopenharmony_ci  if (strtabshdr == NULL)
265da0c48c4Sopenharmony_ci    fail_elf ("Couldn't get strtab section", fname);
266da0c48c4Sopenharmony_ci
267da0c48c4Sopenharmony_ci  if (shdrstrndx == strtabndx)
268da0c48c4Sopenharmony_ci    {
269da0c48c4Sopenharmony_ci      error (0, 0, "%s: Nothing to do, shstrtab == strtab", fname);
270da0c48c4Sopenharmony_ci      release ();
271da0c48c4Sopenharmony_ci      return 0;
272da0c48c4Sopenharmony_ci    }
273da0c48c4Sopenharmony_ci
274da0c48c4Sopenharmony_ci  if ((strtabshdr->sh_flags & SHF_ALLOC) != 0)
275da0c48c4Sopenharmony_ci    fail ("strtab is an allocated section", fname);
276da0c48c4Sopenharmony_ci
277da0c48c4Sopenharmony_ci  size_t phnum;
278da0c48c4Sopenharmony_ci  if (elf_getphdrnum (elf, &phnum) != 0)
279da0c48c4Sopenharmony_ci    fail_elf ("Couldn't get number of phdrs", fname);
280da0c48c4Sopenharmony_ci
281da0c48c4Sopenharmony_ci  /* If there are phdrs we want to maintain the layout of the
282da0c48c4Sopenharmony_ci     allocated sections in the file.  */
283da0c48c4Sopenharmony_ci  bool layout = phnum != 0;
284da0c48c4Sopenharmony_ci
285da0c48c4Sopenharmony_ci  /* Create a new merged strings table that starts with the empty string.  */
286da0c48c4Sopenharmony_ci  strings = dwelf_strtab_init (true);
287da0c48c4Sopenharmony_ci  if (strings == NULL)
288da0c48c4Sopenharmony_ci    fail ("No memory to create merged string table", NULL);
289da0c48c4Sopenharmony_ci
290da0c48c4Sopenharmony_ci  /* Add the strings from all the sections.  */
291da0c48c4Sopenharmony_ci  size_t shdrnum;
292da0c48c4Sopenharmony_ci  if (elf_getshdrnum (elf, &shdrnum) != 0)
293da0c48c4Sopenharmony_ci    fail_elf ("Couldn't get number of sections", fname);
294da0c48c4Sopenharmony_ci  scnstrents = malloc (shdrnum * sizeof (Dwelf_Strent *));
295da0c48c4Sopenharmony_ci  if (scnstrents == NULL)
296da0c48c4Sopenharmony_ci    fail ("couldn't allocate memory for section strings", NULL);
297da0c48c4Sopenharmony_ci
298da0c48c4Sopenharmony_ci  /* While going through all sections keep track of last allocated
299da0c48c4Sopenharmony_ci     offset if needed to keep the layout.  We'll put any unallocated
300da0c48c4Sopenharmony_ci     sections behind those (strtab is unallocated and will change
301da0c48c4Sopenharmony_ci     size).  */
302da0c48c4Sopenharmony_ci  GElf_Off last_offset = 0;
303da0c48c4Sopenharmony_ci  if (layout)
304da0c48c4Sopenharmony_ci    last_offset = (ehdr.e_phoff
305da0c48c4Sopenharmony_ci		   + gelf_fsize (elf, ELF_T_PHDR, phnum, EV_CURRENT));
306da0c48c4Sopenharmony_ci  Elf_Scn *scn = NULL;
307da0c48c4Sopenharmony_ci  while ((scn = elf_nextscn (elf, scn)) != NULL)
308da0c48c4Sopenharmony_ci    {
309da0c48c4Sopenharmony_ci      size_t scnnum = elf_ndxscn (scn);
310da0c48c4Sopenharmony_ci      GElf_Shdr shdr_mem;
311da0c48c4Sopenharmony_ci      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
312da0c48c4Sopenharmony_ci      if (shdr == NULL)
313da0c48c4Sopenharmony_ci	fail_elf_idx ("couldn't get shdr", fname, scnnum);
314da0c48c4Sopenharmony_ci      /* Don't add the .shstrtab section itself, we'll not use it.  */
315da0c48c4Sopenharmony_ci      if (shdr->sh_name != 0 && scnnum != shdrstrndx)
316da0c48c4Sopenharmony_ci	{
317da0c48c4Sopenharmony_ci	  const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
318da0c48c4Sopenharmony_ci	  if (sname == NULL)
319da0c48c4Sopenharmony_ci	    fail_elf_idx ("couldn't get section name", fname, scnnum);
320da0c48c4Sopenharmony_ci	  if ((scnstrents[scnnum] = dwelf_strtab_add (strings, sname)) == NULL)
321da0c48c4Sopenharmony_ci	    fail ("No memory to add to merged string table", NULL);
322da0c48c4Sopenharmony_ci	}
323da0c48c4Sopenharmony_ci
324da0c48c4Sopenharmony_ci      if (layout)
325da0c48c4Sopenharmony_ci	if ((shdr->sh_flags & SHF_ALLOC) != 0)
326da0c48c4Sopenharmony_ci	  {
327da0c48c4Sopenharmony_ci	    GElf_Off off = shdr->sh_offset + (shdr->sh_type != SHT_NOBITS
328da0c48c4Sopenharmony_ci					      ? shdr->sh_size : 0);
329da0c48c4Sopenharmony_ci	    if (last_offset < off)
330da0c48c4Sopenharmony_ci	      last_offset = off;
331da0c48c4Sopenharmony_ci	  }
332da0c48c4Sopenharmony_ci    }
333da0c48c4Sopenharmony_ci
334da0c48c4Sopenharmony_ci  /* Add the strings from all the symbols.  */
335da0c48c4Sopenharmony_ci  size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
336da0c48c4Sopenharmony_ci  Elf_Data *symd = elf_getdata (symtabscn, NULL);
337da0c48c4Sopenharmony_ci  if (symd == NULL)
338da0c48c4Sopenharmony_ci    fail_elf ("couldn't get symtab data", fname);
339da0c48c4Sopenharmony_ci  size_t symsnum = symd->d_size / elsize;
340da0c48c4Sopenharmony_ci  symstrents = malloc (symsnum * sizeof (Dwelf_Strent *));
341da0c48c4Sopenharmony_ci  if (symstrents == NULL)
342da0c48c4Sopenharmony_ci    fail_errno ("Couldn't allocate memory for symbol strings", NULL);
343da0c48c4Sopenharmony_ci  for (size_t i = 0; i < symsnum; i++)
344da0c48c4Sopenharmony_ci    {
345da0c48c4Sopenharmony_ci      GElf_Sym sym_mem;
346da0c48c4Sopenharmony_ci      GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
347da0c48c4Sopenharmony_ci      if (sym == NULL)
348da0c48c4Sopenharmony_ci	fail_elf_idx ("Couldn't get symbol", fname, i);
349da0c48c4Sopenharmony_ci      if (sym->st_name != 0)
350da0c48c4Sopenharmony_ci	{
351da0c48c4Sopenharmony_ci	  const char *sname = elf_strptr (elf, strtabndx, sym->st_name);
352da0c48c4Sopenharmony_ci	  if (sname == NULL)
353da0c48c4Sopenharmony_ci	    fail_elf_idx ("Couldn't get symbol name", fname, i);
354da0c48c4Sopenharmony_ci	  if ((symstrents[i] = dwelf_strtab_add (strings, sname)) == NULL)
355da0c48c4Sopenharmony_ci	    fail_idx ("No memory to add to merged string table symbol",
356da0c48c4Sopenharmony_ci		      fname, i);
357da0c48c4Sopenharmony_ci	}
358da0c48c4Sopenharmony_ci    }
359da0c48c4Sopenharmony_ci
360da0c48c4Sopenharmony_ci  /* We got all strings, build the new string table and store it as
361da0c48c4Sopenharmony_ci     new strtab.  */
362da0c48c4Sopenharmony_ci  dwelf_strtab_finalize (strings, &newstrtabdata);
363da0c48c4Sopenharmony_ci
364da0c48c4Sopenharmony_ci  /* We share at least the empty string so the result is at least 1
365da0c48c4Sopenharmony_ci     byte smaller.  */
366da0c48c4Sopenharmony_ci  if (newstrtabdata.d_size >= shdrstrshdr->sh_size + strtabshdr->sh_size)
367da0c48c4Sopenharmony_ci    fail ("Impossible, merged string table is larger", fname);
368da0c48c4Sopenharmony_ci
369da0c48c4Sopenharmony_ci  struct stat st;
370da0c48c4Sopenharmony_ci  if (fstat (fd, &st) != 0)
371da0c48c4Sopenharmony_ci    fail_errno("Couldn't fstat", fname);
372da0c48c4Sopenharmony_ci
373da0c48c4Sopenharmony_ci  /* Create a new (temporary) ELF file for the result.  */
374da0c48c4Sopenharmony_ci  if (replace)
375da0c48c4Sopenharmony_ci    {
376da0c48c4Sopenharmony_ci      size_t fname_len = strlen (fname);
377da0c48c4Sopenharmony_ci      fnew = malloc (fname_len + sizeof (".XXXXXX"));
378da0c48c4Sopenharmony_ci      if (fnew == NULL)
379da0c48c4Sopenharmony_ci	fail_errno ("couldn't allocate memory for new file name", NULL);
380da0c48c4Sopenharmony_ci      strcpy (mempcpy (fnew, fname, fname_len), ".XXXXXX");
381da0c48c4Sopenharmony_ci
382da0c48c4Sopenharmony_ci      fdnew = mkstemp (fnew);
383da0c48c4Sopenharmony_ci    }
384da0c48c4Sopenharmony_ci  else
385da0c48c4Sopenharmony_ci    {
386da0c48c4Sopenharmony_ci      fnew = argv[2];
387da0c48c4Sopenharmony_ci      fdnew = open (fnew, O_WRONLY | O_CREAT, st.st_mode & ALLPERMS);
388da0c48c4Sopenharmony_ci    }
389da0c48c4Sopenharmony_ci
390da0c48c4Sopenharmony_ci  if (fdnew < 0)
391da0c48c4Sopenharmony_ci    fail_errno ("couldn't create output file", fnew);
392da0c48c4Sopenharmony_ci
393da0c48c4Sopenharmony_ci  elfnew = elf_begin (fdnew, ELF_C_WRITE, NULL);
394da0c48c4Sopenharmony_ci  if (elfnew == NULL)
395da0c48c4Sopenharmony_ci    fail_elf ("couldn't open new ELF for writing", fnew);
396da0c48c4Sopenharmony_ci
397da0c48c4Sopenharmony_ci  /* Create the new ELF header and copy over all the data.  */
398da0c48c4Sopenharmony_ci  if (gelf_newehdr (elfnew, gelf_getclass (elf)) == 0)
399da0c48c4Sopenharmony_ci    fail_elf ("Couldn't create new ehdr", fnew);
400da0c48c4Sopenharmony_ci  GElf_Ehdr newehdr;
401da0c48c4Sopenharmony_ci  if (gelf_getehdr (elfnew, &newehdr) == NULL)
402da0c48c4Sopenharmony_ci    fail_elf ("Couldn't get ehdr", fnew);
403da0c48c4Sopenharmony_ci
404da0c48c4Sopenharmony_ci  newehdr.e_ident[EI_DATA] = ehdr.e_ident[EI_DATA];
405da0c48c4Sopenharmony_ci  newehdr.e_type = ehdr.e_type;
406da0c48c4Sopenharmony_ci  newehdr.e_machine = ehdr.e_machine;
407da0c48c4Sopenharmony_ci  newehdr.e_version = ehdr.e_version;
408da0c48c4Sopenharmony_ci  newehdr.e_entry = ehdr.e_entry;
409da0c48c4Sopenharmony_ci  newehdr.e_flags = ehdr.e_flags;
410da0c48c4Sopenharmony_ci
411da0c48c4Sopenharmony_ci  /* The new file uses the new strtab as shstrtab.  */
412da0c48c4Sopenharmony_ci  size_t newstrtabndx = newsecndx (strtabndx, shdrstrndx, shdrnum,
413da0c48c4Sopenharmony_ci				   fname, "ehdr", 0, "e_shstrndx", 0);
414da0c48c4Sopenharmony_ci  if (newstrtabndx < SHN_LORESERVE)
415da0c48c4Sopenharmony_ci    newehdr.e_shstrndx = newstrtabndx;
416da0c48c4Sopenharmony_ci  else
417da0c48c4Sopenharmony_ci    {
418da0c48c4Sopenharmony_ci      Elf_Scn *zscn = elf_getscn (elfnew, 0);
419da0c48c4Sopenharmony_ci      GElf_Shdr zshdr_mem;
420da0c48c4Sopenharmony_ci      GElf_Shdr *zshdr = gelf_getshdr (zscn, &zshdr_mem);
421da0c48c4Sopenharmony_ci      if (zshdr == NULL)
422da0c48c4Sopenharmony_ci	fail_elf ("Couldn't get section zero", fnew);
423da0c48c4Sopenharmony_ci      zshdr->sh_link = strtabndx;
424da0c48c4Sopenharmony_ci      if (gelf_update_shdr (zscn, zshdr) == 0)
425da0c48c4Sopenharmony_ci	fail_elf ("Couldn't update section zero", fnew);
426da0c48c4Sopenharmony_ci      newehdr.e_shstrndx = SHN_XINDEX;
427da0c48c4Sopenharmony_ci    }
428da0c48c4Sopenharmony_ci
429da0c48c4Sopenharmony_ci  if (gelf_update_ehdr (elfnew, &newehdr) == 0)
430da0c48c4Sopenharmony_ci    fail ("Couldn't update ehdr", fnew);
431da0c48c4Sopenharmony_ci
432da0c48c4Sopenharmony_ci  /* Copy the program headers if any.  */
433da0c48c4Sopenharmony_ci  if (phnum != 0)
434da0c48c4Sopenharmony_ci    {
435da0c48c4Sopenharmony_ci      if (gelf_newphdr (elfnew, phnum) == 0)
436da0c48c4Sopenharmony_ci	fail_elf ("Couldn't create phdrs", fnew);
437da0c48c4Sopenharmony_ci
438da0c48c4Sopenharmony_ci      for (size_t cnt = 0; cnt < phnum; ++cnt)
439da0c48c4Sopenharmony_ci	{
440da0c48c4Sopenharmony_ci	  GElf_Phdr phdr_mem;
441da0c48c4Sopenharmony_ci	  GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
442da0c48c4Sopenharmony_ci	  if (phdr == NULL)
443da0c48c4Sopenharmony_ci	    fail_elf_idx ("Couldn't get phdr", fname, cnt);
444da0c48c4Sopenharmony_ci	  if (gelf_update_phdr (elfnew, cnt, phdr) == 0)
445da0c48c4Sopenharmony_ci	    fail_elf_idx ("Couldn't create phdr", fnew, cnt);
446da0c48c4Sopenharmony_ci	}
447da0c48c4Sopenharmony_ci    }
448da0c48c4Sopenharmony_ci
449da0c48c4Sopenharmony_ci  newshnums = shdrnum - 1;
450da0c48c4Sopenharmony_ci  newscnbufs = calloc (sizeof (void *), newshnums);
451da0c48c4Sopenharmony_ci  if (newscnbufs == NULL)
452da0c48c4Sopenharmony_ci    fail_errno ("Couldn't allocate memory for new section buffers", NULL);
453da0c48c4Sopenharmony_ci
454da0c48c4Sopenharmony_ci  /* Copy the sections, except the shstrtab, fill the strtab with the
455da0c48c4Sopenharmony_ci     combined strings and adjust section references.  */
456da0c48c4Sopenharmony_ci  while ((scn = elf_nextscn (elf, scn)) != NULL)
457da0c48c4Sopenharmony_ci    {
458da0c48c4Sopenharmony_ci      size_t ndx = elf_ndxscn (scn);
459da0c48c4Sopenharmony_ci
460da0c48c4Sopenharmony_ci      GElf_Shdr shdr_mem;
461da0c48c4Sopenharmony_ci      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
462da0c48c4Sopenharmony_ci      if (shdr == NULL)
463da0c48c4Sopenharmony_ci	fail_elf_idx ("Couldn't get shdr", fname, ndx);
464da0c48c4Sopenharmony_ci
465da0c48c4Sopenharmony_ci      /* Section zero is always created.  Skip the shtrtab.  */
466da0c48c4Sopenharmony_ci      if (ndx == 0 || ndx == shdrstrndx)
467da0c48c4Sopenharmony_ci	continue;
468da0c48c4Sopenharmony_ci
469da0c48c4Sopenharmony_ci      Elf_Scn *newscn = elf_newscn (elfnew);
470da0c48c4Sopenharmony_ci      if (newscn == NULL)
471da0c48c4Sopenharmony_ci	fail_elf_idx ("couldn't create new section", fnew, ndx);
472da0c48c4Sopenharmony_ci
473da0c48c4Sopenharmony_ci      GElf_Shdr newshdr;
474da0c48c4Sopenharmony_ci      newshdr.sh_name = (shdr->sh_name != 0
475da0c48c4Sopenharmony_ci			 ? dwelf_strent_off (scnstrents[ndx]) : 0);
476da0c48c4Sopenharmony_ci      newshdr.sh_type = shdr->sh_type;
477da0c48c4Sopenharmony_ci      newshdr.sh_flags = shdr->sh_flags;
478da0c48c4Sopenharmony_ci      newshdr.sh_addr = shdr->sh_addr;
479da0c48c4Sopenharmony_ci      newshdr.sh_size = shdr->sh_size;
480da0c48c4Sopenharmony_ci      if (shdr->sh_link != 0)
481da0c48c4Sopenharmony_ci	newshdr.sh_link = newsecndx (shdr->sh_link, shdrstrndx, shdrnum,
482da0c48c4Sopenharmony_ci				     fname, "shdr", ndx, "sh_link", 0);
483da0c48c4Sopenharmony_ci      else
484da0c48c4Sopenharmony_ci	newshdr.sh_link = 0;
485da0c48c4Sopenharmony_ci      if (SH_INFO_LINK_P (shdr) && shdr->sh_info != 0)
486da0c48c4Sopenharmony_ci	newshdr.sh_info = newsecndx (shdr->sh_info, shdrstrndx, shdrnum,
487da0c48c4Sopenharmony_ci				     fname, "shdr", ndx, "sh_info", 0);
488da0c48c4Sopenharmony_ci
489da0c48c4Sopenharmony_ci      else
490da0c48c4Sopenharmony_ci	newshdr.sh_info = shdr->sh_info;
491da0c48c4Sopenharmony_ci      newshdr.sh_entsize = shdr->sh_entsize;
492da0c48c4Sopenharmony_ci
493da0c48c4Sopenharmony_ci      /* Some sections need a new data buffer because they need to
494da0c48c4Sopenharmony_ci	 manipulate the original data.  Allocate and check here, so we
495da0c48c4Sopenharmony_ci	 have a list of all data buffers we might need to release when
496da0c48c4Sopenharmony_ci	 done.  */
497da0c48c4Sopenharmony_ci      Elf_Data *newdata = elf_newdata (newscn);
498da0c48c4Sopenharmony_ci      if (newdata == NULL)
499da0c48c4Sopenharmony_ci	fail_elf_idx ("Couldn't create new data for section", fnew, ndx);
500da0c48c4Sopenharmony_ci      if (ndx == strtabndx)
501da0c48c4Sopenharmony_ci	*newdata = newstrtabdata;
502da0c48c4Sopenharmony_ci      else
503da0c48c4Sopenharmony_ci	{
504da0c48c4Sopenharmony_ci	  /* The symtab, dynsym, group and symtab_shndx sections
505da0c48c4Sopenharmony_ci	     contain section indexes. Symbol tables (symtab and
506da0c48c4Sopenharmony_ci	     dynsym) contain indexes to strings. Update both if
507da0c48c4Sopenharmony_ci	     necessary.  */
508da0c48c4Sopenharmony_ci	  Elf_Data *data = elf_getdata (scn, NULL);
509da0c48c4Sopenharmony_ci	  if (data == NULL)
510da0c48c4Sopenharmony_ci	    fail_elf_idx ("Couldn't get data from section", fname, ndx);
511da0c48c4Sopenharmony_ci	  *newdata = *data;
512da0c48c4Sopenharmony_ci	  switch (shdr->sh_type)
513da0c48c4Sopenharmony_ci	    {
514da0c48c4Sopenharmony_ci	    case SHT_SYMTAB:
515da0c48c4Sopenharmony_ci	    case SHT_DYNSYM:
516da0c48c4Sopenharmony_ci	      {
517da0c48c4Sopenharmony_ci		/* We need to update the section numbers of the
518da0c48c4Sopenharmony_ci		   symbols and if this symbol table uses the strtab
519da0c48c4Sopenharmony_ci		   section also the name indexes.  */
520da0c48c4Sopenharmony_ci		const bool update_name = shdr->sh_link == strtabndx;
521da0c48c4Sopenharmony_ci		if (update_name && ndx != symtabndx)
522da0c48c4Sopenharmony_ci		  fail ("Only one symbol table using strtab expected", fname);
523da0c48c4Sopenharmony_ci		new_data_buf (newdata, fname, ndx, shdrstrndx, shdrnum);
524da0c48c4Sopenharmony_ci		size_t syms = (data->d_size
525da0c48c4Sopenharmony_ci			       / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT));
526da0c48c4Sopenharmony_ci		for (size_t i = 0; i < syms; i++)
527da0c48c4Sopenharmony_ci		  {
528da0c48c4Sopenharmony_ci		    GElf_Sym sym;
529da0c48c4Sopenharmony_ci		    if (gelf_getsym (data, i, &sym) == NULL)
530da0c48c4Sopenharmony_ci		      fail_elf_idx ("Couldn't get symbol", fname, i);
531da0c48c4Sopenharmony_ci
532da0c48c4Sopenharmony_ci		    if (GELF_ST_TYPE (sym.st_info) == STT_SECTION
533da0c48c4Sopenharmony_ci			&& sym.st_shndx == shdrstrndx)
534da0c48c4Sopenharmony_ci		      fprintf (stderr, "WARNING:"
535da0c48c4Sopenharmony_ci			       " symbol table [%zd] contains section symbol %zd"
536da0c48c4Sopenharmony_ci			       " for old shdrstrndx %zd\n", ndx, i, shdrstrndx);
537da0c48c4Sopenharmony_ci		    else if (sym.st_shndx != SHN_UNDEF
538da0c48c4Sopenharmony_ci			     && sym.st_shndx < SHN_LORESERVE)
539da0c48c4Sopenharmony_ci		      sym.st_shndx = newsecndx (sym.st_shndx, shdrstrndx, shdrnum,
540da0c48c4Sopenharmony_ci					 fname, "section", ndx, "symbol", i);
541da0c48c4Sopenharmony_ci		    if (update_name && sym.st_name != 0)
542da0c48c4Sopenharmony_ci		      sym.st_name = dwelf_strent_off (symstrents[i]);
543da0c48c4Sopenharmony_ci
544da0c48c4Sopenharmony_ci		    /* We explicitly don't update the SHNDX table at
545da0c48c4Sopenharmony_ci		       the same time, we do that below.  */
546da0c48c4Sopenharmony_ci		    if (gelf_update_sym (newdata, i, &sym) == 0)
547da0c48c4Sopenharmony_ci		      fail_elf_idx ("Couldn't update symbol", fnew, i);
548da0c48c4Sopenharmony_ci		  }
549da0c48c4Sopenharmony_ci	      }
550da0c48c4Sopenharmony_ci	      break;
551da0c48c4Sopenharmony_ci
552da0c48c4Sopenharmony_ci	    case SHT_GROUP:
553da0c48c4Sopenharmony_ci	      {
554da0c48c4Sopenharmony_ci		new_data_buf (newdata, fname, ndx, shdrstrndx, shdrnum);
555da0c48c4Sopenharmony_ci		/* A section group contains Elf32_Words. The first
556da0c48c4Sopenharmony_ci		   word is a flag value, the rest of the words are
557da0c48c4Sopenharmony_ci		   indexes of the sections belonging to the group.  */
558da0c48c4Sopenharmony_ci		Elf32_Word *group = (Elf32_Word *) data->d_buf;
559da0c48c4Sopenharmony_ci		Elf32_Word *newgroup = (Elf32_Word *) newdata->d_buf;
560da0c48c4Sopenharmony_ci		size_t words = data->d_size / sizeof (Elf32_Word);
561da0c48c4Sopenharmony_ci		if (words == 0)
562da0c48c4Sopenharmony_ci		  fail_idx ("Not enough data in group section", fname, ndx);
563da0c48c4Sopenharmony_ci		newgroup[0] = group[0];
564da0c48c4Sopenharmony_ci		for (size_t i = 1; i < words; i++)
565da0c48c4Sopenharmony_ci		  newgroup[i] = newsecndx (group[i], shdrstrndx, shdrnum,
566da0c48c4Sopenharmony_ci					   fname, "section", ndx, "group", i);
567da0c48c4Sopenharmony_ci	      }
568da0c48c4Sopenharmony_ci	      break;
569da0c48c4Sopenharmony_ci
570da0c48c4Sopenharmony_ci	    case SHT_SYMTAB_SHNDX:
571da0c48c4Sopenharmony_ci	      {
572da0c48c4Sopenharmony_ci		new_data_buf (newdata, fname, ndx, shdrstrndx, shdrnum);
573da0c48c4Sopenharmony_ci		/* A SHNDX just contains an array of section indexes
574da0c48c4Sopenharmony_ci		   for the corresponding symbol table.  The entry is
575da0c48c4Sopenharmony_ci		   SHN_UNDEF unless the corresponding symbol is
576da0c48c4Sopenharmony_ci		   SHN_XINDEX.  */
577da0c48c4Sopenharmony_ci		Elf32_Word *shndx = (Elf32_Word *) data->d_buf;
578da0c48c4Sopenharmony_ci		Elf32_Word *newshndx = (Elf32_Word *) newdata->d_buf;
579da0c48c4Sopenharmony_ci		size_t words = data->d_size / sizeof (Elf32_Word);
580da0c48c4Sopenharmony_ci		for (size_t i = 0; i < words; i++)
581da0c48c4Sopenharmony_ci		  if (shndx[i] == SHN_UNDEF)
582da0c48c4Sopenharmony_ci		    newshndx[i] = SHN_UNDEF;
583da0c48c4Sopenharmony_ci		  else
584da0c48c4Sopenharmony_ci		    newshndx[i] = newsecndx (shndx[i], shdrstrndx, shdrnum,
585da0c48c4Sopenharmony_ci					     fname, "section", ndx, "shndx", i);
586da0c48c4Sopenharmony_ci	      }
587da0c48c4Sopenharmony_ci	      break;
588da0c48c4Sopenharmony_ci
589da0c48c4Sopenharmony_ci	    case SHT_DYNAMIC:
590da0c48c4Sopenharmony_ci	      FALLTHROUGH;
591da0c48c4Sopenharmony_ci	      /* There are string indexes in here, but
592da0c48c4Sopenharmony_ci		 they (should) point to a allocated string table,
593da0c48c4Sopenharmony_ci		 which we don't alter.  */
594da0c48c4Sopenharmony_ci	    default:
595da0c48c4Sopenharmony_ci	      /* Nothing to do.  Section data doesn't contain section
596da0c48c4Sopenharmony_ci		 or strtab indexes.  */
597da0c48c4Sopenharmony_ci	      break;
598da0c48c4Sopenharmony_ci	    }
599da0c48c4Sopenharmony_ci	}
600da0c48c4Sopenharmony_ci
601da0c48c4Sopenharmony_ci      /* When we are responsible for the layout explicitly set
602da0c48c4Sopenharmony_ci	 sh_addralign, sh_size and sh_offset.  Otherwise libelf will
603da0c48c4Sopenharmony_ci	 calculate those from the Elf_Data.  */
604da0c48c4Sopenharmony_ci      if (layout)
605da0c48c4Sopenharmony_ci	{
606da0c48c4Sopenharmony_ci	  /* We have just one Elf_Data.  */
607da0c48c4Sopenharmony_ci	  newshdr.sh_size = newdata->d_size;
608da0c48c4Sopenharmony_ci	  newshdr.sh_addralign = newdata->d_align;
609da0c48c4Sopenharmony_ci
610da0c48c4Sopenharmony_ci	  /* Keep the offset of allocated sections so they are at the
611da0c48c4Sopenharmony_ci	     same place in the file. Add unallocated ones after the
612da0c48c4Sopenharmony_ci	     allocated ones.  */
613da0c48c4Sopenharmony_ci	  if ((shdr->sh_flags & SHF_ALLOC) != 0)
614da0c48c4Sopenharmony_ci	    newshdr.sh_offset = shdr->sh_offset;
615da0c48c4Sopenharmony_ci	  else
616da0c48c4Sopenharmony_ci	    {
617da0c48c4Sopenharmony_ci	      /* Zero means one.  No alignment constraints.  */
618da0c48c4Sopenharmony_ci	      size_t addralign = newshdr.sh_addralign ?: 1;
619da0c48c4Sopenharmony_ci	      last_offset = (last_offset + addralign - 1) & ~(addralign - 1);
620da0c48c4Sopenharmony_ci	      newshdr.sh_offset = last_offset;
621da0c48c4Sopenharmony_ci	      if (newshdr.sh_type != SHT_NOBITS)
622da0c48c4Sopenharmony_ci		last_offset += newshdr.sh_size;
623da0c48c4Sopenharmony_ci	    }
624da0c48c4Sopenharmony_ci	}
625da0c48c4Sopenharmony_ci      else
626da0c48c4Sopenharmony_ci	{
627da0c48c4Sopenharmony_ci	  newshdr.sh_addralign = 0;
628da0c48c4Sopenharmony_ci	  newshdr.sh_size = 0;
629da0c48c4Sopenharmony_ci	  newshdr.sh_offset = 0;
630da0c48c4Sopenharmony_ci	}
631da0c48c4Sopenharmony_ci
632da0c48c4Sopenharmony_ci      if (gelf_update_shdr (newscn, &newshdr) == 0)
633da0c48c4Sopenharmony_ci	fail_elf_idx ("Couldn't update section header", fnew, ndx);
634da0c48c4Sopenharmony_ci    }
635da0c48c4Sopenharmony_ci
636da0c48c4Sopenharmony_ci  /* If we have phdrs we want elf_update to layout the SHF_ALLOC
637da0c48c4Sopenharmony_ci     sections precisely as in the original file.  In that case we are
638da0c48c4Sopenharmony_ci     also responsible for setting phoff and shoff */
639da0c48c4Sopenharmony_ci  if (layout)
640da0c48c4Sopenharmony_ci    {
641da0c48c4Sopenharmony_ci      /* Position the shdrs after the last (unallocated) section.  */
642da0c48c4Sopenharmony_ci      if (gelf_getehdr (elfnew, &newehdr) == NULL)
643da0c48c4Sopenharmony_ci	fail_elf ("Couldn't get ehdr", fnew);
644da0c48c4Sopenharmony_ci      const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT);
645da0c48c4Sopenharmony_ci      newehdr.e_shoff = ((last_offset + offsize - 1)
646da0c48c4Sopenharmony_ci			 & ~((GElf_Off) (offsize - 1)));
647da0c48c4Sopenharmony_ci
648da0c48c4Sopenharmony_ci      /* The phdrs go in the same place as in the original file.
649da0c48c4Sopenharmony_ci	 Normally right after the ELF header.  */
650da0c48c4Sopenharmony_ci      newehdr.e_phoff = ehdr.e_phoff;
651da0c48c4Sopenharmony_ci
652da0c48c4Sopenharmony_ci      if (gelf_update_ehdr (elfnew, &newehdr) == 0)
653da0c48c4Sopenharmony_ci	fail_elf ("Couldn't update ehdr", fnew);
654da0c48c4Sopenharmony_ci
655da0c48c4Sopenharmony_ci      elf_flagelf (elfnew, ELF_C_SET, ELF_F_LAYOUT);
656da0c48c4Sopenharmony_ci    }
657da0c48c4Sopenharmony_ci
658da0c48c4Sopenharmony_ci  if (elf_update (elfnew, ELF_C_WRITE) == -1)
659da0c48c4Sopenharmony_ci    fail_elf ("Couldn't write ELF", fnew);
660da0c48c4Sopenharmony_ci
661da0c48c4Sopenharmony_ci  elf_end (elfnew);
662da0c48c4Sopenharmony_ci  elfnew = NULL;
663da0c48c4Sopenharmony_ci
664da0c48c4Sopenharmony_ci  /* Try to match mode and owner.group of the original file.  */
665da0c48c4Sopenharmony_ci  if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0)
666da0c48c4Sopenharmony_ci    error (0, errno, "Couldn't fchmod %s", fnew);
667da0c48c4Sopenharmony_ci  if (fchown (fdnew, st.st_uid, st.st_gid) != 0)
668da0c48c4Sopenharmony_ci    error (0, errno, "Couldn't fchown %s", fnew);
669da0c48c4Sopenharmony_ci
670da0c48c4Sopenharmony_ci  /* Finally replace the old file with the new merged strings file.  */
671da0c48c4Sopenharmony_ci  if (replace)
672da0c48c4Sopenharmony_ci    if (rename (fnew, fname) != 0)
673da0c48c4Sopenharmony_ci      fail_errno ("rename", fnew);
674da0c48c4Sopenharmony_ci
675da0c48c4Sopenharmony_ci  /* We are finally done with the new file, don't unlink it now.  */
676da0c48c4Sopenharmony_ci  close (fdnew);
677da0c48c4Sopenharmony_ci  if (replace)
678da0c48c4Sopenharmony_ci    free (fnew);
679da0c48c4Sopenharmony_ci  fnew = NULL;
680da0c48c4Sopenharmony_ci  fdnew = -1;
681da0c48c4Sopenharmony_ci
682da0c48c4Sopenharmony_ci  release ();
683da0c48c4Sopenharmony_ci  return 0;
684da0c48c4Sopenharmony_ci}
685