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>
36 ELFTC_VCSID("$Id: symbols.c 3222 2015-05-24 23:47:23Z kaiwang27 $");
38 /* Symbol table buffer structure. */
40 Elf32_Sym *l32; /* 32bit local symbol */
41 Elf32_Sym *g32; /* 32bit global symbol */
42 Elf64_Sym *l64; /* 64bit local symbol */
43 Elf64_Sym *g64; /* 64bit global symbol */
44 size_t ngs, nls; /* number of each kind */
45 size_t gcap, lcap; /* buffer capacities. */
49 LIST_ENTRY(sthash) sh_next;
52 typedef LIST_HEAD(,sthash) hash_head;
53 #define STHASHSIZE 65536
56 char *buf; /* string table */
57 size_t sz; /* entries */
58 size_t cap; /* buffer capacity */
59 hash_head hash[STHASHSIZE];
63 /* String table buffer structure. */
65 struct strimpl l; /* local symbols */
66 struct strimpl g; /* global symbols */
69 static int is_debug_symbol(unsigned char st_info);
70 static int is_global_symbol(unsigned char st_info);
71 static int is_local_symbol(unsigned char st_info);
72 static int is_local_label(const char *name);
73 static int is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s);
74 static int is_remove_symbol(struct elfcopy *ecp, size_t sc, int i,
75 GElf_Sym *s, const char *name);
76 static int is_weak_symbol(unsigned char st_info);
77 static int lookup_exact_string(hash_head *hash, const char *buf,
79 static int generate_symbols(struct elfcopy *ecp);
80 static void mark_reloc_symbols(struct elfcopy *ecp, size_t sc);
81 static void mark_section_group_symbols(struct elfcopy *ecp, size_t sc);
82 static int match_wildcard(const char *name, const char *pattern);
83 uint32_t str_hash(const char *s);
85 /* Convenient bit vector operation macros. */
86 #define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7))
87 #define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7)))
88 #define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7)))
91 is_debug_symbol(unsigned char st_info)
94 if (GELF_ST_TYPE(st_info) == STT_SECTION ||
95 GELF_ST_TYPE(st_info) == STT_FILE)
102 is_global_symbol(unsigned char st_info)
105 if (GELF_ST_BIND(st_info) == STB_GLOBAL)
112 is_weak_symbol(unsigned char st_info)
115 if (GELF_ST_BIND(st_info) == STB_WEAK)
122 is_local_symbol(unsigned char st_info)
125 if (GELF_ST_BIND(st_info) == STB_LOCAL)
132 is_hidden_symbol(unsigned char st_other)
135 if (GELF_ST_VISIBILITY(st_other) == STV_HIDDEN ||
136 GELF_ST_VISIBILITY(st_other) == STV_INTERNAL)
143 is_local_label(const char *name)
146 /* Compiler generated local symbols that start with .L */
147 if (name[0] == '.' && name[1] == 'L')
154 * Symbols related to relocation are needed.
157 is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s)
160 /* If symbol involves relocation, it is needed. */
161 if (BIT_ISSET(ecp->v_rel, i))
164 /* Symbols refered by COMDAT sections are needed. */
165 if (BIT_ISSET(ecp->v_grp, i))
169 * For relocatable files (.o files), global and weak symbols
172 if (ecp->flags & RELOCATABLE) {
173 if (is_global_symbol(s->st_info) || is_weak_symbol(s->st_info))
181 is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s,
190 SHN_UNDEF, /* st_shndx */
193 if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL)
196 if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL)
200 * Keep the first symbol if it is the special reserved symbol.
201 * XXX Should we generate one if it's missing?
203 if (i == 0 && !memcmp(s, &sym0, sizeof(GElf_Sym)))
206 /* Remove the symbol if the section it refers to was removed. */
207 if (s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE &&
208 ecp->secndx[s->st_shndx] == 0)
211 if (ecp->strip == STRIP_ALL)
214 if (ecp->v_rel == NULL)
215 mark_reloc_symbols(ecp, sc);
217 if (ecp->v_grp == NULL)
218 mark_section_group_symbols(ecp, sc);
220 if (is_needed_symbol(ecp, i, s))
223 if (ecp->strip == STRIP_UNNEEDED)
226 if ((ecp->flags & DISCARD_LOCAL) && is_local_symbol(s->st_info) &&
227 !is_debug_symbol(s->st_info))
230 if ((ecp->flags & DISCARD_LLABEL) && is_local_symbol(s->st_info) &&
231 !is_debug_symbol(s->st_info) && is_local_label(name))
234 if (ecp->strip == STRIP_DEBUG && is_debug_symbol(s->st_info))
241 * Mark symbols refered by relocation entries.
244 mark_reloc_symbols(struct elfcopy *ecp, size_t sc)
255 ecp->v_rel = calloc((sc + 7) / 8, 1);
256 if (ecp->v_rel == NULL)
257 err(EXIT_FAILURE, "calloc failed");
259 if (elf_getshstrndx(ecp->ein, &indx) == 0)
260 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
264 while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
265 if (gelf_getshdr(s, &sh) != &sh)
266 errx(EXIT_FAILURE, "elf_getshdr failed: %s",
269 if (sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA)
273 * Skip if this reloc section won't appear in the
276 if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
277 errx(EXIT_FAILURE, "elf_strptr failed: %s",
279 if (is_remove_section(ecp, name) ||
280 is_remove_reloc_sec(ecp, sh.sh_info))
283 /* Skip if it's not for .symtab */
284 if (sh.sh_link != elf_ndxscn(ecp->symtab->is))
289 while (n < sh.sh_size && (d = elf_getdata(s, d)) != NULL) {
290 len = d->d_size / sh.sh_entsize;
291 for (i = 0; i < len; i++) {
292 if (sh.sh_type == SHT_REL) {
293 if (gelf_getrel(d, i, &r) != &r)
295 "elf_getrel failed: %s",
297 n = GELF_R_SYM(r.r_info);
299 if (gelf_getrela(d, i, &ra) != &ra)
301 "elf_getrela failed: %s",
303 n = GELF_R_SYM(ra.r_info);
306 BIT_SET(ecp->v_rel, n);
308 warnx("invalid symbox index");
311 elferr = elf_errno();
313 errx(EXIT_FAILURE, "elf_getdata failed: %s",
316 elferr = elf_errno();
318 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
323 mark_section_group_symbols(struct elfcopy *ecp, size_t sc)
331 ecp->v_grp = calloc((sc + 7) / 8, 1);
332 if (ecp->v_grp == NULL)
333 err(EXIT_FAILURE, "calloc failed");
335 if (elf_getshstrndx(ecp->ein, &indx) == 0)
336 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
340 while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
341 if (gelf_getshdr(s, &sh) != &sh)
342 errx(EXIT_FAILURE, "elf_getshdr failed: %s",
345 if (sh.sh_type != SHT_GROUP)
348 if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
349 errx(EXIT_FAILURE, "elf_strptr failed: %s",
351 if (is_remove_section(ecp, name))
354 if (sh.sh_info > 0 && sh.sh_info < sc)
355 BIT_SET(ecp->v_grp, sh.sh_info);
356 else if (sh.sh_info != 0)
357 warnx("invalid symbox index");
359 elferr = elf_errno();
361 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
366 generate_symbols(struct elfcopy *ecp)
370 struct symbuf *sy_buf;
371 struct strbuf *st_buf;
379 size_t ishstrndx, namelen, ndx, sc, symndx;
382 if (elf_getshstrndx(ecp->ein, &ishstrndx) == 0)
383 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
385 if ((ec = gelf_getclass(ecp->eout)) == ELFCLASSNONE)
386 errx(EXIT_FAILURE, "gelf_getclass failed: %s",
389 /* Create buffers for .symtab and .strtab. */
390 if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
391 err(EXIT_FAILURE, "calloc failed");
392 if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
393 err(EXIT_FAILURE, "calloc failed");
394 sy_buf->gcap = sy_buf->lcap = 64;
397 st_buf->l.sz = 1; /* '\0' at start. */
402 ecp->symtab->buf = sy_buf;
403 ecp->strtab->buf = st_buf;
408 * Create bit vector v_secsym, which is used to mark sections
409 * that already have corresponding STT_SECTION symbols.
411 ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1);
412 if (ecp->v_secsym == NULL)
413 err(EXIT_FAILURE, "calloc failed");
415 /* Locate .strtab of input object. */
419 while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
420 if (gelf_getshdr(is, &ish) != &ish)
421 errx(EXIT_FAILURE, "elf_getshdr failed: %s",
423 if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
425 errx(EXIT_FAILURE, "elf_strptr failed: %s",
427 if (strcmp(name, ".strtab") == 0) {
428 symndx = elf_ndxscn(is);
432 elferr = elf_errno();
434 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
437 /* Symbol table should exist if this function is called. */
439 warnx("can't find .strtab section");
443 /* Locate .symtab of input object. */
445 while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
446 if (gelf_getshdr(is, &ish) != &ish)
447 errx(EXIT_FAILURE, "elf_getshdr failed: %s",
449 if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
451 errx(EXIT_FAILURE, "elf_strptr failed: %s",
453 if (strcmp(name, ".symtab") == 0)
456 elferr = elf_errno();
458 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
461 errx(EXIT_FAILURE, "can't find .strtab section");
464 * Create bit vector gsym to mark global symbols, and symndx
465 * to keep track of symbol index changes from input object to
466 * output object, it is used by update_reloc() later to update
467 * relocation information.
469 sc = ish.sh_size / ish.sh_entsize;
471 ecp->symndx = calloc(sc, sizeof(*ecp->symndx));
472 if (ecp->symndx == NULL)
473 err(EXIT_FAILURE, "calloc failed");
474 gsym = calloc((sc + 7) / 8, sizeof(*gsym));
476 err(EXIT_FAILURE, "calloc failed");
477 if ((id = elf_getdata(is, NULL)) == NULL) {
478 elferr = elf_errno();
480 errx(EXIT_FAILURE, "elf_getdata failed: %s",
487 /* Copy/Filter each symbol. */
488 for (i = 0; (size_t)i < sc; i++) {
489 if (gelf_getsym(id, i, &sym) != &sym)
490 errx(EXIT_FAILURE, "gelf_getsym failed: %s",
492 if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL)
493 errx(EXIT_FAILURE, "elf_strptr failed: %s",
496 /* Symbol filtering. */
497 if (is_remove_symbol(ecp, sc, i, &sym, name) != 0)
500 /* Check if we need to change the binding of this symbol. */
501 if (is_global_symbol(sym.st_info) ||
502 is_weak_symbol(sym.st_info)) {
504 * XXX Binutils objcopy does not weaken certain
507 if (ecp->flags & WEAKEN_ALL ||
508 lookup_symop_list(ecp, name, SYMOP_WEAKEN) != NULL)
509 sym.st_info = GELF_ST_INFO(STB_WEAK,
510 GELF_ST_TYPE(sym.st_info));
511 /* Do not localize undefined symbols. */
512 if (sym.st_shndx != SHN_UNDEF &&
513 lookup_symop_list(ecp, name, SYMOP_LOCALIZE) !=
515 sym.st_info = GELF_ST_INFO(STB_LOCAL,
516 GELF_ST_TYPE(sym.st_info));
517 if (ecp->flags & KEEP_GLOBAL &&
518 sym.st_shndx != SHN_UNDEF &&
519 lookup_symop_list(ecp, name, SYMOP_KEEPG) == NULL)
520 sym.st_info = GELF_ST_INFO(STB_LOCAL,
521 GELF_ST_TYPE(sym.st_info));
522 if (ecp->flags & LOCALIZE_HIDDEN &&
523 sym.st_shndx != SHN_UNDEF &&
524 is_hidden_symbol(sym.st_other))
525 sym.st_info = GELF_ST_INFO(STB_LOCAL,
526 GELF_ST_TYPE(sym.st_info));
528 /* STB_LOCAL binding. */
529 if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) !=
531 sym.st_info = GELF_ST_INFO(STB_GLOBAL,
532 GELF_ST_TYPE(sym.st_info));
533 /* XXX We should globalize weak symbol? */
536 /* Check if we need to rename this symbol. */
537 if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL)
540 /* Check if we need to prefix the symbols. */
542 if (ecp->prefix_sym != NULL && name != NULL && *name != '\0') {
543 namelen = strlen(name) + strlen(ecp->prefix_sym) + 1;
544 if ((newname = malloc(namelen)) == NULL)
545 err(EXIT_FAILURE, "malloc failed");
546 snprintf(newname, namelen, "%s%s", ecp->prefix_sym,
551 /* Copy symbol, mark global/weak symbol and add to index map. */
552 if (is_global_symbol(sym.st_info) ||
553 is_weak_symbol(sym.st_info)) {
555 ecp->symndx[i] = sy_buf->ngs;
557 ecp->symndx[i] = sy_buf->nls;
558 add_to_symtab(ecp, name, sym.st_value, sym.st_size,
559 sym.st_shndx, sym.st_info, sym.st_other, 0);
565 * If the symbol is a STT_SECTION symbol, mark the section
568 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION)
569 BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]);
573 * Give up if there is no real symbols inside the table.
574 * XXX The logic here needs to be improved. We need to
575 * check if that only local symbol is the reserved symbol.
577 if (sy_buf->nls <= 1 && sy_buf->ngs == 0)
581 * Create STT_SECTION symbols for sections that do not already
582 * got one. However, we do not create STT_SECTION symbol for
583 * .symtab, .strtab, .shstrtab and reloc sec of relocatables.
585 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
588 if (strcmp(s->name, ".symtab") == 0 ||
589 strcmp(s->name, ".strtab") == 0 ||
590 strcmp(s->name, ".shstrtab") == 0)
592 if ((ecp->flags & RELOCATABLE) != 0 &&
593 ((s->type == SHT_REL) || (s->type == SHT_RELA)))
596 if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
597 errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
600 if (!BIT_ISSET(ecp->v_secsym, ndx)) {
602 sym.st_value = s->vma;
604 sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
605 sym.st_other = STV_DEFAULT;
607 * Don't let add_to_symtab() touch sym.st_shndx.
608 * In this case, we know the index already.
610 add_to_symtab(ecp, NULL, sym.st_value, sym.st_size,
611 ndx, sym.st_info, sym.st_other, 1);
616 * Update st_name and index map for global/weak symbols. Note that
617 * global/weak symbols are put after local symbols.
620 for(i = 0; (size_t) i < sc; i++) {
621 if (!BIT_ISSET(gsym, i))
624 /* Update st_name. */
625 if (ec == ELFCLASS32)
626 sy_buf->g32[ecp->symndx[i]].st_name +=
629 sy_buf->g64[ecp->symndx[i]].st_name +=
632 /* Update index map. */
633 ecp->symndx[i] += sy_buf->nls;
648 create_symtab(struct elfcopy *ecp)
650 struct section *s, *sy, *st;
657 * Set section index map for .symtab and .strtab. We need to set
658 * these map because otherwise symbols which refer to .symtab and
659 * .strtab will be removed by symbol filtering unconditionally.
660 * And we have to figure out scn index this way (instead of calling
661 * elf_ndxscn) because we can not create Elf_Scn before we're certain
662 * that .symtab and .strtab will exist in the output object.
665 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
668 if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
669 errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
674 ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1;
675 ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2;
678 * Generate symbols for output object if SYMTAB_INTACT is not set.
679 * If there is no symbol in the input object or all the symbols are
680 * stripped, then free all the resouces allotted for symbol table,
681 * and clear SYMTAB_EXIST flag.
683 if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) {
684 TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list);
685 TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list);
686 free(ecp->symtab->buf);
688 free(ecp->strtab->buf);
692 ecp->flags &= ~SYMTAB_EXIST;
696 /* Create output Elf_Scn for .symtab and .strtab. */
697 if ((sy->os = elf_newscn(ecp->eout)) == NULL ||
698 (st->os = elf_newscn(ecp->eout)) == NULL)
699 errx(EXIT_FAILURE, "elf_newscn failed: %s",
701 /* Update secndx anyway. */
702 ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os);
703 ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os);
706 * Copy .symtab and .strtab section headers from input to output
707 * object to start with, these will be overridden later if need.
709 copy_shdr(ecp, sy, ".symtab", 1, 0);
710 copy_shdr(ecp, st, ".strtab", 1, 0);
712 /* Copy verbatim if symbol table is intact. */
713 if (ecp->flags & SYMTAB_INTACT) {
719 create_symtab_data(ecp);
723 free_symtab(struct elfcopy *ecp)
725 struct symbuf *sy_buf;
726 struct strbuf *st_buf;
727 struct sthash *sh, *shtmp;
730 if (ecp->symtab != NULL && ecp->symtab->buf != NULL) {
731 sy_buf = ecp->symtab->buf;
732 if (sy_buf->l32 != NULL)
734 if (sy_buf->g32 != NULL)
736 if (sy_buf->l64 != NULL)
738 if (sy_buf->g64 != NULL)
742 if (ecp->strtab != NULL && ecp->strtab->buf != NULL) {
743 st_buf = ecp->strtab->buf;
744 if (st_buf->l.buf != NULL)
746 if (st_buf->g.buf != NULL)
748 for (i = 0; i < STHASHSIZE; i++) {
749 LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next,
751 LIST_REMOVE(sh, sh_next);
754 LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next,
756 LIST_REMOVE(sh, sh_next);
762 if (ecp->symndx != NULL) {
766 if (ecp->v_rel != NULL) {
770 if (ecp->v_grp != NULL) {
774 if (ecp->v_secsym != NULL) {
776 ecp->v_secsym = NULL;
781 create_external_symtab(struct elfcopy *ecp)
784 struct symbuf *sy_buf;
785 struct strbuf *st_buf;
789 if (ecp->oec == ELFCLASS32)
790 ecp->symtab = create_external_section(ecp, ".symtab", NULL,
791 NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0);
793 ecp->symtab = create_external_section(ecp, ".symtab", NULL,
794 NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0);
796 ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0,
797 SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0);
799 /* Let sh_link field of .symtab section point to .strtab section. */
800 if (gelf_getshdr(ecp->symtab->os, &sh) == NULL)
801 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
803 sh.sh_link = elf_ndxscn(ecp->strtab->os);
804 if (!gelf_update_shdr(ecp->symtab->os, &sh))
805 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
808 /* Create buffers for .symtab and .strtab. */
809 if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
810 err(EXIT_FAILURE, "calloc failed");
811 if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
812 err(EXIT_FAILURE, "calloc failed");
813 sy_buf->gcap = sy_buf->lcap = 64;
816 st_buf->l.sz = 1; /* '\0' at start. */
821 ecp->symtab->buf = sy_buf;
822 ecp->strtab->buf = st_buf;
824 /* Always create the special symbol at the symtab beginning. */
825 add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF,
826 ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1);
828 /* Create STT_SECTION symbols. */
829 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
832 if (strcmp(s->name, ".symtab") == 0 ||
833 strcmp(s->name, ".strtab") == 0 ||
834 strcmp(s->name, ".shstrtab") == 0)
837 if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) {
838 warnx("elf_ndxscn failed: %s",
842 add_to_symtab(ecp, NULL, 0, 0, ndx,
843 GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1);
848 add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value,
849 uint64_t st_size, uint16_t st_shndx, unsigned char st_info,
850 unsigned char st_other, int ndx_known)
852 struct symbuf *sy_buf;
853 struct strbuf *st_buf;
859 * Convenient macro for copying global/local 32/64 bit symbols
860 * from input object to the buffer created for output object.
861 * It handles buffer growing, st_name calculating and st_shndx
862 * updating for symbols with non-special section index.
864 #define _ADDSYM(B, SZ) do { \
865 if (sy_buf->B##SZ == NULL) { \
866 sy_buf->B##SZ = malloc(sy_buf->B##cap * \
867 sizeof(Elf##SZ##_Sym)); \
868 if (sy_buf->B##SZ == NULL) \
869 err(EXIT_FAILURE, "malloc failed"); \
870 } else if (sy_buf->n##B##s >= sy_buf->B##cap) { \
871 sy_buf->B##cap *= 2; \
872 sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap * \
873 sizeof(Elf##SZ##_Sym)); \
874 if (sy_buf->B##SZ == NULL) \
875 err(EXIT_FAILURE, "realloc failed"); \
877 sy_buf->B##SZ[sy_buf->n##B##s].st_info = st_info; \
878 sy_buf->B##SZ[sy_buf->n##B##s].st_other = st_other; \
879 sy_buf->B##SZ[sy_buf->n##B##s].st_value = st_value; \
880 sy_buf->B##SZ[sy_buf->n##B##s].st_size = st_size; \
882 sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \
883 else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE) \
884 sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \
886 sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = \
887 ecp->secndx[st_shndx]; \
888 if (st_buf->B.buf == NULL) { \
889 st_buf->B.buf = calloc(st_buf->B.cap, \
890 sizeof(*st_buf->B.buf)); \
891 if (st_buf->B.buf == NULL) \
892 err(EXIT_FAILURE, "malloc failed"); \
894 if (name != NULL && *name != '\0') { \
895 pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\
898 sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos; \
900 sy_buf->B##SZ[sy_buf->n##B##s].st_name = \
902 while (st_buf->B.sz + strlen(name) >= \
903 st_buf->B.cap - 1) { \
904 st_buf->B.cap *= 2; \
905 st_buf->B.buf = realloc(st_buf->B.buf, \
907 if (st_buf->B.buf == NULL) \
911 if ((sh = malloc(sizeof(*sh))) == NULL) \
912 err(EXIT_FAILURE, "malloc failed"); \
913 sh->sh_off = st_buf->B.sz; \
914 hash = str_hash(name); \
915 LIST_INSERT_HEAD(&st_buf->B.hash[hash], sh, \
917 strncpy(&st_buf->B.buf[st_buf->B.sz], name, \
919 st_buf->B.buf[st_buf->B.sz + strlen(name)] = '\0'; \
920 st_buf->B.sz += strlen(name) + 1; \
923 sy_buf->B##SZ[sy_buf->n##B##s].st_name = 0; \
927 sy_buf = ecp->symtab->buf;
928 st_buf = ecp->strtab->buf;
930 if (ecp->oec == ELFCLASS32) {
931 if (is_local_symbol(st_info))
936 if (is_local_symbol(st_info))
942 /* Update section size. */
943 ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) *
944 (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym));
945 ecp->strtab->sz = st_buf->l.sz + st_buf->g.sz;
951 finalize_external_symtab(struct elfcopy *ecp)
953 struct symbuf *sy_buf;
954 struct strbuf *st_buf;
958 * Update st_name for global/weak symbols. (global/weak symbols
959 * are put after local symbols)
961 sy_buf = ecp->symtab->buf;
962 st_buf = ecp->strtab->buf;
963 for (i = 0; (size_t) i < sy_buf->ngs; i++) {
964 if (ecp->oec == ELFCLASS32)
965 sy_buf->g32[i].st_name += st_buf->l.sz;
967 sy_buf->g64[i].st_name += st_buf->l.sz;
972 create_symtab_data(struct elfcopy *ecp)
974 struct section *sy, *st;
975 struct symbuf *sy_buf;
976 struct strbuf *st_buf;
977 Elf_Data *gsydata, *lsydata, *gstdata, *lstdata;
983 if (gelf_getshdr(sy->os, ­) == NULL)
984 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
986 if (gelf_getshdr(st->os, &sht) == NULL)
987 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
991 * Create two Elf_Data for .symtab section of output object, one
992 * for local symbols and another for global symbols. Note that
993 * local symbols appear first in the .symtab.
996 if (sy_buf->nls > 0) {
997 if ((lsydata = elf_newdata(sy->os)) == NULL)
998 errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1000 if (ecp->oec == ELFCLASS32) {
1001 lsydata->d_align = 4;
1003 lsydata->d_buf = sy_buf->l32;
1004 lsydata->d_size = sy_buf->nls *
1006 lsydata->d_type = ELF_T_SYM;
1007 lsydata->d_version = EV_CURRENT;
1009 lsydata->d_align = 8;
1011 lsydata->d_buf = sy_buf->l64;
1012 lsydata->d_size = sy_buf->nls *
1014 lsydata->d_type = ELF_T_SYM;
1015 lsydata->d_version = EV_CURRENT;
1018 if (sy_buf->ngs > 0) {
1019 if ((gsydata = elf_newdata(sy->os)) == NULL)
1020 errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1022 if (ecp->oec == ELFCLASS32) {
1023 gsydata->d_align = 4;
1024 gsydata->d_off = sy_buf->nls *
1026 gsydata->d_buf = sy_buf->g32;
1027 gsydata->d_size = sy_buf->ngs *
1029 gsydata->d_type = ELF_T_SYM;
1030 gsydata->d_version = EV_CURRENT;
1032 gsydata->d_align = 8;
1033 gsydata->d_off = sy_buf->nls *
1035 gsydata->d_buf = sy_buf->g64;
1036 gsydata->d_size = sy_buf->ngs *
1038 gsydata->d_type = ELF_T_SYM;
1039 gsydata->d_version = EV_CURRENT;
1044 * Create two Elf_Data for .strtab, one for local symbol name
1045 * and another for globals. Same as .symtab, local symbol names
1049 if ((lstdata = elf_newdata(st->os)) == NULL)
1050 errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1052 lstdata->d_align = 1;
1054 lstdata->d_buf = st_buf->l.buf;
1055 lstdata->d_size = st_buf->l.sz;
1056 lstdata->d_type = ELF_T_BYTE;
1057 lstdata->d_version = EV_CURRENT;
1059 if (st_buf->g.sz > 0) {
1060 if ((gstdata = elf_newdata(st->os)) == NULL)
1061 errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1063 gstdata->d_align = 1;
1064 gstdata->d_off = lstdata->d_size;
1065 gstdata->d_buf = st_buf->g.buf;
1066 gstdata->d_size = st_buf->g.sz;
1067 gstdata->d_type = ELF_T_BYTE;
1068 gstdata->d_version = EV_CURRENT;
1072 shy.sh_addralign = (ecp->oec == ELFCLASS32 ? 4 : 8);
1073 shy.sh_size = sy->sz;
1074 shy.sh_type = SHT_SYMTAB;
1076 shy.sh_entsize = gelf_fsize(ecp->eout, ELF_T_SYM, 1,
1079 * According to SYSV abi, here sh_info is one greater than
1080 * the symbol table index of the last local symbol(binding
1083 shy.sh_info = sy_buf->nls;
1086 sht.sh_addralign = 1;
1087 sht.sh_size = st->sz;
1088 sht.sh_type = SHT_STRTAB;
1094 if (!gelf_update_shdr(sy->os, ­))
1095 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1097 if (!gelf_update_shdr(st->os, &sht))
1098 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1103 add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname,
1108 if ((s = lookup_symop_list(ecp, name, ~0U)) == NULL) {
1109 if ((s = calloc(1, sizeof(*s))) == NULL)
1110 errx(EXIT_FAILURE, "not enough memory");
1112 if (op == SYMOP_REDEF)
1113 s->newname = newname;
1117 STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list);
1121 match_wildcard(const char *name, const char *pattern)
1126 if (*pattern == '!') {
1132 if (!fnmatch(pattern, name, 0))
1135 return (reverse ? !match : match);
1139 lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op)
1143 STAILQ_FOREACH(s, &ecp->v_symop, symop_list) {
1144 if (name == NULL || !strcmp(name, s->name) ||
1145 ((ecp->flags & WILDCARD) && match_wildcard(name, s->name)))
1146 if ((s->op & op) != 0)
1154 lookup_exact_string(hash_head *buckets, const char *buf, const char *s)
1160 LIST_FOREACH(sh, &buckets[hash], sh_next)
1161 if (strcmp(buf + sh->sh_off, s) == 0)
1167 str_hash(const char *s)
1171 for (hash = 2166136261UL; *s; s++)
1172 hash = (hash ^ *s) * 16777619;
1174 return (hash & (STHASHSIZE - 1));