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> 28a85fe12eSEd Maste #include <err.h> 29a85fe12eSEd Maste #include <fnmatch.h> 30a85fe12eSEd Maste #include <stdio.h> 31a85fe12eSEd Maste #include <stdlib.h> 32a85fe12eSEd Maste #include <string.h> 33a85fe12eSEd Maste 34a85fe12eSEd Maste #include "elfcopy.h" 35a85fe12eSEd Maste 36*b00fe64fSEd Maste ELFTC_VCSID("$Id: symbols.c 3191 2015-05-04 17:07:01Z jkoshy $"); 37a85fe12eSEd Maste 38a85fe12eSEd Maste /* Symbol table buffer structure. */ 39a85fe12eSEd Maste struct symbuf { 40a85fe12eSEd Maste Elf32_Sym *l32; /* 32bit local symbol */ 41a85fe12eSEd Maste Elf32_Sym *g32; /* 32bit global symbol */ 42a85fe12eSEd Maste Elf64_Sym *l64; /* 64bit local symbol */ 43a85fe12eSEd Maste Elf64_Sym *g64; /* 64bit global symbol */ 44a85fe12eSEd Maste size_t ngs, nls; /* number of each kind */ 45a85fe12eSEd Maste size_t gcap, lcap; /* buffer capacities. */ 46a85fe12eSEd Maste }; 47a85fe12eSEd Maste 484a85c691SEd Maste struct sthash { 494a85c691SEd Maste LIST_ENTRY(sthash) sh_next; 504a85c691SEd Maste size_t sh_off; 514a85c691SEd Maste }; 524a85c691SEd Maste typedef LIST_HEAD(,sthash) hash_head; 534a85c691SEd Maste #define STHASHSIZE 65536 544a85c691SEd Maste 554a85c691SEd Maste struct strimpl { 564a85c691SEd Maste char *buf; /* string table */ 574a85c691SEd Maste size_t sz; /* entries */ 584a85c691SEd Maste size_t cap; /* buffer capacity */ 594a85c691SEd Maste hash_head hash[STHASHSIZE]; 604a85c691SEd Maste }; 614a85c691SEd Maste 624a85c691SEd Maste 63a85fe12eSEd Maste /* String table buffer structure. */ 64a85fe12eSEd Maste struct strbuf { 654a85c691SEd Maste struct strimpl l; /* local symbols */ 664a85c691SEd Maste struct strimpl g; /* global symbols */ 67a85fe12eSEd Maste }; 68a85fe12eSEd Maste 69a85fe12eSEd Maste static int is_debug_symbol(unsigned char st_info); 70a85fe12eSEd Maste static int is_global_symbol(unsigned char st_info); 71a85fe12eSEd Maste static int is_local_symbol(unsigned char st_info); 72a85fe12eSEd Maste static int is_local_label(const char *name); 73a85fe12eSEd Maste static int is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s); 74a85fe12eSEd Maste static int is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, 75a85fe12eSEd Maste GElf_Sym *s, const char *name); 76a85fe12eSEd Maste static int is_weak_symbol(unsigned char st_info); 774a85c691SEd Maste static int lookup_exact_string(hash_head *hash, const char *buf, 784a85c691SEd Maste const char *s); 79a85fe12eSEd Maste static int generate_symbols(struct elfcopy *ecp); 80a85fe12eSEd Maste static void mark_symbols(struct elfcopy *ecp, size_t sc); 81a85fe12eSEd Maste static int match_wildcard(const char *name, const char *pattern); 824a85c691SEd Maste uint32_t str_hash(const char *s); 83a85fe12eSEd Maste 84a85fe12eSEd Maste /* Convenient bit vector operation macros. */ 85a85fe12eSEd Maste #define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7)) 86a85fe12eSEd Maste #define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7))) 87a85fe12eSEd Maste #define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7))) 88a85fe12eSEd Maste 89a85fe12eSEd Maste static int 90a85fe12eSEd Maste is_debug_symbol(unsigned char st_info) 91a85fe12eSEd Maste { 92a85fe12eSEd Maste 93a85fe12eSEd Maste if (GELF_ST_TYPE(st_info) == STT_SECTION || 94a85fe12eSEd Maste GELF_ST_TYPE(st_info) == STT_FILE) 95a85fe12eSEd Maste return (1); 96a85fe12eSEd Maste 97a85fe12eSEd Maste return (0); 98a85fe12eSEd Maste } 99a85fe12eSEd Maste 100a85fe12eSEd Maste static int 101a85fe12eSEd Maste is_global_symbol(unsigned char st_info) 102a85fe12eSEd Maste { 103a85fe12eSEd Maste 104a85fe12eSEd Maste if (GELF_ST_BIND(st_info) == STB_GLOBAL) 105a85fe12eSEd Maste return (1); 106a85fe12eSEd Maste 107a85fe12eSEd Maste return (0); 108a85fe12eSEd Maste } 109a85fe12eSEd Maste 110a85fe12eSEd Maste static int 111a85fe12eSEd Maste is_weak_symbol(unsigned char st_info) 112a85fe12eSEd Maste { 113a85fe12eSEd Maste 114a85fe12eSEd Maste if (GELF_ST_BIND(st_info) == STB_WEAK) 115a85fe12eSEd Maste return (1); 116a85fe12eSEd Maste 117a85fe12eSEd Maste return (0); 118a85fe12eSEd Maste } 119a85fe12eSEd Maste 120a85fe12eSEd Maste static int 121a85fe12eSEd Maste is_local_symbol(unsigned char st_info) 122a85fe12eSEd Maste { 123a85fe12eSEd Maste 124a85fe12eSEd Maste if (GELF_ST_BIND(st_info) == STB_LOCAL) 125a85fe12eSEd Maste return (1); 126a85fe12eSEd Maste 127a85fe12eSEd Maste return (0); 128a85fe12eSEd Maste } 129a85fe12eSEd Maste 130a85fe12eSEd Maste static int 13167d97fe7SEd Maste is_hidden_symbol(unsigned char st_other) 13267d97fe7SEd Maste { 13367d97fe7SEd Maste 13467d97fe7SEd Maste if (GELF_ST_VISIBILITY(st_other) == STV_HIDDEN || 13567d97fe7SEd Maste GELF_ST_VISIBILITY(st_other) == STV_INTERNAL) 13667d97fe7SEd Maste return (1); 13767d97fe7SEd Maste 13867d97fe7SEd Maste return (0); 13967d97fe7SEd Maste } 14067d97fe7SEd Maste 14167d97fe7SEd Maste static int 142a85fe12eSEd Maste is_local_label(const char *name) 143a85fe12eSEd Maste { 144a85fe12eSEd Maste 145a85fe12eSEd Maste /* Compiler generated local symbols that start with .L */ 146a85fe12eSEd Maste if (name[0] == '.' && name[1] == 'L') 147a85fe12eSEd Maste return (1); 148a85fe12eSEd Maste 149a85fe12eSEd Maste return (0); 150a85fe12eSEd Maste } 151a85fe12eSEd Maste 152a85fe12eSEd Maste /* 153a85fe12eSEd Maste * Symbols related to relocation are needed. 154a85fe12eSEd Maste */ 155a85fe12eSEd Maste static int 156a85fe12eSEd Maste is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s) 157a85fe12eSEd Maste { 158a85fe12eSEd Maste 159a85fe12eSEd Maste /* If symbol involves relocation, it is needed. */ 160a85fe12eSEd Maste if (BIT_ISSET(ecp->v_rel, i)) 161a85fe12eSEd Maste return (1); 162a85fe12eSEd Maste 163a85fe12eSEd Maste /* 164a85fe12eSEd Maste * For relocatable files (.o files), global and weak symbols 165a85fe12eSEd Maste * are needed. 166a85fe12eSEd Maste */ 167a85fe12eSEd Maste if (ecp->flags & RELOCATABLE) { 168a85fe12eSEd Maste if (is_global_symbol(s->st_info) || is_weak_symbol(s->st_info)) 169a85fe12eSEd Maste return (1); 170a85fe12eSEd Maste } 171a85fe12eSEd Maste 172a85fe12eSEd Maste return (0); 173a85fe12eSEd Maste } 174a85fe12eSEd Maste 175a85fe12eSEd Maste static int 176a85fe12eSEd Maste is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, 177a85fe12eSEd Maste const char *name) 178a85fe12eSEd Maste { 179a85fe12eSEd Maste GElf_Sym sym0 = { 180a85fe12eSEd Maste 0, /* st_name */ 181a85fe12eSEd Maste 0, /* st_value */ 182a85fe12eSEd Maste 0, /* st_size */ 183a85fe12eSEd Maste 0, /* st_info */ 184a85fe12eSEd Maste 0, /* st_other */ 185a85fe12eSEd Maste SHN_UNDEF, /* st_shndx */ 186a85fe12eSEd Maste }; 187a85fe12eSEd Maste 188a85fe12eSEd Maste if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) 189a85fe12eSEd Maste return (0); 190a85fe12eSEd Maste 191a85fe12eSEd Maste if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) 192a85fe12eSEd Maste return (1); 193a85fe12eSEd Maste 194a85fe12eSEd Maste /* 195a85fe12eSEd Maste * Keep the first symbol if it is the special reserved symbol. 196a85fe12eSEd Maste * XXX Should we generate one if it's missing? 197a85fe12eSEd Maste */ 198a85fe12eSEd Maste if (i == 0 && !memcmp(s, &sym0, sizeof(GElf_Sym))) 199a85fe12eSEd Maste return (0); 200a85fe12eSEd Maste 201a85fe12eSEd Maste /* Remove the symbol if the section it refers to was removed. */ 202a85fe12eSEd Maste if (s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE && 203a85fe12eSEd Maste ecp->secndx[s->st_shndx] == 0) 204a85fe12eSEd Maste return (1); 205a85fe12eSEd Maste 206a85fe12eSEd Maste if (ecp->strip == STRIP_ALL) 207a85fe12eSEd Maste return (1); 208a85fe12eSEd Maste 209a85fe12eSEd Maste if (ecp->v_rel == NULL) 210a85fe12eSEd Maste mark_symbols(ecp, sc); 211a85fe12eSEd Maste 212a85fe12eSEd Maste if (is_needed_symbol(ecp, i, s)) 213a85fe12eSEd Maste return (0); 214a85fe12eSEd Maste 215a85fe12eSEd Maste if (ecp->strip == STRIP_UNNEEDED) 216a85fe12eSEd Maste return (1); 217a85fe12eSEd Maste 218a85fe12eSEd Maste if ((ecp->flags & DISCARD_LOCAL) && is_local_symbol(s->st_info) && 219a85fe12eSEd Maste !is_debug_symbol(s->st_info)) 220a85fe12eSEd Maste return (1); 221a85fe12eSEd Maste 222a85fe12eSEd Maste if ((ecp->flags & DISCARD_LLABEL) && is_local_symbol(s->st_info) && 223a85fe12eSEd Maste !is_debug_symbol(s->st_info) && is_local_label(name)) 224a85fe12eSEd Maste return (1); 225a85fe12eSEd Maste 226a85fe12eSEd Maste if (ecp->strip == STRIP_DEBUG && is_debug_symbol(s->st_info)) 227a85fe12eSEd Maste return (1); 228a85fe12eSEd Maste 229a85fe12eSEd Maste return (0); 230a85fe12eSEd Maste } 231a85fe12eSEd Maste 232a85fe12eSEd Maste /* 233a85fe12eSEd Maste * Mark symbols refered by relocation entries. 234a85fe12eSEd Maste */ 235a85fe12eSEd Maste static void 236a85fe12eSEd Maste mark_symbols(struct elfcopy *ecp, size_t sc) 237a85fe12eSEd Maste { 238a85fe12eSEd Maste const char *name; 239a85fe12eSEd Maste Elf_Data *d; 240a85fe12eSEd Maste Elf_Scn *s; 241a85fe12eSEd Maste GElf_Rel r; 242a85fe12eSEd Maste GElf_Rela ra; 243a85fe12eSEd Maste GElf_Shdr sh; 244a85fe12eSEd Maste size_t n, indx; 245a85fe12eSEd Maste int elferr, i, len; 246a85fe12eSEd Maste 247a85fe12eSEd Maste ecp->v_rel = calloc((sc + 7) / 8, 1); 248a85fe12eSEd Maste if (ecp->v_rel == NULL) 249a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 250a85fe12eSEd Maste 251a85fe12eSEd Maste if (elf_getshstrndx(ecp->ein, &indx) == 0) 252a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", 253a85fe12eSEd Maste elf_errmsg(-1)); 254a85fe12eSEd Maste 255a85fe12eSEd Maste s = NULL; 256a85fe12eSEd Maste while ((s = elf_nextscn(ecp->ein, s)) != NULL) { 257a85fe12eSEd Maste if (gelf_getshdr(s, &sh) != &sh) 258a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_getshdr failed: %s", 259a85fe12eSEd Maste elf_errmsg(-1)); 260a85fe12eSEd Maste 261a85fe12eSEd Maste if (sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA) 262a85fe12eSEd Maste continue; 263a85fe12eSEd Maste 264a85fe12eSEd Maste /* 265a85fe12eSEd Maste * Skip if this reloc section won't appear in the 266a85fe12eSEd Maste * output object. 267a85fe12eSEd Maste */ 268a85fe12eSEd Maste if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL) 269a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_strptr failed: %s", 270a85fe12eSEd Maste elf_errmsg(-1)); 271a85fe12eSEd Maste if (is_remove_section(ecp, name) || 272a85fe12eSEd Maste is_remove_reloc_sec(ecp, sh.sh_info)) 273a85fe12eSEd Maste continue; 274a85fe12eSEd Maste 275a85fe12eSEd Maste /* Skip if it's not for .symtab */ 276a85fe12eSEd Maste if (sh.sh_link != elf_ndxscn(ecp->symtab->is)) 277a85fe12eSEd Maste continue; 278a85fe12eSEd Maste 279a85fe12eSEd Maste d = NULL; 280a85fe12eSEd Maste n = 0; 281a85fe12eSEd Maste while (n < sh.sh_size && (d = elf_getdata(s, d)) != NULL) { 282a85fe12eSEd Maste len = d->d_size / sh.sh_entsize; 283a85fe12eSEd Maste for (i = 0; i < len; i++) { 284a85fe12eSEd Maste if (sh.sh_type == SHT_REL) { 285a85fe12eSEd Maste if (gelf_getrel(d, i, &r) != &r) 286a85fe12eSEd Maste errx(EXIT_FAILURE, 287a85fe12eSEd Maste "elf_getrel failed: %s", 288a85fe12eSEd Maste elf_errmsg(-1)); 289a85fe12eSEd Maste n = GELF_R_SYM(r.r_info); 290a85fe12eSEd Maste } else { 291a85fe12eSEd Maste if (gelf_getrela(d, i, &ra) != &ra) 292a85fe12eSEd Maste errx(EXIT_FAILURE, 293a85fe12eSEd Maste "elf_getrela failed: %s", 294a85fe12eSEd Maste elf_errmsg(-1)); 295a85fe12eSEd Maste n = GELF_R_SYM(ra.r_info); 296a85fe12eSEd Maste } 297a85fe12eSEd Maste if (n > 0 && n < sc) 298a85fe12eSEd Maste BIT_SET(ecp->v_rel, n); 299a85fe12eSEd Maste else if (n != 0) 300a85fe12eSEd Maste warnx("invalid symbox index"); 301a85fe12eSEd Maste } 302a85fe12eSEd Maste } 303a85fe12eSEd Maste elferr = elf_errno(); 304a85fe12eSEd Maste if (elferr != 0) 305a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_getdata failed: %s", 306a85fe12eSEd Maste elf_errmsg(elferr)); 307a85fe12eSEd Maste } 308a85fe12eSEd Maste elferr = elf_errno(); 309a85fe12eSEd Maste if (elferr != 0) 310a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_nextscn failed: %s", 311a85fe12eSEd Maste elf_errmsg(elferr)); 312a85fe12eSEd Maste } 313a85fe12eSEd Maste 314a85fe12eSEd Maste static int 315a85fe12eSEd Maste generate_symbols(struct elfcopy *ecp) 316a85fe12eSEd Maste { 317a85fe12eSEd Maste struct section *s; 318a85fe12eSEd Maste struct symop *sp; 319a85fe12eSEd Maste struct symbuf *sy_buf; 320a85fe12eSEd Maste struct strbuf *st_buf; 321a85fe12eSEd Maste const char *name; 322a85fe12eSEd Maste char *newname; 323a85fe12eSEd Maste unsigned char *gsym; 324a85fe12eSEd Maste GElf_Shdr ish; 325a85fe12eSEd Maste GElf_Sym sym; 326a85fe12eSEd Maste Elf_Data* id; 327a85fe12eSEd Maste Elf_Scn *is; 328cf781b2eSEd Maste size_t ishstrndx, namelen, ndx, sc, symndx; 329a85fe12eSEd Maste int ec, elferr, i; 330a85fe12eSEd Maste 331a85fe12eSEd Maste if (elf_getshstrndx(ecp->ein, &ishstrndx) == 0) 332a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", 333a85fe12eSEd Maste elf_errmsg(-1)); 334a85fe12eSEd Maste if ((ec = gelf_getclass(ecp->eout)) == ELFCLASSNONE) 335a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getclass failed: %s", 336a85fe12eSEd Maste elf_errmsg(-1)); 337a85fe12eSEd Maste 338a85fe12eSEd Maste /* Create buffers for .symtab and .strtab. */ 339a85fe12eSEd Maste if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL) 340a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 341a85fe12eSEd Maste if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL) 342a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 343a85fe12eSEd Maste sy_buf->gcap = sy_buf->lcap = 64; 3444a85c691SEd Maste st_buf->g.cap = 256; 3454a85c691SEd Maste st_buf->l.cap = 64; 3464a85c691SEd Maste st_buf->l.sz = 1; /* '\0' at start. */ 3474a85c691SEd Maste st_buf->g.sz = 0; 348a85fe12eSEd Maste 349a85fe12eSEd Maste ecp->symtab->sz = 0; 350a85fe12eSEd Maste ecp->strtab->sz = 0; 351a85fe12eSEd Maste ecp->symtab->buf = sy_buf; 352a85fe12eSEd Maste ecp->strtab->buf = st_buf; 353a85fe12eSEd Maste 354a85fe12eSEd Maste /* 355a85fe12eSEd Maste * Create bit vector v_secsym, which is used to mark sections 356a85fe12eSEd Maste * that already have corresponding STT_SECTION symbols. 357a85fe12eSEd Maste */ 358a85fe12eSEd Maste ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1); 359a85fe12eSEd Maste if (ecp->v_secsym == NULL) 360a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 361a85fe12eSEd Maste 362a85fe12eSEd Maste /* Locate .strtab of input object. */ 363a85fe12eSEd Maste symndx = 0; 364a85fe12eSEd Maste name = NULL; 365a85fe12eSEd Maste is = NULL; 366a85fe12eSEd Maste while ((is = elf_nextscn(ecp->ein, is)) != NULL) { 367a85fe12eSEd Maste if (gelf_getshdr(is, &ish) != &ish) 368a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_getshdr failed: %s", 369a85fe12eSEd Maste elf_errmsg(-1)); 370a85fe12eSEd Maste if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) == 371a85fe12eSEd Maste NULL) 372a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_strptr failed: %s", 373a85fe12eSEd Maste elf_errmsg(-1)); 374a85fe12eSEd Maste if (strcmp(name, ".strtab") == 0) { 375a85fe12eSEd Maste symndx = elf_ndxscn(is); 376a85fe12eSEd Maste break; 377a85fe12eSEd Maste } 378a85fe12eSEd Maste } 379a85fe12eSEd Maste elferr = elf_errno(); 380a85fe12eSEd Maste if (elferr != 0) 381a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_nextscn failed: %s", 382a85fe12eSEd Maste elf_errmsg(elferr)); 383a85fe12eSEd Maste 384a85fe12eSEd Maste /* Symbol table should exist if this function is called. */ 385a85fe12eSEd Maste if (symndx == 0) { 386a85fe12eSEd Maste warnx("can't find .strtab section"); 387a85fe12eSEd Maste return (0); 388a85fe12eSEd Maste } 389a85fe12eSEd Maste 390a85fe12eSEd Maste /* Locate .symtab of input object. */ 391a85fe12eSEd Maste is = NULL; 392a85fe12eSEd Maste while ((is = elf_nextscn(ecp->ein, is)) != NULL) { 393a85fe12eSEd Maste if (gelf_getshdr(is, &ish) != &ish) 394a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_getshdr failed: %s", 395a85fe12eSEd Maste elf_errmsg(-1)); 396a85fe12eSEd Maste if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) == 397a85fe12eSEd Maste NULL) 398a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_strptr failed: %s", 399a85fe12eSEd Maste elf_errmsg(-1)); 400a85fe12eSEd Maste if (strcmp(name, ".symtab") == 0) 401a85fe12eSEd Maste break; 402a85fe12eSEd Maste } 403a85fe12eSEd Maste elferr = elf_errno(); 404a85fe12eSEd Maste if (elferr != 0) 405a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_nextscn failed: %s", 406a85fe12eSEd Maste elf_errmsg(elferr)); 407a85fe12eSEd Maste if (is == NULL) 408a85fe12eSEd Maste errx(EXIT_FAILURE, "can't find .strtab section"); 409a85fe12eSEd Maste 410a85fe12eSEd Maste /* 411a85fe12eSEd Maste * Create bit vector gsym to mark global symbols, and symndx 412a85fe12eSEd Maste * to keep track of symbol index changes from input object to 413a85fe12eSEd Maste * output object, it is used by update_reloc() later to update 414a85fe12eSEd Maste * relocation information. 415a85fe12eSEd Maste */ 416a85fe12eSEd Maste gsym = NULL; 417a85fe12eSEd Maste sc = ish.sh_size / ish.sh_entsize; 418a85fe12eSEd Maste if (sc > 0) { 419a85fe12eSEd Maste ecp->symndx = calloc(sc, sizeof(*ecp->symndx)); 420a85fe12eSEd Maste if (ecp->symndx == NULL) 421a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 422a85fe12eSEd Maste gsym = calloc((sc + 7) / 8, sizeof(*gsym)); 423a85fe12eSEd Maste if (gsym == NULL) 424a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 425a85fe12eSEd Maste if ((id = elf_getdata(is, NULL)) == NULL) { 426a85fe12eSEd Maste elferr = elf_errno(); 427a85fe12eSEd Maste if (elferr != 0) 428a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_getdata failed: %s", 429a85fe12eSEd Maste elf_errmsg(elferr)); 430a85fe12eSEd Maste return (0); 431a85fe12eSEd Maste } 432a85fe12eSEd Maste } else 433a85fe12eSEd Maste return (0); 434a85fe12eSEd Maste 435a85fe12eSEd Maste /* Copy/Filter each symbol. */ 436a85fe12eSEd Maste for (i = 0; (size_t)i < sc; i++) { 437a85fe12eSEd Maste if (gelf_getsym(id, i, &sym) != &sym) 438a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getsym failed: %s", 439a85fe12eSEd Maste elf_errmsg(-1)); 440a85fe12eSEd Maste if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL) 441a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_strptr failed: %s", 442a85fe12eSEd Maste elf_errmsg(-1)); 443a85fe12eSEd Maste 444a85fe12eSEd Maste /* Symbol filtering. */ 445a85fe12eSEd Maste if (is_remove_symbol(ecp, sc, i, &sym, name) != 0) 446a85fe12eSEd Maste continue; 447a85fe12eSEd Maste 448a85fe12eSEd Maste /* Check if we need to change the binding of this symbol. */ 449a85fe12eSEd Maste if (is_global_symbol(sym.st_info) || 450a85fe12eSEd Maste is_weak_symbol(sym.st_info)) { 451a85fe12eSEd Maste /* 452a85fe12eSEd Maste * XXX Binutils objcopy does not weaken certain 453a85fe12eSEd Maste * symbols. 454a85fe12eSEd Maste */ 455a85fe12eSEd Maste if (ecp->flags & WEAKEN_ALL || 456a85fe12eSEd Maste lookup_symop_list(ecp, name, SYMOP_WEAKEN) != NULL) 457a85fe12eSEd Maste sym.st_info = GELF_ST_INFO(STB_WEAK, 458a85fe12eSEd Maste GELF_ST_TYPE(sym.st_info)); 459a85fe12eSEd Maste /* Do not localize undefined symbols. */ 460a85fe12eSEd Maste if (sym.st_shndx != SHN_UNDEF && 461a85fe12eSEd Maste lookup_symop_list(ecp, name, SYMOP_LOCALIZE) != 462a85fe12eSEd Maste NULL) 463a85fe12eSEd Maste sym.st_info = GELF_ST_INFO(STB_LOCAL, 464a85fe12eSEd Maste GELF_ST_TYPE(sym.st_info)); 465a85fe12eSEd Maste if (ecp->flags & KEEP_GLOBAL && 466a85fe12eSEd Maste sym.st_shndx != SHN_UNDEF && 467a85fe12eSEd Maste lookup_symop_list(ecp, name, SYMOP_KEEPG) == NULL) 468a85fe12eSEd Maste sym.st_info = GELF_ST_INFO(STB_LOCAL, 469a85fe12eSEd Maste GELF_ST_TYPE(sym.st_info)); 47067d97fe7SEd Maste if (ecp->flags & LOCALIZE_HIDDEN && 47167d97fe7SEd Maste sym.st_shndx != SHN_UNDEF && 47267d97fe7SEd Maste is_hidden_symbol(sym.st_other)) 47367d97fe7SEd Maste sym.st_info = GELF_ST_INFO(STB_LOCAL, 47467d97fe7SEd Maste GELF_ST_TYPE(sym.st_info)); 475a85fe12eSEd Maste } else { 476a85fe12eSEd Maste /* STB_LOCAL binding. */ 477a85fe12eSEd Maste if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) != 478a85fe12eSEd Maste NULL) 479a85fe12eSEd Maste sym.st_info = GELF_ST_INFO(STB_GLOBAL, 480a85fe12eSEd Maste GELF_ST_TYPE(sym.st_info)); 481a85fe12eSEd Maste /* XXX We should globalize weak symbol? */ 482a85fe12eSEd Maste } 483a85fe12eSEd Maste 484a85fe12eSEd Maste /* Check if we need to rename this symbol. */ 485a85fe12eSEd Maste if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL) 486a85fe12eSEd Maste name = sp->newname; 487a85fe12eSEd Maste 488a85fe12eSEd Maste /* Check if we need to prefix the symbols. */ 489a85fe12eSEd Maste newname = NULL; 490a85fe12eSEd Maste if (ecp->prefix_sym != NULL && name != NULL && *name != '\0') { 491a85fe12eSEd Maste namelen = strlen(name) + strlen(ecp->prefix_sym) + 1; 492a85fe12eSEd Maste if ((newname = malloc(namelen)) == NULL) 493a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 494a85fe12eSEd Maste snprintf(newname, namelen, "%s%s", ecp->prefix_sym, 495a85fe12eSEd Maste name); 496a85fe12eSEd Maste name = newname; 497a85fe12eSEd Maste } 498a85fe12eSEd Maste 499a85fe12eSEd Maste /* Copy symbol, mark global/weak symbol and add to index map. */ 500a85fe12eSEd Maste if (is_global_symbol(sym.st_info) || 501a85fe12eSEd Maste is_weak_symbol(sym.st_info)) { 502a85fe12eSEd Maste BIT_SET(gsym, i); 503a85fe12eSEd Maste ecp->symndx[i] = sy_buf->ngs; 504a85fe12eSEd Maste } else 505a85fe12eSEd Maste ecp->symndx[i] = sy_buf->nls; 506a85fe12eSEd Maste add_to_symtab(ecp, name, sym.st_value, sym.st_size, 507a85fe12eSEd Maste sym.st_shndx, sym.st_info, sym.st_other, 0); 508a85fe12eSEd Maste 509a85fe12eSEd Maste if (newname != NULL) 510a85fe12eSEd Maste free(newname); 511a85fe12eSEd Maste 512a85fe12eSEd Maste /* 513a85fe12eSEd Maste * If the symbol is a STT_SECTION symbol, mark the section 514a85fe12eSEd Maste * it points to. 515a85fe12eSEd Maste */ 516a85fe12eSEd Maste if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) 517a85fe12eSEd Maste BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]); 518a85fe12eSEd Maste } 519a85fe12eSEd Maste 520a85fe12eSEd Maste /* 521a85fe12eSEd Maste * Give up if there is no real symbols inside the table. 522a85fe12eSEd Maste * XXX The logic here needs to be improved. We need to 523a85fe12eSEd Maste * check if that only local symbol is the reserved symbol. 524a85fe12eSEd Maste */ 525a85fe12eSEd Maste if (sy_buf->nls <= 1 && sy_buf->ngs == 0) 526a85fe12eSEd Maste return (0); 527a85fe12eSEd Maste 528a85fe12eSEd Maste /* 529a85fe12eSEd Maste * Create STT_SECTION symbols for sections that do not already 530a85fe12eSEd Maste * got one. However, we do not create STT_SECTION symbol for 531a85fe12eSEd Maste * .symtab, .strtab, .shstrtab and reloc sec of relocatables. 532a85fe12eSEd Maste */ 533a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 534a85fe12eSEd Maste if (s->pseudo) 535a85fe12eSEd Maste continue; 536a85fe12eSEd Maste if (strcmp(s->name, ".symtab") == 0 || 537a85fe12eSEd Maste strcmp(s->name, ".strtab") == 0 || 538a85fe12eSEd Maste strcmp(s->name, ".shstrtab") == 0) 539a85fe12eSEd Maste continue; 540a85fe12eSEd Maste if ((ecp->flags & RELOCATABLE) != 0 && 541a85fe12eSEd Maste ((s->type == SHT_REL) || (s->type == SHT_RELA))) 542a85fe12eSEd Maste continue; 543a85fe12eSEd Maste 544a85fe12eSEd Maste if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) 545a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_ndxscn failed: %s", 546a85fe12eSEd Maste elf_errmsg(-1)); 547a85fe12eSEd Maste 548a85fe12eSEd Maste if (!BIT_ISSET(ecp->v_secsym, ndx)) { 549a85fe12eSEd Maste sym.st_name = 0; 550a85fe12eSEd Maste sym.st_value = s->vma; 551a85fe12eSEd Maste sym.st_size = 0; 552a85fe12eSEd Maste sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); 553a85fe12eSEd Maste /* 554a85fe12eSEd Maste * Don't let add_to_symtab() touch sym.st_shndx. 555a85fe12eSEd Maste * In this case, we know the index already. 556a85fe12eSEd Maste */ 557a85fe12eSEd Maste add_to_symtab(ecp, NULL, sym.st_value, sym.st_size, 558a85fe12eSEd Maste ndx, sym.st_info, sym.st_other, 1); 559a85fe12eSEd Maste } 560a85fe12eSEd Maste } 561a85fe12eSEd Maste 562a85fe12eSEd Maste /* 563a85fe12eSEd Maste * Update st_name and index map for global/weak symbols. Note that 564a85fe12eSEd Maste * global/weak symbols are put after local symbols. 565a85fe12eSEd Maste */ 566a85fe12eSEd Maste if (gsym != NULL) { 567a85fe12eSEd Maste for(i = 0; (size_t) i < sc; i++) { 568a85fe12eSEd Maste if (!BIT_ISSET(gsym, i)) 569a85fe12eSEd Maste continue; 570a85fe12eSEd Maste 571a85fe12eSEd Maste /* Update st_name. */ 572a85fe12eSEd Maste if (ec == ELFCLASS32) 573a85fe12eSEd Maste sy_buf->g32[ecp->symndx[i]].st_name += 5744a85c691SEd Maste st_buf->l.sz; 575a85fe12eSEd Maste else 576a85fe12eSEd Maste sy_buf->g64[ecp->symndx[i]].st_name += 5774a85c691SEd Maste st_buf->l.sz; 578a85fe12eSEd Maste 579a85fe12eSEd Maste /* Update index map. */ 580a85fe12eSEd Maste ecp->symndx[i] += sy_buf->nls; 581a85fe12eSEd Maste } 582a85fe12eSEd Maste free(gsym); 583a85fe12eSEd Maste } 584a85fe12eSEd Maste 585a85fe12eSEd Maste return (1); 586a85fe12eSEd Maste } 587a85fe12eSEd Maste 588a85fe12eSEd Maste void 589a85fe12eSEd Maste create_symtab(struct elfcopy *ecp) 590a85fe12eSEd Maste { 591a85fe12eSEd Maste struct section *s, *sy, *st; 592a85fe12eSEd Maste size_t maxndx, ndx; 593a85fe12eSEd Maste 594a85fe12eSEd Maste sy = ecp->symtab; 595a85fe12eSEd Maste st = ecp->strtab; 596a85fe12eSEd Maste 597a85fe12eSEd Maste /* 598a85fe12eSEd Maste * Set section index map for .symtab and .strtab. We need to set 599a85fe12eSEd Maste * these map because otherwise symbols which refer to .symtab and 600a85fe12eSEd Maste * .strtab will be removed by symbol filtering unconditionally. 601a85fe12eSEd Maste * And we have to figure out scn index this way (instead of calling 602a85fe12eSEd Maste * elf_ndxscn) because we can not create Elf_Scn before we're certain 603a85fe12eSEd Maste * that .symtab and .strtab will exist in the output object. 604a85fe12eSEd Maste */ 605a85fe12eSEd Maste maxndx = 0; 606a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 607a85fe12eSEd Maste if (s->os == NULL) 608a85fe12eSEd Maste continue; 609a85fe12eSEd Maste if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) 610a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_ndxscn failed: %s", 611a85fe12eSEd Maste elf_errmsg(-1)); 612a85fe12eSEd Maste if (ndx > maxndx) 613a85fe12eSEd Maste maxndx = ndx; 614a85fe12eSEd Maste } 615a85fe12eSEd Maste ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1; 616a85fe12eSEd Maste ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2; 617a85fe12eSEd Maste 618a85fe12eSEd Maste /* 619a85fe12eSEd Maste * Generate symbols for output object if SYMTAB_INTACT is not set. 620a85fe12eSEd Maste * If there is no symbol in the input object or all the symbols are 621a85fe12eSEd Maste * stripped, then free all the resouces allotted for symbol table, 622a85fe12eSEd Maste * and clear SYMTAB_EXIST flag. 623a85fe12eSEd Maste */ 624a85fe12eSEd Maste if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) { 625a85fe12eSEd Maste TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list); 626a85fe12eSEd Maste TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list); 627a85fe12eSEd Maste free(ecp->symtab); 628a85fe12eSEd Maste free(ecp->strtab); 629a85fe12eSEd Maste ecp->symtab = NULL; 630a85fe12eSEd Maste ecp->strtab = NULL; 631a85fe12eSEd Maste ecp->flags &= ~SYMTAB_EXIST; 632a85fe12eSEd Maste return; 633a85fe12eSEd Maste } 634a85fe12eSEd Maste 635a85fe12eSEd Maste /* Create output Elf_Scn for .symtab and .strtab. */ 636a85fe12eSEd Maste if ((sy->os = elf_newscn(ecp->eout)) == NULL || 637a85fe12eSEd Maste (st->os = elf_newscn(ecp->eout)) == NULL) 638a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newscn failed: %s", 639a85fe12eSEd Maste elf_errmsg(-1)); 640a85fe12eSEd Maste /* Update secndx anyway. */ 641a85fe12eSEd Maste ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os); 642a85fe12eSEd Maste ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os); 643a85fe12eSEd Maste 644a85fe12eSEd Maste /* 645a85fe12eSEd Maste * Copy .symtab and .strtab section headers from input to output 646a85fe12eSEd Maste * object to start with, these will be overridden later if need. 647a85fe12eSEd Maste */ 648a85fe12eSEd Maste copy_shdr(ecp, sy, ".symtab", 1, 0); 649a85fe12eSEd Maste copy_shdr(ecp, st, ".strtab", 1, 0); 650a85fe12eSEd Maste 651a85fe12eSEd Maste /* Copy verbatim if symbol table is intact. */ 652a85fe12eSEd Maste if (ecp->flags & SYMTAB_INTACT) { 653a85fe12eSEd Maste copy_data(sy); 654a85fe12eSEd Maste copy_data(st); 655a85fe12eSEd Maste return; 656a85fe12eSEd Maste } 657a85fe12eSEd Maste 658a85fe12eSEd Maste create_symtab_data(ecp); 659a85fe12eSEd Maste } 660a85fe12eSEd Maste 661a85fe12eSEd Maste void 662a85fe12eSEd Maste free_symtab(struct elfcopy *ecp) 663a85fe12eSEd Maste { 664a85fe12eSEd Maste struct symbuf *sy_buf; 665a85fe12eSEd Maste struct strbuf *st_buf; 6664a85c691SEd Maste struct sthash *sh, *shtmp; 6674a85c691SEd Maste int i; 668a85fe12eSEd Maste 669a85fe12eSEd Maste if (ecp->symtab != NULL && ecp->symtab->buf != NULL) { 670a85fe12eSEd Maste sy_buf = ecp->symtab->buf; 671a85fe12eSEd Maste if (sy_buf->l32 != NULL) 672a85fe12eSEd Maste free(sy_buf->l32); 673a85fe12eSEd Maste if (sy_buf->g32 != NULL) 674a85fe12eSEd Maste free(sy_buf->g32); 675a85fe12eSEd Maste if (sy_buf->l64 != NULL) 676a85fe12eSEd Maste free(sy_buf->l64); 677a85fe12eSEd Maste if (sy_buf->g64 != NULL) 678a85fe12eSEd Maste free(sy_buf->g64); 679a85fe12eSEd Maste } 680a85fe12eSEd Maste 681a85fe12eSEd Maste if (ecp->strtab != NULL && ecp->strtab->buf != NULL) { 682a85fe12eSEd Maste st_buf = ecp->strtab->buf; 6834a85c691SEd Maste if (st_buf->l.buf != NULL) 6844a85c691SEd Maste free(st_buf->l.buf); 6854a85c691SEd Maste if (st_buf->g.buf != NULL) 6864a85c691SEd Maste free(st_buf->g.buf); 6874a85c691SEd Maste for (i = 0; i < STHASHSIZE; i++) { 6884a85c691SEd Maste LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next, 6894a85c691SEd Maste shtmp) { 6904a85c691SEd Maste LIST_REMOVE(sh, sh_next); 6914a85c691SEd Maste free(sh); 6924a85c691SEd Maste } 6934a85c691SEd Maste LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next, 6944a85c691SEd Maste shtmp) { 6954a85c691SEd Maste LIST_REMOVE(sh, sh_next); 6964a85c691SEd Maste free(sh); 6974a85c691SEd Maste } 6984a85c691SEd Maste } 699a85fe12eSEd Maste } 700a85fe12eSEd Maste } 701a85fe12eSEd Maste 702a85fe12eSEd Maste void 703a85fe12eSEd Maste create_external_symtab(struct elfcopy *ecp) 704a85fe12eSEd Maste { 705a85fe12eSEd Maste struct section *s; 706a85fe12eSEd Maste struct symbuf *sy_buf; 707a85fe12eSEd Maste struct strbuf *st_buf; 708a85fe12eSEd Maste GElf_Shdr sh; 709a85fe12eSEd Maste size_t ndx; 710a85fe12eSEd Maste 711a85fe12eSEd Maste if (ecp->oec == ELFCLASS32) 712a85fe12eSEd Maste ecp->symtab = create_external_section(ecp, ".symtab", NULL, 713a85fe12eSEd Maste NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0); 714a85fe12eSEd Maste else 715a85fe12eSEd Maste ecp->symtab = create_external_section(ecp, ".symtab", NULL, 716a85fe12eSEd Maste NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0); 717a85fe12eSEd Maste 718a85fe12eSEd Maste ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0, 719a85fe12eSEd Maste SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0); 720a85fe12eSEd Maste 721a85fe12eSEd Maste /* Let sh_link field of .symtab section point to .strtab section. */ 722a85fe12eSEd Maste if (gelf_getshdr(ecp->symtab->os, &sh) == NULL) 723a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", 724a85fe12eSEd Maste elf_errmsg(-1)); 725a85fe12eSEd Maste sh.sh_link = elf_ndxscn(ecp->strtab->os); 726a85fe12eSEd Maste if (!gelf_update_shdr(ecp->symtab->os, &sh)) 727a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", 728a85fe12eSEd Maste elf_errmsg(-1)); 729a85fe12eSEd Maste 730a85fe12eSEd Maste /* Create buffers for .symtab and .strtab. */ 731a85fe12eSEd Maste if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL) 732a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 733a85fe12eSEd Maste if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL) 734a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 735a85fe12eSEd Maste sy_buf->gcap = sy_buf->lcap = 64; 7364a85c691SEd Maste st_buf->g.cap = 256; 7374a85c691SEd Maste st_buf->l.cap = 64; 7384a85c691SEd Maste st_buf->l.sz = 1; /* '\0' at start. */ 7394a85c691SEd Maste st_buf->g.sz = 0; 740a85fe12eSEd Maste 741a85fe12eSEd Maste ecp->symtab->sz = 0; 742a85fe12eSEd Maste ecp->strtab->sz = 0; 743a85fe12eSEd Maste ecp->symtab->buf = sy_buf; 744a85fe12eSEd Maste ecp->strtab->buf = st_buf; 745a85fe12eSEd Maste 746a85fe12eSEd Maste /* Always create the special symbol at the symtab beginning. */ 747a85fe12eSEd Maste add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF, 748a85fe12eSEd Maste ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1); 749a85fe12eSEd Maste 750a85fe12eSEd Maste /* Create STT_SECTION symbols. */ 751a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 752a85fe12eSEd Maste if (s->pseudo) 753a85fe12eSEd Maste continue; 754a85fe12eSEd Maste if (strcmp(s->name, ".symtab") == 0 || 755a85fe12eSEd Maste strcmp(s->name, ".strtab") == 0 || 756a85fe12eSEd Maste strcmp(s->name, ".shstrtab") == 0) 757a85fe12eSEd Maste continue; 758a85fe12eSEd Maste (void) elf_errno(); 759a85fe12eSEd Maste if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) { 760a85fe12eSEd Maste warnx("elf_ndxscn failed: %s", 761a85fe12eSEd Maste elf_errmsg(-1)); 762a85fe12eSEd Maste continue; 763a85fe12eSEd Maste } 764a85fe12eSEd Maste add_to_symtab(ecp, NULL, 0, 0, ndx, 765a85fe12eSEd Maste GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1); 766a85fe12eSEd Maste } 767a85fe12eSEd Maste } 768a85fe12eSEd Maste 769a85fe12eSEd Maste void 770a85fe12eSEd Maste add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value, 771a85fe12eSEd Maste uint64_t st_size, uint16_t st_shndx, unsigned char st_info, 772a85fe12eSEd Maste unsigned char st_other, int ndx_known) 773a85fe12eSEd Maste { 774a85fe12eSEd Maste struct symbuf *sy_buf; 775a85fe12eSEd Maste struct strbuf *st_buf; 7764a85c691SEd Maste struct sthash *sh; 7774a85c691SEd Maste uint32_t hash; 778a85fe12eSEd Maste int pos; 779a85fe12eSEd Maste 780a85fe12eSEd Maste /* 781a85fe12eSEd Maste * Convenient macro for copying global/local 32/64 bit symbols 782a85fe12eSEd Maste * from input object to the buffer created for output object. 783a85fe12eSEd Maste * It handles buffer growing, st_name calculating and st_shndx 784a85fe12eSEd Maste * updating for symbols with non-special section index. 785a85fe12eSEd Maste */ 786a85fe12eSEd Maste #define _ADDSYM(B, SZ) do { \ 787a85fe12eSEd Maste if (sy_buf->B##SZ == NULL) { \ 788a85fe12eSEd Maste sy_buf->B##SZ = malloc(sy_buf->B##cap * \ 789a85fe12eSEd Maste sizeof(Elf##SZ##_Sym)); \ 790a85fe12eSEd Maste if (sy_buf->B##SZ == NULL) \ 791a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); \ 792a85fe12eSEd Maste } else if (sy_buf->n##B##s >= sy_buf->B##cap) { \ 793a85fe12eSEd Maste sy_buf->B##cap *= 2; \ 794a85fe12eSEd Maste sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap * \ 795a85fe12eSEd Maste sizeof(Elf##SZ##_Sym)); \ 796a85fe12eSEd Maste if (sy_buf->B##SZ == NULL) \ 797a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed"); \ 798a85fe12eSEd Maste } \ 799a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_info = st_info; \ 800a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_other = st_other; \ 801a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_value = st_value; \ 802a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_size = st_size; \ 803a85fe12eSEd Maste if (ndx_known) \ 804a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \ 805a85fe12eSEd Maste else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE) \ 806a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \ 807a85fe12eSEd Maste else \ 808a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = \ 809a85fe12eSEd Maste ecp->secndx[st_shndx]; \ 8104a85c691SEd Maste if (st_buf->B.buf == NULL) { \ 8114a85c691SEd Maste st_buf->B.buf = calloc(st_buf->B.cap, \ 8124a85c691SEd Maste sizeof(*st_buf->B.buf)); \ 8134a85c691SEd Maste if (st_buf->B.buf == NULL) \ 814a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); \ 815a85fe12eSEd Maste } \ 816a85fe12eSEd Maste if (name != NULL && *name != '\0') { \ 8174a85c691SEd Maste pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\ 8184a85c691SEd Maste name); \ 819a85fe12eSEd Maste if (pos != -1) \ 820a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos; \ 821a85fe12eSEd Maste else { \ 822a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_name = \ 8234a85c691SEd Maste st_buf->B.sz; \ 8244a85c691SEd Maste while (st_buf->B.sz + strlen(name) >= \ 8254a85c691SEd Maste st_buf->B.cap - 1) { \ 8264a85c691SEd Maste st_buf->B.cap *= 2; \ 8274a85c691SEd Maste st_buf->B.buf = realloc(st_buf->B.buf, \ 8284a85c691SEd Maste st_buf->B.cap); \ 8294a85c691SEd Maste if (st_buf->B.buf == NULL) \ 830a85fe12eSEd Maste err(EXIT_FAILURE, \ 831a85fe12eSEd Maste "realloc failed"); \ 832a85fe12eSEd Maste } \ 8334a85c691SEd Maste if ((sh = malloc(sizeof(*sh))) == NULL) \ 8344a85c691SEd Maste err(EXIT_FAILURE, "malloc failed"); \ 8354a85c691SEd Maste sh->sh_off = st_buf->B.sz; \ 8364a85c691SEd Maste hash = str_hash(name); \ 8374a85c691SEd Maste LIST_INSERT_HEAD(&st_buf->B.hash[hash], sh, \ 8384a85c691SEd Maste sh_next); \ 8394a85c691SEd Maste strncpy(&st_buf->B.buf[st_buf->B.sz], name, \ 840a85fe12eSEd Maste strlen(name)); \ 8414a85c691SEd Maste st_buf->B.buf[st_buf->B.sz + strlen(name)] = '\0'; \ 8424a85c691SEd Maste st_buf->B.sz += strlen(name) + 1; \ 843a85fe12eSEd Maste } \ 844a85fe12eSEd Maste } else \ 845a85fe12eSEd Maste sy_buf->B##SZ[sy_buf->n##B##s].st_name = 0; \ 846a85fe12eSEd Maste sy_buf->n##B##s++; \ 847a85fe12eSEd Maste } while (0) 848a85fe12eSEd Maste 849a85fe12eSEd Maste sy_buf = ecp->symtab->buf; 850a85fe12eSEd Maste st_buf = ecp->strtab->buf; 851a85fe12eSEd Maste 852a85fe12eSEd Maste if (ecp->oec == ELFCLASS32) { 853a85fe12eSEd Maste if (is_local_symbol(st_info)) 854a85fe12eSEd Maste _ADDSYM(l, 32); 855a85fe12eSEd Maste else 856a85fe12eSEd Maste _ADDSYM(g, 32); 857a85fe12eSEd Maste } else { 858a85fe12eSEd Maste if (is_local_symbol(st_info)) 859a85fe12eSEd Maste _ADDSYM(l, 64); 860a85fe12eSEd Maste else 861a85fe12eSEd Maste _ADDSYM(g, 64); 862a85fe12eSEd Maste } 863a85fe12eSEd Maste 864a85fe12eSEd Maste /* Update section size. */ 865a85fe12eSEd Maste ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) * 866a85fe12eSEd Maste (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym)); 8674a85c691SEd Maste ecp->strtab->sz = st_buf->l.sz + st_buf->g.sz; 868a85fe12eSEd Maste 869a85fe12eSEd Maste #undef _ADDSYM 870a85fe12eSEd Maste } 871a85fe12eSEd Maste 872a85fe12eSEd Maste void 873a85fe12eSEd Maste finalize_external_symtab(struct elfcopy *ecp) 874a85fe12eSEd Maste { 875a85fe12eSEd Maste struct symbuf *sy_buf; 876a85fe12eSEd Maste struct strbuf *st_buf; 877a85fe12eSEd Maste int i; 878a85fe12eSEd Maste 879a85fe12eSEd Maste /* 880a85fe12eSEd Maste * Update st_name for global/weak symbols. (global/weak symbols 881a85fe12eSEd Maste * are put after local symbols) 882a85fe12eSEd Maste */ 883a85fe12eSEd Maste sy_buf = ecp->symtab->buf; 884a85fe12eSEd Maste st_buf = ecp->strtab->buf; 885a85fe12eSEd Maste for (i = 0; (size_t) i < sy_buf->ngs; i++) { 886a85fe12eSEd Maste if (ecp->oec == ELFCLASS32) 8874a85c691SEd Maste sy_buf->g32[i].st_name += st_buf->l.sz; 888a85fe12eSEd Maste else 8894a85c691SEd Maste sy_buf->g64[i].st_name += st_buf->l.sz; 890a85fe12eSEd Maste } 891a85fe12eSEd Maste } 892a85fe12eSEd Maste 893a85fe12eSEd Maste void 894a85fe12eSEd Maste create_symtab_data(struct elfcopy *ecp) 895a85fe12eSEd Maste { 896a85fe12eSEd Maste struct section *sy, *st; 897a85fe12eSEd Maste struct symbuf *sy_buf; 898a85fe12eSEd Maste struct strbuf *st_buf; 899a85fe12eSEd Maste Elf_Data *gsydata, *lsydata, *gstdata, *lstdata; 900a85fe12eSEd Maste GElf_Shdr shy, sht; 901a85fe12eSEd Maste 902a85fe12eSEd Maste sy = ecp->symtab; 903a85fe12eSEd Maste st = ecp->strtab; 904a85fe12eSEd Maste 905a85fe12eSEd Maste if (gelf_getshdr(sy->os, ­) == NULL) 906a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", 907a85fe12eSEd Maste elf_errmsg(-1)); 908a85fe12eSEd Maste if (gelf_getshdr(st->os, &sht) == NULL) 909a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", 910a85fe12eSEd Maste elf_errmsg(-1)); 911a85fe12eSEd Maste 912a85fe12eSEd Maste /* 913a85fe12eSEd Maste * Create two Elf_Data for .symtab section of output object, one 914a85fe12eSEd Maste * for local symbols and another for global symbols. Note that 915a85fe12eSEd Maste * local symbols appear first in the .symtab. 916a85fe12eSEd Maste */ 917a85fe12eSEd Maste sy_buf = sy->buf; 918a85fe12eSEd Maste if (sy_buf->nls > 0) { 919a85fe12eSEd Maste if ((lsydata = elf_newdata(sy->os)) == NULL) 920a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newdata() failed: %s.", 921a85fe12eSEd Maste elf_errmsg(-1)); 922a85fe12eSEd Maste if (ecp->oec == ELFCLASS32) { 923a85fe12eSEd Maste lsydata->d_align = 4; 924a85fe12eSEd Maste lsydata->d_off = 0; 925a85fe12eSEd Maste lsydata->d_buf = sy_buf->l32; 926a85fe12eSEd Maste lsydata->d_size = sy_buf->nls * 927a85fe12eSEd Maste sizeof(Elf32_Sym); 928a85fe12eSEd Maste lsydata->d_type = ELF_T_SYM; 929a85fe12eSEd Maste lsydata->d_version = EV_CURRENT; 930a85fe12eSEd Maste } else { 931a85fe12eSEd Maste lsydata->d_align = 8; 932a85fe12eSEd Maste lsydata->d_off = 0; 933a85fe12eSEd Maste lsydata->d_buf = sy_buf->l64; 934a85fe12eSEd Maste lsydata->d_size = sy_buf->nls * 935a85fe12eSEd Maste sizeof(Elf64_Sym); 936a85fe12eSEd Maste lsydata->d_type = ELF_T_SYM; 937a85fe12eSEd Maste lsydata->d_version = EV_CURRENT; 938a85fe12eSEd Maste } 939a85fe12eSEd Maste } 940a85fe12eSEd Maste if (sy_buf->ngs > 0) { 941a85fe12eSEd Maste if ((gsydata = elf_newdata(sy->os)) == NULL) 942a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newdata() failed: %s.", 943a85fe12eSEd Maste elf_errmsg(-1)); 944a85fe12eSEd Maste if (ecp->oec == ELFCLASS32) { 945a85fe12eSEd Maste gsydata->d_align = 4; 946a85fe12eSEd Maste gsydata->d_off = sy_buf->nls * 947a85fe12eSEd Maste sizeof(Elf32_Sym); 948a85fe12eSEd Maste gsydata->d_buf = sy_buf->g32; 949a85fe12eSEd Maste gsydata->d_size = sy_buf->ngs * 950a85fe12eSEd Maste sizeof(Elf32_Sym); 951a85fe12eSEd Maste gsydata->d_type = ELF_T_SYM; 952a85fe12eSEd Maste gsydata->d_version = EV_CURRENT; 953a85fe12eSEd Maste } else { 954a85fe12eSEd Maste gsydata->d_align = 8; 955a85fe12eSEd Maste gsydata->d_off = sy_buf->nls * 956a85fe12eSEd Maste sizeof(Elf64_Sym); 957a85fe12eSEd Maste gsydata->d_buf = sy_buf->g64; 958a85fe12eSEd Maste gsydata->d_size = sy_buf->ngs * 959a85fe12eSEd Maste sizeof(Elf64_Sym); 960a85fe12eSEd Maste gsydata->d_type = ELF_T_SYM; 961a85fe12eSEd Maste gsydata->d_version = EV_CURRENT; 962a85fe12eSEd Maste } 963a85fe12eSEd Maste } 964a85fe12eSEd Maste 965a85fe12eSEd Maste /* 966a85fe12eSEd Maste * Create two Elf_Data for .strtab, one for local symbol name 967a85fe12eSEd Maste * and another for globals. Same as .symtab, local symbol names 968a85fe12eSEd Maste * appear first. 969a85fe12eSEd Maste */ 970a85fe12eSEd Maste st_buf = st->buf; 971a85fe12eSEd Maste if ((lstdata = elf_newdata(st->os)) == NULL) 972a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newdata() failed: %s.", 973a85fe12eSEd Maste elf_errmsg(-1)); 974a85fe12eSEd Maste lstdata->d_align = 1; 975a85fe12eSEd Maste lstdata->d_off = 0; 9764a85c691SEd Maste lstdata->d_buf = st_buf->l.buf; 9774a85c691SEd Maste lstdata->d_size = st_buf->l.sz; 978a85fe12eSEd Maste lstdata->d_type = ELF_T_BYTE; 979a85fe12eSEd Maste lstdata->d_version = EV_CURRENT; 980a85fe12eSEd Maste 9814a85c691SEd Maste if (st_buf->g.sz > 0) { 982a85fe12eSEd Maste if ((gstdata = elf_newdata(st->os)) == NULL) 983a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_newdata() failed: %s.", 984a85fe12eSEd Maste elf_errmsg(-1)); 985a85fe12eSEd Maste gstdata->d_align = 1; 986a85fe12eSEd Maste gstdata->d_off = lstdata->d_size; 9874a85c691SEd Maste gstdata->d_buf = st_buf->g.buf; 9884a85c691SEd Maste gstdata->d_size = st_buf->g.sz; 989a85fe12eSEd Maste gstdata->d_type = ELF_T_BYTE; 990a85fe12eSEd Maste gstdata->d_version = EV_CURRENT; 991a85fe12eSEd Maste } 992a85fe12eSEd Maste 993a85fe12eSEd Maste shy.sh_addr = 0; 994a85fe12eSEd Maste shy.sh_addralign = (ecp->oec == ELFCLASS32 ? 4 : 8); 995a85fe12eSEd Maste shy.sh_size = sy->sz; 996a85fe12eSEd Maste shy.sh_type = SHT_SYMTAB; 997a85fe12eSEd Maste shy.sh_flags = 0; 998a85fe12eSEd Maste shy.sh_entsize = gelf_fsize(ecp->eout, ELF_T_SYM, 1, 999a85fe12eSEd Maste EV_CURRENT); 1000a85fe12eSEd Maste /* 1001a85fe12eSEd Maste * According to SYSV abi, here sh_info is one greater than 1002a85fe12eSEd Maste * the symbol table index of the last local symbol(binding 1003a85fe12eSEd Maste * STB_LOCAL). 1004a85fe12eSEd Maste */ 1005a85fe12eSEd Maste shy.sh_info = sy_buf->nls; 1006a85fe12eSEd Maste 1007a85fe12eSEd Maste sht.sh_addr = 0; 1008a85fe12eSEd Maste sht.sh_addralign = 1; 1009a85fe12eSEd Maste sht.sh_size = st->sz; 1010a85fe12eSEd Maste sht.sh_type = SHT_STRTAB; 1011a85fe12eSEd Maste sht.sh_flags = 0; 1012a85fe12eSEd Maste sht.sh_entsize = 0; 1013a85fe12eSEd Maste sht.sh_info = 0; 1014a85fe12eSEd Maste sht.sh_link = 0; 1015a85fe12eSEd Maste 1016a85fe12eSEd Maste if (!gelf_update_shdr(sy->os, ­)) 1017a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", 1018a85fe12eSEd Maste elf_errmsg(-1)); 1019a85fe12eSEd Maste if (!gelf_update_shdr(st->os, &sht)) 1020a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", 1021a85fe12eSEd Maste elf_errmsg(-1)); 1022a85fe12eSEd Maste } 1023a85fe12eSEd Maste 1024a85fe12eSEd Maste void 1025a85fe12eSEd Maste add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname, 1026a85fe12eSEd Maste unsigned int op) 1027a85fe12eSEd Maste { 1028a85fe12eSEd Maste struct symop *s; 1029a85fe12eSEd Maste 1030a85fe12eSEd Maste if ((s = lookup_symop_list(ecp, name, ~0U)) == NULL) { 1031a85fe12eSEd Maste if ((s = calloc(1, sizeof(*s))) == NULL) 1032a85fe12eSEd Maste errx(EXIT_FAILURE, "not enough memory"); 1033a85fe12eSEd Maste s->name = name; 1034a85fe12eSEd Maste if (op == SYMOP_REDEF) 1035a85fe12eSEd Maste s->newname = newname; 1036a85fe12eSEd Maste } 1037a85fe12eSEd Maste 1038a85fe12eSEd Maste s->op |= op; 1039a85fe12eSEd Maste STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list); 1040a85fe12eSEd Maste } 1041a85fe12eSEd Maste 1042a85fe12eSEd Maste static int 1043a85fe12eSEd Maste match_wildcard(const char *name, const char *pattern) 1044a85fe12eSEd Maste { 1045a85fe12eSEd Maste int reverse, match; 1046a85fe12eSEd Maste 1047a85fe12eSEd Maste reverse = 0; 1048a85fe12eSEd Maste if (*pattern == '!') { 1049a85fe12eSEd Maste reverse = 1; 1050a85fe12eSEd Maste pattern++; 1051a85fe12eSEd Maste } 1052a85fe12eSEd Maste 1053a85fe12eSEd Maste match = 0; 105467d97fe7SEd Maste if (!fnmatch(pattern, name, 0)) 1055a85fe12eSEd Maste match = 1; 1056a85fe12eSEd Maste 1057a85fe12eSEd Maste return (reverse ? !match : match); 1058a85fe12eSEd Maste } 1059a85fe12eSEd Maste 1060a85fe12eSEd Maste struct symop * 1061a85fe12eSEd Maste lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op) 1062a85fe12eSEd Maste { 1063a85fe12eSEd Maste struct symop *s; 1064a85fe12eSEd Maste 1065a85fe12eSEd Maste STAILQ_FOREACH(s, &ecp->v_symop, symop_list) { 1066a85fe12eSEd Maste if (name == NULL || !strcmp(name, s->name) || 1067a85fe12eSEd Maste ((ecp->flags & WILDCARD) && match_wildcard(name, s->name))) 1068a85fe12eSEd Maste if ((s->op & op) != 0) 1069a85fe12eSEd Maste return (s); 1070a85fe12eSEd Maste } 1071a85fe12eSEd Maste 1072a85fe12eSEd Maste return (NULL); 1073a85fe12eSEd Maste } 1074a85fe12eSEd Maste 1075a85fe12eSEd Maste static int 10764a85c691SEd Maste lookup_exact_string(hash_head *buckets, const char *buf, const char *s) 1077a85fe12eSEd Maste { 10784a85c691SEd Maste struct sthash *sh; 10794a85c691SEd Maste uint32_t hash; 1080a85fe12eSEd Maste 10814a85c691SEd Maste hash = str_hash(s); 10824a85c691SEd Maste LIST_FOREACH(sh, &buckets[hash], sh_next) 10834a85c691SEd Maste if (strcmp(buf + sh->sh_off, s) == 0) 10844a85c691SEd Maste return sh->sh_off; 10854a85c691SEd Maste return (-1); 1086a85fe12eSEd Maste } 1087a85fe12eSEd Maste 10884a85c691SEd Maste uint32_t 10894a85c691SEd Maste str_hash(const char *s) 10904a85c691SEd Maste { 10914a85c691SEd Maste uint32_t hash; 10924a85c691SEd Maste 1093*b00fe64fSEd Maste for (hash = 2166136261UL; *s; s++) 10944a85c691SEd Maste hash = (hash ^ *s) * 16777619; 10954a85c691SEd Maste 10964a85c691SEd Maste return (hash & (STHASHSIZE - 1)); 1097a85fe12eSEd Maste } 1098