From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pg1-x541.google.com (mail-pg1-x541.google.com [IPv6:2607:f8b0:4864:20::541]) by sourceware.org (Postfix) with ESMTPS id 046DE3953801 for ; Tue, 10 Mar 2020 00:12:31 +0000 (GMT) Received: by mail-pg1-x541.google.com with SMTP id u12so5456704pgb.10 for ; Mon, 09 Mar 2020 17:12:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=RSWKIRtPiT2w1wlfHdyHzRcCL+4UGhCq/+L+zivtyh4=; b=iaT2YuEVdhYRczdNvW33ZcvBdeSmK3OQgwh54tMT3JiLpcCRfnjmKeBgBt3eIf8XRM zSGPDEz/EVj/6+8Rsh3CNPkZxEhFCQeIj56n04eA4v2VaeXJNYWQ1GQyxc3CLW9FWKyI +1ho5VmGIVeLpYrnMn+xFsvN8/A2h5NTSsSsOfCj8ZVHXwQJMQMIzNZFs1P351WSLuYi XbDqTW8TLBNfJrnmpyTJYO2Ndo0nN2WpyDtTPXgrbGkoQDLMdhZ+F1Zxtuwm9iv62DCd nHk/6Bo87RS/TiWwwIibHANvMUa/wZHpXDthVelbN8tjUaZ2+seX9ubA6kg0SLKF9Vws h2ww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RSWKIRtPiT2w1wlfHdyHzRcCL+4UGhCq/+L+zivtyh4=; b=YZyzFAz0cQW3RyOerqphfTScoxRqTmLATejfQMyMy/G6PmNGYTVvyDSk2/klPWcA3H UFrKRME/6G9gnXJUIofumxYXK3YGTwtoF1/iADEgNpYlEDMPndCmjWLVo9vknaZw+cLx krKAtRsxzJiUqIB1LsPXIVlR8ilatv56CUI9ics18hT15zm2r1c3LJ109zE+5bxM/1U3 kMPuexZYW+quqQ7mLTM/K+evk2VdKLk0S2sDROErg7ADqzNCIqJP5D8J7z9r6JaLMKXB c9oCKpv9zvUspB5nE/xeQEIw0f/Kfl3ioRCecKwGqFt7YNMCfwnMjvleGEM31K7zMb3F R5iQ== X-Gm-Message-State: ANhLgQ07OT1b0EMTz7QhCEfOTFA3euQQOS/endRJWNr5RJT9V9YNtt7H otoDsriLi7HdgdvOQHLuJMq2Pn1U X-Google-Smtp-Source: ADFU+vsZI7YaEK4gCNH9KQoSdydnK6affKRt9UYW+MepA4g+ZUF/4QPYafMbfGxb3bRN1ddAF/0Tyg== X-Received: by 2002:a63:551a:: with SMTP id j26mr19762889pgb.274.1583799148950; Mon, 09 Mar 2020 17:12:28 -0700 (PDT) Received: from gnu-cfl-2.localdomain (c-73-93-86-59.hsd1.ca.comcast.net. [73.93.86.59]) by smtp.gmail.com with ESMTPSA id k9sm609392pjo.19.2020.03.09.17.12.25 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Mar 2020 17:12:26 -0700 (PDT) Received: from gnu-cfl-2.hsd1.ca.comcast.net (localhost [IPv6:::1]) by gnu-cfl-2.localdomain (Postfix) with ESMTP id DBCBBC04D7 for ; Mon, 9 Mar 2020 17:12:24 -0700 (PDT) From: "H.J. Lu" To: binutils@sourceware.org Subject: [PATCH 2/7] bfd: Improve nm and objdump without section header Date: Mon, 9 Mar 2020 17:12:19 -0700 Message-Id: <20200310001224.131714-4-hjl.tools@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200310001224.131714-1-hjl.tools@gmail.com> References: <20200310001224.131714-1-hjl.tools@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-27.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 10 Mar 2020 00:12:32 -0000 When there is no section header in an executable or shared library, we reconstruct dynamic symbol table from the PT_DYNAMIC segment, which contains DT_HASH/DT_GNU_HASH/DT_MIPS_XHASH, DT_STRTAB, DT_SYMTAB, DT_STRSZ and DT_SYMENT entries, to improve nm and objdump. For DT_HASH, the number of dynamic symbol table entries equals the number of chains. For DT_GNU_HASH/DT_MIPS_XHASH, only defined symbols with non-STB_LOCAL indings are in hash table. Since DT_GNU_HASH/DT_MIPS_XHASH place all symbols with STB_LOCAL binding before symbols with other bindings and all undefined symbols defined ones in dynamic symbol table, the highest symbol index in DT_GNU_HASH/DT_MIPS_XHASH is the highest dynamic symbol table index. dt_symtab, dt_symtab_count and dt_strtab are added to elf_obj_tdata to store dynamic symbol table information. PR ld/25617 * elf-bfd.h (elf_obj_tdata): Add dt_symtab, dt_symtab_count and dt_strtab. (elf_use_dt_symtab_p): New. (_bfd_elf_get_dynamic_symbols): Likewise. (_bfd_elf_get_section_from_dynamic_symbol): Likewise. * elf.c (bfd_elf_get_elf_syms): Use dynamic symbol table if neeeded. (_bfd_elf_get_dynamic_symtab_upper_bound): Likewise. (offset_from_vma): New function. (get_hash_table_data): Likewise. (_bfd_elf_get_dynamic_symbols): Likewise. (_bfd_elf_get_section_from_dynamic_symbol): Likewise. * elfcode.h (elf_object_p): Call _bfd_elf_get_dynamic_symbols to reconstruct dynamic symbol table from PT_DYNAMIC segment if there is no section header. (elf_slurp_symbol_table): Use dynamic symbol table if neeeded. Don't free isymbuf when dynamic symbol table is used. * elflink.c (elf_link_is_defined_archive_symbol): Return wrong format error when dynamic symbol table is used. (elf_link_add_object_symbols): Likewise. --- bfd/elf-bfd.h | 10 + bfd/elf.c | 497 ++++++++++++++++++++++++++++++++++++++++++++++++++ bfd/elfcode.h | 42 ++++- bfd/elflink.c | 12 ++ 4 files changed, 557 insertions(+), 4 deletions(-) diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 5d9e0fedcd..09692b155a 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1876,6 +1876,9 @@ struct elf_obj_tdata Elf_Internal_Shdr dynversym_hdr; Elf_Internal_Shdr dynverref_hdr; Elf_Internal_Shdr dynverdef_hdr; + Elf_Internal_Sym *dt_symtab; + bfd_size_type dt_symtab_count; + char *dt_strtab; elf_section_list * symtab_shndx_list; bfd_vma gp; /* The gp value */ unsigned int gp_size; /* The gp size */ @@ -2030,6 +2033,7 @@ struct elf_obj_tdata #define elf_dyn_lib_class(bfd) (elf_tdata(bfd) -> dyn_lib_class) #define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) #define elf_flags_init(bfd) (elf_tdata(bfd) -> o->flags_init) +#define elf_use_dt_symtab_p(bfd) (elf_tdata(bfd) -> dt_symtab_count != 0) #define elf_known_obj_attributes(bfd) (elf_tdata (bfd) -> known_obj_attributes) #define elf_other_obj_attributes(bfd) (elf_tdata (bfd) -> other_obj_attributes) #define elf_known_obj_attributes_proc(bfd) \ @@ -2403,6 +2407,12 @@ extern bfd_reloc_status_type bfd_elf_perform_complex_relocation extern bfd_boolean _bfd_elf_setup_sections (bfd *); +extern bfd_boolean _bfd_elf_get_dynamic_symbols + (bfd *, Elf_Internal_Phdr *, Elf_Internal_Phdr *, size_t, + bfd_size_type); +extern asection *_bfd_elf_get_section_from_dynamic_symbol + (bfd *, Elf_Internal_Sym *); + extern struct bfd_link_hash_entry *bfd_elf_define_start_stop (struct bfd_link_info *, const char *, asection *); diff --git a/bfd/elf.c b/bfd/elf.c index e6db2ff64d..aa689dcab3 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -405,6 +405,17 @@ bfd_elf_get_elf_syms (bfd *ibfd, if (symcount == 0) return intsym_buf; + if (elf_use_dt_symtab_p (ibfd)) + { + /* Use dynamic symbol table. */ + if (elf_tdata (ibfd)->dt_symtab_count != (symcount + symoffset)) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + return elf_tdata (ibfd)->dt_symtab + symoffset; + } + /* Normal syms might have section extension entries. */ shndx_hdr = NULL; if (elf_symtab_shndx_list (ibfd) != NULL) @@ -1881,6 +1892,485 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) return FALSE; } +/* Find the file offset corresponding to VMA by using the program + headers. */ + +static file_ptr +offset_from_vma (Elf_Internal_Phdr *phdrs, size_t phnum, bfd_vma vma, + bfd_vma size) +{ + Elf_Internal_Phdr *seg; + size_t i; + + for (seg = phdrs, i = 0; i < phnum; ++seg, ++i) + if (seg->p_type == PT_LOAD + && vma >= (seg->p_vaddr & -seg->p_align) + && vma + size <= seg->p_vaddr + seg->p_filesz) + return (file_ptr) (vma - seg->p_vaddr + seg->p_offset); + + bfd_set_error (bfd_error_invalid_operation); + return (file_ptr) -1; +} + +/* Convert hash table to internal form. */ + +static bfd_vma * +get_hash_table_data (bfd *abfd, bfd_size_type number, + unsigned int ent_size, bfd_size_type filesize) +{ + unsigned char *e_data = NULL; + bfd_vma *i_data = NULL; + bfd_size_type size; + + if (ent_size != 4 && ent_size != 8) + return NULL; + + /* If the size_t type is smaller than the bfd_size_type, eg because + you are building a 32-bit tool on a 64-bit host, then make sure + that when (number) is cast to (size_t) no information is lost. */ + if (sizeof (size_t) < sizeof (bfd_size_type) + && (bfd_size_type) ((size_t) number) != number) + { + bfd_set_error (bfd_error_file_too_big); + return NULL; + } + + size = ent_size * number; + /* Be kind to memory checkers (eg valgrind, address sanitizer) by not + attempting to allocate memory when the read is bound to fail. */ + if (size > filesize + || number >= ~(size_t) 0 / ent_size + || number >= ~(size_t) 0 / sizeof (*i_data)) + { + bfd_set_error (bfd_error_file_too_big); + return NULL; + } + + e_data = _bfd_malloc_and_read (abfd, size, size); + if (e_data == NULL) + return NULL; + + i_data = (bfd_vma *) bfd_malloc (number * sizeof (*i_data)); + if (i_data == NULL) + { + free (e_data); + return NULL; + } + + if (ent_size == 4) + while (number--) + i_data[number] = bfd_get_32 (abfd, e_data + number * ent_size); + else + while (number--) + i_data[number] = bfd_get_64 (abfd, e_data + number * ent_size); + + free (e_data); + return i_data; +} + +/* Address of .MIPS.xhash section. FIXME: What is the best way to + support DT_MIPS_XHASH? */ +#define DT_MIPS_XHASH 0x70000036 + +/* Reconstruct dynamic symbol table from PT_DYNAMIC segment. */ + +bfd_boolean +_bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr, + Elf_Internal_Phdr *phdrs, size_t phnum, + bfd_size_type filesize) +{ + bfd_byte *extdyn, *extdynend; + size_t extdynsize; + void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); + bfd_boolean (*swap_symbol_in) (bfd *, const void *, const void *, + Elf_Internal_Sym *); + Elf_Internal_Dyn dyn; + bfd_vma dt_hash = 0; + bfd_vma dt_gnu_hash = 0; + bfd_vma dt_mips_xhash = 0; + bfd_vma dt_strtab = 0; + bfd_vma dt_symtab = 0; + bfd_vma dt_strsz = 0; + bfd_byte *dynbuf = NULL; + char *strbuf = NULL; + bfd_vma *gnubuckets = NULL; + bfd_vma *gnuchains = NULL; + bfd_vma *mipsxlat = NULL; + file_ptr saved_filepos, filepos; + bfd_boolean res = FALSE; + bfd_size_type amt; + bfd_byte *esymbuf = NULL, *esym; + bfd_size_type symcount; + Elf_Internal_Sym *isymbuf = NULL; + Elf_Internal_Sym *isym, *isymend; + size_t extsym_size; + const struct elf_backend_data *bed; + + /* Return TRUE if symbol table is bad. */ + if (elf_bad_symtab (abfd)) + return TRUE; + + /* Return TRUE if DT_HASH/DT_GNU_HASH have bee processed before. */ + if (elf_tdata (abfd)->dt_strtab != NULL) + return TRUE; + + bed = get_elf_backend_data (abfd); + + /* Save file position for elf_object_p. */ + saved_filepos = bfd_tell (abfd); + + if (bfd_seek (abfd, phdr->p_offset, SEEK_SET) != 0) + goto error_return; + + dynbuf = _bfd_malloc_and_read (abfd, phdr->p_filesz, phdr->p_filesz); + if (dynbuf == NULL) + goto error_return; + + extsym_size = bed->s->sizeof_sym; + extdynsize = bed->s->sizeof_dyn; + swap_dyn_in = bed->s->swap_dyn_in; + + extdyn = dynbuf; + if (phdr->p_filesz < extdynsize) + goto error_return; + extdynend = extdyn + phdr->p_filesz; + for (; extdyn <= (extdynend - extdynsize); extdyn += extdynsize) + { + swap_dyn_in (abfd, extdyn, &dyn); + + if (dyn.d_tag == DT_NULL) + break; + + switch (dyn.d_tag) + { + case DT_HASH: + dt_hash = dyn.d_un.d_val; + break; + case DT_GNU_HASH: + if (bed->elf_machine_code != EM_MIPS + && bed->elf_machine_code != EM_MIPS_RS3_LE) + dt_gnu_hash = dyn.d_un.d_val; + break; + case DT_STRTAB: + dt_strtab = dyn.d_un.d_val; + break; + case DT_SYMTAB: + dt_symtab = dyn.d_un.d_val; + break; + case DT_STRSZ: + dt_strsz = dyn.d_un.d_val; + break; + case DT_SYMENT: + if (dyn.d_un.d_val != extsym_size) + goto error_return; + break; + default: + if (dyn.d_tag == DT_MIPS_XHASH + && (bed->elf_machine_code == EM_MIPS + || bed->elf_machine_code == EM_MIPS_RS3_LE)) + { + dt_gnu_hash = dyn.d_un.d_val; + dt_mips_xhash = dyn.d_un.d_val; + } + break; + } + } + + /* Check if we can reconstruct dynamic symbol table from PT_DYNAMIC + segment. */ + if ((!dt_hash && !dt_gnu_hash) + || !dt_strtab + || !dt_symtab + || !dt_strsz) + goto error_return; + + /* Get dynamic string table. */ + filepos = offset_from_vma (phdrs, phnum, dt_strtab, dt_strsz); + if (filepos == (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) != 0) + goto error_return; + + /* Dynamic string table must be valid until ABFD is closed. */ + strbuf = (char *) _bfd_alloc_and_read (abfd, dt_strsz, dt_strsz); + if (strbuf == NULL) + goto error_return; + + /* Get the real symbol count from DT_HASH or DT_GNU_HASH. Prefer + DT_HASH since it is simpler than DT_GNU_HASH. */ + if (dt_hash) + { + unsigned char nb[16]; + unsigned int hash_ent_size; + + switch (bed->elf_machine_code) + { + case EM_ALPHA: + case EM_S390: + case EM_S390_OLD: + if (bed->s->elfclass == ELFCLASS64) + { + hash_ent_size = 8; + break; + } + /* FALLTHROUGH */ + default: + hash_ent_size = 4; + break; + } + + filepos = offset_from_vma (phdrs, phnum, dt_hash, sizeof (nb)); + if (filepos == (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) != 0 + || (bfd_bread (nb, 2 * hash_ent_size, abfd) + != (2 * hash_ent_size))) + goto error_return; + + /* The number of dynamic symbol table entries equals the number + of chains. */ + if (hash_ent_size == 8) + symcount = bfd_get_64 (abfd, nb + hash_ent_size); + else + symcount = bfd_get_32 (abfd, nb + hash_ent_size); + } + else + { + /* For DT_GNU_HASH, only defined symbols with non-STB_LOCAL + bindings are in hash table. Since in dynamic symbol table, + all symbols with STB_LOCAL binding are placed before symbols + with other bindings and all undefined symbols are placed + before defined ones, the highest symbol index in DT_GNU_HASH + is the highest dynamic symbol table index. */ + unsigned char nb[16]; + bfd_vma ngnubuckets; + bfd_vma gnusymidx; + size_t i, ngnuchains; + bfd_vma maxchain = 0xffffffff, bitmaskwords; + bfd_vma buckets_vma; + + filepos = offset_from_vma (phdrs, phnum, dt_gnu_hash, + sizeof (nb)); + if (filepos == (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) != 0 + || bfd_bread (nb, sizeof (nb), abfd) != sizeof (nb)) + goto error_return; + + ngnubuckets = bfd_get_32 (abfd, nb); + gnusymidx = bfd_get_32 (abfd, nb + 4); + bitmaskwords = bfd_get_32 (abfd, nb + 8); + buckets_vma = dt_gnu_hash + 16; + if (bed->s->elfclass == ELFCLASS32) + buckets_vma += bitmaskwords * 4; + else + buckets_vma += bitmaskwords * 8; + filepos = offset_from_vma (phdrs, phnum, buckets_vma, 4); + if (filepos == (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) != 0) + goto error_return; + + gnubuckets = get_hash_table_data (abfd, ngnubuckets, 4, filesize); + if (gnubuckets == NULL) + goto error_return; + + for (i = 0; i < ngnubuckets; i++) + if (gnubuckets[i] != 0) + { + if (gnubuckets[i] < gnusymidx) + goto error_return; + + if (maxchain == 0xffffffff || gnubuckets[i] > maxchain) + maxchain = gnubuckets[i]; + } + + if (maxchain == 0xffffffff) + goto error_return; + + maxchain -= gnusymidx; + filepos = offset_from_vma (phdrs, phnum, + (buckets_vma + + 4 * (ngnubuckets + maxchain)), + 4); + if (filepos == (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) != 0) + goto error_return; + + do + { + if (bfd_bread (nb, 4, abfd) != 4) + goto error_return; + ++maxchain; + if (maxchain == 0) + goto error_return; + } + while ((bfd_get_32 (abfd, nb) & 1) == 0); + + filepos = offset_from_vma (phdrs, phnum, + (buckets_vma + 4 * ngnubuckets), + 4); + if (filepos == (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) != 0) + goto error_return; + + gnuchains = get_hash_table_data (abfd, maxchain, 4, filesize); + if (gnubuckets == NULL) + goto error_return; + ngnuchains = maxchain; + + if (dt_mips_xhash) + { + filepos = offset_from_vma (phdrs, phnum, + (buckets_vma + + 4 * (ngnubuckets + maxchain)), + 4); + if (filepos == (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) != 0) + goto error_return; + + mipsxlat = get_hash_table_data (abfd, maxchain, 4, filesize); + if (mipsxlat == NULL) + goto error_return; + } + + symcount = 0; + for (i = 0; i < ngnubuckets; ++i) + if (gnubuckets[i] != 0) + { + bfd_vma si = gnubuckets[i]; + bfd_vma off = si - gnusymidx; + do + { + if (mipsxlat) + { + if (mipsxlat[off] >= symcount) + symcount = mipsxlat[off] + 1; + } + else + { + if (si >= symcount) + symcount = si + 1; + } + si++; + } + while (off < ngnuchains && (gnuchains[off++] & 1) == 0); + } + } + + /* Swap in dynamic symbol table. */ + if (_bfd_mul_overflow (symcount, extsym_size, &amt)) + { + bfd_set_error (bfd_error_file_too_big); + goto error_return; + } + + filepos = offset_from_vma (phdrs, phnum, dt_symtab, amt); + if (filepos == (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) != 0) + goto error_return; + esymbuf = _bfd_malloc_and_read (abfd, amt, amt); + if (esymbuf == NULL) + goto error_return; + + if (_bfd_mul_overflow (symcount, sizeof (Elf_Internal_Sym), &amt)) + { + bfd_set_error (bfd_error_file_too_big); + goto error_return; + } + + /* Dynamic symbol table must be valid until ABFD is closed. */ + isymbuf = (Elf_Internal_Sym *) bfd_alloc (abfd, amt); + if (isymbuf == NULL) + goto error_return; + + swap_symbol_in = bed->s->swap_symbol_in; + + /* Convert the symbols to internal form. */ + isymend = isymbuf + symcount; + for (esym = esymbuf, isym = isymbuf; + isym < isymend; + esym += extsym_size, isym++) + if (!swap_symbol_in (abfd, esym, NULL, isym) + || isym->st_name >= dt_strsz) + { + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + + elf_tdata (abfd)->dt_strtab = strbuf; + elf_tdata (abfd)->dt_symtab = isymbuf; + elf_tdata (abfd)->dt_symtab_count = symcount; + + res = TRUE; + + error_return: + /* Restore file position for elf_object_p. */ + if (bfd_seek (abfd, saved_filepos, SEEK_SET) != 0) + res = FALSE; + if (dynbuf != NULL) + free (dynbuf); + if (esymbuf != NULL) + free (esymbuf); + if (gnubuckets != NULL) + free (gnubuckets); + if (gnuchains != NULL) + free (gnuchains); + if (mipsxlat != NULL) + free (mipsxlat); + return res; +} + +/* Reconstruct section from dynamic symbol. */ + +asection * +_bfd_elf_get_section_from_dynamic_symbol (bfd *abfd, + Elf_Internal_Sym *isym) +{ + asection *sec; + flagword flags; + + if (!elf_use_dt_symtab_p (abfd)) + return NULL; + + flags = SEC_ALLOC | SEC_LOAD; + switch (ELF_ST_TYPE (isym->st_info)) + { + case STT_FUNC: + case STT_GNU_IFUNC: + sec = bfd_get_section_by_name (abfd, ".text"); + if (sec == NULL) + sec = bfd_make_section_with_flags (abfd, + ".text", + flags | SEC_CODE); + break; + case STT_COMMON: + sec = bfd_com_section_ptr; + break; + case STT_OBJECT: + sec = bfd_get_section_by_name (abfd, ".data"); + if (sec == NULL) + sec = bfd_make_section_with_flags (abfd, + ".data", + flags | SEC_DATA); + break; + case STT_TLS: + sec = bfd_get_section_by_name (abfd, ".tdata"); + if (sec == NULL) + sec = bfd_make_section_with_flags (abfd, + ".tdata", + (flags + | SEC_DATA + | SEC_THREAD_LOCAL)); + break; + default: + sec = bfd_abs_section_ptr; + break; + } + + /* NB: Don't place this section in output. */ + if (sec && 0) + sec->output_section = bfd_abs_section_ptr; + + return sec; +} + /* Get version string. */ const char * @@ -8415,6 +8905,11 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd) if (elf_dynsymtab (abfd) == 0) { + /* Check if there is dynamic symbol table. */ + symcount = elf_tdata (abfd)->dt_symtab_count; + if (symcount) + goto compute_symtab_size; + bfd_set_error (bfd_error_invalid_operation); return -1; } @@ -8425,6 +8920,8 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd) bfd_set_error (bfd_error_file_too_big); return -1; } + + compute_symtab_size: symtab_size = (symcount + 1) * (sizeof (asymbol *)); if (symcount > 0) symtab_size -= sizeof (asymbol *); diff --git a/bfd/elfcode.h b/bfd/elfcode.h index 4dde24e02a..9124015a3e 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -820,6 +820,21 @@ elf_object_p (bfd *abfd) if (bfd_bread (&x_phdr, sizeof x_phdr, abfd) != sizeof x_phdr) goto got_no_match; elf_swap_phdr_in (abfd, &x_phdr, i_phdr); + if (i_phdr->p_filesz != 0) + { + if ((i_phdr->p_offset + i_phdr->p_filesz) > filesize) + goto got_no_match; + /* Try to reconstruct dynamic symbol table from PT_DYNAMIC + segment if there is no section header. */ + if (i_phdr->p_type == PT_DYNAMIC + && i_ehdrp->e_shstrndx == 0 + && i_ehdrp->e_shoff == 0 + && !_bfd_elf_get_dynamic_symbols (abfd, i_phdr, + elf_tdata (abfd)->phdr, + i_ehdrp->e_phnum, + filesize)) + goto got_no_match; + } } } @@ -1223,7 +1238,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) } ebd = get_elf_backend_data (abfd); - symcount = hdr->sh_size / sizeof (Elf_External_Sym); + symcount = elf_tdata (abfd)->dt_symtab_count; + if (symcount == 0) + symcount = hdr->sh_size / sizeof (Elf_External_Sym); if (symcount == 0) sym = symbase = NULL; else @@ -1279,7 +1296,11 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) memcpy (&sym->internal_elf_sym, isym, sizeof (Elf_Internal_Sym)); sym->symbol.the_bfd = abfd; - sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL); + if (elf_use_dt_symtab_p (abfd)) + sym->symbol.name = (elf_tdata (abfd)->dt_strtab + + isym->st_name); + else + sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL); sym->symbol.value = isym->st_value; if (isym->st_shndx == SHN_UNDEF) @@ -1313,6 +1334,15 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) moment) about the alignment. */ sym->symbol.value = isym->st_size; } + else if (elf_use_dt_symtab_p (abfd)) + { + asection *sec; + sec = _bfd_elf_get_section_from_dynamic_symbol (abfd, + isym); + if (sec == NULL) + goto error_return; + sym->symbol.section = sec; + } else { sym->symbol.section @@ -1426,14 +1456,18 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) if (xverbuf != NULL) free (xverbuf); - if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf) + if (isymbuf != NULL + && hdr->contents != (unsigned char *) isymbuf + && !elf_use_dt_symtab_p (abfd)) free (isymbuf); return symcount; error_return: if (xverbuf != NULL) free (xverbuf); - if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf) + if (isymbuf != NULL + && hdr->contents != (unsigned char *) isymbuf + && !elf_use_dt_symtab_p (abfd)) free (isymbuf); return -1; } diff --git a/bfd/elflink.c b/bfd/elflink.c index c04712a10f..ee047889c5 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -3394,6 +3394,12 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef) if (! bfd_check_format (abfd, bfd_object)) return FALSE; + if (elf_use_dt_symtab_p (abfd)) + { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + /* Select the appropriate symbol table. If we don't know if the object file is an IR object, give linker LTO plugin a chance to get the correct symbol table. */ @@ -3927,6 +3933,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) htab = elf_hash_table (info); bed = get_elf_backend_data (abfd); + if (elf_use_dt_symtab_p (abfd)) + { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + if ((abfd->flags & DYNAMIC) == 0) dynamic = FALSE; else -- 2.24.1