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