diff options
author | Ian Lance Taylor <ian@airs.com> | 1997-06-24 02:28:03 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 1997-06-24 02:28:03 +0000 |
commit | 541a4b542560152199f9f71e49f49b6c12154bbe (patch) | |
tree | d7c50d53a815df8515d8a8bd06f57b2b09bc3e83 /bfd/elflink.h | |
parent | 044d7d4944ac9e60f89ea130a2a8c3e49ef0d757 (diff) | |
download | gdb-541a4b542560152199f9f71e49f49b6c12154bbe.zip gdb-541a4b542560152199f9f71e49f49b6c12154bbe.tar.gz gdb-541a4b542560152199f9f71e49f49b6c12154bbe.tar.bz2 |
* elflink.h (elf_merge_symbol): In the case of a new defined
symbol overriding an old defined symbol, return the hash table
entry which we modify, even if it is the target of an
indirection.
(elf_link_add_object_symbols): If the real name of the symbol gets
overridden, convert the versioned symbol into an indirect symbol
to the real symbol.
Diffstat (limited to 'bfd/elflink.h')
-rw-r--r-- | bfd/elflink.h | 171 |
1 files changed, 115 insertions, 56 deletions
diff --git a/bfd/elflink.h b/bfd/elflink.h index f724650..2cbd80a 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -568,6 +568,13 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, NULL, so that it is correct for a regular symbol. */ h->verinfo.vertree = NULL; + + /* In this special case, if H is the target of an indirection, + we want the caller to frob with H rather than with the + indirect symbol. That will permit the caller to redefine the + target of the indirection, rather than the indirect symbol + itself. */ + *sym_hash = h; } /* Handle the special case of a new common symbol merging with an @@ -1376,70 +1383,113 @@ elf_link_add_object_symbols (abfd, info) bfd_ind_section_ptr, (bfd_vma) 0, name, false, collect, (struct bfd_link_hash_entry **) &hi))) goto error_return; + } + else + { + /* In this case the symbol named SHORTNAME is + overriding the indirect symbol we want to + add. We were planning on making SHORTNAME an + indirect symbol referring to NAME. SHORTNAME + is the name without a version. NAME is the + fully versioned name, and it is the default + version. + + Overriding means that we already saw a + definition for the symbol SHORTNAME in a + regular object, and it is overriding the + symbol defined in the dynamic object. + + When this happens, we actually want to change + NAME, the symbol we just added, to refer to + SHORTNAME. This will cause references to + NAME in the shared object to become + references to SHORTNAME in the regular + object. This is what we expect when we + override a function in a shared object: that + the references in the shared object will be + mapped to the definition in the regular + object. */ + + h->root.type = bfd_link_hash_indirect; + h->root.u.i.link = (struct bfd_link_hash_entry *) hi; + if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) + { + h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC; + hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC; + if (! _bfd_elf_link_record_dynamic_symbol (info, hi)) + goto error_return; + } - /* If there is a duplicate definition somewhere, - then HI may not point to an indirect symbol. - We will have reported an error to the user in - that case. */ + /* Now set HI to H, so that the following code + will set the other fields correctly. */ + hi = h; + } - if (hi->root.type == bfd_link_hash_indirect) + /* If there is a duplicate definition somewhere, + then HI may not point to an indirect symbol. We + will have reported an error to the user in that + case. */ + + if (hi->root.type == bfd_link_hash_indirect) + { + struct elf_link_hash_entry *ht; + + /* If the symbol became indirect, then we assume + that we have not seen a definition before. */ + BFD_ASSERT ((hi->elf_link_hash_flags + & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_DEF_REGULAR)) + == 0); + + ht = (struct elf_link_hash_entry *) hi->root.u.i.link; + + /* Copy down any references that we may have + already seen to the symbol which just became + indirect. */ + ht->elf_link_hash_flags |= + (hi->elf_link_hash_flags + & (ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_HASH_REF_REGULAR)); + + /* Copy over the global table offset entry. + This may have been already set up by a + check_relocs routine. */ + if (ht->got_offset == (bfd_vma) -1) { - /* If the symbol became indirect, then we - assume that we have not seen a definition - before. */ - BFD_ASSERT ((hi->elf_link_hash_flags - & (ELF_LINK_HASH_DEF_DYNAMIC - | ELF_LINK_HASH_DEF_REGULAR)) - == 0); + ht->got_offset = hi->got_offset; + hi->got_offset = (bfd_vma) -1; + } + BFD_ASSERT (hi->got_offset == (bfd_vma) -1); - /* Copy down any references that we may have - already seen to the symbol which just - became indirect. */ - h->elf_link_hash_flags |= - (hi->elf_link_hash_flags - & (ELF_LINK_HASH_REF_DYNAMIC - | ELF_LINK_HASH_REF_REGULAR)); + if (ht->dynindx == -1) + { + ht->dynindx = hi->dynindx; + ht->dynstr_index = hi->dynstr_index; + hi->dynindx = -1; + hi->dynstr_index = 0; + } + BFD_ASSERT (hi->dynindx == -1); - /* Copy over the global table offset entry. - This may have been already set up by a - check_relocs routine. */ - if (h->got_offset == (bfd_vma) -1) - { - h->got_offset = hi->got_offset; - hi->got_offset = (bfd_vma) -1; - } - BFD_ASSERT (hi->got_offset == (bfd_vma) -1); + /* FIXME: There may be other information to copy + over for particular targets. */ - if (h->dynindx == -1) + /* See if the new flags lead us to realize that + the symbol must be dynamic. */ + if (! dynsym) + { + if (! dynamic) { - h->dynindx = hi->dynindx; - h->dynstr_index = hi->dynstr_index; - hi->dynindx = -1; - hi->dynstr_index = 0; + if (info->shared + || ((hi->elf_link_hash_flags + & ELF_LINK_HASH_REF_DYNAMIC) + != 0)) + dynsym = true; } - BFD_ASSERT (hi->dynindx == -1); - - /* FIXME: There may be other information to - copy over for particular targets. */ - - /* See if the new flags lead us to realize - that the symbol must be dynamic. */ - if (! dynsym) + else { - if (! dynamic) - { - if (info->shared - || ((hi->elf_link_hash_flags - & ELF_LINK_HASH_REF_DYNAMIC) - != 0)) - dynsym = true; - } - else - { - if ((hi->elf_link_hash_flags - & ELF_LINK_HASH_REF_REGULAR) != 0) - dynsym = true; - } + if ((hi->elf_link_hash_flags + & ELF_LINK_HASH_REF_REGULAR) != 0) + dynsym = true; } } } @@ -1460,7 +1510,16 @@ elf_link_add_object_symbols (abfd, info) &type_change_ok, &size_change_ok)) goto error_return; - if (! override) + if (override) + { + /* Here SHORTNAME is a versioned name, so we + don't expect to see the type of override we + do in the case above. */ + (*_bfd_error_handler) + ("%s: warning: unexpected redefinition of `%s'", + bfd_get_filename (abfd), shortname); + } + else { if (! (_bfd_generic_link_add_one_symbol (info, abfd, shortname, BSF_INDIRECT, |