diff options
author | Alan Modra <amodra@bigpond.net.au> | 2003-07-31 14:34:13 +0000 |
---|---|---|
committer | Alan Modra <amodra@bigpond.net.au> | 2003-07-31 14:34:13 +0000 |
commit | ab0bb610e247682af68055ae862692e2f4961d2c (patch) | |
tree | b4e6e384fb2f140988b131ea6555a7a42372fb2f /bfd/elf64-ppc.c | |
parent | 6be1b939402ffceee4c0f4ae29ea99bae7c7db28 (diff) | |
download | gdb-ab0bb610e247682af68055ae862692e2f4961d2c.tar.gz |
* elf.c (bfd_section_from_r_symndx): Test for SHN_UNDEF.
* elf64-ppc.c (get_fdh): New function, split out from
ppc64_elf_edit_opd.
(ppc64_elf_check_relocs): Use get_fdh.
(func_desc_adjust): Likewise. Tidy.
(ppc64_elf_edit_opd): Tighten reloc checks. Free local_syms on error
exit. Use get_fdh. Account for superfluous dynamic relocs.
(ppc64_elf_relocate_section): Warning fix.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r-- | bfd/elf64-ppc.c | 362 |
1 files changed, 184 insertions, 178 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 07ba432c4ee..50cb5d878a9 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -3509,6 +3509,31 @@ update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend) return TRUE; } +/* Find the function descriptor hash entry from the given function code + hash entry FH. Link the entries via their OH fields. */ +static struct ppc_link_hash_entry * +get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab) +{ + struct ppc_link_hash_entry *fdh = (struct ppc_link_hash_entry *) fh->oh; + + if (fdh == NULL) + { + const char *fd_name = fh->elf.root.root.string + 1; + + fdh = (struct ppc_link_hash_entry *) + elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE); + if (fdh != NULL) + { + fdh->is_func_descriptor = 1; + fdh->oh = &fh->elf; + fh->is_func = 1; + fh->oh = &fdh->elf; + } + } + + return fdh; +} + /* Look through the relocs for a section during the first phase, and calculate needed space in the global offset table, procedure linkage table, and dynamic reloc sections. */ @@ -3837,19 +3862,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, && h != NULL && h->root.root.string[0] == '.' && h->root.root.string[1] != 0) - { - struct elf_link_hash_entry *fdh; + get_fdh ((struct ppc_link_hash_entry *) h, htab); - fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1, - FALSE, FALSE, FALSE); - if (fdh != NULL) - { - ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1; - ((struct ppc_link_hash_entry *) fdh)->oh = h; - ((struct ppc_link_hash_entry *) h)->is_func = 1; - ((struct ppc_link_hash_entry *) h)->oh = fdh; - } - } if (opd_sym_map != NULL && h == NULL && rel + 1 < rel_end @@ -4247,117 +4261,118 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) struct bfd_link_info *info; struct ppc_link_hash_table *htab; struct plt_entry *ent; + struct ppc_link_hash_entry *fh; + struct ppc_link_hash_entry *fdh; + bfd_boolean force_local; - if (h->root.type == bfd_link_hash_indirect) + fh = (struct ppc_link_hash_entry *) h; + if (fh->elf.root.type == bfd_link_hash_indirect) return TRUE; - if (h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + if (fh->elf.root.type == bfd_link_hash_warning) + fh = (struct ppc_link_hash_entry *) fh->elf.root.u.i.link; info = inf; htab = ppc_hash_table (info); /* If this is a function code symbol, transfer dynamic linking information to the function descriptor symbol. */ - if (!((struct ppc_link_hash_entry *) h)->is_func) + if (!fh->is_func) return TRUE; - if (h->root.type == bfd_link_hash_undefweak - && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR)) + if (fh->elf.root.type == bfd_link_hash_undefweak + && (fh->elf.elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR)) htab->have_undefweak = TRUE; - for (ent = h->plt.plist; ent != NULL; ent = ent->next) + for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next) if (ent->plt.refcount > 0) break; - if (ent != NULL - && h->root.root.string[0] == '.' - && h->root.root.string[1] != '\0') - { - struct elf_link_hash_entry *fdh = ((struct ppc_link_hash_entry *) h)->oh; - bfd_boolean force_local; + if (ent == NULL + || fh->elf.root.root.string[0] != '.' + || fh->elf.root.root.string[1] == '\0') + return TRUE; - /* Find the corresponding function descriptor symbol. Create it - as undefined if necessary. */ + /* Find the corresponding function descriptor symbol. Create it + as undefined if necessary. */ - if (fdh == NULL) - fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1, - FALSE, FALSE, TRUE); + fdh = get_fdh (fh, htab); + if (fdh != NULL) + while (fdh->elf.root.type == bfd_link_hash_indirect + || fdh->elf.root.type == bfd_link_hash_warning) + fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link; - if (fdh == NULL - && info->shared - && (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak)) + if (fdh == NULL + && info->shared + && (fh->elf.root.type == bfd_link_hash_undefined + || fh->elf.root.type == bfd_link_hash_undefweak)) + { + bfd *abfd; + asymbol *newsym; + struct bfd_link_hash_entry *bh; + + abfd = fh->elf.root.u.undef.abfd; + newsym = bfd_make_empty_symbol (abfd); + newsym->name = fh->elf.root.root.string + 1; + newsym->section = bfd_und_section_ptr; + newsym->value = 0; + newsym->flags = BSF_OBJECT; + if (fh->elf.root.type == bfd_link_hash_undefweak) + newsym->flags |= BSF_WEAK; + + bh = &fdh->elf.root; + if ( !(_bfd_generic_link_add_one_symbol + (info, abfd, newsym->name, newsym->flags, + newsym->section, newsym->value, NULL, FALSE, FALSE, &bh))) { - bfd *abfd; - asymbol *newsym; - struct bfd_link_hash_entry *bh; - - abfd = h->root.u.undef.abfd; - newsym = bfd_make_empty_symbol (abfd); - newsym->name = h->root.root.string + 1; - newsym->section = bfd_und_section_ptr; - newsym->value = 0; - newsym->flags = BSF_OBJECT; - if (h->root.type == bfd_link_hash_undefweak) - newsym->flags |= BSF_WEAK; - - bh = &fdh->root; - if ( !(_bfd_generic_link_add_one_symbol - (info, abfd, newsym->name, newsym->flags, - newsym->section, newsym->value, NULL, FALSE, FALSE, &bh))) - { - return FALSE; - } - fdh = (struct elf_link_hash_entry *) bh; - fdh->elf_link_hash_flags &= ~ELF_LINK_NON_ELF; - fdh->size = 24; - fdh->type = STT_OBJECT; + return FALSE; } + fdh = (struct ppc_link_hash_entry *) bh; + fdh->elf.elf_link_hash_flags &= ~ELF_LINK_NON_ELF; + fdh->elf.size = 24; + fdh->elf.type = STT_OBJECT; + } - if (fdh != NULL - && (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0 - && (info->shared - || (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - || (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0 - || (fdh->root.type == bfd_link_hash_undefweak - && ELF_ST_VISIBILITY (fdh->other) == STV_DEFAULT))) + if (fdh != NULL + && (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0 + && (info->shared + || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0 + || (fdh->elf.root.type == bfd_link_hash_undefweak + && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT))) + { + if (fdh->elf.dynindx == -1) + if (! bfd_elf64_link_record_dynamic_symbol (info, &fdh->elf)) + return FALSE; + fdh->elf.elf_link_hash_flags + |= (fh->elf.elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_HASH_REF_REGULAR_NONWEAK + | ELF_LINK_NON_GOT_REF)); + if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT) { - if (fdh->dynindx == -1) - if (! bfd_elf64_link_record_dynamic_symbol (info, fdh)) - return FALSE; - fdh->elf_link_hash_flags |= (h->elf_link_hash_flags - & (ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_REF_DYNAMIC - | ELF_LINK_HASH_REF_REGULAR_NONWEAK - | ELF_LINK_NON_GOT_REF)); - if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - { - fdh->plt.plist = h->plt.plist; - fdh->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; - } - ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1; - ((struct ppc_link_hash_entry *) fdh)->oh = h; - ((struct ppc_link_hash_entry *) h)->oh = fdh; + fdh->elf.plt.plist = fh->elf.plt.plist; + fdh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; } - - /* Now that the info is on the function descriptor, clear the - function code sym info. Any function code syms for which we - don't have a definition in a regular file, we force local. - This prevents a shared library from exporting syms that have - been imported from another library. Function code syms that - are really in the library we must leave global to prevent the - linker dragging in a definition from a static library. */ - force_local = (info->shared - && ((h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0 - || fdh == NULL - || (fdh->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0 - || (fdh->elf_link_hash_flags - & ELF_LINK_FORCED_LOCAL) != 0)); - _bfd_elf_link_hash_hide_symbol (info, h, force_local); + fdh->is_func_descriptor = 1; + fdh->oh = &fh->elf; + fh->oh = &fdh->elf; } + /* Now that the info is on the function descriptor, clear the + function code sym info. Any function code syms for which we + don't have a definition in a regular file, we force local. + This prevents a shared library from exporting syms that have + been imported from another library. Function code syms that + are really in the library we must leave global to prevent the + linker dragging in a definition from a static library. */ + force_local + = (info->shared + && ((fh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + || fdh == NULL + || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + || (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)); + _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local); + return TRUE; } @@ -4874,7 +4889,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) need_edit = FALSE; offset = 0; relend = relstart + sec->reloc_count; - for (rel = relstart; rel < relend; rel++) + for (rel = relstart; rel < relend; ) { enum elf_ppc64_reloc_type r_type; unsigned long r_symndx; @@ -4885,26 +4900,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) /* .opd contains a regular array of 24 byte entries. We're only interested in the reloc pointing to a function entry point. */ - r_type = ELF64_R_TYPE (rel->r_info); - if (r_type == R_PPC64_TOC) - continue; - - if (r_type != R_PPC64_ADDR64) - { - (*_bfd_error_handler) - (_("%s: unexpected reloc type %u in .opd section"), - bfd_archive_filename (ibfd), r_type); - need_edit = FALSE; - break; - } - - if (rel + 1 >= relend) - continue; - r_type = ELF64_R_TYPE ((rel + 1)->r_info); - if (r_type != R_PPC64_TOC) - continue; - - if (rel->r_offset != offset) + if (rel->r_offset != offset + || rel + 1 >= relend + || (rel + 1)->r_offset != offset + 8) { /* If someone messes with .opd alignment then after a "ld -r" we might have padding in the middle of .opd. @@ -4918,10 +4916,20 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) break; } + if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64 + || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC) + { + (*_bfd_error_handler) + (_("%s: unexpected reloc type %u in .opd section"), + bfd_archive_filename (ibfd), r_type); + need_edit = FALSE; + break; + } + r_symndx = ELF64_R_SYM (rel->r_info); if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx, ibfd)) - goto error_free_rel; + goto error_ret; if (sym_sec == NULL || sym_sec->owner == NULL) { @@ -4951,6 +4959,11 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) need_edit = TRUE; offset += 24; + rel += 2; + /* Allow for the possibility of a reloc on the third word. */ + if (rel < relend + && rel->r_offset == offset - 8) + rel += 1; } if (need_edit) @@ -4970,10 +4983,10 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) || !bfd_get_section_contents (ibfd, sec, loc, 0, sec->_raw_size)) { + error_ret: if (local_syms != NULL && symtab_hdr->contents != (unsigned char *) local_syms) free (local_syms); - error_free_rel: if (elf_section_data (sec)->relocs != relstart) free (relstart); return FALSE; @@ -4991,16 +5004,22 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) offset = 0; for (rel = relstart; rel < relend; rel++) { + unsigned long r_symndx; + asection *sym_sec; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + + r_symndx = ELF64_R_SYM (rel->r_info); + if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, + r_symndx, ibfd)) + goto error_ret; + if (rel->r_offset == offset) { - unsigned long r_symndx; - asection *sym_sec; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - - r_symndx = ELF64_R_SYM (rel->r_info); - get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_symndx, ibfd); + struct ppc_link_hash_entry *fdh = NULL; + if (h != NULL) + fdh = get_fdh ((struct ppc_link_hash_entry *) h, + ppc_hash_table (info)); skip = (sym_sec->owner != ibfd || sym_sec->output_section == bfd_abs_section_ptr); @@ -5010,27 +5029,6 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) { /* Arrange for the function descriptor sym to be dropped. */ - struct ppc_link_hash_entry *fdh; - struct ppc_link_hash_entry *fh; - - fh = (struct ppc_link_hash_entry *) h; - fdh = (struct ppc_link_hash_entry *) fh->oh; - if (fdh == NULL) - { - const char *fd_name; - struct ppc_link_hash_table *htab; - - fd_name = h->root.root.string + 1; - htab = ppc_hash_table (info); - fdh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, fd_name, - FALSE, FALSE, FALSE); - fdh->is_func_descriptor = 1; - fdh->oh = &fh->elf; - fh->is_func = 1; - fh->oh = &fdh->elf; - } - fdh->elf.root.u.def.value = 0; fdh->elf.root.u.def.section = sym_sec; } @@ -5045,27 +5043,6 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) to this location in the opd section. We've checked above that opd relocs are ordered. */ - struct ppc_link_hash_entry *fdh; - struct ppc_link_hash_entry *fh; - - fh = (struct ppc_link_hash_entry *) h; - fdh = (struct ppc_link_hash_entry *) fh->oh; - if (fdh == NULL) - { - const char *fd_name; - struct ppc_link_hash_table *htab; - - fd_name = h->root.root.string + 1; - htab = ppc_hash_table (info); - fdh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, fd_name, - FALSE, FALSE, FALSE); - fdh->is_func_descriptor = 1; - fdh->oh = &fh->elf; - fh->is_func = 1; - fh->oh = &fdh->elf; - } - fdh->elf.root.u.def.value = wptr - sec->contents; } else @@ -5087,11 +5064,41 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) offset += 24; } - /* We need to adjust any reloc offsets to point to the - new opd entries. While we're at it, we may as well - remove redundant relocs. */ - if (!skip) + if (skip) + { + BFD_ASSERT (MUST_BE_DYN_RELOC (ELF64_R_TYPE (rel->r_info))); + if (info->shared) + { + /* We won't be needing dynamic relocs here. */ + struct ppc_dyn_relocs **pp; + struct ppc_dyn_relocs *p; + + if (h != NULL) + pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs; + else if (sym_sec != NULL) + pp = ((struct ppc_dyn_relocs **) + &elf_section_data (sym_sec)->local_dynrel); + else + pp = ((struct ppc_dyn_relocs **) + &elf_section_data (sec)->local_dynrel); + while ((p = *pp) != NULL) + { + if (p->sec == sec) + { + p->count -= 1; + if (p->count == 0) + *pp = p->next; + break; + } + pp = &p->next; + } + } + } + else { + /* We need to adjust any reloc offsets to point to the + new opd entries. While we're at it, we may as well + remove redundant relocs. */ rel->r_offset += wptr - rptr; if (write_rel != rel) memcpy (write_rel, rel, sizeof (*rel)); @@ -7282,7 +7289,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_vma relocation; bfd_boolean unresolved_reloc; bfd_boolean warned; - long insn, mask; + unsigned long insn, mask; struct ppc_stub_hash_entry *stub_entry; bfd_vma max_br_offset; bfd_vma from; @@ -7437,7 +7444,6 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (tls_mask != 0 && (tls_mask & TLS_TPREL) == 0) { - bfd_vma insn; toctprel: insn = bfd_get_32 (output_bfd, contents + rel->r_offset - 2); insn &= 31 << 21; @@ -7463,7 +7469,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (tls_mask != 0 && (tls_mask & TLS_TPREL) == 0) { - bfd_vma insn, rtra; + bfd_vma rtra; insn = bfd_get_32 (output_bfd, contents + rel->r_offset); if ((insn & ((0x3f << 26) | (31 << 11))) == ((31 << 26) | (13 << 11))) |