xref: /freebsd/contrib/elftoolchain/elfcopy/symbols.c (revision 554491ffbdcfe51993d5b436a9bbca7aba388dd3)
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>
28839529caSEd 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*bee2765cSEd Maste ELFTC_VCSID("$Id: symbols.c 3520 2017-04-17 01:47:52Z kaiwang27 $");
38839529caSEd Maste 
39839529caSEd Maste /* Backwards compatibility for systems with older ELF definitions. */
40839529caSEd Maste #ifndef STB_GNU_UNIQUE
41839529caSEd Maste #define	STB_GNU_UNIQUE 10
42839529caSEd Maste #endif
43839529caSEd 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
is_debug_symbol(unsigned char st_info)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
is_global_symbol(unsigned char st_info)108a85fe12eSEd Maste is_global_symbol(unsigned char st_info)
109a85fe12eSEd Maste {
110a85fe12eSEd Maste 
111839529caSEd Maste 	if (GELF_ST_BIND(st_info) == STB_GLOBAL ||
112839529caSEd 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
is_weak_symbol(unsigned char st_info)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
is_local_symbol(unsigned char st_info)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
is_hidden_symbol(unsigned char st_other)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
is_local_label(const char * name)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
is_needed_symbol(struct elfcopy * ecp,int i,GElf_Sym * s)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 
171b6b6f9ccSEd Maste 	/* Symbols referred 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
is_remove_symbol(struct elfcopy * ecp,size_t sc,int i,GElf_Sym * s,const char * name)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 
212839529caSEd Maste 	/* Keep the symbol if specified by command line option -K. */
213839529caSEd Maste 	if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL)
214839529caSEd Maste 		return (0);
215839529caSEd Maste 
216a85fe12eSEd Maste 	if (ecp->strip == STRIP_ALL)
217a85fe12eSEd Maste 		return (1);
218a85fe12eSEd Maste 
219839529caSEd Maste 	/* Mark symbols used in relocation. */
220a85fe12eSEd Maste 	if (ecp->v_rel == NULL)
2213ef90571SEd Maste 		mark_reloc_symbols(ecp, sc);
2223ef90571SEd Maste 
223839529caSEd Maste 	/* Mark symbols used in section groups. */
2243ef90571SEd Maste 	if (ecp->v_grp == NULL)
2253ef90571SEd Maste 		mark_section_group_symbols(ecp, sc);
226a85fe12eSEd Maste 
227839529caSEd Maste 	/*
228839529caSEd Maste 	 * Strip the symbol if specified by command line option -N,
229839529caSEd Maste 	 * unless it's used in relocation.
230839529caSEd Maste 	 */
231839529caSEd Maste 	if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) {
232839529caSEd Maste 		if (BIT_ISSET(ecp->v_rel, i)) {
233839529caSEd Maste 			warnx("not stripping symbol `%s' because it is named"
234839529caSEd Maste 			    " in a relocation", name);
235839529caSEd Maste 			return (0);
236839529caSEd Maste 		}
237839529caSEd Maste 		return (1);
238839529caSEd Maste 	}
239839529caSEd 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 /*
261b6b6f9ccSEd Maste  * Mark symbols referred by relocation entries.
262a85fe12eSEd Maste  */
263a85fe12eSEd Maste static void
mark_reloc_symbols(struct elfcopy * ecp,size_t sc)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
mark_section_group_symbols(struct elfcopy * ecp,size_t sc)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
generate_symbols(struct elfcopy * ecp)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 		 */
588839529caSEd Maste 		if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
589839529caSEd Maste 		    sym.st_shndx < SHN_LORESERVE) {
590839529caSEd 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 		}
593839529caSEd 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
create_symtab(struct elfcopy * ecp)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 
679*bee2765cSEd Maste 	assert(sy != NULL && st != NULL);
680*bee2765cSEd Maste 
681a85fe12eSEd Maste 	/*
682a85fe12eSEd Maste 	 * Set section index map for .symtab and .strtab. We need to set
683a85fe12eSEd Maste 	 * these map because otherwise symbols which refer to .symtab and
684a85fe12eSEd Maste 	 * .strtab will be removed by symbol filtering unconditionally.
685a85fe12eSEd Maste 	 * And we have to figure out scn index this way (instead of calling
686a85fe12eSEd Maste 	 * elf_ndxscn) because we can not create Elf_Scn before we're certain
687a85fe12eSEd Maste 	 * that .symtab and .strtab will exist in the output object.
688a85fe12eSEd Maste 	 */
689a85fe12eSEd Maste 	maxndx = 0;
690a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
691a85fe12eSEd Maste 		if (s->os == NULL)
692a85fe12eSEd Maste 			continue;
693a85fe12eSEd Maste 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
694a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
695a85fe12eSEd Maste 			    elf_errmsg(-1));
696a85fe12eSEd Maste 		if (ndx > maxndx)
697a85fe12eSEd Maste 			maxndx = ndx;
698a85fe12eSEd Maste 	}
699a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1;
700a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2;
701a85fe12eSEd Maste 
702a85fe12eSEd Maste 	/*
703a85fe12eSEd Maste 	 * Generate symbols for output object if SYMTAB_INTACT is not set.
704a85fe12eSEd Maste 	 * If there is no symbol in the input object or all the symbols are
705a85fe12eSEd Maste 	 * stripped, then free all the resouces allotted for symbol table,
706a85fe12eSEd Maste 	 * and clear SYMTAB_EXIST flag.
707a85fe12eSEd Maste 	 */
708a85fe12eSEd Maste 	if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) {
709a85fe12eSEd Maste 		TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list);
710a85fe12eSEd Maste 		TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list);
7113ef90571SEd Maste 		free(ecp->symtab->buf);
712a85fe12eSEd Maste 		free(ecp->symtab);
7133ef90571SEd Maste 		free(ecp->strtab->buf);
714a85fe12eSEd Maste 		free(ecp->strtab);
715a85fe12eSEd Maste 		ecp->symtab = NULL;
716a85fe12eSEd Maste 		ecp->strtab = NULL;
717a85fe12eSEd Maste 		ecp->flags &= ~SYMTAB_EXIST;
718a85fe12eSEd Maste 		return;
719a85fe12eSEd Maste 	}
720a85fe12eSEd Maste 
721a85fe12eSEd Maste 	/* Create output Elf_Scn for .symtab and .strtab. */
722a85fe12eSEd Maste 	if ((sy->os = elf_newscn(ecp->eout)) == NULL ||
723a85fe12eSEd Maste 	    (st->os = elf_newscn(ecp->eout)) == NULL)
724a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newscn failed: %s",
725a85fe12eSEd Maste 		    elf_errmsg(-1));
726a85fe12eSEd Maste 	/* Update secndx anyway. */
727a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os);
728a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os);
729a85fe12eSEd Maste 
730a85fe12eSEd Maste 	/*
731a85fe12eSEd Maste 	 * Copy .symtab and .strtab section headers from input to output
732a85fe12eSEd Maste 	 * object to start with, these will be overridden later if need.
733a85fe12eSEd Maste 	 */
734a85fe12eSEd Maste 	copy_shdr(ecp, sy, ".symtab", 1, 0);
735a85fe12eSEd Maste 	copy_shdr(ecp, st, ".strtab", 1, 0);
736a85fe12eSEd Maste 
737a85fe12eSEd Maste 	/* Copy verbatim if symbol table is intact. */
738a85fe12eSEd Maste 	if (ecp->flags & SYMTAB_INTACT) {
739a85fe12eSEd Maste 		copy_data(sy);
740a85fe12eSEd Maste 		copy_data(st);
741a85fe12eSEd Maste 		return;
742a85fe12eSEd Maste 	}
743a85fe12eSEd Maste 
744a85fe12eSEd Maste 	create_symtab_data(ecp);
745a85fe12eSEd Maste }
746a85fe12eSEd Maste 
747a85fe12eSEd Maste void
free_symtab(struct elfcopy * ecp)748a85fe12eSEd Maste free_symtab(struct elfcopy *ecp)
749a85fe12eSEd Maste {
750a85fe12eSEd Maste 	struct symbuf	*sy_buf;
751a85fe12eSEd Maste 	struct strbuf	*st_buf;
7524a85c691SEd Maste 	struct sthash	*sh, *shtmp;
7534a85c691SEd Maste 	int i;
754a85fe12eSEd Maste 
755a85fe12eSEd Maste 	if (ecp->symtab != NULL && ecp->symtab->buf != NULL) {
756a85fe12eSEd Maste 		sy_buf = ecp->symtab->buf;
757a85fe12eSEd Maste 		if (sy_buf->l32 != NULL)
758a85fe12eSEd Maste 			free(sy_buf->l32);
759a85fe12eSEd Maste 		if (sy_buf->g32 != NULL)
760a85fe12eSEd Maste 			free(sy_buf->g32);
761a85fe12eSEd Maste 		if (sy_buf->l64 != NULL)
762a85fe12eSEd Maste 			free(sy_buf->l64);
763a85fe12eSEd Maste 		if (sy_buf->g64 != NULL)
764a85fe12eSEd Maste 			free(sy_buf->g64);
765a85fe12eSEd Maste 	}
766a85fe12eSEd Maste 
767a85fe12eSEd Maste 	if (ecp->strtab != NULL && ecp->strtab->buf != NULL) {
768a85fe12eSEd Maste 		st_buf = ecp->strtab->buf;
7694a85c691SEd Maste 		if (st_buf->l.buf != NULL)
7704a85c691SEd Maste 			free(st_buf->l.buf);
7714a85c691SEd Maste 		if (st_buf->g.buf != NULL)
7724a85c691SEd Maste 			free(st_buf->g.buf);
7734a85c691SEd Maste 		for (i = 0; i < STHASHSIZE; i++) {
7744a85c691SEd Maste 			LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next,
7754a85c691SEd Maste 			    shtmp) {
7764a85c691SEd Maste 				LIST_REMOVE(sh, sh_next);
7774a85c691SEd Maste 				free(sh);
7784a85c691SEd Maste 			}
7794a85c691SEd Maste 			LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next,
7804a85c691SEd Maste 			    shtmp) {
7814a85c691SEd Maste 				LIST_REMOVE(sh, sh_next);
7824a85c691SEd Maste 				free(sh);
7834a85c691SEd Maste 			}
7844a85c691SEd Maste 		}
785a85fe12eSEd Maste 	}
7863ef90571SEd Maste 
7873ef90571SEd Maste 	if (ecp->symndx != NULL) {
7883ef90571SEd Maste 		free(ecp->symndx);
7893ef90571SEd Maste 		ecp->symndx = NULL;
7903ef90571SEd Maste 	}
7913ef90571SEd Maste 	if (ecp->v_rel != NULL) {
7923ef90571SEd Maste 		free(ecp->v_rel);
7933ef90571SEd Maste 		ecp->v_rel = NULL;
7943ef90571SEd Maste 	}
7953ef90571SEd Maste 	if (ecp->v_grp != NULL) {
7963ef90571SEd Maste 		free(ecp->v_grp);
7973ef90571SEd Maste 		ecp->v_grp = NULL;
7983ef90571SEd Maste 	}
7993ef90571SEd Maste 	if (ecp->v_secsym != NULL) {
8003ef90571SEd Maste 		free(ecp->v_secsym);
8013ef90571SEd Maste 		ecp->v_secsym = NULL;
8023ef90571SEd Maste 	}
803a85fe12eSEd Maste }
804a85fe12eSEd Maste 
805a85fe12eSEd Maste void
create_external_symtab(struct elfcopy * ecp)806a85fe12eSEd Maste create_external_symtab(struct elfcopy *ecp)
807a85fe12eSEd Maste {
808a85fe12eSEd Maste 	struct section *s;
809a85fe12eSEd Maste 	struct symbuf *sy_buf;
810a85fe12eSEd Maste 	struct strbuf *st_buf;
811a85fe12eSEd Maste 	GElf_Shdr sh;
812a85fe12eSEd Maste 	size_t ndx;
813a85fe12eSEd Maste 
814a85fe12eSEd Maste 	if (ecp->oec == ELFCLASS32)
815a85fe12eSEd Maste 		ecp->symtab = create_external_section(ecp, ".symtab", NULL,
816a85fe12eSEd Maste 		    NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0);
817a85fe12eSEd Maste 	else
818a85fe12eSEd Maste 		ecp->symtab = create_external_section(ecp, ".symtab", NULL,
819a85fe12eSEd Maste 		    NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0);
820a85fe12eSEd Maste 
821a85fe12eSEd Maste 	ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0,
822a85fe12eSEd Maste 	    SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0);
823a85fe12eSEd Maste 
824a85fe12eSEd Maste 	/* Let sh_link field of .symtab section point to .strtab section. */
825a85fe12eSEd Maste 	if (gelf_getshdr(ecp->symtab->os, &sh) == NULL)
826a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
827a85fe12eSEd Maste 		    elf_errmsg(-1));
828a85fe12eSEd Maste 	sh.sh_link = elf_ndxscn(ecp->strtab->os);
829a85fe12eSEd Maste 	if (!gelf_update_shdr(ecp->symtab->os, &sh))
830a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
831a85fe12eSEd Maste 		    elf_errmsg(-1));
832a85fe12eSEd Maste 
833a85fe12eSEd Maste 	/* Create buffers for .symtab and .strtab. */
834a85fe12eSEd Maste 	if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
835a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
836a85fe12eSEd Maste 	if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
837a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
838a85fe12eSEd Maste 	sy_buf->gcap = sy_buf->lcap = 64;
8394a85c691SEd Maste 	st_buf->g.cap = 256;
8404a85c691SEd Maste 	st_buf->l.cap = 64;
8414a85c691SEd Maste 	st_buf->l.sz = 1;	/* '\0' at start. */
8424a85c691SEd Maste 	st_buf->g.sz = 0;
843a85fe12eSEd Maste 
844a85fe12eSEd Maste 	ecp->symtab->sz = 0;
845a85fe12eSEd Maste 	ecp->strtab->sz = 0;
846a85fe12eSEd Maste 	ecp->symtab->buf = sy_buf;
847a85fe12eSEd Maste 	ecp->strtab->buf = st_buf;
848a85fe12eSEd Maste 
849a85fe12eSEd Maste 	/* Always create the special symbol at the symtab beginning. */
850a85fe12eSEd Maste 	add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF,
851a85fe12eSEd Maste 	    ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1);
852a85fe12eSEd Maste 
853a85fe12eSEd Maste 	/* Create STT_SECTION symbols. */
854a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
855a85fe12eSEd Maste 		if (s->pseudo)
856a85fe12eSEd Maste 			continue;
857a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
858a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
859a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
860a85fe12eSEd Maste 			continue;
861a85fe12eSEd Maste 		(void) elf_errno();
862a85fe12eSEd Maste 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) {
863a85fe12eSEd Maste 			warnx("elf_ndxscn failed: %s",
864a85fe12eSEd Maste 			    elf_errmsg(-1));
865a85fe12eSEd Maste 			continue;
866a85fe12eSEd Maste 		}
867a85fe12eSEd Maste 		add_to_symtab(ecp, NULL, 0, 0, ndx,
868a85fe12eSEd Maste 		    GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1);
869a85fe12eSEd Maste 	}
870a85fe12eSEd Maste }
871a85fe12eSEd Maste 
872a85fe12eSEd Maste void
add_to_symtab(struct elfcopy * ecp,const char * name,uint64_t st_value,uint64_t st_size,uint16_t st_shndx,unsigned char st_info,unsigned char st_other,int ndx_known)873a85fe12eSEd Maste add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value,
874a85fe12eSEd Maste     uint64_t st_size, uint16_t st_shndx, unsigned char st_info,
875a85fe12eSEd Maste     unsigned char st_other, int ndx_known)
876a85fe12eSEd Maste {
877a85fe12eSEd Maste 	struct symbuf *sy_buf;
878a85fe12eSEd Maste 	struct strbuf *st_buf;
8794a85c691SEd Maste 	struct sthash *sh;
8804a85c691SEd Maste 	uint32_t hash;
881a85fe12eSEd Maste 	int pos;
882a85fe12eSEd Maste 
883a85fe12eSEd Maste 	/*
884a85fe12eSEd Maste 	 * Convenient macro for copying global/local 32/64 bit symbols
885a85fe12eSEd Maste 	 * from input object to the buffer created for output object.
886a85fe12eSEd Maste 	 * It handles buffer growing, st_name calculating and st_shndx
887a85fe12eSEd Maste 	 * updating for symbols with non-special section index.
888a85fe12eSEd Maste 	 */
889839529caSEd Maste #define	_ST_NAME_EMPTY_l 0
890839529caSEd Maste #define	_ST_NAME_EMPTY_g -1
891a85fe12eSEd Maste #define	_ADDSYM(B, SZ) do {						\
892a85fe12eSEd Maste 	if (sy_buf->B##SZ == NULL) {					\
893a85fe12eSEd Maste 		sy_buf->B##SZ = malloc(sy_buf->B##cap *			\
894a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Sym));				\
895a85fe12eSEd Maste 		if (sy_buf->B##SZ == NULL)				\
896a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");		\
897a85fe12eSEd Maste 	} else if (sy_buf->n##B##s >= sy_buf->B##cap) {			\
898a85fe12eSEd Maste 		sy_buf->B##cap *= 2;					\
899a85fe12eSEd Maste 		sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap *	\
900a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Sym));				\
901a85fe12eSEd Maste 		if (sy_buf->B##SZ == NULL)				\
902a85fe12eSEd Maste 			err(EXIT_FAILURE, "realloc failed");		\
903a85fe12eSEd Maste 	}								\
904a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_info	= st_info;		\
905a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_other	= st_other;		\
906a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_value	= st_value;		\
907a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_size	= st_size;		\
908a85fe12eSEd Maste 	if (ndx_known)							\
909a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;	\
910a85fe12eSEd Maste 	else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE)	\
911a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;	\
912a85fe12eSEd Maste 	else								\
913a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx	=		\
914a85fe12eSEd Maste 			ecp->secndx[st_shndx];				\
9154a85c691SEd Maste 	if (st_buf->B.buf == NULL) {					\
9164a85c691SEd Maste 		st_buf->B.buf = calloc(st_buf->B.cap,			\
9174a85c691SEd Maste 		    sizeof(*st_buf->B.buf));				\
9184a85c691SEd Maste 		if (st_buf->B.buf == NULL)				\
919a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");		\
920a85fe12eSEd Maste 	}								\
921a85fe12eSEd Maste 	if (name != NULL && *name != '\0') {				\
9224a85c691SEd Maste 		pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\
9234a85c691SEd Maste 		    name);						\
924a85fe12eSEd Maste 		if (pos != -1)						\
925a85fe12eSEd Maste 			sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos;	\
926a85fe12eSEd Maste 		else {							\
927a85fe12eSEd Maste 			sy_buf->B##SZ[sy_buf->n##B##s].st_name =	\
9284a85c691SEd Maste 			    st_buf->B.sz;				\
9294a85c691SEd Maste 			while (st_buf->B.sz + strlen(name) >=		\
9304a85c691SEd Maste 			    st_buf->B.cap - 1) {			\
9314a85c691SEd Maste 				st_buf->B.cap *= 2;			\
9324a85c691SEd Maste 				st_buf->B.buf = realloc(st_buf->B.buf,	\
9334a85c691SEd Maste 				    st_buf->B.cap);			\
9344a85c691SEd Maste 				if (st_buf->B.buf == NULL)		\
935a85fe12eSEd Maste 					err(EXIT_FAILURE,		\
936a85fe12eSEd Maste 					    "realloc failed");		\
937a85fe12eSEd Maste 			}						\
9384a85c691SEd Maste 			if ((sh = malloc(sizeof(*sh))) == NULL)		\
9394a85c691SEd Maste 				err(EXIT_FAILURE, "malloc failed");	\
9404a85c691SEd Maste 			sh->sh_off = st_buf->B.sz;			\
9414a85c691SEd Maste 			hash = str_hash(name);				\
9424a85c691SEd Maste 			LIST_INSERT_HEAD(&st_buf->B.hash[hash], sh,	\
9434a85c691SEd Maste 			    sh_next);					\
9444a85c691SEd Maste 			strncpy(&st_buf->B.buf[st_buf->B.sz], name,	\
945a85fe12eSEd Maste 			    strlen(name));				\
9464a85c691SEd Maste 			st_buf->B.buf[st_buf->B.sz + strlen(name)] = '\0'; \
9474a85c691SEd Maste 			st_buf->B.sz += strlen(name) + 1;		\
948a85fe12eSEd Maste 		}							\
949a85fe12eSEd Maste 	} else								\
950839529caSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_name = 		\
951839529caSEd Maste 		    (Elf##SZ##_Word)_ST_NAME_EMPTY_##B;			\
952a85fe12eSEd Maste 	sy_buf->n##B##s++;						\
953a85fe12eSEd Maste } while (0)
954a85fe12eSEd Maste 
955a85fe12eSEd Maste 	sy_buf = ecp->symtab->buf;
956a85fe12eSEd Maste 	st_buf = ecp->strtab->buf;
957a85fe12eSEd Maste 
958a85fe12eSEd Maste 	if (ecp->oec == ELFCLASS32) {
959a85fe12eSEd Maste 		if (is_local_symbol(st_info))
960a85fe12eSEd Maste 			_ADDSYM(l, 32);
961a85fe12eSEd Maste 		else
962a85fe12eSEd Maste 			_ADDSYM(g, 32);
963a85fe12eSEd Maste 	} else {
964a85fe12eSEd Maste 		if (is_local_symbol(st_info))
965a85fe12eSEd Maste 			_ADDSYM(l, 64);
966a85fe12eSEd Maste 		else
967a85fe12eSEd Maste 			_ADDSYM(g, 64);
968a85fe12eSEd Maste 	}
969a85fe12eSEd Maste 
970a85fe12eSEd Maste 	/* Update section size. */
971a85fe12eSEd Maste 	ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) *
972a85fe12eSEd Maste 	    (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym));
9734a85c691SEd Maste 	ecp->strtab->sz = st_buf->l.sz + st_buf->g.sz;
974a85fe12eSEd Maste 
975a85fe12eSEd Maste #undef	_ADDSYM
976839529caSEd Maste #undef	_ST_NAME_EMPTY_l
977839529caSEd Maste #undef	_ST_NAME_EMPTY_g
978a85fe12eSEd Maste }
979a85fe12eSEd Maste 
980a85fe12eSEd Maste void
finalize_external_symtab(struct elfcopy * ecp)981a85fe12eSEd Maste finalize_external_symtab(struct elfcopy *ecp)
982a85fe12eSEd Maste {
983a85fe12eSEd Maste 	struct symbuf *sy_buf;
984a85fe12eSEd Maste 	struct strbuf *st_buf;
985a85fe12eSEd Maste 	int i;
986a85fe12eSEd Maste 
987a85fe12eSEd Maste 	/*
988a85fe12eSEd Maste 	 * Update st_name for global/weak symbols. (global/weak symbols
989a85fe12eSEd Maste 	 * are put after local symbols)
990a85fe12eSEd Maste 	 */
991a85fe12eSEd Maste 	sy_buf = ecp->symtab->buf;
992a85fe12eSEd Maste 	st_buf = ecp->strtab->buf;
993a85fe12eSEd Maste 	for (i = 0; (size_t) i < sy_buf->ngs; i++) {
994839529caSEd Maste 		if (ecp->oec == ELFCLASS32) {
995839529caSEd Maste 			if (sy_buf->g32[i].st_name == (Elf32_Word)-1)
996839529caSEd Maste 				sy_buf->g32[i].st_name = 0;
997839529caSEd Maste 			else
9984a85c691SEd Maste 				sy_buf->g32[i].st_name += st_buf->l.sz;
999839529caSEd Maste 		} else {
1000839529caSEd Maste 			if (sy_buf->g64[i].st_name == (Elf64_Word)-1)
1001839529caSEd Maste 				sy_buf->g64[i].st_name = 0;
1002a85fe12eSEd Maste 			else
10034a85c691SEd Maste 				sy_buf->g64[i].st_name += st_buf->l.sz;
1004a85fe12eSEd Maste 		}
1005a85fe12eSEd Maste 	}
1006839529caSEd Maste }
1007a85fe12eSEd Maste 
1008a85fe12eSEd Maste void
create_symtab_data(struct elfcopy * ecp)1009a85fe12eSEd Maste create_symtab_data(struct elfcopy *ecp)
1010a85fe12eSEd Maste {
1011a85fe12eSEd Maste 	struct section	*sy, *st;
1012a85fe12eSEd Maste 	struct symbuf	*sy_buf;
1013a85fe12eSEd Maste 	struct strbuf	*st_buf;
1014a85fe12eSEd Maste 	Elf_Data	*gsydata, *lsydata, *gstdata, *lstdata;
1015a85fe12eSEd Maste 	GElf_Shdr	 shy, sht;
1016a85fe12eSEd Maste 
1017a85fe12eSEd Maste 	sy = ecp->symtab;
1018a85fe12eSEd Maste 	st = ecp->strtab;
1019a85fe12eSEd Maste 
1020a85fe12eSEd Maste 	if (gelf_getshdr(sy->os, &shy) == NULL)
1021a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1022a85fe12eSEd Maste 		    elf_errmsg(-1));
1023a85fe12eSEd Maste 	if (gelf_getshdr(st->os, &sht) == NULL)
1024a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1025a85fe12eSEd Maste 		    elf_errmsg(-1));
1026a85fe12eSEd Maste 
1027a85fe12eSEd Maste 	/*
1028a85fe12eSEd Maste 	 * Create two Elf_Data for .symtab section of output object, one
1029a85fe12eSEd Maste 	 * for local symbols and another for global symbols. Note that
1030a85fe12eSEd Maste 	 * local symbols appear first in the .symtab.
1031a85fe12eSEd Maste 	 */
1032a85fe12eSEd Maste 	sy_buf = sy->buf;
1033a85fe12eSEd Maste 	if (sy_buf->nls > 0) {
1034a85fe12eSEd Maste 		if ((lsydata = elf_newdata(sy->os)) == NULL)
1035a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1036a85fe12eSEd Maste 			     elf_errmsg(-1));
1037a85fe12eSEd Maste 		if (ecp->oec == ELFCLASS32) {
1038a85fe12eSEd Maste 			lsydata->d_align	= 4;
1039a85fe12eSEd Maste 			lsydata->d_off		= 0;
1040a85fe12eSEd Maste 			lsydata->d_buf		= sy_buf->l32;
1041a85fe12eSEd Maste 			lsydata->d_size		= sy_buf->nls *
1042a85fe12eSEd Maste 				sizeof(Elf32_Sym);
1043a85fe12eSEd Maste 			lsydata->d_type		= ELF_T_SYM;
1044a85fe12eSEd Maste 			lsydata->d_version	= EV_CURRENT;
1045a85fe12eSEd Maste 		} else {
1046a85fe12eSEd Maste 			lsydata->d_align	= 8;
1047a85fe12eSEd Maste 			lsydata->d_off		= 0;
1048a85fe12eSEd Maste 			lsydata->d_buf		= sy_buf->l64;
1049a85fe12eSEd Maste 			lsydata->d_size		= sy_buf->nls *
1050a85fe12eSEd Maste 				sizeof(Elf64_Sym);
1051a85fe12eSEd Maste 			lsydata->d_type		= ELF_T_SYM;
1052a85fe12eSEd Maste 			lsydata->d_version	= EV_CURRENT;
1053a85fe12eSEd Maste 		}
1054a85fe12eSEd Maste 	}
1055a85fe12eSEd Maste 	if (sy_buf->ngs > 0) {
1056a85fe12eSEd Maste 		if ((gsydata = elf_newdata(sy->os)) == NULL)
1057a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1058a85fe12eSEd Maste 			     elf_errmsg(-1));
1059a85fe12eSEd Maste 		if (ecp->oec == ELFCLASS32) {
1060a85fe12eSEd Maste 			gsydata->d_align	= 4;
1061a85fe12eSEd Maste 			gsydata->d_off		= sy_buf->nls *
1062a85fe12eSEd Maste 				sizeof(Elf32_Sym);
1063a85fe12eSEd Maste 			gsydata->d_buf		= sy_buf->g32;
1064a85fe12eSEd Maste 			gsydata->d_size		= sy_buf->ngs *
1065a85fe12eSEd Maste 				sizeof(Elf32_Sym);
1066a85fe12eSEd Maste 			gsydata->d_type		= ELF_T_SYM;
1067a85fe12eSEd Maste 			gsydata->d_version	= EV_CURRENT;
1068a85fe12eSEd Maste 		} else {
1069a85fe12eSEd Maste 			gsydata->d_align	= 8;
1070a85fe12eSEd Maste 			gsydata->d_off		= sy_buf->nls *
1071a85fe12eSEd Maste 				sizeof(Elf64_Sym);
1072a85fe12eSEd Maste 			gsydata->d_buf		= sy_buf->g64;
1073a85fe12eSEd Maste 			gsydata->d_size		= sy_buf->ngs *
1074a85fe12eSEd Maste 				sizeof(Elf64_Sym);
1075a85fe12eSEd Maste 			gsydata->d_type		= ELF_T_SYM;
1076a85fe12eSEd Maste 			gsydata->d_version	= EV_CURRENT;
1077a85fe12eSEd Maste 		}
1078a85fe12eSEd Maste 	}
1079a85fe12eSEd Maste 
1080a85fe12eSEd Maste 	/*
1081a85fe12eSEd Maste 	 * Create two Elf_Data for .strtab, one for local symbol name
1082a85fe12eSEd Maste 	 * and another for globals. Same as .symtab, local symbol names
1083a85fe12eSEd Maste 	 * appear first.
1084a85fe12eSEd Maste 	 */
1085a85fe12eSEd Maste 	st_buf = st->buf;
1086a85fe12eSEd Maste 	if ((lstdata = elf_newdata(st->os)) == NULL)
1087a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1088a85fe12eSEd Maste 		    elf_errmsg(-1));
1089a85fe12eSEd Maste 	lstdata->d_align	= 1;
1090a85fe12eSEd Maste 	lstdata->d_off		= 0;
10914a85c691SEd Maste 	lstdata->d_buf		= st_buf->l.buf;
10924a85c691SEd Maste 	lstdata->d_size		= st_buf->l.sz;
1093a85fe12eSEd Maste 	lstdata->d_type		= ELF_T_BYTE;
1094a85fe12eSEd Maste 	lstdata->d_version	= EV_CURRENT;
1095a85fe12eSEd Maste 
10964a85c691SEd Maste 	if (st_buf->g.sz > 0) {
1097a85fe12eSEd Maste 		if ((gstdata = elf_newdata(st->os)) == NULL)
1098a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1099a85fe12eSEd Maste 			    elf_errmsg(-1));
1100a85fe12eSEd Maste 		gstdata->d_align	= 1;
1101a85fe12eSEd Maste 		gstdata->d_off		= lstdata->d_size;
11024a85c691SEd Maste 		gstdata->d_buf		= st_buf->g.buf;
11034a85c691SEd Maste 		gstdata->d_size		= st_buf->g.sz;
1104a85fe12eSEd Maste 		gstdata->d_type		= ELF_T_BYTE;
1105a85fe12eSEd Maste 		gstdata->d_version	= EV_CURRENT;
1106a85fe12eSEd Maste 	}
1107a85fe12eSEd Maste 
1108a85fe12eSEd Maste 	shy.sh_addr		= 0;
1109a85fe12eSEd Maste 	shy.sh_addralign	= (ecp->oec == ELFCLASS32 ? 4 : 8);
1110a85fe12eSEd Maste 	shy.sh_size		= sy->sz;
1111a85fe12eSEd Maste 	shy.sh_type		= SHT_SYMTAB;
1112a85fe12eSEd Maste 	shy.sh_flags		= 0;
1113a85fe12eSEd Maste 	shy.sh_entsize		= gelf_fsize(ecp->eout, ELF_T_SYM, 1,
1114a85fe12eSEd Maste 	    EV_CURRENT);
1115a85fe12eSEd Maste 	/*
1116a85fe12eSEd Maste 	 * According to SYSV abi, here sh_info is one greater than
1117a85fe12eSEd Maste 	 * the symbol table index of the last local symbol(binding
1118a85fe12eSEd Maste 	 * STB_LOCAL).
1119a85fe12eSEd Maste 	 */
1120a85fe12eSEd Maste 	shy.sh_info		= sy_buf->nls;
1121a85fe12eSEd Maste 
1122a85fe12eSEd Maste 	sht.sh_addr		= 0;
1123a85fe12eSEd Maste 	sht.sh_addralign	= 1;
1124a85fe12eSEd Maste 	sht.sh_size		= st->sz;
1125a85fe12eSEd Maste 	sht.sh_type		= SHT_STRTAB;
1126a85fe12eSEd Maste 	sht.sh_flags		= 0;
1127a85fe12eSEd Maste 	sht.sh_entsize		= 0;
1128a85fe12eSEd Maste 	sht.sh_info		= 0;
1129a85fe12eSEd Maste 	sht.sh_link		= 0;
1130a85fe12eSEd Maste 
1131a85fe12eSEd Maste 	if (!gelf_update_shdr(sy->os, &shy))
1132a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1133a85fe12eSEd Maste 		    elf_errmsg(-1));
1134a85fe12eSEd Maste 	if (!gelf_update_shdr(st->os, &sht))
1135a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1136a85fe12eSEd Maste 		    elf_errmsg(-1));
1137a85fe12eSEd Maste }
1138a85fe12eSEd Maste 
1139a85fe12eSEd Maste void
add_to_symop_list(struct elfcopy * ecp,const char * name,const char * newname,unsigned int op)1140a85fe12eSEd Maste add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname,
1141a85fe12eSEd Maste     unsigned int op)
1142a85fe12eSEd Maste {
1143a85fe12eSEd Maste 	struct symop *s;
1144a85fe12eSEd Maste 
1145839529caSEd Maste 	assert (name != NULL);
1146839529caSEd Maste 	STAILQ_FOREACH(s, &ecp->v_symop, symop_list)
1147839529caSEd Maste 		if (!strcmp(name, s->name))
1148839529caSEd Maste 			goto found;
1149839529caSEd Maste 
1150a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
1151a85fe12eSEd Maste 		errx(EXIT_FAILURE, "not enough memory");
1152839529caSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list);
1153a85fe12eSEd Maste 	s->name = name;
1154839529caSEd Maste found:
1155a85fe12eSEd Maste 	if (op == SYMOP_REDEF)
1156a85fe12eSEd Maste 		s->newname = newname;
1157a85fe12eSEd Maste 	s->op |= op;
1158a85fe12eSEd Maste }
1159a85fe12eSEd Maste 
1160a85fe12eSEd Maste struct symop *
lookup_symop_list(struct elfcopy * ecp,const char * name,unsigned int op)1161a85fe12eSEd Maste lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op)
1162a85fe12eSEd Maste {
1163839529caSEd Maste 	struct symop *s, *ret;
1164839529caSEd Maste 	const char *pattern;
1165a85fe12eSEd Maste 
1166a85fe12eSEd Maste 	STAILQ_FOREACH(s, &ecp->v_symop, symop_list) {
1167839529caSEd Maste 		if ((s->op & op) == 0)
1168839529caSEd Maste 			continue;
1169839529caSEd Maste 		if (name == NULL || !strcmp(name, s->name))
1170a85fe12eSEd Maste 			return (s);
1171839529caSEd Maste 		if ((ecp->flags & WILDCARD) == 0)
1172839529caSEd Maste 			continue;
1173839529caSEd Maste 
1174839529caSEd Maste 		/* Handle wildcards. */
1175839529caSEd Maste 		pattern = s->name;
1176839529caSEd Maste 		if (pattern[0] == '!') {
1177839529caSEd Maste 			/* Negative match. */
1178839529caSEd Maste 			pattern++;
1179839529caSEd Maste 			ret = NULL;
1180839529caSEd Maste 		} else {
1181839529caSEd Maste 			/* Regular wildcard match. */
1182839529caSEd Maste 			ret = s;
1183839529caSEd Maste 		}
1184839529caSEd Maste 		if (!fnmatch(pattern, name, 0))
1185839529caSEd Maste 			return (ret);
1186a85fe12eSEd Maste 	}
1187a85fe12eSEd Maste 
1188a85fe12eSEd Maste 	return (NULL);
1189a85fe12eSEd Maste }
1190a85fe12eSEd Maste 
1191a85fe12eSEd Maste static int
lookup_exact_string(hash_head * buckets,const char * buf,const char * s)11924a85c691SEd Maste lookup_exact_string(hash_head *buckets, const char *buf, const char *s)
1193a85fe12eSEd Maste {
11944a85c691SEd Maste 	struct sthash	*sh;
11954a85c691SEd Maste 	uint32_t	 hash;
1196a85fe12eSEd Maste 
11974a85c691SEd Maste 	hash = str_hash(s);
11984a85c691SEd Maste 	LIST_FOREACH(sh, &buckets[hash], sh_next)
11994a85c691SEd Maste 		if (strcmp(buf + sh->sh_off, s) == 0)
12004a85c691SEd Maste 			return sh->sh_off;
12014a85c691SEd Maste 	return (-1);
1202a85fe12eSEd Maste }
1203a85fe12eSEd Maste 
12044a85c691SEd Maste uint32_t
str_hash(const char * s)12054a85c691SEd Maste str_hash(const char *s)
12064a85c691SEd Maste {
12074a85c691SEd Maste 	uint32_t hash;
12084a85c691SEd Maste 
1209b00fe64fSEd Maste 	for (hash = 2166136261UL; *s; s++)
12104a85c691SEd Maste 		hash = (hash ^ *s) * 16777619;
12114a85c691SEd Maste 
12124a85c691SEd Maste 	return (hash & (STHASHSIZE - 1));
1213a85fe12eSEd Maste }
1214