+ case R_SPARC_TLS_GD_HI22:
+ if (! elf32_sparc_tdata (input_bfd)->has_tlsgd)
+ {
+ /* R_SPARC_REV32 used the same reloc number as
+ R_SPARC_TLS_GD_HI22. */
+ r_type = R_SPARC_REV32;
+ break;
+ }
+ /* Fall through */
+
+ case R_SPARC_TLS_GD_LO10:
+ case R_SPARC_TLS_IE_HI22:
+ case R_SPARC_TLS_IE_LO10:
+ r_type = elf32_sparc_tls_transition (info, input_bfd, r_type,
+ h == NULL);
+ tls_type = GOT_UNKNOWN;
+ if (h == NULL && local_got_offsets)
+ tls_type = elf32_sparc_local_got_tls_type (input_bfd) [r_symndx];
+ else if (h != NULL)
+ {
+ tls_type = elf32_sparc_hash_entry(h)->tls_type;
+ if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE)
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_SPARC_TLS_GD_HI22:
+ case R_SPARC_TLS_IE_HI22:
+ r_type = R_SPARC_TLS_LE_HIX22;
+ break;
+ default:
+ r_type = R_SPARC_TLS_LE_LOX10;
+ break;
+ }
+ }
+ if (tls_type == GOT_TLS_IE)
+ switch (r_type)
+ {
+ case R_SPARC_TLS_GD_HI22:
+ r_type = R_SPARC_TLS_IE_HI22;
+ break;
+ case R_SPARC_TLS_GD_LO10:
+ r_type = R_SPARC_TLS_IE_LO10;
+ break;
+ }
+
+ if (r_type == R_SPARC_TLS_LE_HIX22)
+ {
+ relocation = tpoff (info, relocation);
+ break;
+ }
+ if (r_type == R_SPARC_TLS_LE_LOX10)
+ {
+ /* Change add into xor. */
+ relocation = tpoff (info, relocation);
+ bfd_put_32 (output_bfd, (bfd_get_32 (input_bfd,
+ contents + rel->r_offset)
+ | 0x80182000), contents + rel->r_offset);
+ break;
+ }
+
+ if (h != NULL)
+ {
+ off = h->got.offset;
+ h->got.offset |= 1;
+ }
+ else
+ {
+ BFD_ASSERT (local_got_offsets != NULL);
+ off = local_got_offsets[r_symndx];
+ local_got_offsets[r_symndx] |= 1;
+ }
+
+ r_sparc_tlsldm:
+ if (htab->sgot == NULL)
+ abort ();
+
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ Elf_Internal_Rela outrel;
+ Elf32_External_Rela *loc;
+ int dr_type, indx;
+
+ if (htab->srelgot == NULL)
+ abort ();
+
+ bfd_put_32 (output_bfd, 0, htab->sgot->contents + off);
+ outrel.r_offset = (htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off);
+ indx = h && h->dynindx != -1 ? h->dynindx : 0;
+ if (r_type == R_SPARC_TLS_IE_HI22
+ || r_type == R_SPARC_TLS_IE_LO10)
+ dr_type = R_SPARC_TLS_TPOFF32;
+ else
+ dr_type = R_SPARC_TLS_DTPMOD32;
+ if (dr_type == R_SPARC_TLS_TPOFF32 && indx == 0)
+ outrel.r_addend = relocation - dtpoff_base (info);
+ else
+ outrel.r_addend = 0;
+ outrel.r_info = ELF32_R_INFO (indx, dr_type);
+ loc = (Elf32_External_Rela *) htab->srelgot->contents;
+ loc += htab->srelgot->reloc_count++;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (bfd_byte *) loc);
+
+ if (r_type == R_SPARC_TLS_GD_HI22
+ || r_type == R_SPARC_TLS_GD_LO10)
+ {
+ if (indx == 0)
+ {
+ BFD_ASSERT (! unresolved_reloc);
+ bfd_put_32 (output_bfd,
+ relocation - dtpoff_base (info),
+ htab->sgot->contents + off + 4);
+ }
+ else
+ {
+ bfd_put_32 (output_bfd, 0,
+ htab->sgot->contents + off + 4);
+ outrel.r_info = ELF32_R_INFO (indx,
+ R_SPARC_TLS_DTPOFF32);
+ outrel.r_offset += 4;
+ htab->srelgot->reloc_count++;
+ loc++;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (bfd_byte *) loc);
+ }
+ }
+ else if (dr_type == R_SPARC_TLS_DTPMOD32)
+ {
+ bfd_put_32 (output_bfd, 0,
+ htab->sgot->contents + off + 4);
+ }
+ }
+
+ if (off >= (bfd_vma) -2)
+ abort ();
+
+ relocation = htab->sgot->output_offset + off - got_base;
+ unresolved_reloc = FALSE;
+ howto = _bfd_sparc_elf_howto_table + r_type;
+ break;
+
+ case R_SPARC_TLS_LDM_HI22:
+ case R_SPARC_TLS_LDM_LO10:
+ if (! info->shared)
+ {
+ bfd_put_32 (output_bfd, SPARC_NOP, contents + rel->r_offset);
+ continue;
+ }
+ off = htab->tls_ldm_got.offset;
+ htab->tls_ldm_got.offset |= 1;
+ goto r_sparc_tlsldm;
+
+ case R_SPARC_TLS_LDO_HIX22:
+ case R_SPARC_TLS_LDO_LOX10:
+ if (info->shared)
+ relocation -= dtpoff_base (info);
+ else
+ relocation = tpoff (info, relocation);
+ break;
+
+ case R_SPARC_TLS_LE_HIX22:
+ case R_SPARC_TLS_LE_LOX10:
+ if (info->shared)
+ {
+ Elf_Internal_Rela outrel;
+ bfd_boolean skip, relocate = FALSE;
+
+ BFD_ASSERT (sreloc != NULL);
+ skip = FALSE;
+ outrel.r_offset =
+ _bfd_elf_section_offset (output_bfd, info, input_section,
+ rel->r_offset);
+ if (outrel.r_offset == (bfd_vma) -1)
+ skip = TRUE;
+ else if (outrel.r_offset == (bfd_vma) -2)
+ skip = TRUE, relocate = TRUE;
+ outrel.r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
+ if (skip)
+ memset (&outrel, 0, sizeof outrel);
+ else
+ {
+ outrel.r_info = ELF32_R_INFO (0, r_type);
+ outrel.r_addend = relocation - dtpoff_base (info)
+ + rel->r_addend;
+ }
+
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (bfd_byte *) (((Elf32_External_Rela *)
+ sreloc->contents)
+ + sreloc->reloc_count));
+ ++sreloc->reloc_count;
+ continue;
+ }
+ relocation = tpoff (info, relocation);
+ break;
+
+ case R_SPARC_TLS_LDM_CALL:
+ if (! info->shared)
+ {
+ /* mov %g0, %o0 */
+ bfd_put_32 (output_bfd, 0x90100000, contents + rel->r_offset);
+ continue;
+ }
+ /* Fall through */
+
+ case R_SPARC_TLS_GD_CALL:
+ tls_type = GOT_UNKNOWN;
+ if (h == NULL && local_got_offsets)
+ tls_type = elf32_sparc_local_got_tls_type (input_bfd) [r_symndx];
+ else if (h != NULL)
+ tls_type = elf32_sparc_hash_entry(h)->tls_type;
+ if (! info->shared
+ || (r_type == R_SPARC_TLS_GD_CALL && tls_type == GOT_TLS_IE))
+ {
+ bfd_vma insn;
+
+ if (!info->shared && (h == NULL || h->dynindx == -1))
+ {
+ /* GD -> LE */
+ bfd_put_32 (output_bfd, SPARC_NOP, contents + rel->r_offset);
+ continue;
+ }
+
+ /* GD -> IE */
+ if (rel + 1 < relend
+ && ELF32_R_TYPE (rel[1].r_info) == R_SPARC_TLS_GD_ADD
+ && rel[1].r_offset == rel->r_offset + 4
+ && ELF32_R_SYM (rel[1].r_info) == r_symndx
+ && (((insn = bfd_get_32 (input_bfd,
+ contents + rel[1].r_offset))
+ >> 25) & 0x1f) == 8)
+ {
+ /* We have
+ call __tls_get_addr, %tgd_call(foo)
+ add %reg1, %reg2, %o0, %tgd_add(foo)
+ and change it into IE:
+ ld [%reg1 + %reg2], %o0, %tie_ld(foo)
+ add %g7, %o0, %o0, %tie_add(foo).
+ add is 0x80000000 | (rd << 25) | (rs1 << 14) | rs2,
+ ld is 0xc0000000 | (rd << 25) | (rs1 << 14) | rs2. */
+ bfd_put_32 (output_bfd, insn | 0xc0000000,
+ contents + rel->r_offset);
+ bfd_put_32 (output_bfd, 0x9001c008,
+ contents + rel->r_offset + 4);
+ rel++;
+ continue;
+ }
+
+ bfd_put_32 (output_bfd, 0x9001c008, contents + rel->r_offset);
+ continue;
+ }
+
+ h = (struct elf_link_hash_entry *)
+ bfd_link_hash_lookup (info->hash, "__tls_get_addr", FALSE,
+ FALSE, TRUE);
+ BFD_ASSERT (h != NULL);
+ r_type = R_SPARC_WPLT30;
+ howto = _bfd_sparc_elf_howto_table + r_type;
+ goto r_sparc_wplt30;
+
+ case R_SPARC_TLS_GD_ADD:
+ tls_type = GOT_UNKNOWN;
+ if (h == NULL && local_got_offsets)
+ tls_type = elf32_sparc_local_got_tls_type (input_bfd) [r_symndx];
+ else if (h != NULL)
+ tls_type = elf32_sparc_hash_entry(h)->tls_type;
+ if (! info->shared || tls_type == GOT_TLS_IE)
+ {
+ /* add %reg1, %reg2, %reg3, %tgd_add(foo)
+ changed into IE:
+ ld [%reg1 + %reg2], %reg3, %tie_ld(foo)
+ or LE:
+ add %g7, %reg2, %reg3. */
+ bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ if ((h != NULL && h->dynindx != -1) || info->shared)
+ relocation = insn | 0xc0000000;
+ else
+ relocation = (insn & ~0x7c000) | 0x1c000;
+ bfd_put_32 (output_bfd, relocation, contents + rel->r_offset);
+ }
+ continue;
+
+ case R_SPARC_TLS_LDM_ADD:
+ if (! info->shared)
+ bfd_put_32 (output_bfd, SPARC_NOP, contents + rel->r_offset);
+ continue;
+
+ case R_SPARC_TLS_LDO_ADD:
+ if (! info->shared)
+ {
+ /* Change rs1 into %g7. */
+ bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn = (insn & ~0x7c000) | 0x1c000;
+ bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+ }
+ continue;
+
+ case R_SPARC_TLS_IE_LD:
+ case R_SPARC_TLS_IE_LDX:
+ if (! info->shared && (h == NULL || h->dynindx == -1))
+ {
+ bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ int rs2 = insn & 0x1f;
+ int rd = (insn >> 25) & 0x1f;
+
+ if (rs2 == rd)
+ relocation = SPARC_NOP;
+ else
+ relocation = 0x80100000 | (insn & 0x3e00001f);
+ bfd_put_32 (output_bfd, relocation, contents + rel->r_offset);
+ }
+ continue;
+
+ case R_SPARC_TLS_IE_ADD:
+ /* Totally useless relocation. */
+ continue;
+
+ case R_SPARC_TLS_DTPOFF32:
+ relocation -= dtpoff_base (info);
+ break;
+