From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1039) id 482123858CDA; Thu, 29 Jun 2023 17:36:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 482123858CDA Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: H.J. Lu To: bfd-cvs@sourceware.org Subject: [binutils-gdb] bfd: Improve nm and objdump without section header X-Act-Checkin: binutils-gdb X-Git-Author: H.J. Lu X-Git-Refname: refs/heads/master X-Git-Oldrev: 02c1ba6c94d4bb3f53dfeeb4401c8434c7834a32 X-Git-Newrev: 46675b6b8160e97485583522852ad86507bd9072 Message-Id: <20230629173624.482123858CDA@sourceware.org> Date: Thu, 29 Jun 2023 17:36:23 +0000 (GMT) X-BeenThere: binutils-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 29 Jun 2023 17:36:24 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D46675b6b8160= e97485583522852ad86507bd9072 commit 46675b6b8160e97485583522852ad86507bd9072 Author: H.J. Lu Date: Wed Mar 4 20:32:35 2020 -0800 bfd: Improve nm and objdump without section header =20 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_HAS= H, 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. We can also get symbol version from DT_VERSYM, DT_VERDEF and DT_VERNEED entries. =20 dt_symtab, dt_versym, dt_verdef, dt_verneed, dt_symtab_count, dt_verdef_count, dt_verneed_count and dt_strtab are added to elf_obj_tdata to store dynamic symbol table information. =20 PR ld/25617 * elf-bfd.h (elf_obj_tdata): Add dt_symtab, dt_verdef, dt_verne= ed, dt_symtab_count, dt_verdef_count, dt_verneed_count and dt_strta= b. (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. (_bfd_elf_slurp_version_tables): 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. (_bfd_elf_get_symbol_version_name): 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. Diff: --- bfd/elf-bfd.h | 15 ++ bfd/elf.c | 729 +++++++++++++++++++++++++++++++++++++++++++++++++++++-= ---- bfd/elfcode.h | 55 ++++- bfd/elflink.c | 12 + 4 files changed, 746 insertions(+), 65 deletions(-) diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index e08c5a110e5..ec856764519 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2031,6 +2031,14 @@ 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_byte *dt_versym; + bfd_byte *dt_verdef; + bfd_byte *dt_verneed; + size_t dt_symtab_count; + size_t dt_verdef_count; + size_t dt_verneed_count; + char *dt_strtab; elf_section_list * symtab_shndx_list; bfd_vma gp; /* The gp value */ unsigned int gp_size; /* The gp size */ @@ -2194,6 +2202,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 !=3D 0) #define elf_known_obj_attributes(bfd) (elf_tdata (bfd) -> known_obj_attrib= utes) #define elf_other_obj_attributes(bfd) (elf_tdata (bfd) -> other_obj_attrib= utes) #define elf_known_obj_attributes_proc(bfd) \ @@ -2587,6 +2596,12 @@ extern bfd_reloc_status_type bfd_elf_perform_complex= _relocation extern bool _bfd_elf_setup_sections (bfd *); =20 +extern bool _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 *); =20 diff --git a/bfd/elf.c b/bfd/elf.c index 4584b93a7ae..e506721222e 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -397,6 +397,17 @@ bfd_elf_get_elf_syms (bfd *ibfd, if (symcount =3D=3D 0) return intsym_buf; =20 + if (elf_use_dt_symtab_p (ibfd)) + { + /* Use dynamic symbol table. */ + if (elf_tdata (ibfd)->dt_symtab_count !=3D 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 =3D NULL; if (elf_symtab_shndx_list (ibfd) !=3D NULL) @@ -1873,6 +1884,551 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *f= arg) return false; } =20 +/* 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, + size_t size, size_t *max_size_p) +{ + Elf_Internal_Phdr *seg; + size_t i; + + for (seg =3D phdrs, i =3D 0; i < phnum; ++seg, ++i) + if (seg->p_type =3D=3D PT_LOAD + && vma >=3D (seg->p_vaddr & -seg->p_align) + && vma + size <=3D seg->p_vaddr + seg->p_filesz) + { + if (max_size_p) + *max_size_p =3D seg->p_vaddr + seg->p_filesz - vma; + return 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 =3D NULL; + bfd_vma *i_data =3D NULL; + bfd_size_type size; + + if (ent_size !=3D 4 && ent_size !=3D 8) + return NULL; + + if ((size_t) number !=3D number) + { + bfd_set_error (bfd_error_file_too_big); + return NULL; + } + + size =3D 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 >=3D ~(size_t) 0 / ent_size + || number >=3D ~(size_t) 0 / sizeof (*i_data)) + { + bfd_set_error (bfd_error_file_too_big); + return NULL; + } + + e_data =3D _bfd_malloc_and_read (abfd, size, size); + if (e_data =3D=3D NULL) + return NULL; + + i_data =3D (bfd_vma *) bfd_malloc (number * sizeof (*i_data)); + if (i_data =3D=3D NULL) + { + free (e_data); + return NULL; + } + + if (ent_size =3D=3D 4) + while (number--) + i_data[number] =3D bfd_get_32 (abfd, e_data + number * ent_size); + else + while (number--) + i_data[number] =3D 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. */ + +bool +_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 *); + bool (*swap_symbol_in) (bfd *, const void *, const void *, + Elf_Internal_Sym *); + Elf_Internal_Dyn dyn; + bfd_vma dt_hash =3D 0; + bfd_vma dt_gnu_hash =3D 0; + bfd_vma dt_mips_xhash =3D 0; + bfd_vma dt_strtab =3D 0; + bfd_vma dt_symtab =3D 0; + size_t dt_strsz =3D 0; + bfd_vma dt_versym =3D 0; + bfd_vma dt_verdef =3D 0; + bfd_vma dt_verneed =3D 0; + bfd_byte *dynbuf =3D NULL; + char *strbuf =3D NULL; + bfd_vma *gnubuckets =3D NULL; + bfd_vma *gnuchains =3D NULL; + bfd_vma *mipsxlat =3D NULL; + file_ptr saved_filepos, filepos; + bool res =3D false; + size_t amt; + bfd_byte *esymbuf =3D NULL, *esym; + bfd_size_type symcount; + Elf_Internal_Sym *isymbuf =3D NULL; + Elf_Internal_Sym *isym, *isymend; + bfd_byte *versym =3D NULL; + bfd_byte *verdef =3D NULL; + bfd_byte *verneed =3D NULL; + size_t verdef_size; + size_t verneed_size; + 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 !=3D NULL) + return true; + + bed =3D get_elf_backend_data (abfd); + + /* Save file position for elf_object_p. */ + saved_filepos =3D bfd_tell (abfd); + + if (bfd_seek (abfd, phdr->p_offset, SEEK_SET) !=3D 0) + goto error_return; + + dynbuf =3D _bfd_malloc_and_read (abfd, phdr->p_filesz, phdr->p_filesz); + if (dynbuf =3D=3D NULL) + goto error_return; + + extsym_size =3D bed->s->sizeof_sym; + extdynsize =3D bed->s->sizeof_dyn; + swap_dyn_in =3D bed->s->swap_dyn_in; + + extdyn =3D dynbuf; + if (phdr->p_filesz < extdynsize) + goto error_return; + extdynend =3D extdyn + phdr->p_filesz; + for (; extdyn <=3D (extdynend - extdynsize); extdyn +=3D extdynsize) + { + swap_dyn_in (abfd, extdyn, &dyn); + + if (dyn.d_tag =3D=3D DT_NULL) + break; + + switch (dyn.d_tag) + { + case DT_HASH: + dt_hash =3D dyn.d_un.d_val; + break; + case DT_GNU_HASH: + if (bed->elf_machine_code !=3D EM_MIPS + && bed->elf_machine_code !=3D EM_MIPS_RS3_LE) + dt_gnu_hash =3D dyn.d_un.d_val; + break; + case DT_STRTAB: + dt_strtab =3D dyn.d_un.d_val; + break; + case DT_SYMTAB: + dt_symtab =3D dyn.d_un.d_val; + break; + case DT_STRSZ: + dt_strsz =3D dyn.d_un.d_val; + break; + case DT_SYMENT: + if (dyn.d_un.d_val !=3D extsym_size) + goto error_return; + break; + case DT_VERSYM: + dt_versym =3D dyn.d_un.d_val; + break; + case DT_VERDEF: + dt_verdef =3D dyn.d_un.d_val; + break; + case DT_VERNEED: + dt_verneed =3D dyn.d_un.d_val; + break; + default: + if (dyn.d_tag =3D=3D DT_MIPS_XHASH + && (bed->elf_machine_code =3D=3D EM_MIPS + || bed->elf_machine_code =3D=3D EM_MIPS_RS3_LE)) + { + dt_gnu_hash =3D dyn.d_un.d_val; + dt_mips_xhash =3D 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 =3D offset_from_vma (phdrs, phnum, dt_strtab, dt_strsz, NULL); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) + goto error_return; + + /* Dynamic string table must be valid until ABFD is closed. */ + strbuf =3D (char *) _bfd_alloc_and_read (abfd, dt_strsz, dt_strsz); + if (strbuf =3D=3D 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 =3D=3D ELFCLASS64) + { + hash_ent_size =3D 8; + break; + } + /* FALLTHROUGH */ + default: + hash_ent_size =3D 4; + break; + } + + filepos =3D offset_from_vma (phdrs, phnum, dt_hash, sizeof (nb), + NULL); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0 + || (bfd_bread (nb, 2 * hash_ent_size, abfd) + !=3D (2 * hash_ent_size))) + goto error_return; + + /* The number of dynamic symbol table entries equals the number + of chains. */ + if (hash_ent_size =3D=3D 8) + symcount =3D bfd_get_64 (abfd, nb + hash_ent_size); + else + symcount =3D 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 =3D 0xffffffff, bitmaskwords; + bfd_vma buckets_vma; + + filepos =3D offset_from_vma (phdrs, phnum, dt_gnu_hash, + sizeof (nb), NULL); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0 + || bfd_bread (nb, sizeof (nb), abfd) !=3D sizeof (nb)) + goto error_return; + + ngnubuckets =3D bfd_get_32 (abfd, nb); + gnusymidx =3D bfd_get_32 (abfd, nb + 4); + bitmaskwords =3D bfd_get_32 (abfd, nb + 8); + buckets_vma =3D dt_gnu_hash + 16; + if (bed->s->elfclass =3D=3D ELFCLASS32) + buckets_vma +=3D bitmaskwords * 4; + else + buckets_vma +=3D bitmaskwords * 8; + filepos =3D offset_from_vma (phdrs, phnum, buckets_vma, 4, NULL); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) + goto error_return; + + gnubuckets =3D get_hash_table_data (abfd, ngnubuckets, 4, filesize); + if (gnubuckets =3D=3D NULL) + goto error_return; + + for (i =3D 0; i < ngnubuckets; i++) + if (gnubuckets[i] !=3D 0) + { + if (gnubuckets[i] < gnusymidx) + goto error_return; + + if (maxchain =3D=3D 0xffffffff || gnubuckets[i] > maxchain) + maxchain =3D gnubuckets[i]; + } + + if (maxchain =3D=3D 0xffffffff) + { + symcount =3D 0; + goto empty_gnu_hash; + } + + maxchain -=3D gnusymidx; + filepos =3D offset_from_vma (phdrs, phnum, + (buckets_vma + + 4 * (ngnubuckets + maxchain)), + 4, NULL); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) + goto error_return; + + do + { + if (bfd_bread (nb, 4, abfd) !=3D 4) + goto error_return; + ++maxchain; + if (maxchain =3D=3D 0) + goto error_return; + } + while ((bfd_get_32 (abfd, nb) & 1) =3D=3D 0); + + filepos =3D offset_from_vma (phdrs, phnum, + (buckets_vma + 4 * ngnubuckets), + 4, NULL); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) + goto error_return; + + gnuchains =3D get_hash_table_data (abfd, maxchain, 4, filesize); + if (gnubuckets =3D=3D NULL) + goto error_return; + ngnuchains =3D maxchain; + + if (dt_mips_xhash) + { + filepos =3D offset_from_vma (phdrs, phnum, + (buckets_vma + + 4 * (ngnubuckets + maxchain)), + 4, NULL); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) + goto error_return; + + mipsxlat =3D get_hash_table_data (abfd, maxchain, 4, filesize); + if (mipsxlat =3D=3D NULL) + goto error_return; + } + + symcount =3D 0; + for (i =3D 0; i < ngnubuckets; ++i) + if (gnubuckets[i] !=3D 0) + { + bfd_vma si =3D gnubuckets[i]; + bfd_vma off =3D si - gnusymidx; + do + { + if (mipsxlat) + { + if (mipsxlat[off] >=3D symcount) + symcount =3D mipsxlat[off] + 1; + } + else + { + if (si >=3D symcount) + symcount =3D si + 1; + } + si++; + } + while (off < ngnuchains && (gnuchains[off++] & 1) =3D=3D 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 =3D offset_from_vma (phdrs, phnum, dt_symtab, amt, NULL); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) + goto error_return; + esymbuf =3D _bfd_malloc_and_read (abfd, amt, amt); + if (esymbuf =3D=3D 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 =3D (Elf_Internal_Sym *) bfd_alloc (abfd, amt); + if (isymbuf =3D=3D NULL) + goto error_return; + + swap_symbol_in =3D bed->s->swap_symbol_in; + + /* Convert the symbols to internal form. */ + isymend =3D isymbuf + symcount; + for (esym =3D esymbuf, isym =3D isymbuf; + isym < isymend; + esym +=3D extsym_size, isym++) + if (!swap_symbol_in (abfd, esym, NULL, isym) + || isym->st_name >=3D dt_strsz) + { + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + + if (dt_versym) + { + /* Swap in DT_VERSYM. */ + if (_bfd_mul_overflow (symcount, 2, &amt)) + { + bfd_set_error (bfd_error_file_too_big); + goto error_return; + } + + filepos =3D offset_from_vma (phdrs, phnum, dt_versym, amt, NULL); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) + goto error_return; + + /* DT_VERSYM info must be valid until ABFD is closed. */ + versym =3D _bfd_alloc_and_read (abfd, amt, amt); + + if (dt_verdef) + { + /* Read in DT_VERDEF. */ + filepos =3D offset_from_vma (phdrs, phnum, dt_verdef, + 0, &verdef_size); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) + goto error_return; + + /* DT_VERDEF info must be valid until ABFD is closed. */ + verdef =3D _bfd_alloc_and_read (abfd, verdef_size, + verdef_size); + } + + if (dt_verneed) + { + /* Read in DT_VERNEED. */ + filepos =3D offset_from_vma (phdrs, phnum, dt_verneed, + 0, &verneed_size); + if (filepos =3D=3D (file_ptr) -1 + || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) + goto error_return; + + /* DT_VERNEED info must be valid until ABFD is closed. */ + verneed =3D _bfd_alloc_and_read (abfd, verneed_size, + verneed_size); + } + } + + empty_gnu_hash: + elf_tdata (abfd)->dt_strtab =3D strbuf; + elf_tdata (abfd)->dt_symtab =3D isymbuf; + elf_tdata (abfd)->dt_symtab_count =3D symcount; + elf_tdata (abfd)->dt_versym =3D versym; + elf_tdata (abfd)->dt_verdef =3D verdef; + elf_tdata (abfd)->dt_verneed =3D verneed; + elf_tdata (abfd)->dt_verdef_count + =3D verdef_size / sizeof (Elf_External_Verdef); + elf_tdata (abfd)->dt_verneed_count + =3D verneed_size / sizeof (Elf_External_Verneed); + + res =3D true; + + error_return: + /* Restore file position for elf_object_p. */ + if (bfd_seek (abfd, saved_filepos, SEEK_SET) !=3D 0) + res =3D false; + free (dynbuf); + free (esymbuf); + free (gnubuckets); + free (gnuchains); + 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 =3D SEC_ALLOC | SEC_LOAD; + switch (ELF_ST_TYPE (isym->st_info)) + { + case STT_FUNC: + case STT_GNU_IFUNC: + sec =3D bfd_get_section_by_name (abfd, ".text"); + if (sec =3D=3D NULL) + sec =3D bfd_make_section_with_flags (abfd, + ".text", + flags | SEC_CODE); + break; + case STT_COMMON: + sec =3D bfd_com_section_ptr; + break; + case STT_OBJECT: + sec =3D bfd_get_section_by_name (abfd, ".data"); + if (sec =3D=3D NULL) + sec =3D bfd_make_section_with_flags (abfd, + ".data", + flags | SEC_DATA); + break; + case STT_TLS: + sec =3D bfd_get_section_by_name (abfd, ".tdata"); + if (sec =3D=3D NULL) + sec =3D bfd_make_section_with_flags (abfd, + ".tdata", + (flags + | SEC_DATA + | SEC_THREAD_LOCAL)); + break; + default: + sec =3D bfd_abs_section_ptr; + break; + } + + return sec; +} + /* Get version name. If BASE_P is TRUE, return "Base" for VER_FLG_BASE and return symbol version for symbol version itself. */ =20 @@ -1882,8 +2438,11 @@ _bfd_elf_get_symbol_version_string (bfd *abfd, asymb= ol *symbol, bool *hidden) { const char *version_string =3D NULL; - if (elf_dynversym (abfd) !=3D 0 - && (elf_dynverdef (abfd) !=3D 0 || elf_dynverref (abfd) !=3D 0)) + if ((elf_dynversym (abfd) !=3D 0 + && (elf_dynverdef (abfd) !=3D 0 || elf_dynverref (abfd) !=3D 0)) + || (elf_tdata (abfd)->dt_versym !=3D NULL + && (elf_tdata (abfd)->dt_verdef !=3D NULL + || elf_tdata (abfd)->dt_verneed !=3D NULL))) { unsigned int vernum =3D ((elf_symbol_type *) symbol)->version; =20 @@ -8613,6 +9172,11 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd) =20 if (elf_dynsymtab (abfd) =3D=3D 0) { + /* Check if there is dynamic symbol table. */ + symcount =3D elf_tdata (abfd)->dt_symtab_count; + if (symcount) + goto compute_symtab_size; + bfd_set_error (bfd_error_invalid_operation); return -1; } @@ -8623,6 +9187,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 =3D symcount * (sizeof (asymbol *)); if (symcount =3D=3D 0) symtab_size =3D sizeof (asymbol *); @@ -8830,35 +9396,51 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defa= ult_imported_symver) unsigned int freeidx =3D 0; size_t amt; =20 - if (elf_dynverref (abfd) !=3D 0) + if (elf_dynverref (abfd) !=3D 0 || elf_tdata (abfd)->dt_verneed !=3D NUL= L) { Elf_Internal_Shdr *hdr; Elf_External_Verneed *everneed; Elf_Internal_Verneed *iverneed; unsigned int i; bfd_byte *contents_end; + size_t verneed_count; + size_t verneed_size; =20 - hdr =3D &elf_tdata (abfd)->dynverref_hdr; - - if (hdr->sh_info > hdr->sh_size / sizeof (Elf_External_Verneed)) + if (elf_tdata (abfd)->dt_verneed !=3D NULL) { - error_return_bad_verref: - _bfd_error_handler - (_("%pB: .gnu.version_r invalid entry"), abfd); - bfd_set_error (bfd_error_bad_value); - error_return_verref: - elf_tdata (abfd)->verref =3D NULL; - elf_tdata (abfd)->cverrefs =3D 0; - goto error_return; + hdr =3D NULL; + contents =3D elf_tdata (abfd)->dt_verneed; + verneed_count =3D elf_tdata (abfd)->dt_verneed_count; + verneed_size =3D verneed_count * sizeof (Elf_External_Verneed); } + else + { + hdr =3D &elf_tdata (abfd)->dynverref_hdr; =20 - if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) !=3D 0) - goto error_return_verref; - contents =3D _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size); - if (contents =3D=3D NULL) - goto error_return_verref; + if (hdr->sh_info > hdr->sh_size / sizeof (Elf_External_Verneed)) + { + error_return_bad_verref: + _bfd_error_handler + (_("%pB: .gnu.version_r invalid entry"), abfd); + bfd_set_error (bfd_error_bad_value); + error_return_verref: + elf_tdata (abfd)->verref =3D NULL; + elf_tdata (abfd)->cverrefs =3D 0; + goto error_return; + } + + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) !=3D 0) + goto error_return_verref; + contents =3D _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size); + if (contents =3D=3D NULL) + goto error_return_verref; + + verneed_size =3D hdr->sh_size; + verneed_count =3D hdr->sh_info; + } =20 - if (_bfd_mul_overflow (hdr->sh_info, sizeof (Elf_Internal_Verneed), = &amt)) + if (_bfd_mul_overflow (verneed_count, + sizeof (Elf_Internal_Verneed), &amt)) { bfd_set_error (bfd_error_file_too_big); goto error_return_verref; @@ -8871,10 +9453,11 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defa= ult_imported_symver) =20 BFD_ASSERT (sizeof (Elf_External_Verneed) =3D=3D sizeof (Elf_External_Vernaux)); - contents_end =3D contents + hdr->sh_size - sizeof (Elf_External_Vern= eed); + contents_end =3D (contents + verneed_size + - sizeof (Elf_External_Verneed)); everneed =3D (Elf_External_Verneed *) contents; iverneed =3D elf_tdata (abfd)->verref; - for (i =3D 0; i < hdr->sh_info; i++, iverneed++) + for (i =3D 0; i < verneed_count; i++, iverneed++) { Elf_External_Vernaux *evernaux; Elf_Internal_Vernaux *ivernaux; @@ -8884,9 +9467,13 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defau= lt_imported_symver) =20 iverneed->vn_bfd =3D abfd; =20 - iverneed->vn_filename =3D - bfd_elf_string_from_elf_section (abfd, hdr->sh_link, - iverneed->vn_file); + if (elf_use_dt_symtab_p (abfd)) + iverneed->vn_filename + =3D elf_tdata (abfd)->dt_strtab + iverneed->vn_file; + else + iverneed->vn_filename + =3D bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + iverneed->vn_file); if (iverneed->vn_filename =3D=3D NULL) goto error_return_bad_verref; =20 @@ -8917,9 +9504,13 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defau= lt_imported_symver) { _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux); =20 - ivernaux->vna_nodename =3D - bfd_elf_string_from_elf_section (abfd, hdr->sh_link, - ivernaux->vna_name); + if (elf_use_dt_symtab_p (abfd)) + ivernaux->vna_nodename + =3D elf_tdata (abfd)->dt_strtab + ivernaux->vna_name; + else + ivernaux->vna_nodename + =3D bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + ivernaux->vna_name); if (ivernaux->vna_nodename =3D=3D NULL) goto error_return_bad_verref; =20 @@ -8958,11 +9549,12 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defa= ult_imported_symver) } elf_tdata (abfd)->cverrefs =3D i; =20 - free (contents); + if (elf_tdata (abfd)->dt_verneed =3D=3D NULL) + free (contents); contents =3D NULL; } =20 - if (elf_dynverdef (abfd) !=3D 0) + if (elf_dynverdef (abfd) !=3D 0 || elf_tdata (abfd)->dt_verdef !=3D NULL) { Elf_Internal_Shdr *hdr; Elf_External_Verdef *everdef; @@ -8972,40 +9564,56 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defa= ult_imported_symver) unsigned int i; unsigned int maxidx; bfd_byte *contents_end_def, *contents_end_aux; + size_t verdef_count; + size_t verdef_size; =20 - hdr =3D &elf_tdata (abfd)->dynverdef_hdr; - - if (hdr->sh_size < sizeof (Elf_External_Verdef)) + if (elf_tdata (abfd)->dt_verdef !=3D NULL) { - error_return_bad_verdef: - _bfd_error_handler - (_("%pB: .gnu.version_d invalid entry"), abfd); - bfd_set_error (bfd_error_bad_value); - error_return_verdef: - elf_tdata (abfd)->verdef =3D NULL; - elf_tdata (abfd)->cverdefs =3D 0; - goto error_return; + hdr =3D NULL; + contents =3D elf_tdata (abfd)->dt_verdef; + verdef_count =3D elf_tdata (abfd)->dt_verdef_count; + verdef_size =3D verdef_count * sizeof (Elf_External_Verdef); } + else + { + hdr =3D &elf_tdata (abfd)->dynverdef_hdr; =20 - if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) !=3D 0) - goto error_return_verdef; - contents =3D _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size); - if (contents =3D=3D NULL) - goto error_return_verdef; + if (hdr->sh_size < sizeof (Elf_External_Verdef)) + { + error_return_bad_verdef: + _bfd_error_handler + (_("%pB: .gnu.version_d invalid entry"), abfd); + bfd_set_error (bfd_error_bad_value); + error_return_verdef: + elf_tdata (abfd)->verdef =3D NULL; + elf_tdata (abfd)->cverdefs =3D 0; + goto error_return; + } + + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) !=3D 0) + goto error_return_verdef; + contents =3D _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size); + if (contents =3D=3D NULL) + goto error_return_verdef; =20 - BFD_ASSERT (sizeof (Elf_External_Verdef) - >=3D sizeof (Elf_External_Verdaux)); - contents_end_def =3D contents + hdr->sh_size - - sizeof (Elf_External_Verdef); - contents_end_aux =3D contents + hdr->sh_size - - sizeof (Elf_External_Verdaux); + BFD_ASSERT (sizeof (Elf_External_Verdef) + >=3D sizeof (Elf_External_Verdaux)); + + verdef_count =3D hdr->sh_info; + verdef_size =3D hdr->sh_size; + } + + contents_end_def =3D (contents + verdef_size + - sizeof (Elf_External_Verdef)); + contents_end_aux =3D (contents + verdef_size + - sizeof (Elf_External_Verdaux)); =20 /* We know the number of entries in the section but not the maximum index. Therefore we have to run through all entries and find the maximum. */ everdef =3D (Elf_External_Verdef *) contents; maxidx =3D 0; - for (i =3D 0; i < hdr->sh_info; ++i) + for (i =3D 0; i < verdef_count; ++i) { _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); =20 @@ -9048,7 +9656,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defaul= t_imported_symver) =20 everdef =3D (Elf_External_Verdef *) contents; iverdefarr =3D elf_tdata (abfd)->verdef; - for (i =3D 0; i < hdr->sh_info; i++) + for (i =3D 0; i < verdef_count; ++i) { Elf_External_Verdaux *everdaux; Elf_Internal_Verdaux *iverdaux; @@ -9091,9 +9699,13 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defau= lt_imported_symver) { _bfd_elf_swap_verdaux_in (abfd, everdaux, iverdaux); =20 - iverdaux->vda_nodename =3D - bfd_elf_string_from_elf_section (abfd, hdr->sh_link, - iverdaux->vda_name); + if (elf_use_dt_symtab_p (abfd)) + iverdaux->vda_nodename + =3D elf_tdata (abfd)->dt_strtab + iverdaux->vda_name; + else + iverdaux->vda_nodename + =3D bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + iverdaux->vda_name); if (iverdaux->vda_nodename =3D=3D NULL) goto error_return_bad_verdef; =20 @@ -9128,7 +9740,8 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defaul= t_imported_symver) ((bfd_byte *) everdef + iverdef->vd_next)); } =20 - free (contents); + if (elf_tdata (abfd)->dt_verdef =3D=3D NULL) + free (contents); contents =3D NULL; } else if (default_imported_symver) diff --git a/bfd/elfcode.h b/bfd/elfcode.h index 495e498838d..aae66bcebf8 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -839,6 +839,21 @@ elf_object_p (bfd *abfd) abfd->read_only =3D 1; } } + if (i_phdr->p_filesz !=3D 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 =3D=3D PT_DYNAMIC + && i_ehdrp->e_shstrndx =3D=3D 0 + && i_ehdrp->e_shoff =3D=3D 0 + && !_bfd_elf_get_dynamic_symbols (abfd, i_phdr, + elf_tdata (abfd)->phdr, + i_ehdrp->e_phnum, + filesize)) + goto got_no_match; + } } } =20 @@ -1245,7 +1260,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs,= bool dynamic) if ((elf_dynverdef (abfd) !=3D 0 && elf_tdata (abfd)->verdef =3D=3D NULL) || (elf_dynverref (abfd) !=3D 0 - && elf_tdata (abfd)->verref =3D=3D NULL)) + && elf_tdata (abfd)->verref =3D=3D NULL) + || elf_tdata (abfd)->dt_verdef !=3D NULL + || elf_tdata (abfd)->dt_verneed !=3D NULL) { if (!_bfd_elf_slurp_version_tables (abfd, false)) return -1; @@ -1253,11 +1270,15 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptr= s, bool dynamic) } =20 ebd =3D get_elf_backend_data (abfd); - symcount =3D hdr->sh_size / sizeof (Elf_External_Sym); + symcount =3D elf_tdata (abfd)->dt_symtab_count; + if (symcount =3D=3D 0) + symcount =3D hdr->sh_size / sizeof (Elf_External_Sym); if (symcount =3D=3D 0) sym =3D symbase =3D NULL; else { + size_t i; + isymbuf =3D bfd_elf_get_elf_syms (abfd, hdr, symcount, 0, NULL, NULL, NULL); if (isymbuf =3D=3D NULL) @@ -1304,12 +1325,18 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptr= s, bool dynamic) if (xver !=3D NULL) ++xver; isymend =3D isymbuf + symcount; - for (isym =3D isymbuf + 1, sym =3D symbase; isym < isymend; isym++, = sym++) + for (isym =3D isymbuf + 1, sym =3D symbase, i =3D 1; + isym < isymend; + isym++, sym++, i++) { memcpy (&sym->internal_elf_sym, isym, sizeof (Elf_Internal_Sym)); =20 sym->symbol.the_bfd =3D abfd; - sym->symbol.name =3D bfd_elf_sym_name (abfd, hdr, isym, NULL); + if (elf_use_dt_symtab_p (abfd)) + sym->symbol.name =3D (elf_tdata (abfd)->dt_strtab + + isym->st_name); + else + sym->symbol.name =3D bfd_elf_sym_name (abfd, hdr, isym, NULL); sym->symbol.value =3D isym->st_value; =20 if (isym->st_shndx =3D=3D SHN_UNDEF) @@ -1343,6 +1370,15 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs= , bool dynamic) moment) about the alignment. */ sym->symbol.value =3D isym->st_size; } + else if (elf_use_dt_symtab_p (abfd)) + { + asection *sec; + sec =3D _bfd_elf_get_section_from_dynamic_symbol (abfd, + isym); + if (sec =3D=3D NULL) + goto error_return; + sym->symbol.section =3D sec; + } else { sym->symbol.section @@ -1423,7 +1459,10 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs= , bool dynamic) if (dynamic) sym->symbol.flags |=3D BSF_DYNAMIC; =20 - if (xver !=3D NULL) + if (elf_tdata (abfd)->dt_versym) + sym->version =3D bfd_get_16 (abfd, + elf_tdata (abfd)->dt_versym + 2 * i); + else if (xver !=3D NULL) { Elf_Internal_Versym iversym; =20 @@ -1461,13 +1500,15 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptr= s, bool dynamic) } =20 free (xverbuf); - if (hdr->contents !=3D (unsigned char *) isymbuf) + if (hdr->contents !=3D (unsigned char *) isymbuf + && !elf_use_dt_symtab_p (abfd)) free (isymbuf); return symcount; =20 error_return: free (xverbuf); - if (hdr->contents !=3D (unsigned char *) isymbuf) + if (hdr->contents !=3D (unsigned char *) isymbuf + && !elf_use_dt_symtab_p (abfd)) free (isymbuf); return -1; } diff --git a/bfd/elflink.c b/bfd/elflink.c index 4f879005c22..7217c2f038b 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -3571,6 +3571,12 @@ elf_link_is_defined_archive_symbol (bfd * abfd, cars= ym * symdef) if (! bfd_check_format (abfd, bfd_object)) return false; =20 + 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. */ @@ -4233,6 +4239,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_l= ink_info *info) htab =3D elf_hash_table (info); bed =3D get_elf_backend_data (abfd); =20 + if (elf_use_dt_symtab_p (abfd)) + { + bfd_set_error (bfd_error_wrong_format); + return false; + } + if ((abfd->flags & DYNAMIC) =3D=3D 0) dynamic =3D false; else