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> 28*839529caSEd 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*839529caSEd Maste ELFTC_VCSID("$Id: symbols.c 3376 2016-01-26 18:41:39Z emaste $"); 38*839529caSEd Maste 39*839529caSEd Maste /* Backwards compatibility for systems with older ELF definitions. */ 40*839529caSEd Maste #ifndef STB_GNU_UNIQUE 41*839529caSEd Maste #define STB_GNU_UNIQUE 10 42*839529caSEd Maste #endif 43*839529caSEd 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 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 108a85fe12eSEd Maste is_global_symbol(unsigned char st_info) 109a85fe12eSEd Maste { 110a85fe12eSEd Maste 111*839529caSEd Maste if (GELF_ST_BIND(st_info) == STB_GLOBAL || 112*839529caSEd 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 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 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 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 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 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 1713ef90571SEd Maste /* Symbols refered 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 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 212*839529caSEd Maste /* Keep the symbol if specified by command line option -K. */ 213*839529caSEd Maste if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) 214*839529caSEd Maste return (0); 215*839529caSEd Maste 216a85fe12eSEd Maste if (ecp->strip == STRIP_ALL) 217a85fe12eSEd Maste return (1); 218a85fe12eSEd Maste 219*839529caSEd Maste /* Mark symbols used in relocation. */ 220a85fe12eSEd Maste if (ecp->v_rel == NULL) 2213ef90571SEd Maste mark_reloc_symbols(ecp, sc); 2223ef90571SEd Maste 223*839529caSEd Maste /* Mark symbols used in section groups. */ 2243ef90571SEd Maste if (ecp->v_grp == NULL) 2253ef90571SEd Maste mark_section_group_symbols(ecp, sc); 226a85fe12eSEd Maste 227*839529caSEd Maste /* 228*839529caSEd Maste * Strip the symbol if specified by command line option -N, 229*839529caSEd Maste * unless it's used in relocation. 230*839529caSEd Maste */ 231*839529caSEd Maste if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) { 232*839529caSEd Maste if (BIT_ISSET(ecp->v_rel, i)) { 233*839529caSEd Maste warnx("not stripping symbol `%s' because it is named" 234*839529caSEd Maste " in a relocation", name); 235*839529caSEd Maste return (0); 236*839529caSEd Maste } 237*839529caSEd Maste return (1); 238*839529caSEd Maste } 239*839529caSEd 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 /* 261a85fe12eSEd Maste * Mark symbols refered by relocation entries. 262a85fe12eSEd Maste */ 263a85fe12eSEd Maste static void 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 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 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 */ 588*839529caSEd Maste if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 589*839529caSEd Maste sym.st_shndx < SHN_LORESERVE) { 590*839529caSEd 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 } 593*839529caSEd 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 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 679a85fe12eSEd Maste /* 680a85fe12eSEd Maste * Set section index map for .symtab and .strtab. We need to set 681a85fe12eSEd Maste * these map because otherwise symbols which refer to .symtab and 682a85fe12eSEd Maste * .strtab will be removed by symbol filtering unconditionally. 683a85fe12eSEd Maste * And we have to figure out scn index this way (instead of calling 684a85fe12eSEd Maste * elf_ndxscn) because we can not create Elf_Scn before we're certain 685a85fe12eSEd Maste * that .symtab and .strtab will exist in the output object. 686a85fe12eSEd Maste */ 687a85fe12eSEd Maste maxndx = 0; 688a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 689a85fe12eSEd Maste if (s->os == NULL) 690a85fe12eSEd Maste continue; 691a85fe12eSEd Maste if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) 692a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_ndxscn failed: %s", 693a85fe12eSEd Maste elf_errmsg(-1)); 694a85fe12eSEd Maste if (ndx > maxndx) 695a85fe12eSEd Maste maxndx = ndx; 696a85fe12eSEd Maste } 697a85fe12eSEd Maste ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1; 698a85fe12eSEd Maste ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2; 699a85fe12eSEd Maste 700a85fe12eSEd Maste /* 701a85fe12eSEd Maste * Generate symbols for output object if SYMTAB_INTACT is not set. 702a85fe12eSEd Maste * If there is no symbol in the input object or all the symbols are 703a85fe12eSEd Maste * stripped, then free all the resouces allotted for symbol table, 704a85fe12eSEd Maste * and clear SYMTAB_EXIST flag. 705a85fe12eSEd Maste */ 706a85fe12eSEd Maste if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) { 707a85fe12eSEd Maste TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list); 708a85fe12eSEd Maste TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list); 7093ef90571SEd Maste free(ecp->symtab->buf); 710a85fe12eSEd Maste free(ecp->symtab); 7113ef90571SEd Maste free(ecp->strtab->buf); 712a85fe12eSEd Maste free(ecp->strtab); 713a85fe12eSEd Maste ecp->symtab = NULL; 714a85fe12eSEd Maste ecp->strtab = NULL; 715a85fe12eSEd Maste ecp->flags &= ~SYMTAB_EXIST; 716a85fe12eSEd Maste return; 717a85fe12eSEd Maste } 718a85fe12eSEd Maste 719a85fe12eSEd Maste /* Create output Elf_Scn for .symtab and .strtab. */ 720a85fe12eSEd Maste if ((sy->os = elf_newscn(ecp->eout)) == NULL || 721a85fe12eSEd Maste (st->os = elf_newscn(ecp->eout)) == NULL) 722a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newscn failed: %s", 723a85fe12eSEd Maste elf_errmsg(-1)); 724a85fe12eSEd Maste /* Update secndx anyway. */ 725a85fe12eSEd Maste ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os); 726a85fe12eSEd Maste ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os); 727a85fe12eSEd Maste 728a85fe12eSEd Maste /* 729a85fe12eSEd Maste * Copy .symtab and .strtab section headers from input to output 730a85fe12eSEd Maste * object to start with, these will be overridden later if need. 731a85fe12eSEd Maste */ 732a85fe12eSEd Maste copy_shdr(ecp, sy, ".symtab", 1, 0); 733a85fe12eSEd Maste copy_shdr(ecp, st, ".strtab", 1, 0); 734a85fe12eSEd Maste 735a85fe12eSEd Maste /* Copy verbatim if symbol table is intact. */ 736a85fe12eSEd Maste if (ecp->flags & SYMTAB_INTACT) { 737a85fe12eSEd Maste copy_data(sy); 738a85fe12eSEd Maste copy_data(st); 739a85fe12eSEd Maste return; 740a85fe12eSEd Maste } 741a85fe12eSEd Maste 742a85fe12eSEd Maste create_symtab_data(ecp); 743a85fe12eSEd Maste } 744a85fe12eSEd Maste 745a85fe12eSEd Maste void 746a85fe12eSEd Maste free_symtab(struct elfcopy *ecp) 747a85fe12eSEd Maste { 748a85fe12eSEd Maste struct symbuf *sy_buf; 749a85fe12eSEd Maste struct strbuf *st_buf; 7504a85c691SEd Maste struct sthash *sh, *shtmp; 7514a85c691SEd Maste int i; 752a85fe12eSEd Maste 753a85fe12eSEd Maste if (ecp->symtab != NULL && ecp->symtab->buf != NULL) { 754a85fe12eSEd Maste sy_buf = ecp->symtab->buf; 755a85fe12eSEd Maste if (sy_buf->l32 != NULL) 756a85fe12eSEd Maste free(sy_buf->l32); 757a85fe12eSEd Maste if (sy_buf->g32 != NULL) 758a85fe12eSEd Maste free(sy_buf->g32); 759a85fe12eSEd Maste if (sy_buf->l64 != NULL) 760a85fe12eSEd Maste free(sy_buf->l64); 761a85fe12eSEd Maste if (sy_buf->g64 != NULL) 762a85fe12eSEd Maste free(sy_buf->g64); 763a85fe12eSEd Maste } 764a85fe12eSEd Maste 765a85fe12eSEd Maste if (ecp->strtab != NULL && ecp->strtab->buf != NULL) { 766a85fe12eSEd Maste st_buf = ecp->strtab->buf; 7674a85c691SEd Maste if (st_buf->l.buf != NULL) 7684a85c691SEd Maste free(st_buf->l.buf); 7694a85c691SEd Maste if (st_buf->g.buf != NULL) 7704a85c691SEd Maste free(st_buf->g.buf); 7714a85c691SEd Maste for (i = 0; i < STHASHSIZE; i++) { 7724a85c691SEd Maste LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next, 7734a85c691SEd Maste shtmp) { 7744a85c691SEd Maste LIST_REMOVE(sh, sh_next); 7754a85c691SEd Maste free(sh); 7764a85c691SEd Maste } 7774a85c691SEd Maste LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next, 7784a85c691SEd Maste shtmp) { 7794a85c691SEd Maste LIST_REMOVE(sh, sh_next); 7804a85c691SEd Maste free(sh); 7814a85c691SEd Maste } 7824a85c691SEd Maste } 783a85fe12eSEd Maste } 7843ef90571SEd Maste 7853ef90571SEd Maste if (ecp->symndx != NULL) { 7863ef90571SEd Maste free(ecp->symndx); 7873ef90571SEd Maste ecp->symndx = NULL; 7883ef90571SEd Maste } 7893ef90571SEd Maste if (ecp->v_rel != NULL) { 7903ef90571SEd Maste free(ecp->v_rel); 7913ef90571SEd Maste ecp->v_rel = NULL; 7923ef90571SEd Maste } 7933ef90571SEd Maste if (ecp->v_grp != NULL) { 7943ef90571SEd Maste free(ecp->v_grp); 7953ef90571SEd Maste ecp->v_grp = NULL; 7963ef90571SEd Maste } 7973ef90571SEd Maste if (ecp->v_secsym != NULL) { 7983ef90571SEd Maste free(ecp->v_secsym); 7993ef90571SEd Maste ecp->v_secsym = NULL; 8003ef90571SEd Maste } 801a85fe12eSEd Maste } 802a85fe12eSEd Maste 803a85fe12eSEd Maste void 804a85fe12eSEd Maste create_external_symtab(struct elfcopy *ecp) 805a85fe12eSEd Maste { 806a85fe12eSEd Maste struct section *s; 807a85fe12eSEd Maste struct symbuf *sy_buf; 808a85fe12eSEd Maste struct strbuf *st_buf; 809a85fe12eSEd Maste GElf_Shdr sh; 810a85fe12eSEd Maste size_t ndx; 811a85fe12eSEd Maste 812a85fe12eSEd Maste if (ecp->oec == ELFCLASS32) 813a85fe12eSEd Maste ecp->symtab = create_external_section(ecp, ".symtab", NULL, 814a85fe12eSEd Maste NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0); 815a85fe12eSEd Maste else 816a85fe12eSEd Maste ecp->symtab = create_external_section(ecp, ".symtab", NULL, 817a85fe12eSEd Maste NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0); 818a85fe12eSEd Maste 819a85fe12eSEd Maste ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0, 820a85fe12eSEd Maste SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0); 821a85fe12eSEd Maste 822a85fe12eSEd Maste /* Let sh_link field of .symtab section point to .strtab section. */ 823a85fe12eSEd Maste if (gelf_getshdr(ecp->symtab->os, &sh) == NULL) 824a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", 825a85fe12eSEd Maste elf_errmsg(-1)); 826a85fe12eSEd Maste sh.sh_link = elf_ndxscn(ecp->strtab->os); 827a85fe12eSEd Maste if (!gelf_update_shdr(ecp->symtab->os, &sh)) 828a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", 829a85fe12eSEd Maste elf_errmsg(-1)); 830a85fe12eSEd Maste 831a85fe12eSEd Maste /* Create buffers for .symtab and .strtab. */ 832a85fe12eSEd Maste if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL) 833a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 834a85fe12eSEd Maste if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL) 835a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 836a85fe12eSEd Maste sy_buf->gcap = sy_buf->lcap = 64; 8374a85c691SEd Maste st_buf->g.cap = 256; 8384a85c691SEd Maste st_buf->l.cap = 64; 8394a85c691SEd Maste st_buf->l.sz = 1; /* '\0' at start. */ 8404a85c691SEd Maste st_buf->g.sz = 0; 841a85fe12eSEd Maste 842a85fe12eSEd Maste ecp->symtab->sz = 0; 843a85fe12eSEd Maste ecp->strtab->sz = 0; 844a85fe12eSEd Maste ecp->symtab->buf = sy_buf; 845a85fe12eSEd Maste ecp->strtab->buf = st_buf; 846a85fe12eSEd Maste 847a85fe12eSEd Maste /* Always create the special symbol at the symtab beginning. */ 848a85fe12eSEd Maste add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF, 849a85fe12eSEd Maste ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1); 850a85fe12eSEd Maste 851a85fe12eSEd Maste /* Create STT_SECTION symbols. */ 852a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 853a85fe12eSEd Maste if (s->pseudo) 854a85fe12eSEd Maste continue; 855a85fe12eSEd Maste if (strcmp(s->name, ".symtab") == 0 || 856a85fe12eSEd Maste strcmp(s->name, ".strtab") == 0 || 857a85fe12eSEd Maste strcmp(s->name, ".shstrtab") == 0) 858a85fe12eSEd Maste continue; 859a85fe12eSEd Maste (void) elf_errno(); 860a85fe12eSEd Maste if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) { 861a85fe12eSEd Maste warnx("elf_ndxscn failed: %s", 862a85fe12eSEd Maste elf_errmsg(-1)); 863a85fe12eSEd Maste continue; 864a85fe12eSEd Maste } 865a85fe12eSEd Maste add_to_symtab(ecp, NULL, 0, 0, ndx, 866a85fe12eSEd Maste GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1); 867a85fe12eSEd Maste } 868a85fe12eSEd Maste } 869a85fe12eSEd Maste 870a85fe12eSEd Maste void 871a85fe12eSEd Maste add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value, 872a85fe12eSEd Maste uint64_t st_size, uint16_t st_shndx, unsigned char st_info, 873a85fe12eSEd Maste unsigned char st_other, int ndx_known) 874a85fe12eSEd Maste { 875a85fe12eSEd Maste struct symbuf *sy_buf; 876a85fe12eSEd Maste struct strbuf *st_buf; 8774a85c691SEd Maste struct sthash *sh; 8784a85c691SEd Maste uint32_t hash; 879a85fe12eSEd Maste int pos; 880a85fe12eSEd Maste 881a85fe12eSEd Maste /* 882a85fe12eSEd Maste * Convenient macro for copying global/local 32/64 bit symbols 883a85fe12eSEd Maste * from input object to the buffer created for output object. 884a85fe12eSEd Maste * It handles buffer growing, st_name calculating and st_shndx 885a85fe12eSEd Maste * updating for symbols with non-special section index. 886a85fe12eSEd Maste */ 887*839529caSEd Maste #define _ST_NAME_EMPTY_l 0 888*839529caSEd Maste #define _ST_NAME_EMPTY_g -1 889a85fe12eSEd Maste #define _ADDSYM(B, SZ) do { \ 890a85fe12eSEd Maste if (sy_buf->B##SZ == NULL) { \ 891a85fe12eSEd Maste sy_buf->B##SZ = malloc(sy_buf->B##cap * \ 892a85fe12eSEd Maste sizeof(Elf##SZ##_Sym)); \ 893a85fe12eSEd Maste if (sy_buf->B##SZ == NULL) \ 894a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); \ 895a85fe12eSEd Maste } else if (sy_buf->n##B##s >= sy_buf->B##cap) { \ 896a85fe12eSEd Maste sy_buf->B##cap *= 2; \ 897a85fe12eSEd Maste sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap * \ 898a85fe12eSEd Maste sizeof(Elf##SZ##_Sym)); \ 899a85fe12eSEd Maste if (sy_buf->B##SZ == NULL) \ 900a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed"); \ 901a85fe12eSEd Maste } \ 902a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_info = st_info; \ 903a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_other = st_other; \ 904a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_value = st_value; \ 905a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_size = st_size; \ 906a85fe12eSEd Maste if (ndx_known) \ 907a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \ 908a85fe12eSEd Maste else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE) \ 909a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \ 910a85fe12eSEd Maste else \ 911a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = \ 912a85fe12eSEd Maste ecp->secndx[st_shndx]; \ 9134a85c691SEd Maste if (st_buf->B.buf == NULL) { \ 9144a85c691SEd Maste st_buf->B.buf = calloc(st_buf->B.cap, \ 9154a85c691SEd Maste sizeof(*st_buf->B.buf)); \ 9164a85c691SEd Maste if (st_buf->B.buf == NULL) \ 917a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); \ 918a85fe12eSEd Maste } \ 919a85fe12eSEd Maste if (name != NULL && *name != '\0') { \ 9204a85c691SEd Maste pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\ 9214a85c691SEd Maste name); \ 922a85fe12eSEd Maste if (pos != -1) \ 923a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos; \ 924a85fe12eSEd Maste else { \ 925a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_name = \ 9264a85c691SEd Maste st_buf->B.sz; \ 9274a85c691SEd Maste while (st_buf->B.sz + strlen(name) >= \ 9284a85c691SEd Maste st_buf->B.cap - 1) { \ 9294a85c691SEd Maste st_buf->B.cap *= 2; \ 9304a85c691SEd Maste st_buf->B.buf = realloc(st_buf->B.buf, \ 9314a85c691SEd Maste st_buf->B.cap); \ 9324a85c691SEd Maste if (st_buf->B.buf == NULL) \ 933a85fe12eSEd Maste err(EXIT_FAILURE, \ 934a85fe12eSEd Maste "realloc failed"); \ 935a85fe12eSEd Maste } \ 9364a85c691SEd Maste if ((sh = malloc(sizeof(*sh))) == NULL) \ 9374a85c691SEd Maste err(EXIT_FAILURE, "malloc failed"); \ 9384a85c691SEd Maste sh->sh_off = st_buf->B.sz; \ 9394a85c691SEd Maste hash = str_hash(name); \ 9404a85c691SEd Maste LIST_INSERT_HEAD(&st_buf->B.hash[hash], sh, \ 9414a85c691SEd Maste sh_next); \ 9424a85c691SEd Maste strncpy(&st_buf->B.buf[st_buf->B.sz], name, \ 943a85fe12eSEd Maste strlen(name)); \ 9444a85c691SEd Maste st_buf->B.buf[st_buf->B.sz + strlen(name)] = '\0'; \ 9454a85c691SEd Maste st_buf->B.sz += strlen(name) + 1; \ 946a85fe12eSEd Maste } \ 947a85fe12eSEd Maste } else \ 948*839529caSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_name = \ 949*839529caSEd Maste (Elf##SZ##_Word)_ST_NAME_EMPTY_##B; \ 950a85fe12eSEd Maste sy_buf->n##B##s++; \ 951a85fe12eSEd Maste } while (0) 952a85fe12eSEd Maste 953a85fe12eSEd Maste sy_buf = ecp->symtab->buf; 954a85fe12eSEd Maste st_buf = ecp->strtab->buf; 955a85fe12eSEd Maste 956a85fe12eSEd Maste if (ecp->oec == ELFCLASS32) { 957a85fe12eSEd Maste if (is_local_symbol(st_info)) 958a85fe12eSEd Maste _ADDSYM(l, 32); 959a85fe12eSEd Maste else 960a85fe12eSEd Maste _ADDSYM(g, 32); 961a85fe12eSEd Maste } else { 962a85fe12eSEd Maste if (is_local_symbol(st_info)) 963a85fe12eSEd Maste _ADDSYM(l, 64); 964a85fe12eSEd Maste else 965a85fe12eSEd Maste _ADDSYM(g, 64); 966a85fe12eSEd Maste } 967a85fe12eSEd Maste 968a85fe12eSEd Maste /* Update section size. */ 969a85fe12eSEd Maste ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) * 970a85fe12eSEd Maste (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym)); 9714a85c691SEd Maste ecp->strtab->sz = st_buf->l.sz + st_buf->g.sz; 972a85fe12eSEd Maste 973a85fe12eSEd Maste #undef _ADDSYM 974*839529caSEd Maste #undef _ST_NAME_EMPTY_l 975*839529caSEd Maste #undef _ST_NAME_EMPTY_g 976a85fe12eSEd Maste } 977a85fe12eSEd Maste 978a85fe12eSEd Maste void 979a85fe12eSEd Maste finalize_external_symtab(struct elfcopy *ecp) 980a85fe12eSEd Maste { 981a85fe12eSEd Maste struct symbuf *sy_buf; 982a85fe12eSEd Maste struct strbuf *st_buf; 983a85fe12eSEd Maste int i; 984a85fe12eSEd Maste 985a85fe12eSEd Maste /* 986a85fe12eSEd Maste * Update st_name for global/weak symbols. (global/weak symbols 987a85fe12eSEd Maste * are put after local symbols) 988a85fe12eSEd Maste */ 989a85fe12eSEd Maste sy_buf = ecp->symtab->buf; 990a85fe12eSEd Maste st_buf = ecp->strtab->buf; 991a85fe12eSEd Maste for (i = 0; (size_t) i < sy_buf->ngs; i++) { 992*839529caSEd Maste if (ecp->oec == ELFCLASS32) { 993*839529caSEd Maste if (sy_buf->g32[i].st_name == (Elf32_Word)-1) 994*839529caSEd Maste sy_buf->g32[i].st_name = 0; 995*839529caSEd Maste else 9964a85c691SEd Maste sy_buf->g32[i].st_name += st_buf->l.sz; 997*839529caSEd Maste } else { 998*839529caSEd Maste if (sy_buf->g64[i].st_name == (Elf64_Word)-1) 999*839529caSEd Maste sy_buf->g64[i].st_name = 0; 1000a85fe12eSEd Maste else 10014a85c691SEd Maste sy_buf->g64[i].st_name += st_buf->l.sz; 1002a85fe12eSEd Maste } 1003a85fe12eSEd Maste } 1004*839529caSEd Maste } 1005a85fe12eSEd Maste 1006a85fe12eSEd Maste void 1007a85fe12eSEd Maste create_symtab_data(struct elfcopy *ecp) 1008a85fe12eSEd Maste { 1009a85fe12eSEd Maste struct section *sy, *st; 1010a85fe12eSEd Maste struct symbuf *sy_buf; 1011a85fe12eSEd Maste struct strbuf *st_buf; 1012a85fe12eSEd Maste Elf_Data *gsydata, *lsydata, *gstdata, *lstdata; 1013a85fe12eSEd Maste GElf_Shdr shy, sht; 1014a85fe12eSEd Maste 1015a85fe12eSEd Maste sy = ecp->symtab; 1016a85fe12eSEd Maste st = ecp->strtab; 1017a85fe12eSEd Maste 1018a85fe12eSEd Maste if (gelf_getshdr(sy->os, ­) == NULL) 1019a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", 1020a85fe12eSEd Maste elf_errmsg(-1)); 1021a85fe12eSEd Maste if (gelf_getshdr(st->os, &sht) == NULL) 1022a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", 1023a85fe12eSEd Maste elf_errmsg(-1)); 1024a85fe12eSEd Maste 1025a85fe12eSEd Maste /* 1026a85fe12eSEd Maste * Create two Elf_Data for .symtab section of output object, one 1027a85fe12eSEd Maste * for local symbols and another for global symbols. Note that 1028a85fe12eSEd Maste * local symbols appear first in the .symtab. 1029a85fe12eSEd Maste */ 1030a85fe12eSEd Maste sy_buf = sy->buf; 1031a85fe12eSEd Maste if (sy_buf->nls > 0) { 1032a85fe12eSEd Maste if ((lsydata = elf_newdata(sy->os)) == NULL) 1033a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newdata() failed: %s.", 1034a85fe12eSEd Maste elf_errmsg(-1)); 1035a85fe12eSEd Maste if (ecp->oec == ELFCLASS32) { 1036a85fe12eSEd Maste lsydata->d_align = 4; 1037a85fe12eSEd Maste lsydata->d_off = 0; 1038a85fe12eSEd Maste lsydata->d_buf = sy_buf->l32; 1039a85fe12eSEd Maste lsydata->d_size = sy_buf->nls * 1040a85fe12eSEd Maste sizeof(Elf32_Sym); 1041a85fe12eSEd Maste lsydata->d_type = ELF_T_SYM; 1042a85fe12eSEd Maste lsydata->d_version = EV_CURRENT; 1043a85fe12eSEd Maste } else { 1044a85fe12eSEd Maste lsydata->d_align = 8; 1045a85fe12eSEd Maste lsydata->d_off = 0; 1046a85fe12eSEd Maste lsydata->d_buf = sy_buf->l64; 1047a85fe12eSEd Maste lsydata->d_size = sy_buf->nls * 1048a85fe12eSEd Maste sizeof(Elf64_Sym); 1049a85fe12eSEd Maste lsydata->d_type = ELF_T_SYM; 1050a85fe12eSEd Maste lsydata->d_version = EV_CURRENT; 1051a85fe12eSEd Maste } 1052a85fe12eSEd Maste } 1053a85fe12eSEd Maste if (sy_buf->ngs > 0) { 1054a85fe12eSEd Maste if ((gsydata = elf_newdata(sy->os)) == NULL) 1055a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newdata() failed: %s.", 1056a85fe12eSEd Maste elf_errmsg(-1)); 1057a85fe12eSEd Maste if (ecp->oec == ELFCLASS32) { 1058a85fe12eSEd Maste gsydata->d_align = 4; 1059a85fe12eSEd Maste gsydata->d_off = sy_buf->nls * 1060a85fe12eSEd Maste sizeof(Elf32_Sym); 1061a85fe12eSEd Maste gsydata->d_buf = sy_buf->g32; 1062a85fe12eSEd Maste gsydata->d_size = sy_buf->ngs * 1063a85fe12eSEd Maste sizeof(Elf32_Sym); 1064a85fe12eSEd Maste gsydata->d_type = ELF_T_SYM; 1065a85fe12eSEd Maste gsydata->d_version = EV_CURRENT; 1066a85fe12eSEd Maste } else { 1067a85fe12eSEd Maste gsydata->d_align = 8; 1068a85fe12eSEd Maste gsydata->d_off = sy_buf->nls * 1069a85fe12eSEd Maste sizeof(Elf64_Sym); 1070a85fe12eSEd Maste gsydata->d_buf = sy_buf->g64; 1071a85fe12eSEd Maste gsydata->d_size = sy_buf->ngs * 1072a85fe12eSEd Maste sizeof(Elf64_Sym); 1073a85fe12eSEd Maste gsydata->d_type = ELF_T_SYM; 1074a85fe12eSEd Maste gsydata->d_version = EV_CURRENT; 1075a85fe12eSEd Maste } 1076a85fe12eSEd Maste } 1077a85fe12eSEd Maste 1078a85fe12eSEd Maste /* 1079a85fe12eSEd Maste * Create two Elf_Data for .strtab, one for local symbol name 1080a85fe12eSEd Maste * and another for globals. Same as .symtab, local symbol names 1081a85fe12eSEd Maste * appear first. 1082a85fe12eSEd Maste */ 1083a85fe12eSEd Maste st_buf = st->buf; 1084a85fe12eSEd Maste if ((lstdata = elf_newdata(st->os)) == NULL) 1085a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newdata() failed: %s.", 1086a85fe12eSEd Maste elf_errmsg(-1)); 1087a85fe12eSEd Maste lstdata->d_align = 1; 1088a85fe12eSEd Maste lstdata->d_off = 0; 10894a85c691SEd Maste lstdata->d_buf = st_buf->l.buf; 10904a85c691SEd Maste lstdata->d_size = st_buf->l.sz; 1091a85fe12eSEd Maste lstdata->d_type = ELF_T_BYTE; 1092a85fe12eSEd Maste lstdata->d_version = EV_CURRENT; 1093a85fe12eSEd Maste 10944a85c691SEd Maste if (st_buf->g.sz > 0) { 1095a85fe12eSEd Maste if ((gstdata = elf_newdata(st->os)) == NULL) 1096a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newdata() failed: %s.", 1097a85fe12eSEd Maste elf_errmsg(-1)); 1098a85fe12eSEd Maste gstdata->d_align = 1; 1099a85fe12eSEd Maste gstdata->d_off = lstdata->d_size; 11004a85c691SEd Maste gstdata->d_buf = st_buf->g.buf; 11014a85c691SEd Maste gstdata->d_size = st_buf->g.sz; 1102a85fe12eSEd Maste gstdata->d_type = ELF_T_BYTE; 1103a85fe12eSEd Maste gstdata->d_version = EV_CURRENT; 1104a85fe12eSEd Maste } 1105a85fe12eSEd Maste 1106a85fe12eSEd Maste shy.sh_addr = 0; 1107a85fe12eSEd Maste shy.sh_addralign = (ecp->oec == ELFCLASS32 ? 4 : 8); 1108a85fe12eSEd Maste shy.sh_size = sy->sz; 1109a85fe12eSEd Maste shy.sh_type = SHT_SYMTAB; 1110a85fe12eSEd Maste shy.sh_flags = 0; 1111a85fe12eSEd Maste shy.sh_entsize = gelf_fsize(ecp->eout, ELF_T_SYM, 1, 1112a85fe12eSEd Maste EV_CURRENT); 1113a85fe12eSEd Maste /* 1114a85fe12eSEd Maste * According to SYSV abi, here sh_info is one greater than 1115a85fe12eSEd Maste * the symbol table index of the last local symbol(binding 1116a85fe12eSEd Maste * STB_LOCAL). 1117a85fe12eSEd Maste */ 1118a85fe12eSEd Maste shy.sh_info = sy_buf->nls; 1119a85fe12eSEd Maste 1120a85fe12eSEd Maste sht.sh_addr = 0; 1121a85fe12eSEd Maste sht.sh_addralign = 1; 1122a85fe12eSEd Maste sht.sh_size = st->sz; 1123a85fe12eSEd Maste sht.sh_type = SHT_STRTAB; 1124a85fe12eSEd Maste sht.sh_flags = 0; 1125a85fe12eSEd Maste sht.sh_entsize = 0; 1126a85fe12eSEd Maste sht.sh_info = 0; 1127a85fe12eSEd Maste sht.sh_link = 0; 1128a85fe12eSEd Maste 1129a85fe12eSEd Maste if (!gelf_update_shdr(sy->os, ­)) 1130a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", 1131a85fe12eSEd Maste elf_errmsg(-1)); 1132a85fe12eSEd Maste if (!gelf_update_shdr(st->os, &sht)) 1133a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", 1134a85fe12eSEd Maste elf_errmsg(-1)); 1135a85fe12eSEd Maste } 1136a85fe12eSEd Maste 1137a85fe12eSEd Maste void 1138a85fe12eSEd Maste add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname, 1139a85fe12eSEd Maste unsigned int op) 1140a85fe12eSEd Maste { 1141a85fe12eSEd Maste struct symop *s; 1142a85fe12eSEd Maste 1143*839529caSEd Maste assert (name != NULL); 1144*839529caSEd Maste STAILQ_FOREACH(s, &ecp->v_symop, symop_list) 1145*839529caSEd Maste if (!strcmp(name, s->name)) 1146*839529caSEd Maste goto found; 1147*839529caSEd Maste 1148a85fe12eSEd Maste if ((s = calloc(1, sizeof(*s))) == NULL) 1149a85fe12eSEd Maste errx(EXIT_FAILURE, "not enough memory"); 1150*839529caSEd Maste STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list); 1151a85fe12eSEd Maste s->name = name; 1152*839529caSEd Maste found: 1153a85fe12eSEd Maste if (op == SYMOP_REDEF) 1154a85fe12eSEd Maste s->newname = newname; 1155a85fe12eSEd Maste s->op |= op; 1156a85fe12eSEd Maste } 1157a85fe12eSEd Maste 1158a85fe12eSEd Maste struct symop * 1159a85fe12eSEd Maste lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op) 1160a85fe12eSEd Maste { 1161*839529caSEd Maste struct symop *s, *ret; 1162*839529caSEd Maste const char *pattern; 1163a85fe12eSEd Maste 1164a85fe12eSEd Maste STAILQ_FOREACH(s, &ecp->v_symop, symop_list) { 1165*839529caSEd Maste if ((s->op & op) == 0) 1166*839529caSEd Maste continue; 1167*839529caSEd Maste if (name == NULL || !strcmp(name, s->name)) 1168a85fe12eSEd Maste return (s); 1169*839529caSEd Maste if ((ecp->flags & WILDCARD) == 0) 1170*839529caSEd Maste continue; 1171*839529caSEd Maste 1172*839529caSEd Maste /* Handle wildcards. */ 1173*839529caSEd Maste pattern = s->name; 1174*839529caSEd Maste if (pattern[0] == '!') { 1175*839529caSEd Maste /* Negative match. */ 1176*839529caSEd Maste pattern++; 1177*839529caSEd Maste ret = NULL; 1178*839529caSEd Maste } else { 1179*839529caSEd Maste /* Regular wildcard match. */ 1180*839529caSEd Maste ret = s; 1181*839529caSEd Maste } 1182*839529caSEd Maste if (!fnmatch(pattern, name, 0)) 1183*839529caSEd Maste return (ret); 1184a85fe12eSEd Maste } 1185a85fe12eSEd Maste 1186a85fe12eSEd Maste return (NULL); 1187a85fe12eSEd Maste } 1188a85fe12eSEd Maste 1189a85fe12eSEd Maste static int 11904a85c691SEd Maste lookup_exact_string(hash_head *buckets, const char *buf, const char *s) 1191a85fe12eSEd Maste { 11924a85c691SEd Maste struct sthash *sh; 11934a85c691SEd Maste uint32_t hash; 1194a85fe12eSEd Maste 11954a85c691SEd Maste hash = str_hash(s); 11964a85c691SEd Maste LIST_FOREACH(sh, &buckets[hash], sh_next) 11974a85c691SEd Maste if (strcmp(buf + sh->sh_off, s) == 0) 11984a85c691SEd Maste return sh->sh_off; 11994a85c691SEd Maste return (-1); 1200a85fe12eSEd Maste } 1201a85fe12eSEd Maste 12024a85c691SEd Maste uint32_t 12034a85c691SEd Maste str_hash(const char *s) 12044a85c691SEd Maste { 12054a85c691SEd Maste uint32_t hash; 12064a85c691SEd Maste 1207b00fe64fSEd Maste for (hash = 2166136261UL; *s; s++) 12084a85c691SEd Maste hash = (hash ^ *s) * 16777619; 12094a85c691SEd Maste 12104a85c691SEd Maste return (hash & (STHASHSIZE - 1)); 1211a85fe12eSEd Maste } 1212