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