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