2 * Copyright (c) 2007-2013 Kai Wang
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/param.h>
37 ELFTC_VCSID("$Id: symbols.c 3520 2017-04-17 01:47:52Z kaiwang27 $");
39 /* Backwards compatibility for systems with older ELF definitions. */
40 #ifndef STB_GNU_UNIQUE
41 #define STB_GNU_UNIQUE 10
45 /* Symbol table buffer structure. */
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. */
56 LIST_ENTRY(sthash) sh_next;
59 typedef LIST_HEAD(,sthash) hash_head;
60 #define STHASHSIZE 65536
63 char *buf; /* string table */
64 size_t sz; /* entries */
65 size_t cap; /* buffer capacity */
66 hash_head hash[STHASHSIZE];
70 /* String table buffer structure. */
72 struct strimpl l; /* local symbols */
73 struct strimpl g; /* global symbols */
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,
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);
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)))
97 is_debug_symbol(unsigned char st_info)
100 if (GELF_ST_TYPE(st_info) == STT_SECTION ||
101 GELF_ST_TYPE(st_info) == STT_FILE)
108 is_global_symbol(unsigned char st_info)
111 if (GELF_ST_BIND(st_info) == STB_GLOBAL ||
112 GELF_ST_BIND(st_info) == STB_GNU_UNIQUE)
119 is_weak_symbol(unsigned char st_info)
122 if (GELF_ST_BIND(st_info) == STB_WEAK)
129 is_local_symbol(unsigned char st_info)
132 if (GELF_ST_BIND(st_info) == STB_LOCAL)
139 is_hidden_symbol(unsigned char st_other)
142 if (GELF_ST_VISIBILITY(st_other) == STV_HIDDEN ||
143 GELF_ST_VISIBILITY(st_other) == STV_INTERNAL)
150 is_local_label(const char *name)
153 /* Compiler generated local symbols that start with .L */
154 if (name[0] == '.' && name[1] == 'L')
161 * Symbols related to relocation are needed.
164 is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s)
167 /* If symbol involves relocation, it is needed. */
168 if (BIT_ISSET(ecp->v_rel, i))
171 /* Symbols referred by COMDAT sections are needed. */
172 if (BIT_ISSET(ecp->v_grp, i))
176 * For relocatable files (.o files), global and weak symbols
179 if (ecp->flags & RELOCATABLE) {
180 if (is_global_symbol(s->st_info) || is_weak_symbol(s->st_info))
188 is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s,
197 SHN_UNDEF, /* st_shndx */
201 * Keep the first symbol if it is the special reserved symbol.
202 * XXX Should we generate one if it's missing?
204 if (i == 0 && !memcmp(s, &sym0, sizeof(GElf_Sym)))
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)
212 /* Keep the symbol if specified by command line option -K. */
213 if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL)
216 if (ecp->strip == STRIP_ALL)
219 /* Mark symbols used in relocation. */
220 if (ecp->v_rel == NULL)
221 mark_reloc_symbols(ecp, sc);
223 /* Mark symbols used in section groups. */
224 if (ecp->v_grp == NULL)
225 mark_section_group_symbols(ecp, sc);
228 * Strip the symbol if specified by command line option -N,
229 * unless it's used in relocation.
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);
240 if (is_needed_symbol(ecp, i, s))
243 if (ecp->strip == STRIP_UNNEEDED)
246 if ((ecp->flags & DISCARD_LOCAL) && is_local_symbol(s->st_info) &&
247 !is_debug_symbol(s->st_info))
250 if ((ecp->flags & DISCARD_LLABEL) && is_local_symbol(s->st_info) &&
251 !is_debug_symbol(s->st_info) && is_local_label(name))
254 if (ecp->strip == STRIP_DEBUG && is_debug_symbol(s->st_info))
261 * Mark symbols referred by relocation entries.
264 mark_reloc_symbols(struct elfcopy *ecp, size_t sc)
275 ecp->v_rel = calloc((sc + 7) / 8, 1);
276 if (ecp->v_rel == NULL)
277 err(EXIT_FAILURE, "calloc failed");
279 if (elf_getshstrndx(ecp->ein, &indx) == 0)
280 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
284 while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
285 if (gelf_getshdr(s, &sh) != &sh)
286 errx(EXIT_FAILURE, "elf_getshdr failed: %s",
289 if (sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA)
293 * Skip if this reloc section won't appear in the
296 if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
297 errx(EXIT_FAILURE, "elf_strptr failed: %s",
299 if (is_remove_section(ecp, name) ||
300 is_remove_reloc_sec(ecp, sh.sh_info))
303 /* Skip if it's not for .symtab */
304 if (sh.sh_link != elf_ndxscn(ecp->symtab->is))
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)
315 "elf_getrel failed: %s",
317 n = GELF_R_SYM(r.r_info);
319 if (gelf_getrela(d, i, &ra) != &ra)
321 "elf_getrela failed: %s",
323 n = GELF_R_SYM(ra.r_info);
326 BIT_SET(ecp->v_rel, n);
328 warnx("invalid symbox index");
331 elferr = elf_errno();
333 errx(EXIT_FAILURE, "elf_getdata failed: %s",
336 elferr = elf_errno();
338 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
343 mark_section_group_symbols(struct elfcopy *ecp, size_t sc)
351 ecp->v_grp = calloc((sc + 7) / 8, 1);
352 if (ecp->v_grp == NULL)
353 err(EXIT_FAILURE, "calloc failed");
355 if (elf_getshstrndx(ecp->ein, &indx) == 0)
356 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
360 while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
361 if (gelf_getshdr(s, &sh) != &sh)
362 errx(EXIT_FAILURE, "elf_getshdr failed: %s",
365 if (sh.sh_type != SHT_GROUP)
368 if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
369 errx(EXIT_FAILURE, "elf_strptr failed: %s",
371 if (is_remove_section(ecp, name))
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");
379 elferr = elf_errno();
381 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
386 generate_symbols(struct elfcopy *ecp)
390 struct symbuf *sy_buf;
391 struct strbuf *st_buf;
399 size_t ishstrndx, namelen, ndx, sc, symndx;
402 if (elf_getshstrndx(ecp->ein, &ishstrndx) == 0)
403 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
405 if ((ec = gelf_getclass(ecp->eout)) == ELFCLASSNONE)
406 errx(EXIT_FAILURE, "gelf_getclass failed: %s",
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;
417 st_buf->l.sz = 1; /* '\0' at start. */
422 ecp->symtab->buf = sy_buf;
423 ecp->strtab->buf = st_buf;
428 * Create bit vector v_secsym, which is used to mark sections
429 * that already have corresponding STT_SECTION symbols.
431 ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1);
432 if (ecp->v_secsym == NULL)
433 err(EXIT_FAILURE, "calloc failed");
435 /* Locate .strtab of input object. */
439 while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
440 if (gelf_getshdr(is, &ish) != &ish)
441 errx(EXIT_FAILURE, "elf_getshdr failed: %s",
443 if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
445 errx(EXIT_FAILURE, "elf_strptr failed: %s",
447 if (strcmp(name, ".strtab") == 0) {
448 symndx = elf_ndxscn(is);
452 elferr = elf_errno();
454 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
457 /* Symbol table should exist if this function is called. */
459 warnx("can't find .strtab section");
463 /* Locate .symtab of input object. */
465 while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
466 if (gelf_getshdr(is, &ish) != &ish)
467 errx(EXIT_FAILURE, "elf_getshdr failed: %s",
469 if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
471 errx(EXIT_FAILURE, "elf_strptr failed: %s",
473 if (strcmp(name, ".symtab") == 0)
476 elferr = elf_errno();
478 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
481 errx(EXIT_FAILURE, "can't find .strtab section");
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.
489 sc = ish.sh_size / ish.sh_entsize;
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));
496 err(EXIT_FAILURE, "calloc failed");
497 if ((id = elf_getdata(is, NULL)) == NULL) {
498 elferr = elf_errno();
500 errx(EXIT_FAILURE, "elf_getdata failed: %s",
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",
512 if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL)
513 errx(EXIT_FAILURE, "elf_strptr failed: %s",
516 /* Symbol filtering. */
517 if (is_remove_symbol(ecp, sc, i, &sym, name) != 0)
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)) {
524 * XXX Binutils objcopy does not weaken certain
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) !=
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));
548 /* STB_LOCAL binding. */
549 if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) !=
551 sym.st_info = GELF_ST_INFO(STB_GLOBAL,
552 GELF_ST_TYPE(sym.st_info));
553 /* XXX We should globalize weak symbol? */
556 /* Check if we need to rename this symbol. */
557 if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL)
560 /* Check if we need to prefix the symbols. */
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,
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)) {
575 ecp->symndx[i] = sy_buf->ngs;
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);
585 * If the symbol is a STT_SECTION symbol, mark the section
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]);
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.
600 if (sy_buf->nls <= 1 && sy_buf->ngs == 0)
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.
608 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
611 if (strcmp(s->name, ".symtab") == 0 ||
612 strcmp(s->name, ".strtab") == 0 ||
613 strcmp(s->name, ".shstrtab") == 0)
615 if ((ecp->flags & RELOCATABLE) != 0 &&
616 ((s->type == SHT_REL) || (s->type == SHT_RELA)))
619 if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
620 errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
623 if (!BIT_ISSET(ecp->v_secsym, ndx)) {
625 sym.st_value = s->vma;
627 sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
628 sym.st_other = STV_DEFAULT;
630 * Don't let add_to_symtab() touch sym.st_shndx.
631 * In this case, we know the index already.
633 add_to_symtab(ecp, NULL, sym.st_value, sym.st_size,
634 ndx, sym.st_info, sym.st_other, 1);
639 * Update st_name and index map for global/weak symbols. Note that
640 * global/weak symbols are put after local symbols.
643 for(i = 0; (size_t) i < sc; i++) {
644 if (!BIT_ISSET(gsym, i))
647 /* Update st_name. */
648 if (ec == ELFCLASS32)
649 sy_buf->g32[ecp->symndx[i]].st_name +=
652 sy_buf->g64[ecp->symndx[i]].st_name +=
655 /* Update index map. */
656 ecp->symndx[i] += sy_buf->nls;
671 create_symtab(struct elfcopy *ecp)
673 struct section *s, *sy, *st;
679 assert(sy != NULL && st != NULL);
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.
690 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
693 if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
694 errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
699 ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1;
700 ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2;
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.
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);
713 free(ecp->strtab->buf);
717 ecp->flags &= ~SYMTAB_EXIST;
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",
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);
731 * Copy .symtab and .strtab section headers from input to output
732 * object to start with, these will be overridden later if need.
734 copy_shdr(ecp, sy, ".symtab", 1, 0);
735 copy_shdr(ecp, st, ".strtab", 1, 0);
737 /* Copy verbatim if symbol table is intact. */
738 if (ecp->flags & SYMTAB_INTACT) {
744 create_symtab_data(ecp);
748 free_symtab(struct elfcopy *ecp)
750 struct symbuf *sy_buf;
751 struct strbuf *st_buf;
752 struct sthash *sh, *shtmp;
755 if (ecp->symtab != NULL && ecp->symtab->buf != NULL) {
756 sy_buf = ecp->symtab->buf;
757 if (sy_buf->l32 != NULL)
759 if (sy_buf->g32 != NULL)
761 if (sy_buf->l64 != NULL)
763 if (sy_buf->g64 != NULL)
767 if (ecp->strtab != NULL && ecp->strtab->buf != NULL) {
768 st_buf = ecp->strtab->buf;
769 if (st_buf->l.buf != NULL)
771 if (st_buf->g.buf != NULL)
773 for (i = 0; i < STHASHSIZE; i++) {
774 LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next,
776 LIST_REMOVE(sh, sh_next);
779 LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next,
781 LIST_REMOVE(sh, sh_next);
787 if (ecp->symndx != NULL) {
791 if (ecp->v_rel != NULL) {
795 if (ecp->v_grp != NULL) {
799 if (ecp->v_secsym != NULL) {
801 ecp->v_secsym = NULL;
806 create_external_symtab(struct elfcopy *ecp)
809 struct symbuf *sy_buf;
810 struct strbuf *st_buf;
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);
818 ecp->symtab = create_external_section(ecp, ".symtab", NULL,
819 NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0);
821 ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0,
822 SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0);
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",
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",
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;
841 st_buf->l.sz = 1; /* '\0' at start. */
846 ecp->symtab->buf = sy_buf;
847 ecp->strtab->buf = st_buf;
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);
853 /* Create STT_SECTION symbols. */
854 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
857 if (strcmp(s->name, ".symtab") == 0 ||
858 strcmp(s->name, ".strtab") == 0 ||
859 strcmp(s->name, ".shstrtab") == 0)
862 if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) {
863 warnx("elf_ndxscn failed: %s",
867 add_to_symtab(ecp, NULL, 0, 0, ndx,
868 GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1);
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)
877 struct symbuf *sy_buf;
878 struct strbuf *st_buf;
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.
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"); \
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; \
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; \
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"); \
921 if (name != NULL && *name != '\0') { \
922 pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\
925 sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos; \
927 sy_buf->B##SZ[sy_buf->n##B##s].st_name = \
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, \
934 if (st_buf->B.buf == NULL) \
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, \
944 strncpy(&st_buf->B.buf[st_buf->B.sz], name, \
946 st_buf->B.buf[st_buf->B.sz + strlen(name)] = '\0'; \
947 st_buf->B.sz += strlen(name) + 1; \
950 sy_buf->B##SZ[sy_buf->n##B##s].st_name = \
951 (Elf##SZ##_Word)_ST_NAME_EMPTY_##B; \
955 sy_buf = ecp->symtab->buf;
956 st_buf = ecp->strtab->buf;
958 if (ecp->oec == ELFCLASS32) {
959 if (is_local_symbol(st_info))
964 if (is_local_symbol(st_info))
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;
976 #undef _ST_NAME_EMPTY_l
977 #undef _ST_NAME_EMPTY_g
981 finalize_external_symtab(struct elfcopy *ecp)
983 struct symbuf *sy_buf;
984 struct strbuf *st_buf;
988 * Update st_name for global/weak symbols. (global/weak symbols
989 * are put after local symbols)
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;
998 sy_buf->g32[i].st_name += st_buf->l.sz;
1000 if (sy_buf->g64[i].st_name == (Elf64_Word)-1)
1001 sy_buf->g64[i].st_name = 0;
1003 sy_buf->g64[i].st_name += st_buf->l.sz;
1009 create_symtab_data(struct elfcopy *ecp)
1011 struct section *sy, *st;
1012 struct symbuf *sy_buf;
1013 struct strbuf *st_buf;
1014 Elf_Data *gsydata, *lsydata, *gstdata, *lstdata;
1020 if (gelf_getshdr(sy->os, ­) == NULL)
1021 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1023 if (gelf_getshdr(st->os, &sht) == NULL)
1024 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
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.
1033 if (sy_buf->nls > 0) {
1034 if ((lsydata = elf_newdata(sy->os)) == NULL)
1035 errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1037 if (ecp->oec == ELFCLASS32) {
1038 lsydata->d_align = 4;
1040 lsydata->d_buf = sy_buf->l32;
1041 lsydata->d_size = sy_buf->nls *
1043 lsydata->d_type = ELF_T_SYM;
1044 lsydata->d_version = EV_CURRENT;
1046 lsydata->d_align = 8;
1048 lsydata->d_buf = sy_buf->l64;
1049 lsydata->d_size = sy_buf->nls *
1051 lsydata->d_type = ELF_T_SYM;
1052 lsydata->d_version = EV_CURRENT;
1055 if (sy_buf->ngs > 0) {
1056 if ((gsydata = elf_newdata(sy->os)) == NULL)
1057 errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1059 if (ecp->oec == ELFCLASS32) {
1060 gsydata->d_align = 4;
1061 gsydata->d_off = sy_buf->nls *
1063 gsydata->d_buf = sy_buf->g32;
1064 gsydata->d_size = sy_buf->ngs *
1066 gsydata->d_type = ELF_T_SYM;
1067 gsydata->d_version = EV_CURRENT;
1069 gsydata->d_align = 8;
1070 gsydata->d_off = sy_buf->nls *
1072 gsydata->d_buf = sy_buf->g64;
1073 gsydata->d_size = sy_buf->ngs *
1075 gsydata->d_type = ELF_T_SYM;
1076 gsydata->d_version = EV_CURRENT;
1081 * Create two Elf_Data for .strtab, one for local symbol name
1082 * and another for globals. Same as .symtab, local symbol names
1086 if ((lstdata = elf_newdata(st->os)) == NULL)
1087 errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1089 lstdata->d_align = 1;
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;
1096 if (st_buf->g.sz > 0) {
1097 if ((gstdata = elf_newdata(st->os)) == NULL)
1098 errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
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;
1109 shy.sh_addralign = (ecp->oec == ELFCLASS32 ? 4 : 8);
1110 shy.sh_size = sy->sz;
1111 shy.sh_type = SHT_SYMTAB;
1113 shy.sh_entsize = gelf_fsize(ecp->eout, ELF_T_SYM, 1,
1116 * According to SYSV abi, here sh_info is one greater than
1117 * the symbol table index of the last local symbol(binding
1120 shy.sh_info = sy_buf->nls;
1123 sht.sh_addralign = 1;
1124 sht.sh_size = st->sz;
1125 sht.sh_type = SHT_STRTAB;
1131 if (!gelf_update_shdr(sy->os, ­))
1132 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1134 if (!gelf_update_shdr(st->os, &sht))
1135 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1140 add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname,
1145 assert (name != NULL);
1146 STAILQ_FOREACH(s, &ecp->v_symop, symop_list)
1147 if (!strcmp(name, s->name))
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);
1155 if (op == SYMOP_REDEF)
1156 s->newname = newname;
1161 lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op)
1163 struct symop *s, *ret;
1164 const char *pattern;
1166 STAILQ_FOREACH(s, &ecp->v_symop, symop_list) {
1167 if ((s->op & op) == 0)
1169 if (name == NULL || !strcmp(name, s->name))
1171 if ((ecp->flags & WILDCARD) == 0)
1174 /* Handle wildcards. */
1176 if (pattern[0] == '!') {
1177 /* Negative match. */
1181 /* Regular wildcard match. */
1184 if (!fnmatch(pattern, name, 0))
1192 lookup_exact_string(hash_head *buckets, const char *buf, const char *s)
1198 LIST_FOREACH(sh, &buckets[hash], sh_next)
1199 if (strcmp(buf + sh->sh_off, s) == 0)
1205 str_hash(const char *s)
1209 for (hash = 2166136261UL; *s; s++)
1210 hash = (hash ^ *s) * 16777619;
1212 return (hash & (STHASHSIZE - 1));