xref: /freebsd/contrib/elftoolchain/elfcopy/symbols.c (revision 839529caa9c35f92b638dbe074655598e7a6bb6f)
1a85fe12eSEd Maste /*-
2a85fe12eSEd Maste  * Copyright (c) 2007-2013 Kai Wang
3a85fe12eSEd Maste  * All rights reserved.
4a85fe12eSEd Maste  *
5a85fe12eSEd Maste  * Redistribution and use in source and binary forms, with or without
6a85fe12eSEd Maste  * modification, are permitted provided that the following conditions
7a85fe12eSEd Maste  * are met:
8a85fe12eSEd Maste  * 1. Redistributions of source code must retain the above copyright
9a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer.
10a85fe12eSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
11a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer in the
12a85fe12eSEd Maste  *    documentation and/or other materials provided with the distribution.
13a85fe12eSEd Maste  *
14a85fe12eSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a85fe12eSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a85fe12eSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a85fe12eSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a85fe12eSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a85fe12eSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a85fe12eSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a85fe12eSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a85fe12eSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a85fe12eSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a85fe12eSEd Maste  * SUCH DAMAGE.
25a85fe12eSEd Maste  */
26a85fe12eSEd Maste 
27a85fe12eSEd Maste #include <sys/param.h>
28*839529caSEd Maste #include <assert.h>
29a85fe12eSEd Maste #include <err.h>
30a85fe12eSEd Maste #include <fnmatch.h>
31a85fe12eSEd Maste #include <stdio.h>
32a85fe12eSEd Maste #include <stdlib.h>
33a85fe12eSEd Maste #include <string.h>
34a85fe12eSEd Maste 
35a85fe12eSEd Maste #include "elfcopy.h"
36a85fe12eSEd Maste 
37*839529caSEd Maste ELFTC_VCSID("$Id: symbols.c 3376 2016-01-26 18:41:39Z emaste $");
38*839529caSEd Maste 
39*839529caSEd Maste /* Backwards compatibility for systems with older ELF definitions. */
40*839529caSEd Maste #ifndef STB_GNU_UNIQUE
41*839529caSEd Maste #define	STB_GNU_UNIQUE 10
42*839529caSEd Maste #endif
43*839529caSEd Maste 
44a85fe12eSEd Maste 
45a85fe12eSEd Maste /* Symbol table buffer structure. */
46a85fe12eSEd Maste struct symbuf {
47a85fe12eSEd Maste 	Elf32_Sym *l32;		/* 32bit local symbol */
48a85fe12eSEd Maste 	Elf32_Sym *g32;		/* 32bit global symbol */
49a85fe12eSEd Maste 	Elf64_Sym *l64;		/* 64bit local symbol */
50a85fe12eSEd Maste 	Elf64_Sym *g64;		/* 64bit global symbol */
51a85fe12eSEd Maste 	size_t ngs, nls;	/* number of each kind */
52a85fe12eSEd Maste 	size_t gcap, lcap; 	/* buffer capacities. */
53a85fe12eSEd Maste };
54a85fe12eSEd Maste 
554a85c691SEd Maste struct sthash {
564a85c691SEd Maste 	LIST_ENTRY(sthash) sh_next;
574a85c691SEd Maste 	size_t sh_off;
584a85c691SEd Maste };
594a85c691SEd Maste typedef LIST_HEAD(,sthash) hash_head;
604a85c691SEd Maste #define STHASHSIZE 65536
614a85c691SEd Maste 
624a85c691SEd Maste struct strimpl {
634a85c691SEd Maste 	char *buf;		/* string table */
644a85c691SEd Maste 	size_t sz;		/* entries */
654a85c691SEd Maste 	size_t cap;		/* buffer capacity */
664a85c691SEd Maste 	hash_head hash[STHASHSIZE];
674a85c691SEd Maste };
684a85c691SEd Maste 
694a85c691SEd Maste 
70a85fe12eSEd Maste /* String table buffer structure. */
71a85fe12eSEd Maste struct strbuf {
724a85c691SEd Maste 	struct strimpl l;	/* local symbols */
734a85c691SEd Maste 	struct strimpl g;	/* global symbols */
74a85fe12eSEd Maste };
75a85fe12eSEd Maste 
76a85fe12eSEd Maste static int	is_debug_symbol(unsigned char st_info);
77a85fe12eSEd Maste static int	is_global_symbol(unsigned char st_info);
78a85fe12eSEd Maste static int	is_local_symbol(unsigned char st_info);
79a85fe12eSEd Maste static int	is_local_label(const char *name);
80a85fe12eSEd Maste static int	is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s);
81a85fe12eSEd Maste static int	is_remove_symbol(struct elfcopy *ecp, size_t sc, int i,
82a85fe12eSEd Maste 		    GElf_Sym *s, const char *name);
83a85fe12eSEd Maste static int	is_weak_symbol(unsigned char st_info);
844a85c691SEd Maste static int	lookup_exact_string(hash_head *hash, const char *buf,
854a85c691SEd Maste 		    const char *s);
86a85fe12eSEd Maste static int	generate_symbols(struct elfcopy *ecp);
873ef90571SEd Maste static void	mark_reloc_symbols(struct elfcopy *ecp, size_t sc);
883ef90571SEd Maste static void	mark_section_group_symbols(struct elfcopy *ecp, size_t sc);
894a85c691SEd Maste uint32_t	str_hash(const char *s);
90a85fe12eSEd Maste 
91a85fe12eSEd Maste /* Convenient bit vector operation macros. */
92a85fe12eSEd Maste #define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7))
93a85fe12eSEd Maste #define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7)))
94a85fe12eSEd Maste #define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7)))
95a85fe12eSEd Maste 
96a85fe12eSEd Maste static int
97a85fe12eSEd Maste is_debug_symbol(unsigned char st_info)
98a85fe12eSEd Maste {
99a85fe12eSEd Maste 
100a85fe12eSEd Maste 	if (GELF_ST_TYPE(st_info) == STT_SECTION ||
101a85fe12eSEd Maste 	    GELF_ST_TYPE(st_info) == STT_FILE)
102a85fe12eSEd Maste 		return (1);
103a85fe12eSEd Maste 
104a85fe12eSEd Maste 	return (0);
105a85fe12eSEd Maste }
106a85fe12eSEd Maste 
107a85fe12eSEd Maste static int
108a85fe12eSEd Maste is_global_symbol(unsigned char st_info)
109a85fe12eSEd Maste {
110a85fe12eSEd Maste 
111*839529caSEd Maste 	if (GELF_ST_BIND(st_info) == STB_GLOBAL ||
112*839529caSEd Maste 	    GELF_ST_BIND(st_info) == STB_GNU_UNIQUE)
113a85fe12eSEd Maste 		return (1);
114a85fe12eSEd Maste 
115a85fe12eSEd Maste 	return (0);
116a85fe12eSEd Maste }
117a85fe12eSEd Maste 
118a85fe12eSEd Maste static int
119a85fe12eSEd Maste is_weak_symbol(unsigned char st_info)
120a85fe12eSEd Maste {
121a85fe12eSEd Maste 
122a85fe12eSEd Maste 	if (GELF_ST_BIND(st_info) == STB_WEAK)
123a85fe12eSEd Maste 		return (1);
124a85fe12eSEd Maste 
125a85fe12eSEd Maste 	return (0);
126a85fe12eSEd Maste }
127a85fe12eSEd Maste 
128a85fe12eSEd Maste static int
129a85fe12eSEd Maste is_local_symbol(unsigned char st_info)
130a85fe12eSEd Maste {
131a85fe12eSEd Maste 
132a85fe12eSEd Maste 	if (GELF_ST_BIND(st_info) == STB_LOCAL)
133a85fe12eSEd Maste 		return (1);
134a85fe12eSEd Maste 
135a85fe12eSEd Maste 	return (0);
136a85fe12eSEd Maste }
137a85fe12eSEd Maste 
138a85fe12eSEd Maste static int
13967d97fe7SEd Maste is_hidden_symbol(unsigned char st_other)
14067d97fe7SEd Maste {
14167d97fe7SEd Maste 
14267d97fe7SEd Maste 	if (GELF_ST_VISIBILITY(st_other) == STV_HIDDEN ||
14367d97fe7SEd Maste 	    GELF_ST_VISIBILITY(st_other) == STV_INTERNAL)
14467d97fe7SEd Maste 		return (1);
14567d97fe7SEd Maste 
14667d97fe7SEd Maste 	return (0);
14767d97fe7SEd Maste }
14867d97fe7SEd Maste 
14967d97fe7SEd Maste static int
150a85fe12eSEd Maste is_local_label(const char *name)
151a85fe12eSEd Maste {
152a85fe12eSEd Maste 
153a85fe12eSEd Maste 	/* Compiler generated local symbols that start with .L */
154a85fe12eSEd Maste 	if (name[0] == '.' && name[1] == 'L')
155a85fe12eSEd Maste 		return (1);
156a85fe12eSEd Maste 
157a85fe12eSEd Maste 	return (0);
158a85fe12eSEd Maste }
159a85fe12eSEd Maste 
160a85fe12eSEd Maste /*
161a85fe12eSEd Maste  * Symbols related to relocation are needed.
162a85fe12eSEd Maste  */
163a85fe12eSEd Maste static int
164a85fe12eSEd Maste is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s)
165a85fe12eSEd Maste {
166a85fe12eSEd Maste 
167a85fe12eSEd Maste 	/* If symbol involves relocation, it is needed. */
168a85fe12eSEd Maste 	if (BIT_ISSET(ecp->v_rel, i))
169a85fe12eSEd Maste 		return (1);
170a85fe12eSEd Maste 
1713ef90571SEd Maste 	/* Symbols refered by COMDAT sections are needed. */
1723ef90571SEd Maste 	if (BIT_ISSET(ecp->v_grp, i))
1733ef90571SEd Maste 		return (1);
1743ef90571SEd Maste 
175a85fe12eSEd Maste 	/*
176a85fe12eSEd Maste 	 * For relocatable files (.o files), global and weak symbols
177a85fe12eSEd Maste 	 * are needed.
178a85fe12eSEd Maste 	 */
179a85fe12eSEd Maste 	if (ecp->flags & RELOCATABLE) {
180a85fe12eSEd Maste 		if (is_global_symbol(s->st_info) || is_weak_symbol(s->st_info))
181a85fe12eSEd Maste 			return (1);
182a85fe12eSEd Maste 	}
183a85fe12eSEd Maste 
184a85fe12eSEd Maste 	return (0);
185a85fe12eSEd Maste }
186a85fe12eSEd Maste 
187a85fe12eSEd Maste static int
188a85fe12eSEd Maste is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s,
189a85fe12eSEd Maste     const char *name)
190a85fe12eSEd Maste {
191a85fe12eSEd Maste 	GElf_Sym sym0 = {
192a85fe12eSEd Maste 		0, 		/* st_name */
193a85fe12eSEd Maste 		0,		/* st_value */
194a85fe12eSEd Maste 		0,		/* st_size */
195a85fe12eSEd Maste 		0,		/* st_info */
196a85fe12eSEd Maste 		0,		/* st_other */
197a85fe12eSEd Maste 		SHN_UNDEF,	/* st_shndx */
198a85fe12eSEd Maste 	};
199a85fe12eSEd Maste 
200a85fe12eSEd Maste 	/*
201a85fe12eSEd Maste 	 * Keep the first symbol if it is the special reserved symbol.
202a85fe12eSEd Maste 	 * XXX Should we generate one if it's missing?
203a85fe12eSEd Maste 	 */
204a85fe12eSEd Maste 	if (i == 0 && !memcmp(s, &sym0, sizeof(GElf_Sym)))
205a85fe12eSEd Maste 		return (0);
206a85fe12eSEd Maste 
207a85fe12eSEd Maste 	/* Remove the symbol if the section it refers to was removed. */
208a85fe12eSEd Maste 	if (s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE &&
209a85fe12eSEd Maste 	    ecp->secndx[s->st_shndx] == 0)
210a85fe12eSEd Maste 		return (1);
211a85fe12eSEd Maste 
212*839529caSEd Maste 	/* Keep the symbol if specified by command line option -K. */
213*839529caSEd Maste 	if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL)
214*839529caSEd Maste 		return (0);
215*839529caSEd Maste 
216a85fe12eSEd Maste 	if (ecp->strip == STRIP_ALL)
217a85fe12eSEd Maste 		return (1);
218a85fe12eSEd Maste 
219*839529caSEd Maste 	/* Mark symbols used in relocation. */
220a85fe12eSEd Maste 	if (ecp->v_rel == NULL)
2213ef90571SEd Maste 		mark_reloc_symbols(ecp, sc);
2223ef90571SEd Maste 
223*839529caSEd Maste 	/* Mark symbols used in section groups. */
2243ef90571SEd Maste 	if (ecp->v_grp == NULL)
2253ef90571SEd Maste 		mark_section_group_symbols(ecp, sc);
226a85fe12eSEd Maste 
227*839529caSEd Maste 	/*
228*839529caSEd Maste 	 * Strip the symbol if specified by command line option -N,
229*839529caSEd Maste 	 * unless it's used in relocation.
230*839529caSEd Maste 	 */
231*839529caSEd Maste 	if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) {
232*839529caSEd Maste 		if (BIT_ISSET(ecp->v_rel, i)) {
233*839529caSEd Maste 			warnx("not stripping symbol `%s' because it is named"
234*839529caSEd Maste 			    " in a relocation", name);
235*839529caSEd Maste 			return (0);
236*839529caSEd Maste 		}
237*839529caSEd Maste 		return (1);
238*839529caSEd Maste 	}
239*839529caSEd Maste 
240a85fe12eSEd Maste 	if (is_needed_symbol(ecp, i, s))
241a85fe12eSEd Maste 		return (0);
242a85fe12eSEd Maste 
243a85fe12eSEd Maste 	if (ecp->strip == STRIP_UNNEEDED)
244a85fe12eSEd Maste 		return (1);
245a85fe12eSEd Maste 
246a85fe12eSEd Maste 	if ((ecp->flags & DISCARD_LOCAL) && is_local_symbol(s->st_info) &&
247a85fe12eSEd Maste 	    !is_debug_symbol(s->st_info))
248a85fe12eSEd Maste 		return (1);
249a85fe12eSEd Maste 
250a85fe12eSEd Maste 	if ((ecp->flags & DISCARD_LLABEL) && is_local_symbol(s->st_info) &&
251a85fe12eSEd Maste 	    !is_debug_symbol(s->st_info) && is_local_label(name))
252a85fe12eSEd Maste 		return (1);
253a85fe12eSEd Maste 
254a85fe12eSEd Maste 	if (ecp->strip == STRIP_DEBUG && is_debug_symbol(s->st_info))
255a85fe12eSEd Maste 		return (1);
256a85fe12eSEd Maste 
257a85fe12eSEd Maste 	return (0);
258a85fe12eSEd Maste }
259a85fe12eSEd Maste 
260a85fe12eSEd Maste /*
261a85fe12eSEd Maste  * Mark symbols refered by relocation entries.
262a85fe12eSEd Maste  */
263a85fe12eSEd Maste static void
2643ef90571SEd Maste mark_reloc_symbols(struct elfcopy *ecp, size_t sc)
265a85fe12eSEd Maste {
266a85fe12eSEd Maste 	const char	*name;
267a85fe12eSEd Maste 	Elf_Data	*d;
268a85fe12eSEd Maste 	Elf_Scn		*s;
269a85fe12eSEd Maste 	GElf_Rel	 r;
270a85fe12eSEd Maste 	GElf_Rela	 ra;
271a85fe12eSEd Maste 	GElf_Shdr	 sh;
272a85fe12eSEd Maste 	size_t		 n, indx;
273a85fe12eSEd Maste 	int		 elferr, i, len;
274a85fe12eSEd Maste 
275a85fe12eSEd Maste 	ecp->v_rel = calloc((sc + 7) / 8, 1);
276a85fe12eSEd Maste 	if (ecp->v_rel == NULL)
277a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
278a85fe12eSEd Maste 
279a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
280a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
281a85fe12eSEd Maste 		    elf_errmsg(-1));
282a85fe12eSEd Maste 
283a85fe12eSEd Maste 	s = NULL;
284a85fe12eSEd Maste 	while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
285a85fe12eSEd Maste 		if (gelf_getshdr(s, &sh) != &sh)
286a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
287a85fe12eSEd Maste 			    elf_errmsg(-1));
288a85fe12eSEd Maste 
289a85fe12eSEd Maste 		if (sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA)
290a85fe12eSEd Maste 			continue;
291a85fe12eSEd Maste 
292a85fe12eSEd Maste 		/*
293a85fe12eSEd Maste 		 * Skip if this reloc section won't appear in the
294a85fe12eSEd Maste 		 * output object.
295a85fe12eSEd Maste 		 */
296a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
297a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
298a85fe12eSEd Maste 			    elf_errmsg(-1));
299a85fe12eSEd Maste 		if (is_remove_section(ecp, name) ||
300a85fe12eSEd Maste 		    is_remove_reloc_sec(ecp, sh.sh_info))
301a85fe12eSEd Maste 			continue;
302a85fe12eSEd Maste 
303a85fe12eSEd Maste 		/* Skip if it's not for .symtab */
304a85fe12eSEd Maste 		if (sh.sh_link != elf_ndxscn(ecp->symtab->is))
305a85fe12eSEd Maste 			continue;
306a85fe12eSEd Maste 
307a85fe12eSEd Maste 		d = NULL;
308a85fe12eSEd Maste 		n = 0;
309a85fe12eSEd Maste 		while (n < sh.sh_size && (d = elf_getdata(s, d)) != NULL) {
310a85fe12eSEd Maste 			len = d->d_size / sh.sh_entsize;
311a85fe12eSEd Maste 			for (i = 0; i < len; i++) {
312a85fe12eSEd Maste 				if (sh.sh_type == SHT_REL) {
313a85fe12eSEd Maste 					if (gelf_getrel(d, i, &r) != &r)
314a85fe12eSEd Maste 						errx(EXIT_FAILURE,
315a85fe12eSEd Maste 						    "elf_getrel failed: %s",
316a85fe12eSEd Maste 						     elf_errmsg(-1));
317a85fe12eSEd Maste 					n = GELF_R_SYM(r.r_info);
318a85fe12eSEd Maste 				} else {
319a85fe12eSEd Maste 					if (gelf_getrela(d, i, &ra) != &ra)
320a85fe12eSEd Maste 						errx(EXIT_FAILURE,
321a85fe12eSEd Maste 						    "elf_getrela failed: %s",
322a85fe12eSEd Maste 						     elf_errmsg(-1));
323a85fe12eSEd Maste 					n = GELF_R_SYM(ra.r_info);
324a85fe12eSEd Maste 				}
325a85fe12eSEd Maste 				if (n > 0 && n < sc)
326a85fe12eSEd Maste 					BIT_SET(ecp->v_rel, n);
327a85fe12eSEd Maste 				else if (n != 0)
328a85fe12eSEd Maste 					warnx("invalid symbox index");
329a85fe12eSEd Maste 			}
330a85fe12eSEd Maste 		}
331a85fe12eSEd Maste 		elferr = elf_errno();
332a85fe12eSEd Maste 		if (elferr != 0)
333a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getdata failed: %s",
334a85fe12eSEd Maste 			    elf_errmsg(elferr));
335a85fe12eSEd Maste 	}
336a85fe12eSEd Maste 	elferr = elf_errno();
337a85fe12eSEd Maste 	if (elferr != 0)
338a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
339a85fe12eSEd Maste 		    elf_errmsg(elferr));
340a85fe12eSEd Maste }
341a85fe12eSEd Maste 
3423ef90571SEd Maste static void
3433ef90571SEd Maste mark_section_group_symbols(struct elfcopy *ecp, size_t sc)
3443ef90571SEd Maste {
3453ef90571SEd Maste 	const char	*name;
3463ef90571SEd Maste 	Elf_Scn		*s;
3473ef90571SEd Maste 	GElf_Shdr	 sh;
3483ef90571SEd Maste 	size_t		 indx;
3493ef90571SEd Maste 	int		 elferr;
3503ef90571SEd Maste 
3513ef90571SEd Maste 	ecp->v_grp = calloc((sc + 7) / 8, 1);
3523ef90571SEd Maste 	if (ecp->v_grp == NULL)
3533ef90571SEd Maste 		err(EXIT_FAILURE, "calloc failed");
3543ef90571SEd Maste 
3553ef90571SEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
3563ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
3573ef90571SEd Maste 		    elf_errmsg(-1));
3583ef90571SEd Maste 
3593ef90571SEd Maste 	s = NULL;
3603ef90571SEd Maste 	while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
3613ef90571SEd Maste 		if (gelf_getshdr(s, &sh) != &sh)
3623ef90571SEd Maste 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
3633ef90571SEd Maste 			    elf_errmsg(-1));
3643ef90571SEd Maste 
3653ef90571SEd Maste 		if (sh.sh_type != SHT_GROUP)
3663ef90571SEd Maste 			continue;
3673ef90571SEd Maste 
3683ef90571SEd Maste 		if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
3693ef90571SEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
3703ef90571SEd Maste 			    elf_errmsg(-1));
3713ef90571SEd Maste 		if (is_remove_section(ecp, name))
3723ef90571SEd Maste 			continue;
3733ef90571SEd Maste 
3743ef90571SEd Maste 		if (sh.sh_info > 0 && sh.sh_info < sc)
3753ef90571SEd Maste 			BIT_SET(ecp->v_grp, sh.sh_info);
3763ef90571SEd Maste 		else if (sh.sh_info != 0)
3773ef90571SEd Maste 			warnx("invalid symbox index");
3783ef90571SEd Maste 	}
3793ef90571SEd Maste 	elferr = elf_errno();
3803ef90571SEd Maste 	if (elferr != 0)
3813ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
3823ef90571SEd Maste 		    elf_errmsg(elferr));
3833ef90571SEd Maste }
3843ef90571SEd Maste 
385a85fe12eSEd Maste static int
386a85fe12eSEd Maste generate_symbols(struct elfcopy *ecp)
387a85fe12eSEd Maste {
388a85fe12eSEd Maste 	struct section	*s;
389a85fe12eSEd Maste 	struct symop	*sp;
390a85fe12eSEd Maste 	struct symbuf	*sy_buf;
391a85fe12eSEd Maste 	struct strbuf	*st_buf;
392a85fe12eSEd Maste 	const char	*name;
393a85fe12eSEd Maste 	char		*newname;
394a85fe12eSEd Maste 	unsigned char	*gsym;
395a85fe12eSEd Maste 	GElf_Shdr	 ish;
396a85fe12eSEd Maste 	GElf_Sym	 sym;
397a85fe12eSEd Maste 	Elf_Data*	 id;
398a85fe12eSEd Maste 	Elf_Scn		*is;
399cf781b2eSEd Maste 	size_t		 ishstrndx, namelen, ndx, sc, symndx;
400a85fe12eSEd Maste 	int		 ec, elferr, i;
401a85fe12eSEd Maste 
402a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &ishstrndx) == 0)
403a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
404a85fe12eSEd Maste 		    elf_errmsg(-1));
405a85fe12eSEd Maste 	if ((ec = gelf_getclass(ecp->eout)) == ELFCLASSNONE)
406a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getclass failed: %s",
407a85fe12eSEd Maste 		    elf_errmsg(-1));
408a85fe12eSEd Maste 
409a85fe12eSEd Maste 	/* Create buffers for .symtab and .strtab. */
410a85fe12eSEd Maste 	if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
411a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
412a85fe12eSEd Maste 	if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
413a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
414a85fe12eSEd Maste 	sy_buf->gcap = sy_buf->lcap = 64;
4154a85c691SEd Maste 	st_buf->g.cap = 256;
4164a85c691SEd Maste 	st_buf->l.cap = 64;
4174a85c691SEd Maste 	st_buf->l.sz = 1;	/* '\0' at start. */
4184a85c691SEd Maste 	st_buf->g.sz = 0;
419a85fe12eSEd Maste 
420a85fe12eSEd Maste 	ecp->symtab->sz = 0;
421a85fe12eSEd Maste 	ecp->strtab->sz = 0;
422a85fe12eSEd Maste 	ecp->symtab->buf = sy_buf;
423a85fe12eSEd Maste 	ecp->strtab->buf = st_buf;
424a85fe12eSEd Maste 
4253ef90571SEd Maste 	gsym = NULL;
4263ef90571SEd Maste 
427a85fe12eSEd Maste 	/*
428a85fe12eSEd Maste 	 * Create bit vector v_secsym, which is used to mark sections
429a85fe12eSEd Maste 	 * that already have corresponding STT_SECTION symbols.
430a85fe12eSEd Maste 	 */
431a85fe12eSEd Maste 	ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1);
432a85fe12eSEd Maste 	if (ecp->v_secsym == NULL)
433a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
434a85fe12eSEd Maste 
435a85fe12eSEd Maste 	/* Locate .strtab of input object. */
436a85fe12eSEd Maste 	symndx = 0;
437a85fe12eSEd Maste 	name = NULL;
438a85fe12eSEd Maste 	is = NULL;
439a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
440a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) != &ish)
441a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
442a85fe12eSEd Maste 			    elf_errmsg(-1));
443a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
444a85fe12eSEd Maste 		    NULL)
445a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
446a85fe12eSEd Maste 			    elf_errmsg(-1));
447a85fe12eSEd Maste 		if (strcmp(name, ".strtab") == 0) {
448a85fe12eSEd Maste 			symndx = elf_ndxscn(is);
449a85fe12eSEd Maste 			break;
450a85fe12eSEd Maste 		}
451a85fe12eSEd Maste 	}
452a85fe12eSEd Maste 	elferr = elf_errno();
453a85fe12eSEd Maste 	if (elferr != 0)
454a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
455a85fe12eSEd Maste 		    elf_errmsg(elferr));
456a85fe12eSEd Maste 
457a85fe12eSEd Maste 	/* Symbol table should exist if this function is called. */
458a85fe12eSEd Maste 	if (symndx == 0) {
459a85fe12eSEd Maste 		warnx("can't find .strtab section");
4603ef90571SEd Maste 		goto clean;
461a85fe12eSEd Maste 	}
462a85fe12eSEd Maste 
463a85fe12eSEd Maste 	/* Locate .symtab of input object. */
464a85fe12eSEd Maste 	is = NULL;
465a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
466a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) != &ish)
467a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
468a85fe12eSEd Maste 			    elf_errmsg(-1));
469a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
470a85fe12eSEd Maste 		    NULL)
471a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
472a85fe12eSEd Maste 			    elf_errmsg(-1));
473a85fe12eSEd Maste 		if (strcmp(name, ".symtab") == 0)
474a85fe12eSEd Maste 			break;
475a85fe12eSEd Maste 	}
476a85fe12eSEd Maste 	elferr = elf_errno();
477a85fe12eSEd Maste 	if (elferr != 0)
478a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
479a85fe12eSEd Maste 		    elf_errmsg(elferr));
480a85fe12eSEd Maste 	if (is == NULL)
481a85fe12eSEd Maste 		errx(EXIT_FAILURE, "can't find .strtab section");
482a85fe12eSEd Maste 
483a85fe12eSEd Maste 	/*
484a85fe12eSEd Maste 	 * Create bit vector gsym to mark global symbols, and symndx
485a85fe12eSEd Maste 	 * to keep track of symbol index changes from input object to
486a85fe12eSEd Maste 	 * output object, it is used by update_reloc() later to update
487a85fe12eSEd Maste 	 * relocation information.
488a85fe12eSEd Maste 	 */
489a85fe12eSEd Maste 	sc = ish.sh_size / ish.sh_entsize;
490a85fe12eSEd Maste 	if (sc > 0) {
491a85fe12eSEd Maste 		ecp->symndx = calloc(sc, sizeof(*ecp->symndx));
492a85fe12eSEd Maste 		if (ecp->symndx == NULL)
493a85fe12eSEd Maste 			err(EXIT_FAILURE, "calloc failed");
494a85fe12eSEd Maste 		gsym = calloc((sc + 7) / 8, sizeof(*gsym));
495a85fe12eSEd Maste 		if (gsym == NULL)
496a85fe12eSEd Maste 			err(EXIT_FAILURE, "calloc failed");
497a85fe12eSEd Maste 		if ((id = elf_getdata(is, NULL)) == NULL) {
498a85fe12eSEd Maste 			elferr = elf_errno();
499a85fe12eSEd Maste 			if (elferr != 0)
500a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_getdata failed: %s",
501a85fe12eSEd Maste 				    elf_errmsg(elferr));
5023ef90571SEd Maste 			goto clean;
503a85fe12eSEd Maste 		}
504a85fe12eSEd Maste 	} else
505a85fe12eSEd Maste 		return (0);
506a85fe12eSEd Maste 
507a85fe12eSEd Maste 	/* Copy/Filter each symbol. */
508a85fe12eSEd Maste 	for (i = 0; (size_t)i < sc; i++) {
509a85fe12eSEd Maste 		if (gelf_getsym(id, i, &sym) != &sym)
510a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getsym failed: %s",
511a85fe12eSEd Maste 			    elf_errmsg(-1));
512a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL)
513a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
514a85fe12eSEd Maste 			    elf_errmsg(-1));
515a85fe12eSEd Maste 
516a85fe12eSEd Maste 		/* Symbol filtering. */
517a85fe12eSEd Maste 		if (is_remove_symbol(ecp, sc, i, &sym, name) != 0)
518a85fe12eSEd Maste 			continue;
519a85fe12eSEd Maste 
520a85fe12eSEd Maste 		/* Check if we need to change the binding of this symbol. */
521a85fe12eSEd Maste 		if (is_global_symbol(sym.st_info) ||
522a85fe12eSEd Maste 		    is_weak_symbol(sym.st_info)) {
523a85fe12eSEd Maste 			/*
524a85fe12eSEd Maste 			 * XXX Binutils objcopy does not weaken certain
525a85fe12eSEd Maste 			 * symbols.
526a85fe12eSEd Maste 			 */
527a85fe12eSEd Maste 			if (ecp->flags & WEAKEN_ALL ||
528a85fe12eSEd Maste 			    lookup_symop_list(ecp, name, SYMOP_WEAKEN) != NULL)
529a85fe12eSEd Maste 				sym.st_info = GELF_ST_INFO(STB_WEAK,
530a85fe12eSEd Maste 				    GELF_ST_TYPE(sym.st_info));
531a85fe12eSEd Maste 			/* Do not localize undefined symbols. */
532a85fe12eSEd Maste 			if (sym.st_shndx != SHN_UNDEF &&
533a85fe12eSEd Maste 			    lookup_symop_list(ecp, name, SYMOP_LOCALIZE) !=
534a85fe12eSEd Maste 			    NULL)
535a85fe12eSEd Maste 				sym.st_info = GELF_ST_INFO(STB_LOCAL,
536a85fe12eSEd Maste 				    GELF_ST_TYPE(sym.st_info));
537a85fe12eSEd Maste 			if (ecp->flags & KEEP_GLOBAL &&
538a85fe12eSEd Maste 			    sym.st_shndx != SHN_UNDEF &&
539a85fe12eSEd Maste 			    lookup_symop_list(ecp, name, SYMOP_KEEPG) == NULL)
540a85fe12eSEd Maste 				sym.st_info = GELF_ST_INFO(STB_LOCAL,
541a85fe12eSEd Maste 				    GELF_ST_TYPE(sym.st_info));
54267d97fe7SEd Maste 			if (ecp->flags & LOCALIZE_HIDDEN &&
54367d97fe7SEd Maste 			    sym.st_shndx != SHN_UNDEF &&
54467d97fe7SEd Maste 			    is_hidden_symbol(sym.st_other))
54567d97fe7SEd Maste 				sym.st_info = GELF_ST_INFO(STB_LOCAL,
54667d97fe7SEd Maste 				    GELF_ST_TYPE(sym.st_info));
547a85fe12eSEd Maste 		} else {
548a85fe12eSEd Maste 			/* STB_LOCAL binding. */
549a85fe12eSEd Maste 			if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) !=
550a85fe12eSEd Maste 			    NULL)
551a85fe12eSEd Maste 				sym.st_info = GELF_ST_INFO(STB_GLOBAL,
552a85fe12eSEd Maste 				    GELF_ST_TYPE(sym.st_info));
553a85fe12eSEd Maste 			/* XXX We should globalize weak symbol? */
554a85fe12eSEd Maste 		}
555a85fe12eSEd Maste 
556a85fe12eSEd Maste 		/* Check if we need to rename this symbol. */
557a85fe12eSEd Maste 		if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL)
558a85fe12eSEd Maste 			name = sp->newname;
559a85fe12eSEd Maste 
560a85fe12eSEd Maste 		/* Check if we need to prefix the symbols. */
561a85fe12eSEd Maste 		newname = NULL;
562a85fe12eSEd Maste 		if (ecp->prefix_sym != NULL && name != NULL && *name != '\0') {
563a85fe12eSEd Maste 			namelen = strlen(name) + strlen(ecp->prefix_sym) + 1;
564a85fe12eSEd Maste 			if ((newname = malloc(namelen)) == NULL)
565a85fe12eSEd Maste 				err(EXIT_FAILURE, "malloc failed");
566a85fe12eSEd Maste 			snprintf(newname, namelen, "%s%s", ecp->prefix_sym,
567a85fe12eSEd Maste 			    name);
568a85fe12eSEd Maste 			name = newname;
569a85fe12eSEd Maste 		}
570a85fe12eSEd Maste 
571a85fe12eSEd Maste 		/* Copy symbol, mark global/weak symbol and add to index map. */
572a85fe12eSEd Maste 		if (is_global_symbol(sym.st_info) ||
573a85fe12eSEd Maste 		    is_weak_symbol(sym.st_info)) {
574a85fe12eSEd Maste 			BIT_SET(gsym, i);
575a85fe12eSEd Maste 			ecp->symndx[i] = sy_buf->ngs;
576a85fe12eSEd Maste 		} else
577a85fe12eSEd Maste 			ecp->symndx[i] = sy_buf->nls;
578a85fe12eSEd Maste 		add_to_symtab(ecp, name, sym.st_value, sym.st_size,
579a85fe12eSEd Maste 		    sym.st_shndx, sym.st_info, sym.st_other, 0);
580a85fe12eSEd Maste 
581a85fe12eSEd Maste 		if (newname != NULL)
582a85fe12eSEd Maste 			free(newname);
583a85fe12eSEd Maste 
584a85fe12eSEd Maste 		/*
585a85fe12eSEd Maste 		 * If the symbol is a STT_SECTION symbol, mark the section
586a85fe12eSEd Maste 		 * it points to.
587a85fe12eSEd Maste 		 */
588*839529caSEd Maste 		if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
589*839529caSEd Maste 		    sym.st_shndx < SHN_LORESERVE) {
590*839529caSEd Maste 			assert(ecp->secndx[sym.st_shndx] < (uint64_t)ecp->nos);
591a85fe12eSEd Maste 			BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]);
592a85fe12eSEd Maste 		}
593*839529caSEd Maste 	}
594a85fe12eSEd Maste 
595a85fe12eSEd Maste 	/*
596a85fe12eSEd Maste 	 * Give up if there is no real symbols inside the table.
597a85fe12eSEd Maste 	 * XXX The logic here needs to be improved. We need to
598a85fe12eSEd Maste 	 * check if that only local symbol is the reserved symbol.
599a85fe12eSEd Maste 	 */
600a85fe12eSEd Maste 	if (sy_buf->nls <= 1 && sy_buf->ngs == 0)
6013ef90571SEd Maste 		goto clean;
602a85fe12eSEd Maste 
603a85fe12eSEd Maste 	/*
604a85fe12eSEd Maste 	 * Create STT_SECTION symbols for sections that do not already
605a85fe12eSEd Maste 	 * got one. However, we do not create STT_SECTION symbol for
606a85fe12eSEd Maste 	 * .symtab, .strtab, .shstrtab and reloc sec of relocatables.
607a85fe12eSEd Maste 	 */
608a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
609a85fe12eSEd Maste 		if (s->pseudo)
610a85fe12eSEd Maste 			continue;
611a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
612a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
613a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
614a85fe12eSEd Maste 			continue;
615a85fe12eSEd Maste 		if ((ecp->flags & RELOCATABLE) != 0 &&
616a85fe12eSEd Maste 		    ((s->type == SHT_REL) || (s->type == SHT_RELA)))
617a85fe12eSEd Maste 			continue;
618a85fe12eSEd Maste 
619a85fe12eSEd Maste 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
620a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
621a85fe12eSEd Maste 			    elf_errmsg(-1));
622a85fe12eSEd Maste 
623a85fe12eSEd Maste 		if (!BIT_ISSET(ecp->v_secsym, ndx)) {
624a85fe12eSEd Maste 			sym.st_name  = 0;
625a85fe12eSEd Maste 			sym.st_value = s->vma;
626a85fe12eSEd Maste 			sym.st_size  = 0;
627a85fe12eSEd Maste 			sym.st_info  = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
6283ef90571SEd Maste 			sym.st_other = STV_DEFAULT;
629a85fe12eSEd Maste 			/*
630a85fe12eSEd Maste 			 * Don't let add_to_symtab() touch sym.st_shndx.
631a85fe12eSEd Maste 			 * In this case, we know the index already.
632a85fe12eSEd Maste 			 */
633a85fe12eSEd Maste 			add_to_symtab(ecp, NULL, sym.st_value, sym.st_size,
634a85fe12eSEd Maste 			    ndx, sym.st_info, sym.st_other, 1);
635a85fe12eSEd Maste 		}
636a85fe12eSEd Maste 	}
637a85fe12eSEd Maste 
638a85fe12eSEd Maste 	/*
639a85fe12eSEd Maste 	 * Update st_name and index map for global/weak symbols. Note that
640a85fe12eSEd Maste 	 * global/weak symbols are put after local symbols.
641a85fe12eSEd Maste 	 */
642a85fe12eSEd Maste 	if (gsym != NULL) {
643a85fe12eSEd Maste 		for(i = 0; (size_t) i < sc; i++) {
644a85fe12eSEd Maste 			if (!BIT_ISSET(gsym, i))
645a85fe12eSEd Maste 				continue;
646a85fe12eSEd Maste 
647a85fe12eSEd Maste 			/* Update st_name. */
648a85fe12eSEd Maste 			if (ec == ELFCLASS32)
649a85fe12eSEd Maste 				sy_buf->g32[ecp->symndx[i]].st_name +=
6504a85c691SEd Maste 				    st_buf->l.sz;
651a85fe12eSEd Maste 			else
652a85fe12eSEd Maste 				sy_buf->g64[ecp->symndx[i]].st_name +=
6534a85c691SEd Maste 				    st_buf->l.sz;
654a85fe12eSEd Maste 
655a85fe12eSEd Maste 			/* Update index map. */
656a85fe12eSEd Maste 			ecp->symndx[i] += sy_buf->nls;
657a85fe12eSEd Maste 		}
658a85fe12eSEd Maste 		free(gsym);
659a85fe12eSEd Maste 	}
660a85fe12eSEd Maste 
661a85fe12eSEd Maste 	return (1);
6623ef90571SEd Maste 
6633ef90571SEd Maste clean:
6643ef90571SEd Maste 	free(gsym);
6653ef90571SEd Maste 	free_symtab(ecp);
6663ef90571SEd Maste 
6673ef90571SEd Maste 	return (0);
668a85fe12eSEd Maste }
669a85fe12eSEd Maste 
670a85fe12eSEd Maste void
671a85fe12eSEd Maste create_symtab(struct elfcopy *ecp)
672a85fe12eSEd Maste {
673a85fe12eSEd Maste 	struct section	*s, *sy, *st;
674a85fe12eSEd Maste 	size_t		 maxndx, ndx;
675a85fe12eSEd Maste 
676a85fe12eSEd Maste 	sy = ecp->symtab;
677a85fe12eSEd Maste 	st = ecp->strtab;
678a85fe12eSEd Maste 
679a85fe12eSEd Maste 	/*
680a85fe12eSEd Maste 	 * Set section index map for .symtab and .strtab. We need to set
681a85fe12eSEd Maste 	 * these map because otherwise symbols which refer to .symtab and
682a85fe12eSEd Maste 	 * .strtab will be removed by symbol filtering unconditionally.
683a85fe12eSEd Maste 	 * And we have to figure out scn index this way (instead of calling
684a85fe12eSEd Maste 	 * elf_ndxscn) because we can not create Elf_Scn before we're certain
685a85fe12eSEd Maste 	 * that .symtab and .strtab will exist in the output object.
686a85fe12eSEd Maste 	 */
687a85fe12eSEd Maste 	maxndx = 0;
688a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
689a85fe12eSEd Maste 		if (s->os == NULL)
690a85fe12eSEd Maste 			continue;
691a85fe12eSEd Maste 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
692a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
693a85fe12eSEd Maste 			    elf_errmsg(-1));
694a85fe12eSEd Maste 		if (ndx > maxndx)
695a85fe12eSEd Maste 			maxndx = ndx;
696a85fe12eSEd Maste 	}
697a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1;
698a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2;
699a85fe12eSEd Maste 
700a85fe12eSEd Maste 	/*
701a85fe12eSEd Maste 	 * Generate symbols for output object if SYMTAB_INTACT is not set.
702a85fe12eSEd Maste 	 * If there is no symbol in the input object or all the symbols are
703a85fe12eSEd Maste 	 * stripped, then free all the resouces allotted for symbol table,
704a85fe12eSEd Maste 	 * and clear SYMTAB_EXIST flag.
705a85fe12eSEd Maste 	 */
706a85fe12eSEd Maste 	if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) {
707a85fe12eSEd Maste 		TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list);
708a85fe12eSEd Maste 		TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list);
7093ef90571SEd Maste 		free(ecp->symtab->buf);
710a85fe12eSEd Maste 		free(ecp->symtab);
7113ef90571SEd Maste 		free(ecp->strtab->buf);
712a85fe12eSEd Maste 		free(ecp->strtab);
713a85fe12eSEd Maste 		ecp->symtab = NULL;
714a85fe12eSEd Maste 		ecp->strtab = NULL;
715a85fe12eSEd Maste 		ecp->flags &= ~SYMTAB_EXIST;
716a85fe12eSEd Maste 		return;
717a85fe12eSEd Maste 	}
718a85fe12eSEd Maste 
719a85fe12eSEd Maste 	/* Create output Elf_Scn for .symtab and .strtab. */
720a85fe12eSEd Maste 	if ((sy->os = elf_newscn(ecp->eout)) == NULL ||
721a85fe12eSEd Maste 	    (st->os = elf_newscn(ecp->eout)) == NULL)
722a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newscn failed: %s",
723a85fe12eSEd Maste 		    elf_errmsg(-1));
724a85fe12eSEd Maste 	/* Update secndx anyway. */
725a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os);
726a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os);
727a85fe12eSEd Maste 
728a85fe12eSEd Maste 	/*
729a85fe12eSEd Maste 	 * Copy .symtab and .strtab section headers from input to output
730a85fe12eSEd Maste 	 * object to start with, these will be overridden later if need.
731a85fe12eSEd Maste 	 */
732a85fe12eSEd Maste 	copy_shdr(ecp, sy, ".symtab", 1, 0);
733a85fe12eSEd Maste 	copy_shdr(ecp, st, ".strtab", 1, 0);
734a85fe12eSEd Maste 
735a85fe12eSEd Maste 	/* Copy verbatim if symbol table is intact. */
736a85fe12eSEd Maste 	if (ecp->flags & SYMTAB_INTACT) {
737a85fe12eSEd Maste 		copy_data(sy);
738a85fe12eSEd Maste 		copy_data(st);
739a85fe12eSEd Maste 		return;
740a85fe12eSEd Maste 	}
741a85fe12eSEd Maste 
742a85fe12eSEd Maste 	create_symtab_data(ecp);
743a85fe12eSEd Maste }
744a85fe12eSEd Maste 
745a85fe12eSEd Maste void
746a85fe12eSEd Maste free_symtab(struct elfcopy *ecp)
747a85fe12eSEd Maste {
748a85fe12eSEd Maste 	struct symbuf	*sy_buf;
749a85fe12eSEd Maste 	struct strbuf	*st_buf;
7504a85c691SEd Maste 	struct sthash	*sh, *shtmp;
7514a85c691SEd Maste 	int i;
752a85fe12eSEd Maste 
753a85fe12eSEd Maste 	if (ecp->symtab != NULL && ecp->symtab->buf != NULL) {
754a85fe12eSEd Maste 		sy_buf = ecp->symtab->buf;
755a85fe12eSEd Maste 		if (sy_buf->l32 != NULL)
756a85fe12eSEd Maste 			free(sy_buf->l32);
757a85fe12eSEd Maste 		if (sy_buf->g32 != NULL)
758a85fe12eSEd Maste 			free(sy_buf->g32);
759a85fe12eSEd Maste 		if (sy_buf->l64 != NULL)
760a85fe12eSEd Maste 			free(sy_buf->l64);
761a85fe12eSEd Maste 		if (sy_buf->g64 != NULL)
762a85fe12eSEd Maste 			free(sy_buf->g64);
763a85fe12eSEd Maste 	}
764a85fe12eSEd Maste 
765a85fe12eSEd Maste 	if (ecp->strtab != NULL && ecp->strtab->buf != NULL) {
766a85fe12eSEd Maste 		st_buf = ecp->strtab->buf;
7674a85c691SEd Maste 		if (st_buf->l.buf != NULL)
7684a85c691SEd Maste 			free(st_buf->l.buf);
7694a85c691SEd Maste 		if (st_buf->g.buf != NULL)
7704a85c691SEd Maste 			free(st_buf->g.buf);
7714a85c691SEd Maste 		for (i = 0; i < STHASHSIZE; i++) {
7724a85c691SEd Maste 			LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next,
7734a85c691SEd Maste 			    shtmp) {
7744a85c691SEd Maste 				LIST_REMOVE(sh, sh_next);
7754a85c691SEd Maste 				free(sh);
7764a85c691SEd Maste 			}
7774a85c691SEd Maste 			LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next,
7784a85c691SEd Maste 			    shtmp) {
7794a85c691SEd Maste 				LIST_REMOVE(sh, sh_next);
7804a85c691SEd Maste 				free(sh);
7814a85c691SEd Maste 			}
7824a85c691SEd Maste 		}
783a85fe12eSEd Maste 	}
7843ef90571SEd Maste 
7853ef90571SEd Maste 	if (ecp->symndx != NULL) {
7863ef90571SEd Maste 		free(ecp->symndx);
7873ef90571SEd Maste 		ecp->symndx = NULL;
7883ef90571SEd Maste 	}
7893ef90571SEd Maste 	if (ecp->v_rel != NULL) {
7903ef90571SEd Maste 		free(ecp->v_rel);
7913ef90571SEd Maste 		ecp->v_rel = NULL;
7923ef90571SEd Maste 	}
7933ef90571SEd Maste 	if (ecp->v_grp != NULL) {
7943ef90571SEd Maste 		free(ecp->v_grp);
7953ef90571SEd Maste 		ecp->v_grp = NULL;
7963ef90571SEd Maste 	}
7973ef90571SEd Maste 	if (ecp->v_secsym != NULL) {
7983ef90571SEd Maste 		free(ecp->v_secsym);
7993ef90571SEd Maste 		ecp->v_secsym = NULL;
8003ef90571SEd Maste 	}
801a85fe12eSEd Maste }
802a85fe12eSEd Maste 
803a85fe12eSEd Maste void
804a85fe12eSEd Maste create_external_symtab(struct elfcopy *ecp)
805a85fe12eSEd Maste {
806a85fe12eSEd Maste 	struct section *s;
807a85fe12eSEd Maste 	struct symbuf *sy_buf;
808a85fe12eSEd Maste 	struct strbuf *st_buf;
809a85fe12eSEd Maste 	GElf_Shdr sh;
810a85fe12eSEd Maste 	size_t ndx;
811a85fe12eSEd Maste 
812a85fe12eSEd Maste 	if (ecp->oec == ELFCLASS32)
813a85fe12eSEd Maste 		ecp->symtab = create_external_section(ecp, ".symtab", NULL,
814a85fe12eSEd Maste 		    NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0);
815a85fe12eSEd Maste 	else
816a85fe12eSEd Maste 		ecp->symtab = create_external_section(ecp, ".symtab", NULL,
817a85fe12eSEd Maste 		    NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0);
818a85fe12eSEd Maste 
819a85fe12eSEd Maste 	ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0,
820a85fe12eSEd Maste 	    SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0);
821a85fe12eSEd Maste 
822a85fe12eSEd Maste 	/* Let sh_link field of .symtab section point to .strtab section. */
823a85fe12eSEd Maste 	if (gelf_getshdr(ecp->symtab->os, &sh) == NULL)
824a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
825a85fe12eSEd Maste 		    elf_errmsg(-1));
826a85fe12eSEd Maste 	sh.sh_link = elf_ndxscn(ecp->strtab->os);
827a85fe12eSEd Maste 	if (!gelf_update_shdr(ecp->symtab->os, &sh))
828a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
829a85fe12eSEd Maste 		    elf_errmsg(-1));
830a85fe12eSEd Maste 
831a85fe12eSEd Maste 	/* Create buffers for .symtab and .strtab. */
832a85fe12eSEd Maste 	if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
833a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
834a85fe12eSEd Maste 	if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
835a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
836a85fe12eSEd Maste 	sy_buf->gcap = sy_buf->lcap = 64;
8374a85c691SEd Maste 	st_buf->g.cap = 256;
8384a85c691SEd Maste 	st_buf->l.cap = 64;
8394a85c691SEd Maste 	st_buf->l.sz = 1;	/* '\0' at start. */
8404a85c691SEd Maste 	st_buf->g.sz = 0;
841a85fe12eSEd Maste 
842a85fe12eSEd Maste 	ecp->symtab->sz = 0;
843a85fe12eSEd Maste 	ecp->strtab->sz = 0;
844a85fe12eSEd Maste 	ecp->symtab->buf = sy_buf;
845a85fe12eSEd Maste 	ecp->strtab->buf = st_buf;
846a85fe12eSEd Maste 
847a85fe12eSEd Maste 	/* Always create the special symbol at the symtab beginning. */
848a85fe12eSEd Maste 	add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF,
849a85fe12eSEd Maste 	    ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1);
850a85fe12eSEd Maste 
851a85fe12eSEd Maste 	/* Create STT_SECTION symbols. */
852a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
853a85fe12eSEd Maste 		if (s->pseudo)
854a85fe12eSEd Maste 			continue;
855a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
856a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
857a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
858a85fe12eSEd Maste 			continue;
859a85fe12eSEd Maste 		(void) elf_errno();
860a85fe12eSEd Maste 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) {
861a85fe12eSEd Maste 			warnx("elf_ndxscn failed: %s",
862a85fe12eSEd Maste 			    elf_errmsg(-1));
863a85fe12eSEd Maste 			continue;
864a85fe12eSEd Maste 		}
865a85fe12eSEd Maste 		add_to_symtab(ecp, NULL, 0, 0, ndx,
866a85fe12eSEd Maste 		    GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1);
867a85fe12eSEd Maste 	}
868a85fe12eSEd Maste }
869a85fe12eSEd Maste 
870a85fe12eSEd Maste void
871a85fe12eSEd Maste add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value,
872a85fe12eSEd Maste     uint64_t st_size, uint16_t st_shndx, unsigned char st_info,
873a85fe12eSEd Maste     unsigned char st_other, int ndx_known)
874a85fe12eSEd Maste {
875a85fe12eSEd Maste 	struct symbuf *sy_buf;
876a85fe12eSEd Maste 	struct strbuf *st_buf;
8774a85c691SEd Maste 	struct sthash *sh;
8784a85c691SEd Maste 	uint32_t hash;
879a85fe12eSEd Maste 	int pos;
880a85fe12eSEd Maste 
881a85fe12eSEd Maste 	/*
882a85fe12eSEd Maste 	 * Convenient macro for copying global/local 32/64 bit symbols
883a85fe12eSEd Maste 	 * from input object to the buffer created for output object.
884a85fe12eSEd Maste 	 * It handles buffer growing, st_name calculating and st_shndx
885a85fe12eSEd Maste 	 * updating for symbols with non-special section index.
886a85fe12eSEd Maste 	 */
887*839529caSEd Maste #define	_ST_NAME_EMPTY_l 0
888*839529caSEd Maste #define	_ST_NAME_EMPTY_g -1
889a85fe12eSEd Maste #define	_ADDSYM(B, SZ) do {						\
890a85fe12eSEd Maste 	if (sy_buf->B##SZ == NULL) {					\
891a85fe12eSEd Maste 		sy_buf->B##SZ = malloc(sy_buf->B##cap *			\
892a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Sym));				\
893a85fe12eSEd Maste 		if (sy_buf->B##SZ == NULL)				\
894a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");		\
895a85fe12eSEd Maste 	} else if (sy_buf->n##B##s >= sy_buf->B##cap) {			\
896a85fe12eSEd Maste 		sy_buf->B##cap *= 2;					\
897a85fe12eSEd Maste 		sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap *	\
898a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Sym));				\
899a85fe12eSEd Maste 		if (sy_buf->B##SZ == NULL)				\
900a85fe12eSEd Maste 			err(EXIT_FAILURE, "realloc failed");		\
901a85fe12eSEd Maste 	}								\
902a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_info	= st_info;		\
903a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_other	= st_other;		\
904a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_value	= st_value;		\
905a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_size	= st_size;		\
906a85fe12eSEd Maste 	if (ndx_known)							\
907a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;	\
908a85fe12eSEd Maste 	else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE)	\
909a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;	\
910a85fe12eSEd Maste 	else								\
911a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx	=		\
912a85fe12eSEd Maste 			ecp->secndx[st_shndx];				\
9134a85c691SEd Maste 	if (st_buf->B.buf == NULL) {					\
9144a85c691SEd Maste 		st_buf->B.buf = calloc(st_buf->B.cap,			\
9154a85c691SEd Maste 		    sizeof(*st_buf->B.buf));				\
9164a85c691SEd Maste 		if (st_buf->B.buf == NULL)				\
917a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");		\
918a85fe12eSEd Maste 	}								\
919a85fe12eSEd Maste 	if (name != NULL && *name != '\0') {				\
9204a85c691SEd Maste 		pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\
9214a85c691SEd Maste 		    name);						\
922a85fe12eSEd Maste 		if (pos != -1)						\
923a85fe12eSEd Maste 			sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos;	\
924a85fe12eSEd Maste 		else {							\
925a85fe12eSEd Maste 			sy_buf->B##SZ[sy_buf->n##B##s].st_name =	\
9264a85c691SEd Maste 			    st_buf->B.sz;				\
9274a85c691SEd Maste 			while (st_buf->B.sz + strlen(name) >=		\
9284a85c691SEd Maste 			    st_buf->B.cap - 1) {			\
9294a85c691SEd Maste 				st_buf->B.cap *= 2;			\
9304a85c691SEd Maste 				st_buf->B.buf = realloc(st_buf->B.buf,	\
9314a85c691SEd Maste 				    st_buf->B.cap);			\
9324a85c691SEd Maste 				if (st_buf->B.buf == NULL)		\
933a85fe12eSEd Maste 					err(EXIT_FAILURE,		\
934a85fe12eSEd Maste 					    "realloc failed");		\
935a85fe12eSEd Maste 			}						\
9364a85c691SEd Maste 			if ((sh = malloc(sizeof(*sh))) == NULL)		\
9374a85c691SEd Maste 				err(EXIT_FAILURE, "malloc failed");	\
9384a85c691SEd Maste 			sh->sh_off = st_buf->B.sz;			\
9394a85c691SEd Maste 			hash = str_hash(name);				\
9404a85c691SEd Maste 			LIST_INSERT_HEAD(&st_buf->B.hash[hash], sh,	\
9414a85c691SEd Maste 			    sh_next);					\
9424a85c691SEd Maste 			strncpy(&st_buf->B.buf[st_buf->B.sz], name,	\
943a85fe12eSEd Maste 			    strlen(name));				\
9444a85c691SEd Maste 			st_buf->B.buf[st_buf->B.sz + strlen(name)] = '\0'; \
9454a85c691SEd Maste 			st_buf->B.sz += strlen(name) + 1;		\
946a85fe12eSEd Maste 		}							\
947a85fe12eSEd Maste 	} else								\
948*839529caSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_name = 		\
949*839529caSEd Maste 		    (Elf##SZ##_Word)_ST_NAME_EMPTY_##B;			\
950a85fe12eSEd Maste 	sy_buf->n##B##s++;						\
951a85fe12eSEd Maste } while (0)
952a85fe12eSEd Maste 
953a85fe12eSEd Maste 	sy_buf = ecp->symtab->buf;
954a85fe12eSEd Maste 	st_buf = ecp->strtab->buf;
955a85fe12eSEd Maste 
956a85fe12eSEd Maste 	if (ecp->oec == ELFCLASS32) {
957a85fe12eSEd Maste 		if (is_local_symbol(st_info))
958a85fe12eSEd Maste 			_ADDSYM(l, 32);
959a85fe12eSEd Maste 		else
960a85fe12eSEd Maste 			_ADDSYM(g, 32);
961a85fe12eSEd Maste 	} else {
962a85fe12eSEd Maste 		if (is_local_symbol(st_info))
963a85fe12eSEd Maste 			_ADDSYM(l, 64);
964a85fe12eSEd Maste 		else
965a85fe12eSEd Maste 			_ADDSYM(g, 64);
966a85fe12eSEd Maste 	}
967a85fe12eSEd Maste 
968a85fe12eSEd Maste 	/* Update section size. */
969a85fe12eSEd Maste 	ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) *
970a85fe12eSEd Maste 	    (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym));
9714a85c691SEd Maste 	ecp->strtab->sz = st_buf->l.sz + st_buf->g.sz;
972a85fe12eSEd Maste 
973a85fe12eSEd Maste #undef	_ADDSYM
974*839529caSEd Maste #undef	_ST_NAME_EMPTY_l
975*839529caSEd Maste #undef	_ST_NAME_EMPTY_g
976a85fe12eSEd Maste }
977a85fe12eSEd Maste 
978a85fe12eSEd Maste void
979a85fe12eSEd Maste finalize_external_symtab(struct elfcopy *ecp)
980a85fe12eSEd Maste {
981a85fe12eSEd Maste 	struct symbuf *sy_buf;
982a85fe12eSEd Maste 	struct strbuf *st_buf;
983a85fe12eSEd Maste 	int i;
984a85fe12eSEd Maste 
985a85fe12eSEd Maste 	/*
986a85fe12eSEd Maste 	 * Update st_name for global/weak symbols. (global/weak symbols
987a85fe12eSEd Maste 	 * are put after local symbols)
988a85fe12eSEd Maste 	 */
989a85fe12eSEd Maste 	sy_buf = ecp->symtab->buf;
990a85fe12eSEd Maste 	st_buf = ecp->strtab->buf;
991a85fe12eSEd Maste 	for (i = 0; (size_t) i < sy_buf->ngs; i++) {
992*839529caSEd Maste 		if (ecp->oec == ELFCLASS32) {
993*839529caSEd Maste 			if (sy_buf->g32[i].st_name == (Elf32_Word)-1)
994*839529caSEd Maste 				sy_buf->g32[i].st_name = 0;
995*839529caSEd Maste 			else
9964a85c691SEd Maste 				sy_buf->g32[i].st_name += st_buf->l.sz;
997*839529caSEd Maste 		} else {
998*839529caSEd Maste 			if (sy_buf->g64[i].st_name == (Elf64_Word)-1)
999*839529caSEd Maste 				sy_buf->g64[i].st_name = 0;
1000a85fe12eSEd Maste 			else
10014a85c691SEd Maste 				sy_buf->g64[i].st_name += st_buf->l.sz;
1002a85fe12eSEd Maste 		}
1003a85fe12eSEd Maste 	}
1004*839529caSEd Maste }
1005a85fe12eSEd Maste 
1006a85fe12eSEd Maste void
1007a85fe12eSEd Maste create_symtab_data(struct elfcopy *ecp)
1008a85fe12eSEd Maste {
1009a85fe12eSEd Maste 	struct section	*sy, *st;
1010a85fe12eSEd Maste 	struct symbuf	*sy_buf;
1011a85fe12eSEd Maste 	struct strbuf	*st_buf;
1012a85fe12eSEd Maste 	Elf_Data	*gsydata, *lsydata, *gstdata, *lstdata;
1013a85fe12eSEd Maste 	GElf_Shdr	 shy, sht;
1014a85fe12eSEd Maste 
1015a85fe12eSEd Maste 	sy = ecp->symtab;
1016a85fe12eSEd Maste 	st = ecp->strtab;
1017a85fe12eSEd Maste 
1018a85fe12eSEd Maste 	if (gelf_getshdr(sy->os, &shy) == NULL)
1019a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1020a85fe12eSEd Maste 		    elf_errmsg(-1));
1021a85fe12eSEd Maste 	if (gelf_getshdr(st->os, &sht) == NULL)
1022a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1023a85fe12eSEd Maste 		    elf_errmsg(-1));
1024a85fe12eSEd Maste 
1025a85fe12eSEd Maste 	/*
1026a85fe12eSEd Maste 	 * Create two Elf_Data for .symtab section of output object, one
1027a85fe12eSEd Maste 	 * for local symbols and another for global symbols. Note that
1028a85fe12eSEd Maste 	 * local symbols appear first in the .symtab.
1029a85fe12eSEd Maste 	 */
1030a85fe12eSEd Maste 	sy_buf = sy->buf;
1031a85fe12eSEd Maste 	if (sy_buf->nls > 0) {
1032a85fe12eSEd Maste 		if ((lsydata = elf_newdata(sy->os)) == NULL)
1033a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1034a85fe12eSEd Maste 			     elf_errmsg(-1));
1035a85fe12eSEd Maste 		if (ecp->oec == ELFCLASS32) {
1036a85fe12eSEd Maste 			lsydata->d_align	= 4;
1037a85fe12eSEd Maste 			lsydata->d_off		= 0;
1038a85fe12eSEd Maste 			lsydata->d_buf		= sy_buf->l32;
1039a85fe12eSEd Maste 			lsydata->d_size		= sy_buf->nls *
1040a85fe12eSEd Maste 				sizeof(Elf32_Sym);
1041a85fe12eSEd Maste 			lsydata->d_type		= ELF_T_SYM;
1042a85fe12eSEd Maste 			lsydata->d_version	= EV_CURRENT;
1043a85fe12eSEd Maste 		} else {
1044a85fe12eSEd Maste 			lsydata->d_align	= 8;
1045a85fe12eSEd Maste 			lsydata->d_off		= 0;
1046a85fe12eSEd Maste 			lsydata->d_buf		= sy_buf->l64;
1047a85fe12eSEd Maste 			lsydata->d_size		= sy_buf->nls *
1048a85fe12eSEd Maste 				sizeof(Elf64_Sym);
1049a85fe12eSEd Maste 			lsydata->d_type		= ELF_T_SYM;
1050a85fe12eSEd Maste 			lsydata->d_version	= EV_CURRENT;
1051a85fe12eSEd Maste 		}
1052a85fe12eSEd Maste 	}
1053a85fe12eSEd Maste 	if (sy_buf->ngs > 0) {
1054a85fe12eSEd Maste 		if ((gsydata = elf_newdata(sy->os)) == NULL)
1055a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1056a85fe12eSEd Maste 			     elf_errmsg(-1));
1057a85fe12eSEd Maste 		if (ecp->oec == ELFCLASS32) {
1058a85fe12eSEd Maste 			gsydata->d_align	= 4;
1059a85fe12eSEd Maste 			gsydata->d_off		= sy_buf->nls *
1060a85fe12eSEd Maste 				sizeof(Elf32_Sym);
1061a85fe12eSEd Maste 			gsydata->d_buf		= sy_buf->g32;
1062a85fe12eSEd Maste 			gsydata->d_size		= sy_buf->ngs *
1063a85fe12eSEd Maste 				sizeof(Elf32_Sym);
1064a85fe12eSEd Maste 			gsydata->d_type		= ELF_T_SYM;
1065a85fe12eSEd Maste 			gsydata->d_version	= EV_CURRENT;
1066a85fe12eSEd Maste 		} else {
1067a85fe12eSEd Maste 			gsydata->d_align	= 8;
1068a85fe12eSEd Maste 			gsydata->d_off		= sy_buf->nls *
1069a85fe12eSEd Maste 				sizeof(Elf64_Sym);
1070a85fe12eSEd Maste 			gsydata->d_buf		= sy_buf->g64;
1071a85fe12eSEd Maste 			gsydata->d_size		= sy_buf->ngs *
1072a85fe12eSEd Maste 				sizeof(Elf64_Sym);
1073a85fe12eSEd Maste 			gsydata->d_type		= ELF_T_SYM;
1074a85fe12eSEd Maste 			gsydata->d_version	= EV_CURRENT;
1075a85fe12eSEd Maste 		}
1076a85fe12eSEd Maste 	}
1077a85fe12eSEd Maste 
1078a85fe12eSEd Maste 	/*
1079a85fe12eSEd Maste 	 * Create two Elf_Data for .strtab, one for local symbol name
1080a85fe12eSEd Maste 	 * and another for globals. Same as .symtab, local symbol names
1081a85fe12eSEd Maste 	 * appear first.
1082a85fe12eSEd Maste 	 */
1083a85fe12eSEd Maste 	st_buf = st->buf;
1084a85fe12eSEd Maste 	if ((lstdata = elf_newdata(st->os)) == NULL)
1085a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1086a85fe12eSEd Maste 		    elf_errmsg(-1));
1087a85fe12eSEd Maste 	lstdata->d_align	= 1;
1088a85fe12eSEd Maste 	lstdata->d_off		= 0;
10894a85c691SEd Maste 	lstdata->d_buf		= st_buf->l.buf;
10904a85c691SEd Maste 	lstdata->d_size		= st_buf->l.sz;
1091a85fe12eSEd Maste 	lstdata->d_type		= ELF_T_BYTE;
1092a85fe12eSEd Maste 	lstdata->d_version	= EV_CURRENT;
1093a85fe12eSEd Maste 
10944a85c691SEd Maste 	if (st_buf->g.sz > 0) {
1095a85fe12eSEd Maste 		if ((gstdata = elf_newdata(st->os)) == NULL)
1096a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1097a85fe12eSEd Maste 			    elf_errmsg(-1));
1098a85fe12eSEd Maste 		gstdata->d_align	= 1;
1099a85fe12eSEd Maste 		gstdata->d_off		= lstdata->d_size;
11004a85c691SEd Maste 		gstdata->d_buf		= st_buf->g.buf;
11014a85c691SEd Maste 		gstdata->d_size		= st_buf->g.sz;
1102a85fe12eSEd Maste 		gstdata->d_type		= ELF_T_BYTE;
1103a85fe12eSEd Maste 		gstdata->d_version	= EV_CURRENT;
1104a85fe12eSEd Maste 	}
1105a85fe12eSEd Maste 
1106a85fe12eSEd Maste 	shy.sh_addr		= 0;
1107a85fe12eSEd Maste 	shy.sh_addralign	= (ecp->oec == ELFCLASS32 ? 4 : 8);
1108a85fe12eSEd Maste 	shy.sh_size		= sy->sz;
1109a85fe12eSEd Maste 	shy.sh_type		= SHT_SYMTAB;
1110a85fe12eSEd Maste 	shy.sh_flags		= 0;
1111a85fe12eSEd Maste 	shy.sh_entsize		= gelf_fsize(ecp->eout, ELF_T_SYM, 1,
1112a85fe12eSEd Maste 	    EV_CURRENT);
1113a85fe12eSEd Maste 	/*
1114a85fe12eSEd Maste 	 * According to SYSV abi, here sh_info is one greater than
1115a85fe12eSEd Maste 	 * the symbol table index of the last local symbol(binding
1116a85fe12eSEd Maste 	 * STB_LOCAL).
1117a85fe12eSEd Maste 	 */
1118a85fe12eSEd Maste 	shy.sh_info		= sy_buf->nls;
1119a85fe12eSEd Maste 
1120a85fe12eSEd Maste 	sht.sh_addr		= 0;
1121a85fe12eSEd Maste 	sht.sh_addralign	= 1;
1122a85fe12eSEd Maste 	sht.sh_size		= st->sz;
1123a85fe12eSEd Maste 	sht.sh_type		= SHT_STRTAB;
1124a85fe12eSEd Maste 	sht.sh_flags		= 0;
1125a85fe12eSEd Maste 	sht.sh_entsize		= 0;
1126a85fe12eSEd Maste 	sht.sh_info		= 0;
1127a85fe12eSEd Maste 	sht.sh_link		= 0;
1128a85fe12eSEd Maste 
1129a85fe12eSEd Maste 	if (!gelf_update_shdr(sy->os, &shy))
1130a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1131a85fe12eSEd Maste 		    elf_errmsg(-1));
1132a85fe12eSEd Maste 	if (!gelf_update_shdr(st->os, &sht))
1133a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1134a85fe12eSEd Maste 		    elf_errmsg(-1));
1135a85fe12eSEd Maste }
1136a85fe12eSEd Maste 
1137a85fe12eSEd Maste void
1138a85fe12eSEd Maste add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname,
1139a85fe12eSEd Maste     unsigned int op)
1140a85fe12eSEd Maste {
1141a85fe12eSEd Maste 	struct symop *s;
1142a85fe12eSEd Maste 
1143*839529caSEd Maste 	assert (name != NULL);
1144*839529caSEd Maste 	STAILQ_FOREACH(s, &ecp->v_symop, symop_list)
1145*839529caSEd Maste 		if (!strcmp(name, s->name))
1146*839529caSEd Maste 			goto found;
1147*839529caSEd Maste 
1148a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
1149a85fe12eSEd Maste 		errx(EXIT_FAILURE, "not enough memory");
1150*839529caSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list);
1151a85fe12eSEd Maste 	s->name = name;
1152*839529caSEd Maste found:
1153a85fe12eSEd Maste 	if (op == SYMOP_REDEF)
1154a85fe12eSEd Maste 		s->newname = newname;
1155a85fe12eSEd Maste 	s->op |= op;
1156a85fe12eSEd Maste }
1157a85fe12eSEd Maste 
1158a85fe12eSEd Maste struct symop *
1159a85fe12eSEd Maste lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op)
1160a85fe12eSEd Maste {
1161*839529caSEd Maste 	struct symop *s, *ret;
1162*839529caSEd Maste 	const char *pattern;
1163a85fe12eSEd Maste 
1164a85fe12eSEd Maste 	STAILQ_FOREACH(s, &ecp->v_symop, symop_list) {
1165*839529caSEd Maste 		if ((s->op & op) == 0)
1166*839529caSEd Maste 			continue;
1167*839529caSEd Maste 		if (name == NULL || !strcmp(name, s->name))
1168a85fe12eSEd Maste 				return (s);
1169*839529caSEd Maste 		if ((ecp->flags & WILDCARD) == 0)
1170*839529caSEd Maste 			continue;
1171*839529caSEd Maste 
1172*839529caSEd Maste 		/* Handle wildcards. */
1173*839529caSEd Maste 		pattern = s->name;
1174*839529caSEd Maste 		if (pattern[0] == '!') {
1175*839529caSEd Maste 			/* Negative match. */
1176*839529caSEd Maste 			pattern++;
1177*839529caSEd Maste 			ret = NULL;
1178*839529caSEd Maste 		} else {
1179*839529caSEd Maste 			/* Regular wildcard match. */
1180*839529caSEd Maste 			ret = s;
1181*839529caSEd Maste 		}
1182*839529caSEd Maste 		if (!fnmatch(pattern, name, 0))
1183*839529caSEd Maste 			return (ret);
1184a85fe12eSEd Maste 	}
1185a85fe12eSEd Maste 
1186a85fe12eSEd Maste 	return (NULL);
1187a85fe12eSEd Maste }
1188a85fe12eSEd Maste 
1189a85fe12eSEd Maste static int
11904a85c691SEd Maste lookup_exact_string(hash_head *buckets, const char *buf, const char *s)
1191a85fe12eSEd Maste {
11924a85c691SEd Maste 	struct sthash	*sh;
11934a85c691SEd Maste 	uint32_t	 hash;
1194a85fe12eSEd Maste 
11954a85c691SEd Maste 	hash = str_hash(s);
11964a85c691SEd Maste 	LIST_FOREACH(sh, &buckets[hash], sh_next)
11974a85c691SEd Maste 		if (strcmp(buf + sh->sh_off, s) == 0)
11984a85c691SEd Maste 			return sh->sh_off;
11994a85c691SEd Maste 	return (-1);
1200a85fe12eSEd Maste }
1201a85fe12eSEd Maste 
12024a85c691SEd Maste uint32_t
12034a85c691SEd Maste str_hash(const char *s)
12044a85c691SEd Maste {
12054a85c691SEd Maste 	uint32_t hash;
12064a85c691SEd Maste 
1207b00fe64fSEd Maste 	for (hash = 2166136261UL; *s; s++)
12084a85c691SEd Maste 		hash = (hash ^ *s) * 16777619;
12094a85c691SEd Maste 
12104a85c691SEd Maste 	return (hash & (STHASHSIZE - 1));
1211a85fe12eSEd Maste }
1212