| /* ELF executable support for BFD. |
| |
| Copyright (C) 1993-2021 Free Software Foundation, Inc. |
| |
| This file is part of BFD, the Binary File Descriptor library. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| MA 02110-1301, USA. */ |
| |
| |
| /* |
| SECTION |
| ELF backends |
| |
| BFD support for ELF formats is being worked on. |
| Currently, the best supported back ends are for sparc and i386 |
| (running svr4 or Solaris 2). |
| |
| Documentation of the internals of the support code still needs |
| to be written. The code is changing quickly enough that we |
| haven't bothered yet. */ |
| |
| /* For sparc64-cross-sparc32. */ |
| #define _SYSCALL32 |
| #include "sysdep.h" |
| #include <limits.h> |
| #include "bfd.h" |
| #include "bfdlink.h" |
| #include "libbfd.h" |
| #define ARCH_SIZE 0 |
| #include "elf-bfd.h" |
| #include "libiberty.h" |
| #include "safe-ctype.h" |
| #include "elf-linux-core.h" |
| |
| #ifdef CORE_HEADER |
| #include CORE_HEADER |
| #endif |
| |
| static int elf_sort_sections (const void *, const void *); |
| static bool assign_file_positions_except_relocs (bfd *, struct bfd_link_info *); |
| static bool swap_out_syms (bfd *, struct elf_strtab_hash **, int, |
| struct bfd_link_info *); |
| static bool elf_parse_notes (bfd *abfd, char *buf, size_t size, |
| file_ptr offset, size_t align); |
| |
| /* Swap version information in and out. The version information is |
| currently size independent. If that ever changes, this code will |
| need to move into elfcode.h. */ |
| |
| /* Swap in a Verdef structure. */ |
| |
| void |
| _bfd_elf_swap_verdef_in (bfd *abfd, |
| const Elf_External_Verdef *src, |
| Elf_Internal_Verdef *dst) |
| { |
| dst->vd_version = H_GET_16 (abfd, src->vd_version); |
| dst->vd_flags = H_GET_16 (abfd, src->vd_flags); |
| dst->vd_ndx = H_GET_16 (abfd, src->vd_ndx); |
| dst->vd_cnt = H_GET_16 (abfd, src->vd_cnt); |
| dst->vd_hash = H_GET_32 (abfd, src->vd_hash); |
| dst->vd_aux = H_GET_32 (abfd, src->vd_aux); |
| dst->vd_next = H_GET_32 (abfd, src->vd_next); |
| } |
| |
| /* Swap out a Verdef structure. */ |
| |
| void |
| _bfd_elf_swap_verdef_out (bfd *abfd, |
| const Elf_Internal_Verdef *src, |
| Elf_External_Verdef *dst) |
| { |
| H_PUT_16 (abfd, src->vd_version, dst->vd_version); |
| H_PUT_16 (abfd, src->vd_flags, dst->vd_flags); |
| H_PUT_16 (abfd, src->vd_ndx, dst->vd_ndx); |
| H_PUT_16 (abfd, src->vd_cnt, dst->vd_cnt); |
| H_PUT_32 (abfd, src->vd_hash, dst->vd_hash); |
| H_PUT_32 (abfd, src->vd_aux, dst->vd_aux); |
| H_PUT_32 (abfd, src->vd_next, dst->vd_next); |
| } |
| |
| /* Swap in a Verdaux structure. */ |
| |
| void |
| _bfd_elf_swap_verdaux_in (bfd *abfd, |
| const Elf_External_Verdaux *src, |
| Elf_Internal_Verdaux *dst) |
| { |
| dst->vda_name = H_GET_32 (abfd, src->vda_name); |
| dst->vda_next = H_GET_32 (abfd, src->vda_next); |
| } |
| |
| /* Swap out a Verdaux structure. */ |
| |
| void |
| _bfd_elf_swap_verdaux_out (bfd *abfd, |
| const Elf_Internal_Verdaux *src, |
| Elf_External_Verdaux *dst) |
| { |
| H_PUT_32 (abfd, src->vda_name, dst->vda_name); |
| H_PUT_32 (abfd, src->vda_next, dst->vda_next); |
| } |
| |
| /* Swap in a Verneed structure. */ |
| |
| void |
| _bfd_elf_swap_verneed_in (bfd *abfd, |
| const Elf_External_Verneed *src, |
| Elf_Internal_Verneed *dst) |
| { |
| dst->vn_version = H_GET_16 (abfd, src->vn_version); |
| dst->vn_cnt = H_GET_16 (abfd, src->vn_cnt); |
| dst->vn_file = H_GET_32 (abfd, src->vn_file); |
| dst->vn_aux = H_GET_32 (abfd, src->vn_aux); |
| dst->vn_next = H_GET_32 (abfd, src->vn_next); |
| } |
| |
| /* Swap out a Verneed structure. */ |
| |
| void |
| _bfd_elf_swap_verneed_out (bfd *abfd, |
| const Elf_Internal_Verneed *src, |
| Elf_External_Verneed *dst) |
| { |
| H_PUT_16 (abfd, src->vn_version, dst->vn_version); |
| H_PUT_16 (abfd, src->vn_cnt, dst->vn_cnt); |
| H_PUT_32 (abfd, src->vn_file, dst->vn_file); |
| H_PUT_32 (abfd, src->vn_aux, dst->vn_aux); |
| H_PUT_32 (abfd, src->vn_next, dst->vn_next); |
| } |
| |
| /* Swap in a Vernaux structure. */ |
| |
| void |
| _bfd_elf_swap_vernaux_in (bfd *abfd, |
| const Elf_External_Vernaux *src, |
| Elf_Internal_Vernaux *dst) |
| { |
| dst->vna_hash = H_GET_32 (abfd, src->vna_hash); |
| dst->vna_flags = H_GET_16 (abfd, src->vna_flags); |
| dst->vna_other = H_GET_16 (abfd, src->vna_other); |
| dst->vna_name = H_GET_32 (abfd, src->vna_name); |
| dst->vna_next = H_GET_32 (abfd, src->vna_next); |
| } |
| |
| /* Swap out a Vernaux structure. */ |
| |
| void |
| _bfd_elf_swap_vernaux_out (bfd *abfd, |
| const Elf_Internal_Vernaux *src, |
| Elf_External_Vernaux *dst) |
| { |
| H_PUT_32 (abfd, src->vna_hash, dst->vna_hash); |
| H_PUT_16 (abfd, src->vna_flags, dst->vna_flags); |
| H_PUT_16 (abfd, src->vna_other, dst->vna_other); |
| H_PUT_32 (abfd, src->vna_name, dst->vna_name); |
| H_PUT_32 (abfd, src->vna_next, dst->vna_next); |
| } |
| |
| /* Swap in a Versym structure. */ |
| |
| void |
| _bfd_elf_swap_versym_in (bfd *abfd, |
| const Elf_External_Versym *src, |
| Elf_Internal_Versym *dst) |
| { |
| dst->vs_vers = H_GET_16 (abfd, src->vs_vers); |
| } |
| |
| /* Swap out a Versym structure. */ |
| |
| void |
| _bfd_elf_swap_versym_out (bfd *abfd, |
| const Elf_Internal_Versym *src, |
| Elf_External_Versym *dst) |
| { |
| H_PUT_16 (abfd, src->vs_vers, dst->vs_vers); |
| } |
| |
| /* Standard ELF hash function. Do not change this function; you will |
| cause invalid hash tables to be generated. */ |
| |
| unsigned long |
| bfd_elf_hash (const char *namearg) |
| { |
| const unsigned char *name = (const unsigned char *) namearg; |
| unsigned long h = 0; |
| unsigned long g; |
| int ch; |
| |
| while ((ch = *name++) != '\0') |
| { |
| h = (h << 4) + ch; |
| if ((g = (h & 0xf0000000)) != 0) |
| { |
| h ^= g >> 24; |
| /* The ELF ABI says `h &= ~g', but this is equivalent in |
| this case and on some machines one insn instead of two. */ |
| h ^= g; |
| } |
| } |
| return h & 0xffffffff; |
| } |
| |
| /* DT_GNU_HASH hash function. Do not change this function; you will |
| cause invalid hash tables to be generated. */ |
| |
| unsigned long |
| bfd_elf_gnu_hash (const char *namearg) |
| { |
| const unsigned char *name = (const unsigned char *) namearg; |
| unsigned long h = 5381; |
| unsigned char ch; |
| |
| while ((ch = *name++) != '\0') |
| h = (h << 5) + h + ch; |
| return h & 0xffffffff; |
| } |
| |
| /* Create a tdata field OBJECT_SIZE bytes in length, zeroed out and with |
| the object_id field of an elf_obj_tdata field set to OBJECT_ID. */ |
| bool |
| bfd_elf_allocate_object (bfd *abfd, |
| size_t object_size, |
| enum elf_target_id object_id) |
| { |
| BFD_ASSERT (object_size >= sizeof (struct elf_obj_tdata)); |
| abfd->tdata.any = bfd_zalloc (abfd, object_size); |
| if (abfd->tdata.any == NULL) |
| return false; |
| |
| elf_object_id (abfd) = object_id; |
| if (abfd->direction != read_direction) |
| { |
| struct output_elf_obj_tdata *o = bfd_zalloc (abfd, sizeof *o); |
| if (o == NULL) |
| return false; |
| elf_tdata (abfd)->o = o; |
| elf_program_header_size (abfd) = (bfd_size_type) -1; |
| } |
| return true; |
| } |
| |
| |
| bool |
| bfd_elf_make_object (bfd *abfd) |
| { |
| const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
| return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata), |
| bed->target_id); |
| } |
| |
| bool |
| bfd_elf_mkcorefile (bfd *abfd) |
| { |
| /* I think this can be done just like an object file. */ |
| if (!abfd->xvec->_bfd_set_format[(int) bfd_object] (abfd)) |
| return false; |
| elf_tdata (abfd)->core = bfd_zalloc (abfd, sizeof (*elf_tdata (abfd)->core)); |
| return elf_tdata (abfd)->core != NULL; |
| } |
| |
| char * |
| bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) |
| { |
| Elf_Internal_Shdr **i_shdrp; |
| bfd_byte *shstrtab = NULL; |
| file_ptr offset; |
| bfd_size_type shstrtabsize; |
| |
| i_shdrp = elf_elfsections (abfd); |
| if (i_shdrp == 0 |
| || shindex >= elf_numsections (abfd) |
| || i_shdrp[shindex] == 0) |
| return NULL; |
| |
| shstrtab = i_shdrp[shindex]->contents; |
| if (shstrtab == NULL) |
| { |
| /* No cached one, attempt to read, and cache what we read. */ |
| offset = i_shdrp[shindex]->sh_offset; |
| shstrtabsize = i_shdrp[shindex]->sh_size; |
| |
| /* Allocate and clear an extra byte at the end, to prevent crashes |
| in case the string table is not terminated. */ |
| if (shstrtabsize + 1 <= 1 |
| || bfd_seek (abfd, offset, SEEK_SET) != 0 |
| || (shstrtab = _bfd_alloc_and_read (abfd, shstrtabsize + 1, |
| shstrtabsize)) == NULL) |
| { |
| /* Once we've failed to read it, make sure we don't keep |
| trying. Otherwise, we'll keep allocating space for |
| the string table over and over. */ |
| i_shdrp[shindex]->sh_size = 0; |
| } |
| else |
| shstrtab[shstrtabsize] = '\0'; |
| i_shdrp[shindex]->contents = shstrtab; |
| } |
| return (char *) shstrtab; |
| } |
| |
| char * |
| bfd_elf_string_from_elf_section (bfd *abfd, |
| unsigned int shindex, |
| unsigned int strindex) |
| { |
| Elf_Internal_Shdr *hdr; |
| |
| if (strindex == 0) |
| return ""; |
| |
| if (elf_elfsections (abfd) == NULL || shindex >= elf_numsections (abfd)) |
| return NULL; |
| |
| hdr = elf_elfsections (abfd)[shindex]; |
| |
| if (hdr->contents == NULL) |
| { |
| if (hdr->sh_type != SHT_STRTAB && hdr->sh_type < SHT_LOOS) |
| { |
| /* PR 17512: file: f057ec89. */ |
| /* xgettext:c-format */ |
| _bfd_error_handler (_("%pB: attempt to load strings from" |
| " a non-string section (number %d)"), |
| abfd, shindex); |
| return NULL; |
| } |
| |
| if (bfd_elf_get_str_section (abfd, shindex) == NULL) |
| return NULL; |
| } |
| else |
| { |
| /* PR 24273: The string section's contents may have already |
| been loaded elsewhere, eg because a corrupt file has the |
| string section index in the ELF header pointing at a group |
| section. So be paranoid, and test that the last byte of |
| the section is zero. */ |
| if (hdr->sh_size == 0 || hdr->contents[hdr->sh_size - 1] != 0) |
| return NULL; |
| } |
| |
| if (strindex >= hdr->sh_size) |
| { |
| unsigned int shstrndx = elf_elfheader(abfd)->e_shstrndx; |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: invalid string offset %u >= %" PRIu64 " for section `%s'"), |
| abfd, strindex, (uint64_t) hdr->sh_size, |
| (shindex == shstrndx && strindex == hdr->sh_name |
| ? ".shstrtab" |
| : bfd_elf_string_from_elf_section (abfd, shstrndx, hdr->sh_name))); |
| return NULL; |
| } |
| |
| return ((char *) hdr->contents) + strindex; |
| } |
| |
| /* Read and convert symbols to internal format. |
| SYMCOUNT specifies the number of symbols to read, starting from |
| symbol SYMOFFSET. If any of INTSYM_BUF, EXTSYM_BUF or EXTSHNDX_BUF |
| are non-NULL, they are used to store the internal symbols, external |
| symbols, and symbol section index extensions, respectively. |
| Returns a pointer to the internal symbol buffer (malloced if necessary) |
| or NULL if there were no symbols or some kind of problem. */ |
| |
| Elf_Internal_Sym * |
| bfd_elf_get_elf_syms (bfd *ibfd, |
| Elf_Internal_Shdr *symtab_hdr, |
| size_t symcount, |
| size_t symoffset, |
| Elf_Internal_Sym *intsym_buf, |
| void *extsym_buf, |
| Elf_External_Sym_Shndx *extshndx_buf) |
| { |
| Elf_Internal_Shdr *shndx_hdr; |
| void *alloc_ext; |
| const bfd_byte *esym; |
| Elf_External_Sym_Shndx *alloc_extshndx; |
| Elf_External_Sym_Shndx *shndx; |
| Elf_Internal_Sym *alloc_intsym; |
| Elf_Internal_Sym *isym; |
| Elf_Internal_Sym *isymend; |
| const struct elf_backend_data *bed; |
| size_t extsym_size; |
| size_t amt; |
| file_ptr pos; |
| |
| if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) |
| abort (); |
| |
| if (symcount == 0) |
| return intsym_buf; |
| |
| /* Normal syms might have section extension entries. */ |
| shndx_hdr = NULL; |
| if (elf_symtab_shndx_list (ibfd) != NULL) |
| { |
| elf_section_list * entry; |
| Elf_Internal_Shdr **sections = elf_elfsections (ibfd); |
| |
| /* Find an index section that is linked to this symtab section. */ |
| for (entry = elf_symtab_shndx_list (ibfd); entry != NULL; entry = entry->next) |
| { |
| /* PR 20063. */ |
| if (entry->hdr.sh_link >= elf_numsections (ibfd)) |
| continue; |
| |
| if (sections[entry->hdr.sh_link] == symtab_hdr) |
| { |
| shndx_hdr = & entry->hdr; |
| break; |
| }; |
| } |
| |
| if (shndx_hdr == NULL) |
| { |
| if (symtab_hdr == & elf_symtab_hdr (ibfd)) |
| /* Not really accurate, but this was how the old code used to work. */ |
| shndx_hdr = & elf_symtab_shndx_list (ibfd)->hdr; |
| /* Otherwise we do nothing. The assumption is that |
| the index table will not be needed. */ |
| } |
| } |
| |
| /* Read the symbols. */ |
| alloc_ext = NULL; |
| alloc_extshndx = NULL; |
| alloc_intsym = NULL; |
| bed = get_elf_backend_data (ibfd); |
| extsym_size = bed->s->sizeof_sym; |
| if (_bfd_mul_overflow (symcount, extsym_size, &amt)) |
| { |
| bfd_set_error (bfd_error_file_too_big); |
| intsym_buf = NULL; |
| goto out; |
| } |
| pos = symtab_hdr->sh_offset + symoffset * extsym_size; |
| if (extsym_buf == NULL) |
| { |
| alloc_ext = bfd_malloc (amt); |
| extsym_buf = alloc_ext; |
| } |
| if (extsym_buf == NULL |
| || bfd_seek (ibfd, pos, SEEK_SET) != 0 |
| || bfd_bread (extsym_buf, amt, ibfd) != amt) |
| { |
| intsym_buf = NULL; |
| goto out; |
| } |
| |
| if (shndx_hdr == NULL || shndx_hdr->sh_size == 0) |
| extshndx_buf = NULL; |
| else |
| { |
| if (_bfd_mul_overflow (symcount, sizeof (Elf_External_Sym_Shndx), &amt)) |
| { |
| bfd_set_error (bfd_error_file_too_big); |
| intsym_buf = NULL; |
| goto out; |
| } |
| pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx); |
| if (extshndx_buf == NULL) |
| { |
| alloc_extshndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); |
| extshndx_buf = alloc_extshndx; |
| } |
| if (extshndx_buf == NULL |
| || bfd_seek (ibfd, pos, SEEK_SET) != 0 |
| || bfd_bread (extshndx_buf, amt, ibfd) != amt) |
| { |
| intsym_buf = NULL; |
| goto out; |
| } |
| } |
| |
| if (intsym_buf == NULL) |
| { |
| if (_bfd_mul_overflow (symcount, sizeof (Elf_Internal_Sym), &amt)) |
| { |
| bfd_set_error (bfd_error_file_too_big); |
| goto out; |
| } |
| alloc_intsym = (Elf_Internal_Sym *) bfd_malloc (amt); |
| intsym_buf = alloc_intsym; |
| if (intsym_buf == NULL) |
| goto out; |
| } |
| |
| /* Convert the symbols to internal form. */ |
| isymend = intsym_buf + symcount; |
| for (esym = (const bfd_byte *) extsym_buf, isym = intsym_buf, |
| shndx = extshndx_buf; |
| isym < isymend; |
| esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL) |
| if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym)) |
| { |
| symoffset += (esym - (bfd_byte *) extsym_buf) / extsym_size; |
| /* xgettext:c-format */ |
| _bfd_error_handler (_("%pB symbol number %lu references" |
| " nonexistent SHT_SYMTAB_SHNDX section"), |
| ibfd, (unsigned long) symoffset); |
| free (alloc_intsym); |
| intsym_buf = NULL; |
| goto out; |
| } |
| |
| out: |
| free (alloc_ext); |
| free (alloc_extshndx); |
| |
| return intsym_buf; |
| } |
| |
| /* Look up a symbol name. */ |
| const char * |
| bfd_elf_sym_name (bfd *abfd, |
| Elf_Internal_Shdr *symtab_hdr, |
| Elf_Internal_Sym *isym, |
| asection *sym_sec) |
| { |
| const char *name; |
| unsigned int iname = isym->st_name; |
| unsigned int shindex = symtab_hdr->sh_link; |
| |
| if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION |
| /* Check for a bogus st_shndx to avoid crashing. */ |
| && isym->st_shndx < elf_numsections (abfd)) |
| { |
| iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name; |
| shindex = elf_elfheader (abfd)->e_shstrndx; |
| } |
| |
| name = bfd_elf_string_from_elf_section (abfd, shindex, iname); |
| if (name == NULL) |
| name = "(null)"; |
| else if (sym_sec && *name == '\0') |
| name = bfd_section_name (sym_sec); |
| |
| return name; |
| } |
| |
| /* Elf_Internal_Shdr->contents is an array of these for SHT_GROUP |
| sections. The first element is the flags, the rest are section |
| pointers. */ |
| |
| typedef union elf_internal_group { |
| Elf_Internal_Shdr *shdr; |
| unsigned int flags; |
| } Elf_Internal_Group; |
| |
| /* Return the name of the group signature symbol. Why isn't the |
| signature just a string? */ |
| |
| static const char * |
| group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr) |
| { |
| Elf_Internal_Shdr *hdr; |
| unsigned char esym[sizeof (Elf64_External_Sym)]; |
| Elf_External_Sym_Shndx eshndx; |
| Elf_Internal_Sym isym; |
| |
| /* First we need to ensure the symbol table is available. Make sure |
| that it is a symbol table section. */ |
| if (ghdr->sh_link >= elf_numsections (abfd)) |
| return NULL; |
| hdr = elf_elfsections (abfd) [ghdr->sh_link]; |
| if (hdr->sh_type != SHT_SYMTAB |
| || ! bfd_section_from_shdr (abfd, ghdr->sh_link)) |
| return NULL; |
| |
| /* Go read the symbol. */ |
| hdr = &elf_tdata (abfd)->symtab_hdr; |
| if (bfd_elf_get_elf_syms (abfd, hdr, 1, ghdr->sh_info, |
| &isym, esym, &eshndx) == NULL) |
| return NULL; |
| |
| return bfd_elf_sym_name (abfd, hdr, &isym, NULL); |
| } |
| |
| /* Set next_in_group list pointer, and group name for NEWSECT. */ |
| |
| static bool |
| setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) |
| { |
| unsigned int num_group = elf_tdata (abfd)->num_group; |
| |
| /* If num_group is zero, read in all SHT_GROUP sections. The count |
| is set to -1 if there are no SHT_GROUP sections. */ |
| if (num_group == 0) |
| { |
| unsigned int i, shnum; |
| |
| /* First count the number of groups. If we have a SHT_GROUP |
| section with just a flag word (ie. sh_size is 4), ignore it. */ |
| shnum = elf_numsections (abfd); |
| num_group = 0; |
| |
| #define IS_VALID_GROUP_SECTION_HEADER(shdr, minsize) \ |
| ( (shdr)->sh_type == SHT_GROUP \ |
| && (shdr)->sh_size >= minsize \ |
| && (shdr)->sh_entsize == GRP_ENTRY_SIZE \ |
| && ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0) |
| |
| for (i = 0; i < shnum; i++) |
| { |
| Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; |
| |
| if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE)) |
| num_group += 1; |
| } |
| |
| if (num_group == 0) |
| { |
| num_group = (unsigned) -1; |
| elf_tdata (abfd)->num_group = num_group; |
| elf_tdata (abfd)->group_sect_ptr = NULL; |
| } |
| else |
| { |
| /* We keep a list of elf section headers for group sections, |
| so we can find them quickly. */ |
| size_t amt; |
| |
| elf_tdata (abfd)->num_group = num_group; |
| amt = num_group * sizeof (Elf_Internal_Shdr *); |
| elf_tdata (abfd)->group_sect_ptr |
| = (Elf_Internal_Shdr **) bfd_zalloc (abfd, amt); |
| if (elf_tdata (abfd)->group_sect_ptr == NULL) |
| return false; |
| num_group = 0; |
| |
| for (i = 0; i < shnum; i++) |
| { |
| Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; |
| |
| if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE)) |
| { |
| unsigned char *src; |
| Elf_Internal_Group *dest; |
| |
| /* Make sure the group section has a BFD section |
| attached to it. */ |
| if (!bfd_section_from_shdr (abfd, i)) |
| return false; |
| |
| /* Add to list of sections. */ |
| elf_tdata (abfd)->group_sect_ptr[num_group] = shdr; |
| num_group += 1; |
| |
| /* Read the raw contents. */ |
| BFD_ASSERT (sizeof (*dest) >= 4 && sizeof (*dest) % 4 == 0); |
| shdr->contents = NULL; |
| if (_bfd_mul_overflow (shdr->sh_size, |
| sizeof (*dest) / 4, &amt) |
| || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 |
| || !(shdr->contents |
| = _bfd_alloc_and_read (abfd, amt, shdr->sh_size))) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: invalid size field in group section" |
| " header: %#" PRIx64 ""), |
| abfd, (uint64_t) shdr->sh_size); |
| bfd_set_error (bfd_error_bad_value); |
| -- num_group; |
| continue; |
| } |
| |
| /* Translate raw contents, a flag word followed by an |
| array of elf section indices all in target byte order, |
| to the flag word followed by an array of elf section |
| pointers. */ |
| src = shdr->contents + shdr->sh_size; |
| dest = (Elf_Internal_Group *) (shdr->contents + amt); |
| |
| while (1) |
| { |
| unsigned int idx; |
| |
| src -= 4; |
| --dest; |
| idx = H_GET_32 (abfd, src); |
| if (src == shdr->contents) |
| { |
| dest->shdr = NULL; |
| dest->flags = idx; |
| if (shdr->bfd_section != NULL && (idx & GRP_COMDAT)) |
| shdr->bfd_section->flags |
| |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; |
| break; |
| } |
| if (idx < shnum) |
| { |
| dest->shdr = elf_elfsections (abfd)[idx]; |
| /* PR binutils/23199: All sections in a |
| section group should be marked with |
| SHF_GROUP. But some tools generate |
| broken objects without SHF_GROUP. Fix |
| them up here. */ |
| dest->shdr->sh_flags |= SHF_GROUP; |
| } |
| if (idx >= shnum |
| || dest->shdr->sh_type == SHT_GROUP) |
| { |
| _bfd_error_handler |
| (_("%pB: invalid entry in SHT_GROUP section [%u]"), |
| abfd, i); |
| dest->shdr = NULL; |
| } |
| } |
| } |
| } |
| |
| /* PR 17510: Corrupt binaries might contain invalid groups. */ |
| if (num_group != (unsigned) elf_tdata (abfd)->num_group) |
| { |
| elf_tdata (abfd)->num_group = num_group; |
| |
| /* If all groups are invalid then fail. */ |
| if (num_group == 0) |
| { |
| elf_tdata (abfd)->group_sect_ptr = NULL; |
| elf_tdata (abfd)->num_group = num_group = -1; |
| _bfd_error_handler |
| (_("%pB: no valid group sections found"), abfd); |
| bfd_set_error (bfd_error_bad_value); |
| } |
| } |
| } |
| } |
| |
| if (num_group != (unsigned) -1) |
| { |
| unsigned int search_offset = elf_tdata (abfd)->group_search_offset; |
| unsigned int j; |
| |
| for (j = 0; j < num_group; j++) |
| { |
| /* Begin search from previous found group. */ |
| unsigned i = (j + search_offset) % num_group; |
| |
| Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i]; |
| Elf_Internal_Group *idx; |
| bfd_size_type n_elt; |
| |
| if (shdr == NULL) |
| continue; |
| |
| idx = (Elf_Internal_Group *) shdr->contents; |
| if (idx == NULL || shdr->sh_size < 4) |
| { |
| /* See PR 21957 for a reproducer. */ |
| /* xgettext:c-format */ |
| _bfd_error_handler (_("%pB: group section '%pA' has no contents"), |
| abfd, shdr->bfd_section); |
| elf_tdata (abfd)->group_sect_ptr[i] = NULL; |
| bfd_set_error (bfd_error_bad_value); |
| return false; |
| } |
| n_elt = shdr->sh_size / 4; |
| |
| /* Look through this group's sections to see if current |
| section is a member. */ |
| while (--n_elt != 0) |
| if ((++idx)->shdr == hdr) |
| { |
| asection *s = NULL; |
| |
| /* We are a member of this group. Go looking through |
| other members to see if any others are linked via |
| next_in_group. */ |
| idx = (Elf_Internal_Group *) shdr->contents; |
| n_elt = shdr->sh_size / 4; |
| while (--n_elt != 0) |
| if ((++idx)->shdr != NULL |
| && (s = idx->shdr->bfd_section) != NULL |
| && elf_next_in_group (s) != NULL) |
| break; |
| if (n_elt != 0) |
| { |
| /* Snarf the group name from other member, and |
| insert current section in circular list. */ |
| elf_group_name (newsect) = elf_group_name (s); |
| elf_next_in_group (newsect) = elf_next_in_group (s); |
| elf_next_in_group (s) = newsect; |
| } |
| else |
| { |
| const char *gname; |
| |
| gname = group_signature (abfd, shdr); |
| if (gname == NULL) |
| return false; |
| elf_group_name (newsect) = gname; |
| |
| /* Start a circular list with one element. */ |
| elf_next_in_group (newsect) = newsect; |
| } |
| |
| /* If the group section has been created, point to the |
| new member. */ |
| if (shdr->bfd_section != NULL) |
| elf_next_in_group (shdr->bfd_section) = newsect; |
| |
| elf_tdata (abfd)->group_search_offset = i; |
| j = num_group - 1; |
| break; |
| } |
| } |
| } |
| |
| if (elf_group_name (newsect) == NULL) |
| { |
| /* xgettext:c-format */ |
| _bfd_error_handler (_("%pB: no group info for section '%pA'"), |
| abfd, newsect); |
| return false; |
| } |
| return true; |
| } |
| |
| bool |
| _bfd_elf_setup_sections (bfd *abfd) |
| { |
| unsigned int i; |
| unsigned int num_group = elf_tdata (abfd)->num_group; |
| bool result = true; |
| asection *s; |
| |
| /* Process SHF_LINK_ORDER. */ |
| for (s = abfd->sections; s != NULL; s = s->next) |
| { |
| Elf_Internal_Shdr *this_hdr = &elf_section_data (s)->this_hdr; |
| if ((this_hdr->sh_flags & SHF_LINK_ORDER) != 0) |
| { |
| unsigned int elfsec = this_hdr->sh_link; |
| /* An sh_link value of 0 is now allowed. It indicates that linked |
| to section has already been discarded, but that the current |
| section has been retained for some other reason. This linking |
| section is still a candidate for later garbage collection |
| however. */ |
| if (elfsec == 0) |
| { |
| elf_linked_to_section (s) = NULL; |
| } |
| else |
| { |
| asection *linksec = NULL; |
| |
| if (elfsec < elf_numsections (abfd)) |
| { |
| this_hdr = elf_elfsections (abfd)[elfsec]; |
| linksec = this_hdr->bfd_section; |
| } |
| |
| /* PR 1991, 2008: |
| Some strip/objcopy may leave an incorrect value in |
| sh_link. We don't want to proceed. */ |
| if (linksec == NULL) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: sh_link [%d] in section `%pA' is incorrect"), |
| s->owner, elfsec, s); |
| result = false; |
| } |
| |
| elf_linked_to_section (s) = linksec; |
| } |
| } |
| else if (this_hdr->sh_type == SHT_GROUP |
| && elf_next_in_group (s) == NULL) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: SHT_GROUP section [index %d] has no SHF_GROUP sections"), |
| abfd, elf_section_data (s)->this_idx); |
| result = false; |
| } |
| } |
| |
| /* Process section groups. */ |
| if (num_group == (unsigned) -1) |
| return result; |
| |
| for (i = 0; i < num_group; i++) |
| { |
| Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i]; |
| Elf_Internal_Group *idx; |
| unsigned int n_elt; |
| |
| /* PR binutils/18758: Beware of corrupt binaries with invalid group data. */ |
| if (shdr == NULL || shdr->bfd_section == NULL || shdr->contents == NULL) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: section group entry number %u is corrupt"), |
| abfd, i); |
| result = false; |
| continue; |
| } |
| |
| idx = (Elf_Internal_Group *) shdr->contents; |
| n_elt = shdr->sh_size / 4; |
| |
| while (--n_elt != 0) |
| { |
| ++ idx; |
| |
| if (idx->shdr == NULL) |
| continue; |
| else if (idx->shdr->bfd_section) |
| elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section; |
| else if (idx->shdr->sh_type != SHT_RELA |
| && idx->shdr->sh_type != SHT_REL) |
| { |
| /* There are some unknown sections in the group. */ |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: unknown type [%#x] section `%s' in group [%pA]"), |
| abfd, |
| idx->shdr->sh_type, |
| bfd_elf_string_from_elf_section (abfd, |
| (elf_elfheader (abfd) |
| ->e_shstrndx), |
| idx->shdr->sh_name), |
| shdr->bfd_section); |
| result = false; |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| bool |
| bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec) |
| { |
| return elf_next_in_group (sec) != NULL; |
| } |
| |
| const char * |
| bfd_elf_group_name (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec) |
| { |
| if (elf_sec_group (sec) != NULL) |
| return elf_group_name (sec); |
| return NULL; |
| } |
| |
| static char * |
| convert_debug_to_zdebug (bfd *abfd, const char *name) |
| { |
| unsigned int len = strlen (name); |
| char *new_name = bfd_alloc (abfd, len + 2); |
| if (new_name == NULL) |
| return NULL; |
| new_name[0] = '.'; |
| new_name[1] = 'z'; |
| memcpy (new_name + 2, name + 1, len); |
| return new_name; |
| } |
| |
| static char * |
| convert_zdebug_to_debug (bfd *abfd, const char *name) |
| { |
| unsigned int len = strlen (name); |
| char *new_name = bfd_alloc (abfd, len); |
| if (new_name == NULL) |
| return NULL; |
| new_name[0] = '.'; |
| memcpy (new_name + 1, name + 2, len - 1); |
| return new_name; |
| } |
| |
| /* This a copy of lto_section defined in GCC (lto-streamer.h). */ |
| |
| struct lto_section |
| { |
| int16_t major_version; |
| int16_t minor_version; |
| unsigned char slim_object; |
| |
| /* Flags is a private field that is not defined publicly. */ |
| uint16_t flags; |
| }; |
| |
| /* Make a BFD section from an ELF section. We store a pointer to the |
| BFD section in the bfd_section field of the header. */ |
| |
| bool |
| _bfd_elf_make_section_from_shdr (bfd *abfd, |
| Elf_Internal_Shdr *hdr, |
| const char *name, |
| int shindex) |
| { |
| asection *newsect; |
| flagword flags; |
| const struct elf_backend_data *bed; |
| unsigned int opb = bfd_octets_per_byte (abfd, NULL); |
| |
| if (hdr->bfd_section != NULL) |
| return true; |
| |
| newsect = bfd_make_section_anyway (abfd, name); |
| if (newsect == NULL) |
| return false; |
| |
| hdr->bfd_section = newsect; |
| elf_section_data (newsect)->this_hdr = *hdr; |
| elf_section_data (newsect)->this_idx = shindex; |
| |
| /* Always use the real type/flags. */ |
| elf_section_type (newsect) = hdr->sh_type; |
| elf_section_flags (newsect) = hdr->sh_flags; |
| |
| newsect->filepos = hdr->sh_offset; |
| |
| flags = SEC_NO_FLAGS; |
| if (hdr->sh_type != SHT_NOBITS) |
| flags |= SEC_HAS_CONTENTS; |
| if (hdr->sh_type == SHT_GROUP) |
| flags |= SEC_GROUP; |
| if ((hdr->sh_flags & SHF_ALLOC) != 0) |
| { |
| flags |= SEC_ALLOC; |
| if (hdr->sh_type != SHT_NOBITS) |
| flags |= SEC_LOAD; |
| } |
| if ((hdr->sh_flags & SHF_WRITE) == 0) |
| flags |= SEC_READONLY; |
| if ((hdr->sh_flags & SHF_EXECINSTR) != 0) |
| flags |= SEC_CODE; |
| else if ((flags & SEC_LOAD) != 0) |
| flags |= SEC_DATA; |
| if ((hdr->sh_flags & SHF_MERGE) != 0) |
| { |
| flags |= SEC_MERGE; |
| newsect->entsize = hdr->sh_entsize; |
| } |
| if ((hdr->sh_flags & SHF_STRINGS) != 0) |
| flags |= SEC_STRINGS; |
| if (hdr->sh_flags & SHF_GROUP) |
| if (!setup_group (abfd, hdr, newsect)) |
| return false; |
| if ((hdr->sh_flags & SHF_TLS) != 0) |
| flags |= SEC_THREAD_LOCAL; |
| if ((hdr->sh_flags & SHF_EXCLUDE) != 0) |
| flags |= SEC_EXCLUDE; |
| |
| switch (elf_elfheader (abfd)->e_ident[EI_OSABI]) |
| { |
| /* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE, |
| but binutils as of 2019-07-23 did not set the EI_OSABI header |
| byte. */ |
| case ELFOSABI_GNU: |
| case ELFOSABI_FREEBSD: |
| if ((hdr->sh_flags & SHF_GNU_RETAIN) != 0) |
| elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_retain; |
| /* Fall through */ |
| case ELFOSABI_NONE: |
| if ((hdr->sh_flags & SHF_GNU_MBIND) != 0) |
| elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_mbind; |
| break; |
| } |
| |
| if ((flags & SEC_ALLOC) == 0) |
| { |
| /* The debugging sections appear to be recognized only by name, |
| not any sort of flag. Their SEC_ALLOC bits are cleared. */ |
| if (name [0] == '.') |
| { |
| if (startswith (name, ".debug") |
| || startswith (name, ".gnu.debuglto_.debug_") |
| || startswith (name, ".gnu.linkonce.wi.") |
| || startswith (name, ".zdebug")) |
| flags |= SEC_DEBUGGING | SEC_ELF_OCTETS; |
| else if (startswith (name, GNU_BUILD_ATTRS_SECTION_NAME) |
| || startswith (name, ".note.gnu")) |
| { |
| flags |= SEC_ELF_OCTETS; |
| opb = 1; |
| } |
| else if (startswith (name, ".line") |
| || startswith (name, ".stab") |
| || strcmp (name, ".gdb_index") == 0) |
| flags |= SEC_DEBUGGING; |
| } |
| } |
| |
| if (!bfd_set_section_vma (newsect, hdr->sh_addr / opb) |
| || !bfd_set_section_size (newsect, hdr->sh_size) |
| || !bfd_set_section_alignment (newsect, bfd_log2 (hdr->sh_addralign))) |
| return false; |
| |
| /* As a GNU extension, if the name begins with .gnu.linkonce, we |
| only link a single copy of the section. This is used to support |
| g++. g++ will emit each template expansion in its own section. |
| The symbols will be defined as weak, so that multiple definitions |
| are permitted. The GNU linker extension is to actually discard |
| all but one of the sections. */ |
| if (startswith (name, ".gnu.linkonce") |
| && elf_next_in_group (newsect) == NULL) |
| flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; |
| |
| if (!bfd_set_section_flags (newsect, flags)) |
| return false; |
| |
| bed = get_elf_backend_data (abfd); |
| if (bed->elf_backend_section_flags) |
| if (!bed->elf_backend_section_flags (hdr)) |
| return false; |
| |
| /* We do not parse the PT_NOTE segments as we are interested even in the |
| separate debug info files which may have the segments offsets corrupted. |
| PT_NOTEs from the core files are currently not parsed using BFD. */ |
| if (hdr->sh_type == SHT_NOTE) |
| { |
| bfd_byte *contents; |
| |
| if (!bfd_malloc_and_get_section (abfd, newsect, &contents)) |
| return false; |
| |
| elf_parse_notes (abfd, (char *) contents, hdr->sh_size, |
| hdr->sh_offset, hdr->sh_addralign); |
| free (contents); |
| } |
| |
| if ((newsect->flags & SEC_ALLOC) != 0) |
| { |
| Elf_Internal_Phdr *phdr; |
| unsigned int i, nload; |
| |
| /* Some ELF linkers produce binaries with all the program header |
| p_paddr fields zero. If we have such a binary with more than |
| one PT_LOAD header, then leave the section lma equal to vma |
| so that we don't create sections with overlapping lma. */ |
| phdr = elf_tdata (abfd)->phdr; |
| for (nload = 0, i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) |
| if (phdr->p_paddr != 0) |
| break; |
| else if (phdr->p_type == PT_LOAD && phdr->p_memsz != 0) |
| ++nload; |
| if (i >= elf_elfheader (abfd)->e_phnum && nload > 1) |
| return true; |
| |
| phdr = elf_tdata (abfd)->phdr; |
| for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) |
| { |
| if (((phdr->p_type == PT_LOAD |
| && (hdr->sh_flags & SHF_TLS) == 0) |
| || phdr->p_type == PT_TLS) |
| && ELF_SECTION_IN_SEGMENT (hdr, phdr)) |
| { |
| if ((newsect->flags & SEC_LOAD) == 0) |
| newsect->lma = (phdr->p_paddr |
| + hdr->sh_addr - phdr->p_vaddr) / opb; |
| else |
| /* We used to use the same adjustment for SEC_LOAD |
| sections, but that doesn't work if the segment |
| is packed with code from multiple VMAs. |
| Instead we calculate the section LMA based on |
| the segment LMA. It is assumed that the |
| segment will contain sections with contiguous |
| LMAs, even if the VMAs are not. */ |
| newsect->lma = (phdr->p_paddr |
| + hdr->sh_offset - phdr->p_offset) / opb; |
| |
| /* With contiguous segments, we can't tell from file |
| offsets whether a section with zero size should |
| be placed at the end of one segment or the |
| beginning of the next. Decide based on vaddr. */ |
| if (hdr->sh_addr >= phdr->p_vaddr |
| && (hdr->sh_addr + hdr->sh_size |
| <= phdr->p_vaddr + phdr->p_memsz)) |
| break; |
| } |
| } |
| } |
| |
| /* Compress/decompress DWARF debug sections with names: .debug_* and |
| .zdebug_*, after the section flags is set. */ |
| if ((newsect->flags & SEC_DEBUGGING) |
| && ((name[1] == 'd' && name[6] == '_') |
| || (name[1] == 'z' && name[7] == '_'))) |
| { |
| enum { nothing, compress, decompress } action = nothing; |
| int compression_header_size; |
| bfd_size_type uncompressed_size; |
| unsigned int uncompressed_align_power; |
| bool compressed |
| = bfd_is_section_compressed_with_header (abfd, newsect, |
| &compression_header_size, |
| &uncompressed_size, |
| &uncompressed_align_power); |
| if (compressed) |
| { |
| /* Compressed section. Check if we should decompress. */ |
| if ((abfd->flags & BFD_DECOMPRESS)) |
| action = decompress; |
| } |
| |
| /* Compress the uncompressed section or convert from/to .zdebug* |
| section. Check if we should compress. */ |
| if (action == nothing) |
| { |
| if (newsect->size != 0 |
| && (abfd->flags & BFD_COMPRESS) |
| && compression_header_size >= 0 |
| && uncompressed_size > 0 |
| && (!compressed |
| || ((compression_header_size > 0) |
| != ((abfd->flags & BFD_COMPRESS_GABI) != 0)))) |
| action = compress; |
| else |
| return true; |
| } |
| |
| if (action == compress) |
| { |
| if (!bfd_init_section_compress_status (abfd, newsect)) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: unable to initialize compress status for section %s"), |
| abfd, name); |
| return false; |
| } |
| } |
| else |
| { |
| if (!bfd_init_section_decompress_status (abfd, newsect)) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: unable to initialize decompress status for section %s"), |
| abfd, name); |
| return false; |
| } |
| } |
| |
| if (abfd->is_linker_input) |
| { |
| if (name[1] == 'z' |
| && (action == decompress |
| || (action == compress |
| && (abfd->flags & BFD_COMPRESS_GABI) != 0))) |
| { |
| /* Convert section name from .zdebug_* to .debug_* so |
| that linker will consider this section as a debug |
| section. */ |
| char *new_name = convert_zdebug_to_debug (abfd, name); |
| if (new_name == NULL) |
| return false; |
| bfd_rename_section (newsect, new_name); |
| } |
| } |
| else |
| /* For objdump, don't rename the section. For objcopy, delay |
| section rename to elf_fake_sections. */ |
| newsect->flags |= SEC_ELF_RENAME; |
| } |
| |
| /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode information |
| section. */ |
| if (startswith (name, ".gnu.lto_.lto.")) |
| { |
| struct lto_section lsection; |
| if (bfd_get_section_contents (abfd, newsect, &lsection, 0, |
| sizeof (struct lto_section))) |
| abfd->lto_slim_object = lsection.slim_object; |
| } |
| |
| return true; |
| } |
| |
| const char *const bfd_elf_section_type_names[] = |
| { |
| "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB", |
| "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE", |
| "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM", |
| }; |
| |
| /* ELF relocs are against symbols. If we are producing relocatable |
| output, and the reloc is against an external symbol, and nothing |
| has given us any additional addend, the resulting reloc will also |
| be against the same symbol. In such a case, we don't want to |
| change anything about the way the reloc is handled, since it will |
| all be done at final link time. Rather than put special case code |
| into bfd_perform_relocation, all the reloc types use this howto |
| function, or should call this function for relocatable output. */ |
| |
| bfd_reloc_status_type |
| bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, |
| arelent *reloc_entry, |
| asymbol *symbol, |
| void *data ATTRIBUTE_UNUSED, |
| asection *input_section, |
| bfd *output_bfd, |
| char **error_message ATTRIBUTE_UNUSED) |
| { |
| if (output_bfd != NULL |
| && (symbol->flags & BSF_SECTION_SYM) == 0 |
| && (! reloc_entry->howto->partial_inplace |
| || reloc_entry->addend == 0)) |
| { |
| reloc_entry->address += input_section->output_offset; |
| return bfd_reloc_ok; |
| } |
| |
| /* In some cases the relocation should be treated as output section |
| relative, as when linking ELF DWARF into PE COFF. Many ELF |
| targets lack section relative relocations and instead use |
| ordinary absolute relocations for references between DWARF |
| sections. That is arguably a bug in those targets but it happens |
| to work for the usual case of linking to non-loaded ELF debug |
| sections with VMAs forced to zero. PE COFF on the other hand |
| doesn't allow a section VMA of zero. */ |
| if (output_bfd == NULL |
| && !reloc_entry->howto->pc_relative |
| && (symbol->section->flags & SEC_DEBUGGING) != 0 |
| && (input_section->flags & SEC_DEBUGGING) != 0) |
| reloc_entry->addend -= symbol->section->output_section->vma; |
| |
| return bfd_reloc_continue; |
| } |
| |
| /* Returns TRUE if section A matches section B. |
| Names, addresses and links may be different, but everything else |
| should be the same. */ |
| |
| static bool |
| section_match (const Elf_Internal_Shdr * a, |
| const Elf_Internal_Shdr * b) |
| { |
| if (a->sh_type != b->sh_type |
| || ((a->sh_flags ^ b->sh_flags) & ~SHF_INFO_LINK) != 0 |
| || a->sh_addralign != b->sh_addralign |
| || a->sh_entsize != b->sh_entsize) |
| return false; |
| if (a->sh_type == SHT_SYMTAB |
| || a->sh_type == SHT_STRTAB) |
| return true; |
| return a->sh_size == b->sh_size; |
| } |
| |
| /* Find a section in OBFD that has the same characteristics |
| as IHEADER. Return the index of this section or SHN_UNDEF if |
| none can be found. Check's section HINT first, as this is likely |
| to be the correct section. */ |
| |
| static unsigned int |
| find_link (const bfd *obfd, const Elf_Internal_Shdr *iheader, |
| const unsigned int hint) |
| { |
| Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd); |
| unsigned int i; |
| |
| BFD_ASSERT (iheader != NULL); |
| |
| /* See PR 20922 for a reproducer of the NULL test. */ |
| if (hint < elf_numsections (obfd) |
| && oheaders[hint] != NULL |
| && section_match (oheaders[hint], iheader)) |
| return hint; |
| |
| for (i = 1; i < elf_numsections (obfd); i++) |
| { |
| Elf_Internal_Shdr * oheader = oheaders[i]; |
| |
| if (oheader == NULL) |
| continue; |
| if (section_match (oheader, iheader)) |
| /* FIXME: Do we care if there is a potential for |
| multiple matches ? */ |
| return i; |
| } |
| |
| return SHN_UNDEF; |
| } |
| |
| /* PR 19938: Attempt to set the ELF section header fields of an OS or |
| Processor specific section, based upon a matching input section. |
| Returns TRUE upon success, FALSE otherwise. */ |
| |
| static bool |
| copy_special_section_fields (const bfd *ibfd, |
| bfd *obfd, |
| const Elf_Internal_Shdr *iheader, |
| Elf_Internal_Shdr *oheader, |
| const unsigned int secnum) |
| { |
| const struct elf_backend_data *bed = get_elf_backend_data (obfd); |
| const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd); |
| bool changed = false; |
| unsigned int sh_link; |
| |
| if (oheader->sh_type == SHT_NOBITS) |
| { |
| /* This is a feature for objcopy --only-keep-debug: |
| When a section's type is changed to NOBITS, we preserve |
| the sh_link and sh_info fields so that they can be |
| matched up with the original. |
| |
| Note: Strictly speaking these assignments are wrong. |
| The sh_link and sh_info fields should point to the |
| relevent sections in the output BFD, which may not be in |
| the same location as they were in the input BFD. But |
| the whole point of this action is to preserve the |
| original values of the sh_link and sh_info fields, so |
| that they can be matched up with the section headers in |
| the original file. So strictly speaking we may be |
| creating an invalid ELF file, but it is only for a file |
| that just contains debug info and only for sections |
| without any contents. */ |
| if (oheader->sh_link == 0) |
| oheader->sh_link = iheader->sh_link; |
| if (oheader->sh_info == 0) |
| oheader->sh_info = iheader->sh_info; |
| return true; |
| } |
| |
| /* Allow the target a chance to decide how these fields should be set. */ |
| if (bed->elf_backend_copy_special_section_fields (ibfd, obfd, |
| iheader, oheader)) |
| return true; |
| |
| /* We have an iheader which might match oheader, and which has non-zero |
| sh_info and/or sh_link fields. Attempt to follow those links and find |
| the section in the output bfd which corresponds to the linked section |
| in the input bfd. */ |
| if (iheader->sh_link != SHN_UNDEF) |
| { |
| /* See PR 20931 for a reproducer. */ |
| if (iheader->sh_link >= elf_numsections (ibfd)) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: invalid sh_link field (%d) in section number %d"), |
| ibfd, iheader->sh_link, secnum); |
| return false; |
| } |
| |
| sh_link = find_link (obfd, iheaders[iheader->sh_link], iheader->sh_link); |
| if (sh_link != SHN_UNDEF) |
| { |
| oheader->sh_link = sh_link; |
| changed = true; |
| } |
| else |
| /* FIXME: Should we install iheader->sh_link |
| if we could not find a match ? */ |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: failed to find link section for section %d"), obfd, secnum); |
| } |
| |
| if (iheader->sh_info) |
| { |
| /* The sh_info field can hold arbitrary information, but if the |
| SHF_LINK_INFO flag is set then it should be interpreted as a |
| section index. */ |
| if (iheader->sh_flags & SHF_INFO_LINK) |
| { |
| sh_link = find_link (obfd, iheaders[iheader->sh_info], |
| iheader->sh_info); |
| if (sh_link != SHN_UNDEF) |
| oheader->sh_flags |= SHF_INFO_LINK; |
| } |
| else |
| /* No idea what it means - just copy it. */ |
| sh_link = iheader->sh_info; |
| |
| if (sh_link != SHN_UNDEF) |
| { |
| oheader->sh_info = sh_link; |
| changed = true; |
| } |
| else |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: failed to find info section for section %d"), obfd, secnum); |
| } |
| |
| return changed; |
| } |
| |
| /* Copy the program header and other data from one object module to |
| another. */ |
| |
| bool |
| _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) |
| { |
| const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd); |
| Elf_Internal_Shdr **oheaders = elf_elfsections (obfd); |
| const struct elf_backend_data *bed; |
| unsigned int i; |
| |
| if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour |
| || bfd_get_flavour (obfd) != bfd_target_elf_flavour) |
| return true; |
| |
| if (!elf_flags_init (obfd)) |
| { |
| elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; |
| elf_flags_init (obfd) = true; |
| } |
| |
| elf_gp (obfd) = elf_gp (ibfd); |
| |
| /* Also copy the EI_OSABI field. */ |
| elf_elfheader (obfd)->e_ident[EI_OSABI] = |
| elf_elfheader (ibfd)->e_ident[EI_OSABI]; |
| |
| /* If set, copy the EI_ABIVERSION field. */ |
| if (elf_elfheader (ibfd)->e_ident[EI_ABIVERSION]) |
| elf_elfheader (obfd)->e_ident[EI_ABIVERSION] |
| = elf_elfheader (ibfd)->e_ident[EI_ABIVERSION]; |
| |
| /* Copy object attributes. */ |
| _bfd_elf_copy_obj_attributes (ibfd, obfd); |
| |
| if (iheaders == NULL || oheaders == NULL) |
| return true; |
| |
| bed = get_elf_backend_data (obfd); |
| |
| /* Possibly copy other fields in the section header. */ |
| for (i = 1; i < elf_numsections (obfd); i++) |
| { |
| unsigned int j; |
| Elf_Internal_Shdr * oheader = oheaders[i]; |
| |
| /* Ignore ordinary sections. SHT_NOBITS sections are considered however |
| because of a special case need for generating separate debug info |
| files. See below for more details. */ |
| if (oheader == NULL |
| || (oheader->sh_type != SHT_NOBITS |
| && oheader->sh_type < SHT_LOOS)) |
| continue; |
| |
| /* Ignore empty sections, and sections whose |
| fields have already been initialised. */ |
| if (oheader->sh_size == 0 |
| || (oheader->sh_info != 0 && oheader->sh_link != 0)) |
| continue; |
| |
| /* Scan for the matching section in the input bfd. |
| First we try for a direct mapping between the input and output sections. */ |
| for (j = 1; j < elf_numsections (ibfd); j++) |
| { |
| const Elf_Internal_Shdr * iheader = iheaders[j]; |
| |
| if (iheader == NULL) |
| continue; |
| |
| if (oheader->bfd_section != NULL |
| && iheader->bfd_section != NULL |
| && iheader->bfd_section->output_section != NULL |
| && iheader->bfd_section->output_section == oheader->bfd_section) |
| { |
| /* We have found a connection from the input section to the |
| output section. Attempt to copy the header fields. If |
| this fails then do not try any further sections - there |
| should only be a one-to-one mapping between input and output. */ |
| if (! copy_special_section_fields (ibfd, obfd, iheader, oheader, i)) |
| j = elf_numsections (ibfd); |
| break; |
| } |
| } |
| |
| if (j < elf_numsections (ibfd)) |
| continue; |
| |
| /* That failed. So try to deduce the corresponding input section. |
| Unfortunately we cannot compare names as the output string table |
| is empty, so instead we check size, address and type. */ |
| for (j = 1; j < elf_numsections (ibfd); j++) |
| { |
| const Elf_Internal_Shdr * iheader = iheaders[j]; |
| |
| if (iheader == NULL) |
| continue; |
| |
| /* Try matching fields in the input section's header. |
| Since --only-keep-debug turns all non-debug sections into |
| SHT_NOBITS sections, the output SHT_NOBITS type matches any |
| input type. */ |
| if ((oheader->sh_type == SHT_NOBITS |
| || iheader->sh_type == oheader->sh_type) |
| && (iheader->sh_flags & ~ SHF_INFO_LINK) |
| == (oheader->sh_flags & ~ SHF_INFO_LINK) |
| && iheader->sh_addralign == oheader->sh_addralign |
| && iheader->sh_entsize == oheader->sh_entsize |
| && iheader->sh_size == oheader->sh_size |
| && iheader->sh_addr == oheader->sh_addr |
| && (iheader->sh_info != oheader->sh_info |
| || iheader->sh_link != oheader->sh_link)) |
| { |
| if (copy_special_section_fields (ibfd, obfd, iheader, oheader, i)) |
| break; |
| } |
| } |
| |
| if (j == elf_numsections (ibfd) && oheader->sh_type >= SHT_LOOS) |
| { |
| /* Final attempt. Call the backend copy function |
| with a NULL input section. */ |
| (void) bed->elf_backend_copy_special_section_fields (ibfd, obfd, |
| NULL, oheader); |
| } |
| } |
| |
| return true; |
| } |
| |
| static const char * |
| get_segment_type (unsigned int p_type) |
| { |
| const char *pt; |
| switch (p_type) |
| { |
| case PT_NULL: pt = "NULL"; break; |
| case PT_LOAD: pt = "LOAD"; break; |
| case PT_DYNAMIC: pt = "DYNAMIC"; break; |
| case PT_INTERP: pt = "INTERP"; break; |
| case PT_NOTE: pt = "NOTE"; break; |
| case PT_SHLIB: pt = "SHLIB"; break; |
| case PT_PHDR: pt = "PHDR"; break; |
| case PT_TLS: pt = "TLS"; break; |
| case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break; |
| case PT_GNU_STACK: pt = "STACK"; break; |
| case PT_GNU_RELRO: pt = "RELRO"; break; |
| default: pt = NULL; break; |
| } |
| return pt; |
| } |
| |
| /* Print out the program headers. */ |
| |
| bool |
| _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) |
| { |
| FILE *f = (FILE *) farg; |
| Elf_Internal_Phdr *p; |
| asection *s; |
| bfd_byte *dynbuf = NULL; |
| |
| p = elf_tdata (abfd)->phdr; |
| if (p != NULL) |
| { |
| unsigned int i, c; |
| |
| fprintf (f, _("\nProgram Header:\n")); |
| c = elf_elfheader (abfd)->e_phnum; |
| for (i = 0; i < c; i++, p++) |
| { |
| const char *pt = get_segment_type (p->p_type); |
| char buf[20]; |
| |
| if (pt == NULL) |
| { |
| sprintf (buf, "0x%lx", p->p_type); |
| pt = buf; |
| } |
| fprintf (f, "%8s off 0x", pt); |
| bfd_fprintf_vma (abfd, f, p->p_offset); |
| fprintf (f, " vaddr 0x"); |
| bfd_fprintf_vma (abfd, f, p->p_vaddr); |
| fprintf (f, " paddr 0x"); |
| bfd_fprintf_vma (abfd, f, p->p_paddr); |
| fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align)); |
| fprintf (f, " filesz 0x"); |
| bfd_fprintf_vma (abfd, f, p->p_filesz); |
| fprintf (f, " memsz 0x"); |
| bfd_fprintf_vma (abfd, f, p->p_memsz); |
| fprintf (f, " flags %c%c%c", |
| (p->p_flags & PF_R) != 0 ? 'r' : '-', |
| (p->p_flags & PF_W) != 0 ? 'w' : '-', |
| (p->p_flags & PF_X) != 0 ? 'x' : '-'); |
| if ((p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)) != 0) |
| fprintf (f, " %lx", p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)); |
| fprintf (f, "\n"); |
| } |
| } |
| |
| s = bfd_get_section_by_name (abfd, ".dynamic"); |
| if (s != NULL) |
| { |
| unsigned int elfsec; |
| unsigned long shlink; |
| bfd_byte *extdyn, *extdynend; |
| size_t extdynsize; |
| void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); |
| |
| fprintf (f, _("\nDynamic Section:\n")); |
| |
| if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) |
| goto error_return; |
| |
| elfsec = _bfd_elf_section_from_bfd_section (abfd, s); |
| if (elfsec == SHN_BAD) |
| goto error_return; |
| shlink = elf_elfsections (abfd)[elfsec]->sh_link; |
| |
| extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; |
| swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; |
| |
| extdyn = dynbuf; |
| /* PR 17512: file: 6f427532. */ |
| if (s->size < extdynsize) |
| goto error_return; |
| extdynend = extdyn + s->size; |
| /* PR 17512: file: id:000006,sig:06,src:000000,op:flip4,pos:5664. |
| Fix range check. */ |
| for (; extdyn <= (extdynend - extdynsize); extdyn += extdynsize) |
| { |
| Elf_Internal_Dyn dyn; |
| const char *name = ""; |
| char ab[20]; |
| bool stringp; |
| const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
| |
| (*swap_dyn_in) (abfd, extdyn, &dyn); |
| |
| if (dyn.d_tag == DT_NULL) |
| break; |
| |
| stringp = false; |
| switch (dyn.d_tag) |
| { |
| default: |
| if (bed->elf_backend_get_target_dtag) |
| name = (*bed->elf_backend_get_target_dtag) (dyn.d_tag); |
| |
| if (!strcmp (name, "")) |
| { |
| sprintf (ab, "%#" BFD_VMA_FMT "x", dyn.d_tag); |
| name = ab; |
| } |
| break; |
| |
| case DT_NEEDED: name = "NEEDED"; stringp = true; break; |
| case DT_PLTRELSZ: name = "PLTRELSZ"; break; |
| case DT_PLTGOT: name = "PLTGOT"; break; |
| case DT_HASH: name = "HASH"; break; |
| case DT_STRTAB: name = "STRTAB"; break; |
| case DT_SYMTAB: name = "SYMTAB"; break; |
| case DT_RELA: name = "RELA"; break; |
| case DT_RELASZ: name = "RELASZ"; break; |
| case DT_RELAENT: name = "RELAENT"; break; |
| case DT_STRSZ: name = "STRSZ"; break; |
| case DT_SYMENT: name = "SYMENT"; break; |
| case DT_INIT: name = "INIT"; break; |
| case DT_FINI: name = "FINI"; break; |
| case DT_SONAME: name = "SONAME"; stringp = true; break; |
| case DT_RPATH: name = "RPATH"; stringp = true; break; |
| case DT_SYMBOLIC: name = "SYMBOLIC"; break; |
| case DT_REL: name = "REL"; break; |
| case DT_RELSZ: name = "RELSZ"; break; |
| case DT_RELENT: name = "RELENT"; break; |
| case DT_PLTREL: name = "PLTREL"; break; |
| case DT_DEBUG: name = "DEBUG"; break; |
| case DT_TEXTREL: name = "TEXTREL"; break; |
| case DT_JMPREL: name = "JMPREL"; break; |
| case DT_BIND_NOW: name = "BIND_NOW"; break; |
| case DT_INIT_ARRAY: name = "INIT_ARRAY"; break; |
| case DT_FINI_ARRAY: name = "FINI_ARRAY"; break; |
| case DT_INIT_ARRAYSZ: name = "INIT_ARRAYSZ"; break; |
| case DT_FINI_ARRAYSZ: name = "FINI_ARRAYSZ"; break; |
| case DT_RUNPATH: name = "RUNPATH"; stringp = true; break; |
| case DT_FLAGS: name = "FLAGS"; break; |
| case DT_PREINIT_ARRAY: name = "PREINIT_ARRAY"; break; |
| case DT_PREINIT_ARRAYSZ: name = "PREINIT_ARRAYSZ"; break; |
| case DT_CHECKSUM: name = "CHECKSUM"; break; |
| case DT_PLTPADSZ: name = "PLTPADSZ"; break; |
| case DT_MOVEENT: name = "MOVEENT"; break; |
| case DT_MOVESZ: name = "MOVESZ"; break; |
| case DT_FEATURE: name = "FEATURE"; break; |
| case DT_POSFLAG_1: name = "POSFLAG_1"; break; |
| case DT_SYMINSZ: name = "SYMINSZ"; break; |
| case DT_SYMINENT: name = "SYMINENT"; break; |
| case DT_CONFIG: name = "CONFIG"; stringp = true; break; |
| case DT_DEPAUDIT: name = "DEPAUDIT"; stringp = true; break; |
| case DT_AUDIT: name = "AUDIT"; stringp = true; break; |
| case DT_PLTPAD: name = "PLTPAD"; break; |
| case DT_MOVETAB: name = "MOVETAB"; break; |
| case DT_SYMINFO: name = "SYMINFO"; break; |
| case DT_RELACOUNT: name = "RELACOUNT"; break; |
| case DT_RELCOUNT: name = "RELCOUNT"; break; |
| case DT_FLAGS_1: name = "FLAGS_1"; break; |
| case DT_VERSYM: name = "VERSYM"; break; |
| case DT_VERDEF: name = "VERDEF"; break; |
| case DT_VERDEFNUM: name = "VERDEFNUM"; break; |
| case DT_VERNEED: name = "VERNEED"; break; |
| case DT_VERNEEDNUM: name = "VERNEEDNUM"; break; |
| case DT_AUXILIARY: name = "AUXILIARY"; stringp = true; break; |
| case DT_USED: name = "USED"; break; |
| case DT_FILTER: name = "FILTER"; stringp = true; break; |
| case DT_GNU_HASH: name = "GNU_HASH"; break; |
| } |
| |
| fprintf (f, " %-20s ", name); |
| if (! stringp) |
| { |
| fprintf (f, "0x"); |
| bfd_fprintf_vma (abfd, f, dyn.d_un.d_val); |
| } |
| else |
| { |
| const char *string; |
| unsigned int tagv = dyn.d_un.d_val; |
| |
| string = bfd_elf_string_from_elf_section (abfd, shlink, tagv); |
| if (string == NULL) |
| goto error_return; |
| fprintf (f, "%s", string); |
| } |
| fprintf (f, "\n"); |
| } |
| |
| free (dynbuf); |
| dynbuf = NULL; |
| } |
| |
| if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL) |
| || (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL)) |
| { |
| if (! _bfd_elf_slurp_version_tables (abfd, false)) |
| return false; |
| } |
| |
| if (elf_dynverdef (abfd) != 0) |
| { |
| Elf_Internal_Verdef *t; |
| |
| fprintf (f, _("\nVersion definitions:\n")); |
| for (t = elf_tdata (abfd)->verdef; t != NULL; t = t->vd_nextdef) |
| { |
| fprintf (f, "%d 0x%2.2x 0x%8.8lx %s\n", t->vd_ndx, |
| t->vd_flags, t->vd_hash, |
| t->vd_nodename ? t->vd_nodename : "<corrupt>"); |
| if (t->vd_auxptr != NULL && t->vd_auxptr->vda_nextptr != NULL) |
| { |
| Elf_Internal_Verdaux *a; |
| |
| fprintf (f, "\t"); |
| for (a = t->vd_auxptr->vda_nextptr; |
| a != NULL; |
| a = a->vda_nextptr) |
| fprintf (f, "%s ", |
| a->vda_nodename ? a->vda_nodename : "<corrupt>"); |
| fprintf (f, "\n"); |
| } |
| } |
| } |
| |
| if (elf_dynverref (abfd) != 0) |
| { |
| Elf_Internal_Verneed *t; |
| |
| fprintf (f, _("\nVersion References:\n")); |
| for (t = elf_tdata (abfd)->verref; t != NULL; t = t->vn_nextref) |
| { |
| Elf_Internal_Vernaux *a; |
| |
| fprintf (f, _(" required from %s:\n"), |
| t->vn_filename ? t->vn_filename : "<corrupt>"); |
| for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) |
| fprintf (f, " 0x%8.8lx 0x%2.2x %2.2d %s\n", a->vna_hash, |
| a->vna_flags, a->vna_other, |
| a->vna_nodename ? a->vna_nodename : "<corrupt>"); |
| } |
| } |
| |
| return true; |
| |
| error_return: |
| free (dynbuf); |
| return false; |
| } |
| |
| /* Get version name. If BASE_P is TRUE, return "Base" for VER_FLG_BASE |
| and return symbol version for symbol version itself. */ |
| |
| const char * |
| _bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol, |
| bool base_p, |
| bool *hidden) |
| { |
| const char *version_string = NULL; |
| if (elf_dynversym (abfd) != 0 |
| && (elf_dynverdef (abfd) != 0 || elf_dynverref (abfd) != 0)) |
| { |
| unsigned int vernum = ((elf_symbol_type *) symbol)->version; |
| |
| *hidden = (vernum & VERSYM_HIDDEN) != 0; |
| vernum &= VERSYM_VERSION; |
| |
| if (vernum == 0) |
| version_string = ""; |
| else if (vernum == 1 |
| && (vernum > elf_tdata (abfd)->cverdefs |
| || (elf_tdata (abfd)->verdef[0].vd_flags |
| == VER_FLG_BASE))) |
| version_string = base_p ? "Base" : ""; |
| else if (vernum <= elf_tdata (abfd)->cverdefs) |
| { |
| const char *nodename |
| = elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; |
| version_string = ""; |
| if (base_p |
| || nodename == NULL |
| || symbol->name == NULL |
| || strcmp (symbol->name, nodename) != 0) |
| version_string = nodename; |
| } |
| else |
| { |
| Elf_Internal_Verneed *t; |
| |
| version_string = _("<corrupt>"); |
| for (t = elf_tdata (abfd)->verref; |
| t != NULL; |
| t = t->vn_nextref) |
| { |
| Elf_Internal_Vernaux *a; |
| |
| for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) |
| { |
| if (a->vna_other == vernum) |
| { |
| *hidden = true; |
| version_string = a->vna_nodename; |
| break; |
| } |
| } |
| } |
| } |
| } |
| return version_string; |
| } |
| |
| /* Display ELF-specific fields of a symbol. */ |
| |
| void |
| bfd_elf_print_symbol (bfd *abfd, |
| void *filep, |
| asymbol *symbol, |
| bfd_print_symbol_type how) |
| { |
| FILE *file = (FILE *) filep; |
| switch (how) |
| { |
| case bfd_print_symbol_name: |
| fprintf (file, "%s", symbol->name); |
| break; |
| case bfd_print_symbol_more: |
| fprintf (file, "elf "); |
| bfd_fprintf_vma (abfd, file, symbol->value); |
| fprintf (file, " %x", symbol->flags); |
| break; |
| case bfd_print_symbol_all: |
| { |
| const char *section_name; |
| const char *name = NULL; |
| const struct elf_backend_data *bed; |
| unsigned char st_other; |
| bfd_vma val; |
| const char *version_string; |
| bool hidden; |
| |
| section_name = symbol->section ? symbol->section->name : "(*none*)"; |
| |
| bed = get_elf_backend_data (abfd); |
| if (bed->elf_backend_print_symbol_all) |
| name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol); |
| |
| if (name == NULL) |
| { |
| name = symbol->name; |
| bfd_print_symbol_vandf (abfd, file, symbol); |
| } |
| |
| fprintf (file, " %s\t", section_name); |
| /* Print the "other" value for a symbol. For common symbols, |
| we've already printed the size; now print the alignment. |
| For other symbols, we have no specified alignment, and |
| we've printed the address; now print the size. */ |
| if (symbol->section && bfd_is_com_section (symbol->section)) |
| val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value; |
| else |
| val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_size; |
| bfd_fprintf_vma (abfd, file, val); |
| |
| /* If we have version information, print it. */ |
| version_string = _bfd_elf_get_symbol_version_string (abfd, |
| symbol, |
| true, |
| &hidden); |
| if (version_string) |
| { |
| if (!hidden) |
| fprintf (file, " %-11s", version_string); |
| else |
| { |
| int i; |
| |
| fprintf (file, " (%s)", version_string); |
| for (i = 10 - strlen (version_string); i > 0; --i) |
| putc (' ', file); |
| } |
| } |
| |
| /* If the st_other field is not zero, print it. */ |
| st_other = ((elf_symbol_type *) symbol)->internal_elf_sym.st_other; |
| |
| switch (st_other) |
| { |
| case 0: break; |
| case STV_INTERNAL: fprintf (file, " .internal"); break; |
| case STV_HIDDEN: fprintf (file, " .hidden"); break; |
| case STV_PROTECTED: fprintf (file, " .protected"); break; |
| default: |
| /* Some other non-defined flags are also present, so print |
| everything hex. */ |
| fprintf (file, " 0x%02x", (unsigned int) st_other); |
| } |
| |
| fprintf (file, " %s", name); |
| } |
| break; |
| } |
| } |
| |
| /* ELF .o/exec file reading */ |
| |
| /* Create a new bfd section from an ELF section header. */ |
| |
| bool |
| bfd_section_from_shdr (bfd *abfd, unsigned int shindex) |
| { |
| Elf_Internal_Shdr *hdr; |
| Elf_Internal_Ehdr *ehdr; |
| const struct elf_backend_data *bed; |
| const char *name; |
| bool ret = true; |
| |
| if (shindex >= elf_numsections (abfd)) |
| return false; |
| |
| /* PR17512: A corrupt ELF binary might contain a loop of sections via |
| sh_link or sh_info. Detect this here, by refusing to load a |
| section that we are already in the process of loading. */ |
| if (elf_tdata (abfd)->being_created[shindex]) |
| { |
| _bfd_error_handler |
| (_("%pB: warning: loop in section dependencies detected"), abfd); |
| return false; |
| } |
| elf_tdata (abfd)->being_created[shindex] = true; |
| |
| hdr = elf_elfsections (abfd)[shindex]; |
| ehdr = elf_elfheader (abfd); |
| name = bfd_elf_string_from_elf_section (abfd, ehdr->e_shstrndx, |
| hdr->sh_name); |
| if (name == NULL) |
| goto fail; |
| |
| bed = get_elf_backend_data (abfd); |
| switch (hdr->sh_type) |
| { |
| case SHT_NULL: |
| /* Inactive section. Throw it away. */ |
| goto success; |
| |
| case SHT_PROGBITS: /* Normal section with contents. */ |
| case SHT_NOBITS: /* .bss section. */ |
| case SHT_HASH: /* .hash section. */ |
| case SHT_NOTE: /* .note section. */ |
| case SHT_INIT_ARRAY: /* .init_array section. */ |
| case SHT_FINI_ARRAY: /* .fini_array section. */ |
| case SHT_PREINIT_ARRAY: /* .preinit_array section. */ |
| case SHT_GNU_LIBLIST: /* .gnu.liblist section. */ |
| case SHT_GNU_HASH: /* .gnu.hash section. */ |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
| goto success; |
| |
| case SHT_DYNAMIC: /* Dynamic linking information. */ |
| if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) |
| goto fail; |
| |
| if (hdr->sh_link > elf_numsections (abfd)) |
| { |
| /* PR 10478: Accept Solaris binaries with a sh_link |
| field set to SHN_BEFORE or SHN_AFTER. */ |
| switch (bfd_get_arch (abfd)) |
| { |
| case bfd_arch_i386: |
| case bfd_arch_sparc: |
| if (hdr->sh_link == (SHN_LORESERVE & 0xffff) /* SHN_BEFORE */ |
| || hdr->sh_link == ((SHN_LORESERVE + 1) & 0xffff) /* SHN_AFTER */) |
| break; |
| /* Otherwise fall through. */ |
| default: |
| goto fail; |
| } |
| } |
| else if (elf_elfsections (abfd)[hdr->sh_link] == NULL) |
| goto fail; |
| else if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB) |
| { |
| Elf_Internal_Shdr *dynsymhdr; |
| |
| /* The shared libraries distributed with hpux11 have a bogus |
| sh_link field for the ".dynamic" section. Find the |
| string table for the ".dynsym" section instead. */ |
| if (elf_dynsymtab (abfd) != 0) |
| { |
| dynsymhdr = elf_elfsections (abfd)[elf_dynsymtab (abfd)]; |
| hdr->sh_link = dynsymhdr->sh_link; |
| } |
| else |
| { |
| unsigned int i, num_sec; |
| |
| num_sec = elf_numsections (abfd); |
| for (i = 1; i < num_sec; i++) |
| { |
| dynsymhdr = elf_elfsections (abfd)[i]; |
| if (dynsymhdr->sh_type == SHT_DYNSYM) |
| { |
| hdr->sh_link = dynsymhdr->sh_link; |
| break; |
| } |
| } |
| } |
| } |
| goto success; |
| |
| case SHT_SYMTAB: /* A symbol table. */ |
| if (elf_onesymtab (abfd) == shindex) |
| goto success; |
| |
| if (hdr->sh_entsize != bed->s->sizeof_sym) |
| goto fail; |
| |
| if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size) |
| { |
| if (hdr->sh_size != 0) |
| goto fail; |
| /* Some assemblers erroneously set sh_info to one with a |
| zero sh_size. ld sees this as a global symbol count |
| of (unsigned) -1. Fix it here. */ |
| hdr->sh_info = 0; |
| goto success; |
| } |
| |
| /* PR 18854: A binary might contain more than one symbol table. |
| Unusual, but possible. Warn, but continue. */ |
| if (elf_onesymtab (abfd) != 0) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: warning: multiple symbol tables detected" |
| " - ignoring the table in section %u"), |
| abfd, shindex); |
| goto success; |
| } |
| elf_onesymtab (abfd) = shindex; |
| elf_symtab_hdr (abfd) = *hdr; |
| elf_elfsections (abfd)[shindex] = hdr = & elf_symtab_hdr (abfd); |
| abfd->flags |= HAS_SYMS; |
| |
| /* Sometimes a shared object will map in the symbol table. If |
| SHF_ALLOC is set, and this is a shared object, then we also |
| treat this section as a BFD section. We can not base the |
| decision purely on SHF_ALLOC, because that flag is sometimes |
| set in a relocatable object file, which would confuse the |
| linker. */ |
| if ((hdr->sh_flags & SHF_ALLOC) != 0 |
| && (abfd->flags & DYNAMIC) != 0 |
| && ! _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
| shindex)) |
| goto fail; |
| |
| /* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we |
| can't read symbols without that section loaded as well. It |
| is most likely specified by the next section header. */ |
| { |
| elf_section_list * entry; |
| unsigned int i, num_sec; |
| |
| for (entry = elf_symtab_shndx_list (abfd); entry != NULL; entry = entry->next) |
| if (entry->hdr.sh_link == shindex) |
| goto success; |
| |
| num_sec = elf_numsections (abfd); |
| for (i = shindex + 1; i < num_sec; i++) |
| { |
| Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; |
| |
| if (hdr2->sh_type == SHT_SYMTAB_SHNDX |
| && hdr2->sh_link == shindex) |
| break; |
| } |
| |
| if (i == num_sec) |
| for (i = 1; i < shindex; i++) |
| { |
| Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; |
| |
| if (hdr2->sh_type == SHT_SYMTAB_SHNDX |
| && hdr2->sh_link == shindex) |
| break; |
| } |
| |
| if (i != shindex) |
| ret = bfd_section_from_shdr (abfd, i); |
| /* else FIXME: we have failed to find the symbol table - should we issue an error ? */ |
| goto success; |
| } |
| |
| case SHT_DYNSYM: /* A dynamic symbol table. */ |
| if (elf_dynsymtab (abfd) == shindex) |
| goto success; |
| |
| if (hdr->sh_entsize != bed->s->sizeof_sym) |
| goto fail; |
| |
| if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size) |
| { |
| if (hdr->sh_size != 0) |
| goto fail; |
| |
| /* Some linkers erroneously set sh_info to one with a |
| zero sh_size. ld sees this as a global symbol count |
| of (unsigned) -1. Fix it here. */ |
| hdr->sh_info = 0; |
| goto success; |
| } |
| |
| /* PR 18854: A binary might contain more than one dynamic symbol table. |
| Unusual, but possible. Warn, but continue. */ |
| if (elf_dynsymtab (abfd) != 0) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: warning: multiple dynamic symbol tables detected" |
| " - ignoring the table in section %u"), |
| abfd, shindex); |
| goto success; |
| } |
| elf_dynsymtab (abfd) = shindex; |
| elf_tdata (abfd)->dynsymtab_hdr = *hdr; |
| elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr; |
| abfd->flags |= HAS_SYMS; |
| |
| /* Besides being a symbol table, we also treat this as a regular |
| section, so that objcopy can handle it. */ |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
| goto success; |
| |
| case SHT_SYMTAB_SHNDX: /* Symbol section indices when >64k sections. */ |
| { |
| elf_section_list * entry; |
| |
| for (entry = elf_symtab_shndx_list (abfd); entry != NULL; entry = entry->next) |
| if (entry->ndx == shindex) |
| goto success; |
| |
| entry = bfd_alloc (abfd, sizeof (*entry)); |
| if (entry == NULL) |
| goto fail; |
| entry->ndx = shindex; |
| entry->hdr = * hdr; |
| entry->next = elf_symtab_shndx_list (abfd); |
| elf_symtab_shndx_list (abfd) = entry; |
| elf_elfsections (abfd)[shindex] = & entry->hdr; |
| goto success; |
| } |
| |
| case SHT_STRTAB: /* A string table. */ |
| if (hdr->bfd_section != NULL) |
| goto success; |
| |
| if (ehdr->e_shstrndx == shindex) |
| { |
| elf_tdata (abfd)->shstrtab_hdr = *hdr; |
| elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr; |
| goto success; |
| } |
| |
| if (elf_elfsections (abfd)[elf_onesymtab (abfd)]->sh_link == shindex) |
| { |
| symtab_strtab: |
| elf_tdata (abfd)->strtab_hdr = *hdr; |
| elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->strtab_hdr; |
| goto success; |
| } |
| |
| if (elf_elfsections (abfd)[elf_dynsymtab (abfd)]->sh_link == shindex) |
| { |
| dynsymtab_strtab: |
| elf_tdata (abfd)->dynstrtab_hdr = *hdr; |
| hdr = &elf_tdata (abfd)->dynstrtab_hdr; |
| elf_elfsections (abfd)[shindex] = hdr; |
| /* We also treat this as a regular section, so that objcopy |
| can handle it. */ |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
| shindex); |
| goto success; |
| } |
| |
| /* If the string table isn't one of the above, then treat it as a |
| regular section. We need to scan all the headers to be sure, |
| just in case this strtab section appeared before the above. */ |
| if (elf_onesymtab (abfd) == 0 || elf_dynsymtab (abfd) == 0) |
| { |
| unsigned int i, num_sec; |
| |
| num_sec = elf_numsections (abfd); |
| for (i = 1; i < num_sec; i++) |
| { |
| Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; |
| if (hdr2->sh_link == shindex) |
| { |
| /* Prevent endless recursion on broken objects. */ |
| if (i == shindex) |
| goto fail; |
| if (! bfd_section_from_shdr (abfd, i)) |
| goto fail; |
| if (elf_onesymtab (abfd) == i) |
| goto symtab_strtab; |
| if (elf_dynsymtab (abfd) == i) |
| goto dynsymtab_strtab; |
| } |
| } |
| } |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
| goto success; |
| |
| case SHT_REL: |
| case SHT_RELA: |
| /* *These* do a lot of work -- but build no sections! */ |
| { |
| asection *target_sect; |
| Elf_Internal_Shdr *hdr2, **p_hdr; |
| unsigned int num_sec = elf_numsections (abfd); |
| struct bfd_elf_section_data *esdt; |
| |
| if (hdr->sh_entsize |
| != (bfd_size_type) (hdr->sh_type == SHT_REL |
| ? bed->s->sizeof_rel : bed->s->sizeof_rela)) |
| goto fail; |
| |
| /* Check for a bogus link to avoid crashing. */ |
| if (hdr->sh_link >= num_sec) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: invalid link %u for reloc section %s (index %u)"), |
| abfd, hdr->sh_link, name, shindex); |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
| shindex); |
| goto success; |
| } |
| |
| /* For some incomprehensible reason Oracle distributes |
| libraries for Solaris in which some of the objects have |
| bogus sh_link fields. It would be nice if we could just |
| reject them, but, unfortunately, some people need to use |
| them. We scan through the section headers; if we find only |
| one suitable symbol table, we clobber the sh_link to point |
| to it. I hope this doesn't break anything. |
| |
| Don't do it on executable nor shared library. */ |
| if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0 |
| && elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_SYMTAB |
| && elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_DYNSYM) |
| { |
| unsigned int scan; |
| int found; |
| |
| found = 0; |
| for (scan = 1; scan < num_sec; scan++) |
| { |
| if (elf_elfsections (abfd)[scan]->sh_type == SHT_SYMTAB |
| || elf_elfsections (abfd)[scan]->sh_type == SHT_DYNSYM) |
| { |
| if (found != 0) |
| { |
| found = 0; |
| break; |
| } |
| found = scan; |
| } |
| } |
| if (found != 0) |
| hdr->sh_link = found; |
| } |
| |
| /* Get the symbol table. */ |
| if ((elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_SYMTAB |
| || elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_DYNSYM) |
| && ! bfd_section_from_shdr (abfd, hdr->sh_link)) |
| goto fail; |
| |
| /* If this is an alloc section in an executable or shared |
| library, or the reloc section does not use the main symbol |
| table we don't treat it as a reloc section. BFD can't |
| adequately represent such a section, so at least for now, |
| we don't try. We just present it as a normal section. We |
| also can't use it as a reloc section if it points to the |
| null section, an invalid section, another reloc section, or |
| its sh_link points to the null section. */ |
| if (((abfd->flags & (DYNAMIC | EXEC_P)) != 0 |
| && (hdr->sh_flags & SHF_ALLOC) != 0) |
| || hdr->sh_link == SHN_UNDEF |
| || hdr->sh_link != elf_onesymtab (abfd) |
| || hdr->sh_info == SHN_UNDEF |
| || hdr->sh_info >= num_sec |
| || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL |
| || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA) |
| { |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
| shindex); |
| goto success; |
| } |
| |
| if (! bfd_section_from_shdr (abfd, hdr->sh_info)) |
| goto fail; |
| |
| target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info); |
| if (target_sect == NULL) |
| goto fail; |
| |
| esdt = elf_section_data (target_sect); |
| if (hdr->sh_type == SHT_RELA) |
| p_hdr = &esdt->rela.hdr; |
| else |
| p_hdr = &esdt->rel.hdr; |
| |
| /* PR 17512: file: 0b4f81b7. |
| Also see PR 24456, for a file which deliberately has two reloc |
| sections. */ |
| if (*p_hdr != NULL) |
| { |
| if (!bed->init_secondary_reloc_section (abfd, hdr, name, shindex)) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: warning: secondary relocation section '%s' " |
| "for section %pA found - ignoring"), |
| abfd, name, target_sect); |
| } |
| else |
| esdt->has_secondary_relocs = true; |
| goto success; |
| } |
| |
| hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2)); |
| if (hdr2 == NULL) |
| goto fail; |
| *hdr2 = *hdr; |
| *p_hdr = hdr2; |
| elf_elfsections (abfd)[shindex] = hdr2; |
| target_sect->reloc_count += (NUM_SHDR_ENTRIES (hdr) |
| * bed->s->int_rels_per_ext_rel); |
| target_sect->flags |= SEC_RELOC; |
| target_sect->relocation = NULL; |
| target_sect->rel_filepos = hdr->sh_offset; |
| /* In the section to which the relocations apply, mark whether |
| its relocations are of the REL or RELA variety. */ |
| if (hdr->sh_size != 0) |
| { |
| if (hdr->sh_type == SHT_RELA) |
| target_sect->use_rela_p = 1; |
| } |
| abfd->flags |= HAS_RELOC; |
| goto success; |
| } |
| |
| case SHT_GNU_verdef: |
| elf_dynverdef (abfd) = shindex; |
| elf_tdata (abfd)->dynverdef_hdr = *hdr; |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
| goto success; |
| |
| case SHT_GNU_versym: |
| if (hdr->sh_entsize != sizeof (Elf_External_Versym)) |
| goto fail; |
| |
| elf_dynversym (abfd) = shindex; |
| elf_tdata (abfd)->dynversym_hdr = *hdr; |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
| goto success; |
| |
| case SHT_GNU_verneed: |
| elf_dynverref (abfd) = shindex; |
| elf_tdata (abfd)->dynverref_hdr = *hdr; |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
| goto success; |
| |
| case SHT_SHLIB: |
| goto success; |
| |
| case SHT_GROUP: |
| if (! IS_VALID_GROUP_SECTION_HEADER (hdr, GRP_ENTRY_SIZE)) |
| goto fail; |
| |
| if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) |
| goto fail; |
| |
| goto success; |
| |
| default: |
| /* Possibly an attributes section. */ |
| if (hdr->sh_type == SHT_GNU_ATTRIBUTES |
| || hdr->sh_type == bed->obj_attrs_section_type) |
| { |
| if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) |
| goto fail; |
| _bfd_elf_parse_attributes (abfd, hdr); |
| goto success; |
| } |
| |
| /* Check for any processor-specific section types. */ |
| if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex)) |
| goto success; |
| |
| if (hdr->sh_type >= SHT_LOUSER && hdr->sh_type <= SHT_HIUSER) |
| { |
| if ((hdr->sh_flags & SHF_ALLOC) != 0) |
| /* FIXME: How to properly handle allocated section reserved |
| for applications? */ |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: unknown type [%#x] section `%s'"), |
| abfd, hdr->sh_type, name); |
| else |
| { |
| /* Allow sections reserved for applications. */ |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
| shindex); |
| goto success; |
| } |
| } |
| else if (hdr->sh_type >= SHT_LOPROC |
| && hdr->sh_type <= SHT_HIPROC) |
| /* FIXME: We should handle this section. */ |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: unknown type [%#x] section `%s'"), |
| abfd, hdr->sh_type, name); |
| else if (hdr->sh_type >= SHT_LOOS && hdr->sh_type <= SHT_HIOS) |
| { |
| /* Unrecognised OS-specific sections. */ |
| if ((hdr->sh_flags & SHF_OS_NONCONFORMING) != 0) |
| /* SHF_OS_NONCONFORMING indicates that special knowledge is |
| required to correctly process the section and the file should |
| be rejected with an error message. */ |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: unknown type [%#x] section `%s'"), |
| abfd, hdr->sh_type, name); |
| else |
| { |
| /* Otherwise it should be processed. */ |
| ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
| goto success; |
| } |
| } |
| else |
| /* FIXME: We should handle this section. */ |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: unknown type [%#x] section `%s'"), |
| abfd, hdr->sh_type, name); |
| |
| goto fail; |
| } |
| |
| fail: |
| ret = false; |
| success: |
| elf_tdata (abfd)->being_created[shindex] = false; |
| return ret; |
| } |
| |
| /* Return the local symbol specified by ABFD, R_SYMNDX. */ |
| |
| Elf_Internal_Sym * |
| bfd_sym_from_r_symndx (struct sym_cache *cache, |
| bfd *abfd, |
| unsigned long r_symndx) |
| { |
| unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE; |
| |
| if (cache->abfd != abfd || cache->indx[ent] != r_symndx) |
| { |
| Elf_Internal_Shdr *symtab_hdr; |
| unsigned char esym[sizeof (Elf64_External_Sym)]; |
| Elf_External_Sym_Shndx eshndx; |
| |
| symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
| if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx, |
| &cache->sym[ent], esym, &eshndx) == NULL) |
| return NULL; |
| |
| if (cache->abfd != abfd) |
| { |
| memset (cache->indx, -1, sizeof (cache->indx)); |
| cache->abfd = abfd; |
| } |
| cache->indx[ent] = r_symndx; |
| } |
| |
| return &cache->sym[ent]; |
| } |
| |
| /* Given an ELF section number, retrieve the corresponding BFD |
| section. */ |
| |
| asection * |
| bfd_section_from_elf_index (bfd *abfd, unsigned int sec_index) |
| { |
| if (sec_index >= elf_numsections (abfd)) |
| return NULL; |
| return elf_elfsections (abfd)[sec_index]->bfd_section; |
| } |
| |
| static const struct bfd_elf_special_section special_sections_b[] = |
| { |
| { STRING_COMMA_LEN (".bss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_c[] = |
| { |
| { STRING_COMMA_LEN (".comment"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".ctf"), 0, SHT_PROGBITS, 0 }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_d[] = |
| { |
| { STRING_COMMA_LEN (".data"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".data1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, |
| /* There are more DWARF sections than these, but they needn't be added here |
| unless you have to cope with broken compilers that don't emit section |
| attributes or you want to help the user writing assembler. */ |
| { STRING_COMMA_LEN (".debug"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".debug_line"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".debug_info"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".debug_abbrev"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".debug_aranges"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".dynamic"), 0, SHT_DYNAMIC, SHF_ALLOC }, |
| { STRING_COMMA_LEN (".dynstr"), 0, SHT_STRTAB, SHF_ALLOC }, |
| { STRING_COMMA_LEN (".dynsym"), 0, SHT_DYNSYM, SHF_ALLOC }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_f[] = |
| { |
| { STRING_COMMA_LEN (".fini"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, |
| { STRING_COMMA_LEN (".fini_array"), -2, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE }, |
| { NULL, 0 , 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_g[] = |
| { |
| { STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".gnu.linkonce.n"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".gnu.linkonce.p"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".gnu.lto_"), -1, SHT_PROGBITS, SHF_EXCLUDE }, |
| { STRING_COMMA_LEN (".got"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".gnu.version"), 0, SHT_GNU_versym, 0 }, |
| { STRING_COMMA_LEN (".gnu.version_d"), 0, SHT_GNU_verdef, 0 }, |
| { STRING_COMMA_LEN (".gnu.version_r"), 0, SHT_GNU_verneed, 0 }, |
| { STRING_COMMA_LEN (".gnu.liblist"), 0, SHT_GNU_LIBLIST, SHF_ALLOC }, |
| { STRING_COMMA_LEN (".gnu.conflict"), 0, SHT_RELA, SHF_ALLOC }, |
| { STRING_COMMA_LEN (".gnu.hash"), 0, SHT_GNU_HASH, SHF_ALLOC }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_h[] = |
| { |
| { STRING_COMMA_LEN (".hash"), 0, SHT_HASH, SHF_ALLOC }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_i[] = |
| { |
| { STRING_COMMA_LEN (".init"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, |
| { STRING_COMMA_LEN (".init_array"), -2, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".interp"), 0, SHT_PROGBITS, 0 }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_l[] = |
| { |
| { STRING_COMMA_LEN (".line"), 0, SHT_PROGBITS, 0 }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_n[] = |
| { |
| { STRING_COMMA_LEN (".noinit"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".note.GNU-stack"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".note"), -1, SHT_NOTE, 0 }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_p[] = |
| { |
| { STRING_COMMA_LEN (".persistent.bss"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".persistent"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".preinit_array"), -2, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE }, |
| { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_r[] = |
| { |
| { STRING_COMMA_LEN (".rodata"), -2, SHT_PROGBITS, SHF_ALLOC }, |
| { STRING_COMMA_LEN (".rodata1"), 0, SHT_PROGBITS, SHF_ALLOC }, |
| { STRING_COMMA_LEN (".rela"), -1, SHT_RELA, 0 }, |
| { STRING_COMMA_LEN (".rel"), -1, SHT_REL, 0 }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_s[] = |
| { |
| { STRING_COMMA_LEN (".shstrtab"), 0, SHT_STRTAB, 0 }, |
| { STRING_COMMA_LEN (".strtab"), 0, SHT_STRTAB, 0 }, |
| { STRING_COMMA_LEN (".symtab"), 0, SHT_SYMTAB, 0 }, |
| /* See struct bfd_elf_special_section declaration for the semantics of |
| this special case where .prefix_length != strlen (.prefix). */ |
| { ".stabstr", 5, 3, SHT_STRTAB, 0 }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_t[] = |
| { |
| { STRING_COMMA_LEN (".text"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, |
| { STRING_COMMA_LEN (".tbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, |
| { STRING_COMMA_LEN (".tdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section special_sections_z[] = |
| { |
| { STRING_COMMA_LEN (".zdebug_line"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".zdebug_info"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".zdebug_abbrev"), 0, SHT_PROGBITS, 0 }, |
| { STRING_COMMA_LEN (".zdebug_aranges"), 0, SHT_PROGBITS, 0 }, |
| { NULL, 0, 0, 0, 0 } |
| }; |
| |
| static const struct bfd_elf_special_section * const special_sections[] = |
| { |
| special_sections_b, /* 'b' */ |
| special_sections_c, /* 'c' */ |
| special_sections_d, /* 'd' */ |
| NULL, /* 'e' */ |
| special_sections_f, /* 'f' */ |
| special_sections_g, /* 'g' */ |
| special_sections_h, /* 'h' */ |
| special_sections_i, /* 'i' */ |
| NULL, /* 'j' */ |
| NULL, /* 'k' */ |
| special_sections_l, /* 'l' */ |
| NULL, /* 'm' */ |
| special_sections_n, /* 'n' */ |
| NULL, /* 'o' */ |
| special_sections_p, /* 'p' */ |
| NULL, /* 'q' */ |
| special_sections_r, /* 'r' */ |
| special_sections_s, /* 's' */ |
| special_sections_t, /* 't' */ |
| NULL, /* 'u' */ |
| NULL, /* 'v' */ |
| NULL, /* 'w' */ |
| NULL, /* 'x' */ |
| NULL, /* 'y' */ |
| special_sections_z /* 'z' */ |
| }; |
| |
| const struct bfd_elf_special_section * |
| _bfd_elf_get_special_section (const char *name, |
| const struct bfd_elf_special_section *spec, |
| unsigned int rela) |
| { |
| int i; |
| int len; |
| |
| len = strlen (name); |
| |
| for (i = 0; spec[i].prefix != NULL; i++) |
| { |
| int suffix_len; |
| int prefix_len = spec[i].prefix_length; |
| |
| if (len < prefix_len) |
| continue; |
| if (memcmp (name, spec[i].prefix, prefix_len) != 0) |
| continue; |
| |
| suffix_len = spec[i].suffix_length; |
| if (suffix_len <= 0) |
| { |
| if (name[prefix_len] != 0) |
| { |
| if (suffix_len == 0) |
| continue; |
| if (name[prefix_len] != '.' |
| && (suffix_len == -2 |
| || (rela && spec[i].type == SHT_REL))) |
| continue; |
| } |
| } |
| else |
| { |
| if (len < prefix_len + suffix_len) |
| continue; |
| if (memcmp (name + len - suffix_len, |
| spec[i].prefix + prefix_len, |
| suffix_len) != 0) |
| continue; |
| } |
| return &spec[i]; |
| } |
| |
| return NULL; |
| } |
| |
| const struct bfd_elf_special_section * |
| _bfd_elf_get_sec_type_attr (bfd *abfd, asection *sec) |
| { |
| int i; |
| const struct bfd_elf_special_section *spec; |
| const struct elf_backend_data *bed; |
| |
| /* See if this is one of the special sections. */ |
| if (sec->name == NULL) |
| return NULL; |
| |
| bed = get_elf_backend_data (abfd); |
| spec = bed->special_sections; |
| if (spec) |
| { |
| spec = _bfd_elf_get_special_section (sec->name, |
| bed->special_sections, |
| sec->use_rela_p); |
| if (spec != NULL) |
| return spec; |
| } |
| |
| if (sec->name[0] != '.') |
| return NULL; |
| |
| i = sec->name[1] - 'b'; |
| if (i < 0 || i > 'z' - 'b') |
| return NULL; |
| |
| spec = special_sections[i]; |
| |
| if (spec == NULL) |
| return NULL; |
| |
| return _bfd_elf_get_special_section (sec->name, spec, sec->use_rela_p); |
| } |
| |
| bool |
| _bfd_elf_new_section_hook (bfd *abfd, asection *sec) |
| { |
| struct bfd_elf_section_data *sdata; |
| const struct elf_backend_data *bed; |
| const struct bfd_elf_special_section *ssect; |
| |
| sdata = (struct bfd_elf_section_data *) sec->used_by_bfd; |
| if (sdata == NULL) |
| { |
| sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd, |
| sizeof (*sdata)); |
| if (sdata == NULL) |
| return false; |
| sec->used_by_bfd = sdata; |
| } |
| |
| /* Indicate whether or not this section should use RELA relocations. */ |
| bed = get_elf_backend_data (abfd); |
| sec->use_rela_p = bed->default_use_rela_p; |
| |
| /* Set up ELF section type and flags for newly created sections, if |
| there is an ABI mandated section. */ |
| ssect = (*bed->get_sec_type_attr) (abfd, sec); |
| if (ssect != NULL) |
| { |
| elf_section_type (sec) = ssect->type; |
| elf_section_flags (sec) = ssect->attr; |
| } |
| |
| return _bfd_generic_new_section_hook (abfd, sec); |
| } |
| |
| /* Create a new bfd section from an ELF program header. |
| |
| Since program segments have no names, we generate a synthetic name |
| of the form segment<NUM>, where NUM is generally the index in the |
| program header table. For segments that are split (see below) we |
| generate the names segment<NUM>a and segment<NUM>b. |
| |
| Note that some program segments may have a file size that is different than |
| (less than) the memory size. All this means is that at execution the |
| system must allocate the amount of memory specified by the memory size, |
| |