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, ­) == 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, ­))
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