summaryrefslogtreecommitdiff
path: root/bfd/elfxx-sparc.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@redhat.com>2010-02-11 19:57:40 +0000
committerDavid S. Miller <davem@redhat.com>2010-02-11 19:57:40 +0000
commit92821c0b8ad9ff32883b8bf56e13f5b1167b5bce (patch)
tree95955b7c470271ffae9546b8ca75242646cdc364 /bfd/elfxx-sparc.c
parent77591e131c078f9b02bfef2ce62f680e3e640e69 (diff)
downloadbinutils-redhat-92821c0b8ad9ff32883b8bf56e13f5b1167b5bce.tar.gz
bfd/
* elfxx-sparc.c (_bfd_sparc_elf_check_relocs): For R_SPARC_GOTDATA_OP_HIX22 and R_SPARC_GOTDATA_OP_LOX10, only bump the GOT refcount for global symbols. (_bfd_sparc_elf_gc_sweep_hook): Likewise only decrement the GOT count for these relocs on global symbols. (gdopoff): New. (_bfd_sparc_elf_relocate_section): Perform GOTDATA optimizations on local symbol references which are not STT_GNU_IFUNC. Handle relocation of them like R_SPARC_HIX22 and R_SPARC_LOX10 respectively, and deal with negative vs. non-negative values properly. ld/testsuite * ld-sparc/gotop32.s: Add local symbol case. * ld-sparc/gotop64.s: Likewise. * ld-sparc/gotop32.rd: Adjust expected results. * ld-sparc/gotop32.td: Likewise. * ld-sparc/gotop64.dd: Likewise. * ld-sparc/gotop64.rd: Likewise. * ld-sparc/gotop64.td: Likewise.
Diffstat (limited to 'bfd/elfxx-sparc.c')
-rw-r--r--bfd/elfxx-sparc.c111
1 files changed, 85 insertions, 26 deletions
diff --git a/bfd/elfxx-sparc.c b/bfd/elfxx-sparc.c
index bc36920db9..1947d1a1e8 100644
--- a/bfd/elfxx-sparc.c
+++ b/bfd/elfxx-sparc.c
@@ -1345,8 +1345,6 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_SPARC_GOT10:
case R_SPARC_GOT13:
case R_SPARC_GOT22:
- case R_SPARC_GOTDATA_HIX22:
- case R_SPARC_GOTDATA_LOX10:
case R_SPARC_GOTDATA_OP_HIX22:
case R_SPARC_GOTDATA_OP_LOX10:
tls_type = GOT_NORMAL;
@@ -1386,7 +1384,16 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
_bfd_sparc_elf_local_got_tls_type (abfd)
= (char *) (local_got_refcounts + symtab_hdr->sh_info);
}
- local_got_refcounts[r_symndx] += 1;
+ switch (r_type)
+ {
+ case R_SPARC_GOTDATA_OP_HIX22:
+ case R_SPARC_GOTDATA_OP_LOX10:
+ break;
+
+ default:
+ local_got_refcounts[r_symndx] += 1;
+ break;
+ }
old_tls_type = _bfd_sparc_elf_local_got_tls_type (abfd) [r_symndx];
}
@@ -1766,8 +1773,17 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
}
else
{
- if (local_got_refcounts[r_symndx] > 0)
- local_got_refcounts[r_symndx]--;
+ switch (r_type)
+ {
+ case R_SPARC_GOTDATA_OP_HIX22:
+ case R_SPARC_GOTDATA_OP_LOX10:
+ break;
+
+ default:
+ if (local_got_refcounts[r_symndx] > 0)
+ local_got_refcounts[r_symndx]--;
+ break;
+ }
}
break;
@@ -2672,6 +2688,21 @@ tpoff (struct bfd_link_info *info, bfd_vma address)
return address - htab->tls_size - htab->tls_sec->vma;
}
+/* Return the relocation value for a %gdop relocation. */
+
+static bfd_vma
+gdopoff (struct bfd_link_info *info, bfd_vma address)
+{
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+ bfd_vma got_base;
+
+ got_base = (htab->hgot->root.u.def.value
+ + htab->hgot->root.u.def.section->output_offset
+ + htab->hgot->root.u.def.section->output_section->vma);
+
+ return address - got_base;
+}
+
/* Relocate a SPARC ELF section. */
bfd_boolean
@@ -2821,10 +2852,17 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
switch (r_type)
{
- case R_SPARC_GOTDATA_HIX22:
- case R_SPARC_GOTDATA_LOX10:
+ case R_SPARC_GOTDATA_OP:
+ continue;
+
case R_SPARC_GOTDATA_OP_HIX22:
case R_SPARC_GOTDATA_OP_LOX10:
+ r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22
+ ? R_SPARC_GOT22
+ : R_SPARC_GOT10);
+ howto = _bfd_sparc_elf_howto_table + r_type;
+ /* Fall through. */
+
case R_SPARC_GOT10:
case R_SPARC_GOT13:
case R_SPARC_GOT22:
@@ -2911,19 +2949,37 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
switch (r_type)
{
- case R_SPARC_GOTDATA_HIX22:
- case R_SPARC_GOTDATA_LOX10:
case R_SPARC_GOTDATA_OP_HIX22:
case R_SPARC_GOTDATA_OP_LOX10:
- /* We don't support these code transformation optimizations
- yet, so just leave the sequence alone and treat as
- GOT22/GOT10. */
- if (r_type == R_SPARC_GOTDATA_HIX22
- || r_type == R_SPARC_GOTDATA_OP_HIX22)
- r_type = R_SPARC_GOT22;
+ if (SYMBOL_REFERENCES_LOCAL (info, h))
+ r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22
+ ? R_SPARC_GOTDATA_HIX22
+ : R_SPARC_GOTDATA_LOX10);
else
- r_type = R_SPARC_GOT10;
- /* Fall through. */
+ r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22
+ ? R_SPARC_GOT22
+ : R_SPARC_GOT10);
+ howto = _bfd_sparc_elf_howto_table + r_type;
+ break;
+
+ case R_SPARC_GOTDATA_OP:
+ if (SYMBOL_REFERENCES_LOCAL (info, h))
+ {
+ bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* {ld,ldx} [%rs1 + %rs2], %rd --> add %rs1, %rs2, %rd */
+ relocation = 0x80000000 | (insn & 0x3e07c01f);
+ bfd_put_32 (output_bfd, relocation, contents + rel->r_offset);
+ }
+ continue;
+ }
+
+ switch (r_type)
+ {
+ case R_SPARC_GOTDATA_HIX22:
+ case R_SPARC_GOTDATA_LOX10:
+ relocation = gdopoff (info, relocation);
+ break;
case R_SPARC_GOT10:
case R_SPARC_GOT13:
@@ -3576,11 +3632,6 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
}
continue;
- case R_SPARC_GOTDATA_OP:
- /* We don't support gotdata code transformation optimizations
- yet, so simply leave the sequence as-is. */
- continue;
-
case R_SPARC_TLS_IE_LD:
case R_SPARC_TLS_IE_LDX:
if (! info->shared && (h == NULL || h->dynindx == -1))
@@ -3704,12 +3755,15 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
r = bfd_reloc_ok;
}
- else if (r_type == R_SPARC_HIX22)
+ else if (r_type == R_SPARC_HIX22
+ || r_type == R_SPARC_GOTDATA_HIX22)
{
bfd_vma x;
relocation += rel->r_addend;
- relocation = relocation ^ MINUS_ONE;
+ if (r_type == R_SPARC_HIX22
+ || (bfd_signed_vma) relocation < 0)
+ relocation = relocation ^ MINUS_ONE;
x = bfd_get_32 (input_bfd, contents + rel->r_offset);
x = (x & ~(bfd_vma) 0x3fffff) | ((relocation >> 10) & 0x3fffff);
@@ -3720,12 +3774,17 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
bfd_arch_bits_per_address (input_bfd),
relocation);
}
- else if (r_type == R_SPARC_LOX10)
+ else if (r_type == R_SPARC_LOX10
+ || r_type == R_SPARC_GOTDATA_LOX10)
{
bfd_vma x;
relocation += rel->r_addend;
- relocation = (relocation & 0x3ff) | 0x1c00;
+ if (r_type == R_SPARC_LOX10
+ || (bfd_signed_vma) relocation < 0)
+ relocation = (relocation & 0x3ff) | 0x1c00;
+ else
+ relocation = (relocation & 0x3ff);
x = bfd_get_32 (input_bfd, contents + rel->r_offset);
x = (x & ~(bfd_vma) 0x1fff) | relocation;