summaryrefslogtreecommitdiff
path: root/bfd/elf32-sh.c
diff options
context:
space:
mode:
authorStephen Clarke <stephen.clarke@earthling.net>2002-10-14 19:29:54 +0000
committerStephen Clarke <stephen.clarke@earthling.net>2002-10-14 19:29:54 +0000
commit69949eaec514698b48cfd4fcc51884dac5e5d788 (patch)
tree71cbf029872b68b4a988c28682a5f1910820af35 /bfd/elf32-sh.c
parentdaf326d897f9674c4e413bf7f7c5bd55f6372c48 (diff)
downloadgdb-69949eaec514698b48cfd4fcc51884dac5e5d788.tar.gz
* elf32-sh.c (elf_sh_link_hash_entry): Replace
datalabel_got_offset with union of datalabel_got offset and refcount. (sh_elf_link_hash_newfunc): Initialize datalabel_got.refcount. (allocate_dynrelocs): Delete unnecessary code for STT_DATALABEL type. Create entry in got for datalabel version of symbol if datalabel_got.refcount > 0. (sh_elf_relocate_section): Use datalabel_got union. (sh_elf_gc_sweep_hook): Pull common code to initialize h and eh out of switch statement. Declare seen_stt_datalabel. Initialize it. Decrement datalabel_got.refcount for got relocs when seen_stt_datalabel is true. Decrement local_got_refcounts entry for datalabel got relocs of local symbols. (sh_elf_copy_indirect_symbol): Copy datalabel_got field over. (sh_elf_check_relocs): Declare seen_stt_datalabel. Initialize it. When seen_stt_datalabel is true, increment datalabel_got refcount rather than got.refcount. (sh_elf_finish_dynamic_symbol): Create relocs to initialize got entry for datalabel version of symbol.
Diffstat (limited to 'bfd/elf32-sh.c')
-rw-r--r--bfd/elf32-sh.c415
1 files changed, 283 insertions, 132 deletions
diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c
index 53d2841e6e6..8da4d886c0b 100644
--- a/bfd/elf32-sh.c
+++ b/bfd/elf32-sh.c
@@ -3505,7 +3505,11 @@ struct elf_sh_link_hash_entry
struct elf_link_hash_entry root;
#ifdef INCLUDE_SHMEDIA
- bfd_vma datalabel_got_offset;
+ union
+ {
+ bfd_signed_vma refcount;
+ bfd_vma offset;
+ } datalabel_got;
#endif
/* Track dynamic relocs copied for this symbol. */
@@ -3616,13 +3620,10 @@ sh_elf_link_hash_newfunc (entry, table, string)
table, string));
if (ret != (struct elf_sh_link_hash_entry *) NULL)
{
- struct elf_sh_link_hash_entry *eh;
-
- eh = (struct elf_sh_link_hash_entry *) ret;
- eh->dyn_relocs = NULL;
- eh->gotplt_refcount = 0;
+ ret->dyn_relocs = NULL;
+ ret->gotplt_refcount = 0;
#ifdef INCLUDE_SHMEDIA
- ret->datalabel_got_offset = (bfd_vma) -1;
+ ret->datalabel_got.refcount = ret->root.got.refcount;
#endif
ret->tls_type = GOT_UNKNOWN;
ret->tls_tpoff32 = false;
@@ -4127,20 +4128,7 @@ allocate_dynrelocs (h, inf)
}
s = htab->sgot;
-#ifdef INCLUDE_SHMEDIA
- if (h->type == STT_DATALABEL)
- {
- struct elf_sh_link_hash_entry *hsh;
-
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
- hsh = (struct elf_sh_link_hash_entry *)h;
- hsh->datalabel_got_offset = s->_raw_size;
- }
- else
- h->got.offset = s->_raw_size;
-#else
h->got.offset = s->_raw_size;
-#endif
s->_raw_size += 4;
/* R_SH_TLS_GD needs 2 consecutive GOT slots. */
if (tls_type == GOT_TLS_GD)
@@ -4159,6 +4147,32 @@ allocate_dynrelocs (h, inf)
else
h->got.offset = (bfd_vma) -1;
+#ifdef INCLUDE_SHMEDIA
+ if (eh->datalabel_got.refcount > 0)
+ {
+ asection *s;
+ boolean dyn;
+
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1
+ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ {
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ s = htab->sgot;
+ eh->datalabel_got.offset = s->_raw_size;
+ s->_raw_size += 4;
+ dyn = htab->root.dynamic_sections_created;
+ if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
+ htab->srelgot->_raw_size += sizeof (Elf32_External_Rela);
+ }
+ else
+ eh->datalabel_got.offset = (bfd_vma) -1;
+#endif
+
if (eh->dyn_relocs == NULL)
return true;
@@ -4999,7 +5013,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
struct elf_sh_link_hash_entry *hsh;
hsh = (struct elf_sh_link_hash_entry *)h;
- off = hsh->datalabel_got_offset;
+ off = hsh->datalabel_got.offset;
}
#endif
BFD_ASSERT (off != (bfd_vma) -1);
@@ -5035,7 +5049,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
struct elf_sh_link_hash_entry *hsh;
hsh = (struct elf_sh_link_hash_entry *)h;
- hsh->datalabel_got_offset |= 1;
+ hsh->datalabel_got.offset |= 1;
}
else
#endif
@@ -5893,128 +5907,170 @@ sh_elf_gc_sweep_hook (abfd, info, sec, relocs)
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; rel++)
- switch (sh_elf_optimized_tls_reloc (info, ELF32_R_TYPE (rel->r_info),
- ELF32_R_SYM (rel->r_info)
- >= symtab_hdr->sh_info))
- {
- case R_SH_TLS_LD_32:
- if (sh_elf_hash_table (info)->tls_ldm_got.refcount > 0)
- sh_elf_hash_table (info)->tls_ldm_got.refcount -= 1;
- break;
+ {
+#ifdef INCLUDE_SHMEDIA
+ int seen_stt_datalabel = 0;
+#endif
- case R_SH_GOT32:
- case R_SH_GOTOFF:
- case R_SH_GOTPC:
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx < symtab_hdr->sh_info)
+ h = NULL;
+ else
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
#ifdef INCLUDE_SHMEDIA
- case R_SH_GOT_LOW16:
- case R_SH_GOT_MEDLOW16:
- case R_SH_GOT_MEDHI16:
- case R_SH_GOT_HI16:
- case R_SH_GOT10BY4:
- case R_SH_GOT10BY8:
- case R_SH_GOTOFF_LOW16:
- case R_SH_GOTOFF_MEDLOW16:
- case R_SH_GOTOFF_MEDHI16:
- case R_SH_GOTOFF_HI16:
- case R_SH_GOTPC_LOW16:
- case R_SH_GOTPC_MEDLOW16:
- case R_SH_GOTPC_MEDHI16:
- case R_SH_GOTPC_HI16:
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ {
+ seen_stt_datalabel |= h->type == STT_DATALABEL;
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
#endif
- case R_SH_TLS_GD_32:
- case R_SH_TLS_IE_32:
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
- {
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (h->got.refcount > 0)
- h->got.refcount -= 1;
- }
- else if (local_got_refcounts != NULL)
- {
- if (local_got_refcounts[r_symndx] > 0)
- local_got_refcounts[r_symndx] -= 1;
- }
- break;
+ }
+ eh = (struct elf_sh_link_hash_entry *) h;
- case R_SH_DIR32:
- case R_SH_REL32:
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
- {
- struct elf_sh_link_hash_entry *eh;
- struct elf_sh_dyn_relocs **pp;
- struct elf_sh_dyn_relocs *p;
+ switch (sh_elf_optimized_tls_reloc (info, ELF32_R_TYPE (rel->r_info),
+ ELF32_R_SYM (rel->r_info)
+ >= symtab_hdr->sh_info))
+ {
+ case R_SH_TLS_LD_32:
+ if (sh_elf_hash_table (info)->tls_ldm_got.refcount > 0)
+ sh_elf_hash_table (info)->tls_ldm_got.refcount -= 1;
+ break;
+
+ case R_SH_GOT32:
+ case R_SH_GOTOFF:
+ case R_SH_GOTPC:
+#ifdef INCLUDE_SHMEDIA
+ case R_SH_GOT_LOW16:
+ case R_SH_GOT_MEDLOW16:
+ case R_SH_GOT_MEDHI16:
+ case R_SH_GOT_HI16:
+ case R_SH_GOT10BY4:
+ case R_SH_GOT10BY8:
+ case R_SH_GOTOFF_LOW16:
+ case R_SH_GOTOFF_MEDLOW16:
+ case R_SH_GOTOFF_MEDHI16:
+ case R_SH_GOTOFF_HI16:
+ case R_SH_GOTPC_LOW16:
+ case R_SH_GOTPC_MEDLOW16:
+ case R_SH_GOTPC_MEDHI16:
+ case R_SH_GOTPC_HI16:
+#endif
+ case R_SH_TLS_GD_32:
+ case R_SH_TLS_IE_32:
+ if (h != NULL)
+ {
+#ifdef INCLUDE_SHMEDIA
+ if (seen_stt_datalabel)
+ {
+ if (eh->datalabel_got.refcount > 0)
+ eh->datalabel_got.refcount -= 1;
+ }
+ else
+#endif
+ if (h->got.refcount > 0)
+ h->got.refcount -= 1;
+ }
+ else if (local_got_refcounts != NULL)
+ {
+#ifdef INCLUDE_SHMEDIA
+ if (rel->r_addend & 1)
+ {
+ if (local_got_refcounts[symtab_hdr->sh_info + r_symndx] > 0)
+ local_got_refcounts[symtab_hdr->sh_info + r_symndx] -= 1;
+ }
+ else
+#endif
+ if (local_got_refcounts[r_symndx] > 0)
+ local_got_refcounts[r_symndx] -= 1;
+ }
+ break;
+
+ case R_SH_DIR32:
+ case R_SH_REL32:
+ if (h != NULL)
+ {
+ struct elf_sh_dyn_relocs **pp;
+ struct elf_sh_dyn_relocs *p;
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (!info->shared && h->plt.refcount > 0)
- h->plt.refcount -= 1;
+ if (!info->shared && h->plt.refcount > 0)
+ h->plt.refcount -= 1;
- eh = (struct elf_sh_link_hash_entry *) h;
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+ if (p->sec == sec)
+ {
+ if (ELF32_R_TYPE (rel->r_info) == R_SH_REL32)
+ p->pc_count -= 1;
+ p->count -= 1;
+ if (p->count == 0)
+ *pp = p->next;
+ break;
+ }
+ }
+ break;
+
+ case R_SH_PLT32:
+#ifdef INCLUDE_SHMEDIA
+ case R_SH_PLT_LOW16:
+ case R_SH_PLT_MEDLOW16:
+ case R_SH_PLT_MEDHI16:
+ case R_SH_PLT_HI16:
+#endif
+ if (h != NULL)
+ {
+ if (h->plt.refcount > 0)
+ h->plt.refcount -= 1;
+ }
+ break;
- for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
- if (p->sec == sec)
+ case R_SH_GOTPLT32:
+#ifdef INCLUDE_SHMEDIA
+ case R_SH_GOTPLT_LOW16:
+ case R_SH_GOTPLT_MEDLOW16:
+ case R_SH_GOTPLT_MEDHI16:
+ case R_SH_GOTPLT_HI16:
+ case R_SH_GOTPLT10BY4:
+ case R_SH_GOTPLT10BY8:
+#endif
+ if (h != NULL)
+ {
+ if (eh->gotplt_refcount > 0)
{
- if (ELF32_R_TYPE (rel->r_info) == R_SH_REL32)
- p->pc_count -= 1;
- p->count -= 1;
- if (p->count == 0)
- *pp = p->next;
- break;
+ eh->gotplt_refcount -= 1;
+ if (h->plt.refcount > 0)
+ h->plt.refcount -= 1;
}
- }
- break;
-
- case R_SH_PLT32:
#ifdef INCLUDE_SHMEDIA
- case R_SH_PLT_LOW16:
- case R_SH_PLT_MEDLOW16:
- case R_SH_PLT_MEDHI16:
- case R_SH_PLT_HI16:
+ else if (seen_stt_datalabel)
+ {
+ if (eh->datalabel_got.refcount > 0)
+ eh->datalabel_got.refcount -= 1;
+ }
#endif
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
- {
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
- }
- break;
-
- case R_SH_GOTPLT32:
+ else if (h->got.refcount > 0)
+ h->got.refcount -= 1;
+ }
+ else if (local_got_refcounts != NULL)
+ {
#ifdef INCLUDE_SHMEDIA
- case R_SH_GOTPLT_LOW16:
- case R_SH_GOTPLT_MEDLOW16:
- case R_SH_GOTPLT_MEDHI16:
- case R_SH_GOTPLT_HI16:
- case R_SH_GOTPLT10BY4:
- case R_SH_GOTPLT10BY8:
+ if (rel->r_addend & 1)
+ {
+ if (local_got_refcounts[symtab_hdr->sh_info + r_symndx] > 0)
+ local_got_refcounts[symtab_hdr->sh_info + r_symndx] -= 1;
+ }
+ else
#endif
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
- {
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- eh = (struct elf_sh_link_hash_entry *) h;
- if (eh->gotplt_refcount > 0)
- {
- eh->gotplt_refcount -= 1;
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
- }
- else if (h->got.refcount > 0)
- h->got.refcount -= 1;
- }
- else if (local_got_refcounts != NULL)
- {
- if (local_got_refcounts[r_symndx] > 0)
- local_got_refcounts[r_symndx] -= 1;
- }
- break;
+ if (local_got_refcounts[r_symndx] > 0)
+ local_got_refcounts[r_symndx] -= 1;
+ }
+ break;
- default:
- break;
- }
+ default:
+ break;
+ }
+ }
return true;
}
@@ -6027,6 +6083,9 @@ sh_elf_copy_indirect_symbol (bed, dir, ind)
struct elf_link_hash_entry *dir, *ind;
{
struct elf_sh_link_hash_entry *edir, *eind;
+#ifdef INCLUDE_SHMEDIA
+ bfd_signed_vma tmp;
+#endif
edir = (struct elf_sh_link_hash_entry *) dir;
eind = (struct elf_sh_link_hash_entry *) ind;
@@ -6065,6 +6124,16 @@ sh_elf_copy_indirect_symbol (bed, dir, ind)
}
edir->gotplt_refcount = eind->gotplt_refcount;
eind->gotplt_refcount = 0;
+#ifdef INCLUDE_SHMEDIA
+ tmp = edir->datalabel_got.refcount;
+ if (tmp < 1)
+ {
+ edir->datalabel_got.refcount = eind->datalabel_got.refcount;
+ eind->datalabel_got.refcount = tmp;
+ }
+ else
+ BFD_ASSERT (eind->datalabel_got.refcount < 1);
+#endif
if (ind->root.type == bfd_link_hash_indirect
&& dir->got.refcount <= 0)
@@ -6145,6 +6214,9 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
{
struct elf_link_hash_entry *h;
unsigned long r_symndx;
+#ifdef INCLUDE_SHMEDIA
+ int seen_stt_datalabel = 0;
+#endif
r_symndx = ELF32_R_SYM (rel->r_info);
r_type = ELF32_R_TYPE (rel->r_info);
@@ -6152,7 +6224,17 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+#ifdef INCLUDE_SHMEDIA
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ {
+ seen_stt_datalabel |= h->type == STT_DATALABEL;
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+#endif
+ }
r_type = sh_elf_optimized_tls_reloc (info, r_type, h == NULL);
if (! info->shared
@@ -6256,7 +6338,17 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
if (h != NULL)
{
- h->got.refcount += 1;
+#ifdef INCLUDE_SHMEDIA
+ if (seen_stt_datalabel)
+ {
+ struct elf_sh_link_hash_entry *eh =
+ (struct elf_sh_link_hash_entry *)h;
+
+ eh->datalabel_got.refcount += 1;
+ }
+ else
+#endif
+ h->got.refcount += 1;
old_tls_type = sh_elf_hash_entry (h)->tls_type;
}
else
@@ -6293,7 +6385,12 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
= (char *) (local_got_refcounts + symtab_hdr->sh_info);
#endif
}
- local_got_refcounts[r_symndx] += 1;
+#ifdef INCLUDE_SHMEDIA
+ if (rel->r_addend & 1)
+ local_got_refcounts[symtab_hdr->sh_info + r_symndx] += 1;
+ else
+#endif
+ local_got_refcounts[r_symndx] += 1;
old_tls_type = sh_elf_local_got_tls_type (abfd) [r_symndx];
}
@@ -6948,6 +7045,60 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
++srel->reloc_count;
}
+#ifdef INCLUDE_SHMEDIA
+ {
+ struct elf_sh_link_hash_entry *eh;
+
+ eh = (struct elf_sh_link_hash_entry *) h;
+ if (eh->datalabel_got.offset != (bfd_vma) -1)
+ {
+ asection *sgot;
+ asection *srel;
+ Elf_Internal_Rela rel;
+
+ /* This symbol has a datalabel entry in the global offset table.
+ Set it up. */
+
+ sgot = htab->sgot;
+ srel = htab->srelgot;
+ BFD_ASSERT (sgot != NULL && srel != NULL);
+
+ rel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + (eh->datalabel_got.offset &~ (bfd_vma) 1));
+
+ /* If this is a static link, or it is a -Bsymbolic link and the
+ symbol is defined locally or was forced to be local because
+ of a version file, we just want to emit a RELATIVE reloc.
+ The entry in the global offset table will already have been
+ initialized in the relocate_section function. */
+ if (info->shared
+ && (info->symbolic
+ || h->dynindx == -1
+ || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+ {
+ rel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
+ rel.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+ else
+ {
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents
+ + eh->datalabel_got.offset);
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_GLOB_DAT);
+ rel.r_addend = 0;
+ }
+
+ bfd_elf32_swap_reloca_out (output_bfd, &rel,
+ ((Elf32_External_Rela *) srel->contents
+ + srel->reloc_count));
+ ++srel->reloc_count;
+ }
+ }
+#endif
+
if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
{
asection *s;