alpha tls ld fixes

Richard Henderson rth@redhat.com
Wed Jan 22 00:50:00 GMT 2003


Started just to unify all LDM relocs to use the same got entry,
but that uncovered other problems in relaxation, and finally,
incorrect handling of dynamic symbols for which we no longer
need a plt entry.

Need to test relaxation vs glibc next...


r~


        * elf64-alpha.c (ALPHA_ELF_LINK_HASH_PLT_LOC): New.
        (struct alpha_elf_link_hash_entry): Add plt_old_section, plt_old_value.
        (elf64_alpha_adjust_dynamic_symbol): Set them.
        (elf64_alpha_size_plt_section_1): Reset them when plt entry removed.
        (elf64_alpha_relax_tls_get_addr): Handle LDM relocs.  Frob the
        symbol index when relaxing LDM to TPREL.
        (elf64_alpha_relax_section): Likewise.  Allow relaxation of GD
        relocs, even if the target isn't locally defined.
        (elf64_alpha_check_relocs): Frob LDM reloc symndx to zero.
        (elf64_alpha_relocate_section): Likewise.  Force TP-relative
        relocs vs symndx 0 to the tp base.

Index: elf64-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-alpha.c,v
retrieving revision 1.90
diff -c -p -d -r1.90 elf64-alpha.c
*** elf64-alpha.c	21 Jan 2003 08:59:25 -0000	1.90
--- elf64-alpha.c	22 Jan 2003 00:42:08 -0000
*************** struct alpha_elf_link_hash_entry
*** 177,182 ****
--- 177,187 ----
  #define ALPHA_ELF_LINK_HASH_LU_TLSLDM	0x20
  #define ALPHA_ELF_LINK_HASH_LU_FUNC	0x38
  #define ALPHA_ELF_LINK_HASH_TLS_IE	0x40
+ #define ALPHA_ELF_LINK_HASH_PLT_LOC	0x80
+ 
+   /* Used to undo the localization of a plt symbol.  */
+   asection *plt_old_section;
+   bfd_vma plt_old_value;
  
    /* Used to implement multiple .got subsections.  */
    struct alpha_elf_got_entry
*************** elf64_alpha_relax_tls_get_addr (info, sy
*** 1753,1768 ****
    unsigned int insn;
    Elf_Internal_Rela *gpdisp, *hint;
    bfd_boolean dynamic, use_gottprel, pos1_unusable;
  
    dynamic = alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info);
  
-   /* ??? For LD relaxation, we need a symbol referencing the beginning
-      of the TLS segment.  */
-   /* ??? The STN_UNDEF symbol (dynindex 0) works fine for this.  Adjust
-      the code below to expect that.  */
-   if (!is_gd)
-     return TRUE;
- 
    /* If a TLS symbol is accessed using IE at least once, there is no point
       to use dynamic model for it.  */
    if (is_gd && info->h && (info->h->flags & ALPHA_ELF_LINK_HASH_TLS_IE))
--- 1758,1767 ----
    unsigned int insn;
    Elf_Internal_Rela *gpdisp, *hint;
    bfd_boolean dynamic, use_gottprel, pos1_unusable;
+   unsigned long new_symndx;
  
    dynamic = alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info);
  
    /* If a TLS symbol is accessed using IE at least once, there is no point
       to use dynamic model for it.  */
    if (is_gd && info->h && (info->h->flags & ALPHA_ELF_LINK_HASH_TLS_IE))
*************** elf64_alpha_relax_tls_get_addr (info, sy
*** 1868,1873 ****
--- 1867,1873 ----
       as appropriate.  */
  
    use_gottprel = FALSE;
+   new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : 0;
    switch (!dynamic && !info->link_info->shared)
      {
      case 1:
*************** elf64_alpha_relax_tls_get_addr (info, sy
*** 1886,1893 ****
  	    bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
  
  	    irel[0].r_offset = pos[0] - info->contents;
! 	    irel[0].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
! 					   R_ALPHA_TPREL16);
  	    irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
  	    break;
  	  }
--- 1886,1892 ----
  	    bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
  
  	    irel[0].r_offset = pos[0] - info->contents;
! 	    irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPREL16);
  	    irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
  	    break;
  	  }
*************** elf64_alpha_relax_tls_get_addr (info, sy
*** 1901,1911 ****
  	    bfd_put_32 (info->abfd, (bfd_vma) insn, pos[1]);
  
  	    irel[0].r_offset = pos[0] - info->contents;
! 	    irel[0].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
! 					   R_ALPHA_TPRELHI);
  	    irel[1].r_offset = pos[1] - info->contents;
! 	    irel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
! 					   R_ALPHA_TPRELLO);
  	    break;
  	  }
        }
--- 1900,1908 ----
  	    bfd_put_32 (info->abfd, (bfd_vma) insn, pos[1]);
  
  	    irel[0].r_offset = pos[0] - info->contents;
! 	    irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPRELHI);
  	    irel[1].r_offset = pos[1] - info->contents;
! 	    irel[1].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPRELLO);
  	    break;
  	  }
        }
*************** elf64_alpha_relax_tls_get_addr (info, sy
*** 1919,1926 ****
        bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
  
        irel[0].r_offset = pos[0] - info->contents;
!       irel[0].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
! 				     R_ALPHA_GOTTPREL);
        irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
        break;
      }
--- 1916,1922 ----
        bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
  
        irel[0].r_offset = pos[0] - info->contents;
!       irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_GOTTPREL);
        irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
        break;
      }
*************** elf64_alpha_relax_section (abfd, sec, li
*** 2123,2128 ****
--- 2119,2125 ----
        bfd_vma symval;
        struct alpha_elf_got_entry *gotent;
        unsigned long r_type = ELF64_R_TYPE (irel->r_info);
+       unsigned long r_symndx = ELF64_R_SYM (irel->r_info);
  
        /* Early exit for unhandled or unrelaxable relocations.  */
        switch (r_type)
*************** elf64_alpha_relax_section (abfd, sec, li
*** 2133,2146 ****
  	case R_ALPHA_GOTDTPREL:
  	case R_ALPHA_GOTTPREL:
  	case R_ALPHA_TLSGD:
  	case R_ALPHA_TLSLDM:
  	  break;
  	default:
  	  continue;
  	}
  
        /* Get the value of the symbol referred to by the reloc.  */
!       if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
  	{
  	  /* A local symbol.  */
  	  Elf_Internal_Sym *isym;
--- 2130,2149 ----
  	case R_ALPHA_GOTDTPREL:
  	case R_ALPHA_GOTTPREL:
  	case R_ALPHA_TLSGD:
+ 	  break;
+ 
  	case R_ALPHA_TLSLDM:
+ 	  /* The symbol for a TLSLDM reloc is ignored.  Collapse the
+              reloc to the 0 symbol so that they all match.  */
+ 	  r_symndx = 0;
  	  break;
+ 
  	default:
  	  continue;
  	}
  
        /* Get the value of the symbol referred to by the reloc.  */
!       if (r_symndx < symtab_hdr->sh_info)
  	{
  	  /* A local symbol.  */
  	  Elf_Internal_Sym *isym;
*************** elf64_alpha_relax_section (abfd, sec, li
*** 2157,2183 ****
  		goto error_return;
  	    }
  
! 	  isym = isymbuf + ELF64_R_SYM (irel->r_info);
! 	  if (isym->st_shndx == SHN_UNDEF)
! 	    continue;
! 	  else if (isym->st_shndx == SHN_ABS)
! 	    info.tsec = bfd_abs_section_ptr;
! 	  else if (isym->st_shndx == SHN_COMMON)
! 	    info.tsec = bfd_com_section_ptr;
  	  else
! 	    info.tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
  
  	  info.h = NULL;
  	  info.other = isym->st_other;
! 	  info.first_gotent = &local_got_entries[ELF64_R_SYM(irel->r_info)];
! 	  symval = isym->st_value;
  	}
        else
  	{
  	  unsigned long indx;
  	  struct alpha_elf_link_hash_entry *h;
  
! 	  indx = ELF64_R_SYM (irel->r_info) - symtab_hdr->sh_info;
  	  h = alpha_elf_sym_hashes (abfd)[indx];
  	  BFD_ASSERT (h != NULL);
  
--- 2160,2197 ----
  		goto error_return;
  	    }
  
! 	  isym = isymbuf + r_symndx;
! 
! 	  /* Given the symbol for a TLSLDM reloc is ignored, this also
! 	     means forcing the symbol value to the tp base.  */
! 	  if (r_type == R_ALPHA_TLSLDM)
! 	    {
! 	      info.tsec = bfd_abs_section_ptr;
! 	      symval = alpha_get_tprel_base (info.tls_segment);
! 	    }
  	  else
! 	    {
! 	      symval = isym->st_value;
! 	      if (isym->st_shndx == SHN_UNDEF)
! 	        continue;
! 	      else if (isym->st_shndx == SHN_ABS)
! 	        info.tsec = bfd_abs_section_ptr;
! 	      else if (isym->st_shndx == SHN_COMMON)
! 	        info.tsec = bfd_com_section_ptr;
! 	      else
! 	        info.tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
! 	    }
  
  	  info.h = NULL;
  	  info.other = isym->st_other;
! 	  info.first_gotent = &local_got_entries[r_symndx];
  	}
        else
  	{
  	  unsigned long indx;
  	  struct alpha_elf_link_hash_entry *h;
  
! 	  indx = r_symndx - symtab_hdr->sh_info;
  	  h = alpha_elf_sym_hashes (abfd)[indx];
  	  BFD_ASSERT (h != NULL);
  
*************** elf64_alpha_relax_section (abfd, sec, li
*** 2193,2205 ****
  	  /* If the symbol isn't defined in the current module, again
  	     we can't do anything.  */
  	  if (!(h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
! 	    continue;
  
  	  info.h = h;
- 	  info.tsec = h->root.root.u.def.section;
  	  info.other = h->root.other;
  	  info.first_gotent = &h->got_entries;
- 	  symval = h->root.root.u.def.value;
  	}
  
        /* Search for the got entry to be used by this relocation.  */
--- 2207,2229 ----
  	  /* If the symbol isn't defined in the current module, again
  	     we can't do anything.  */
  	  if (!(h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
! 	    {
! 	      /* Except for TLSGD relocs, which can sometimes be
! 		 relaxed to GOTTPREL relocs.  */
! 	      if (r_type != R_ALPHA_TLSGD)
! 		continue;
! 	      info.tsec = bfd_abs_section_ptr;
! 	      symval = 0;
! 	    }
! 	  else
! 	    {
! 	      info.tsec = h->root.root.u.def.section;
! 	      symval = h->root.root.u.def.value;
! 	    }
  
  	  info.h = h;
  	  info.other = h->root.other;
  	  info.first_gotent = &h->got_entries;
  	}
  
        /* Search for the got entry to be used by this relocation.  */
*************** elf64_alpha_check_relocs (abfd, info, se
*** 3117,3124 ****
  	    need = NEED_DYNREL;
  	  break;
  
- 	case R_ALPHA_TLSGD:
  	case R_ALPHA_TLSLDM:
  	case R_ALPHA_GOTDTPREL:
  	  need = NEED_GOT | NEED_GOT_ENTRY;
  	  break;
--- 3141,3155 ----
  	    need = NEED_DYNREL;
  	  break;
  
  	case R_ALPHA_TLSLDM:
+ 	  /* The symbol for a TLSLDM reloc is ignored.  Collapse the
+ 	     reloc to the 0 symbol so that they all match.  */
+ 	  r_symndx = 0;
+ 	  h = 0;
+ 	  maybe_dynamic = FALSE;
+ 	  /* FALLTHRU */
+ 
+ 	case R_ALPHA_TLSGD:
  	case R_ALPHA_GOTDTPREL:
  	  need = NEED_GOT | NEED_GOT_ENTRY;
  	  break;
*************** elf64_alpha_adjust_dynamic_symbol (info,
*** 3320,3325 ****
--- 3351,3359 ----
        if (! info->shared
  	  && h->root.type != bfd_link_hash_defweak)
  	{
+ 	  ah->plt_old_section = h->root.u.def.section;
+ 	  ah->plt_old_value = h->root.u.def.value;
+ 	  ah->flags |= ALPHA_ELF_LINK_HASH_PLT_LOC;
  	  h->root.u.def.section = s;
  	  h->root.u.def.value = h->plt.offset;
  	}
*************** elf64_alpha_size_plt_section_1 (h, data)
*** 3801,3806 ****
--- 3835,3848 ----
      {
        h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
        h->root.plt.offset = -1;
+ 
+       /* Undo the definition frobbing begun in adjust_dynamic_symbol.  */
+       if (h->flags & ALPHA_ELF_LINK_HASH_PLT_LOC)
+ 	{
+ 	  h->root.root.u.def.section = h->plt_old_section;
+ 	  h->root.root.u.def.value = h->plt_old_value;
+ 	  h->flags &= ~ALPHA_ELF_LINK_HASH_PLT_LOC;
+ 	}
      }
  
    return TRUE;
*************** elf64_alpha_relocate_section (output_bfd
*** 4364,4374 ****
--- 4406,4433 ----
        howto = elf64_alpha_howto_table + r_type;
        r_symndx = ELF64_R_SYM(rel->r_info);
  
+       /* The symbol for a TLSLDM reloc is ignored.  Collapse the
+ 	 reloc to the 0 symbol so that they all match.  */
+       if (r_type == R_ALPHA_TLSLDM)
+ 	r_symndx = 0;
+ 
        if (r_symndx < symtab_hdr->sh_info)
  	{
  	  sym = local_syms + r_symndx;
  	  sec = local_sections[r_symndx];
  	  value = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+ 
+ 	  /* If this is a tp-relative relocation against sym 0,
+ 	     this is hackery from relax_section.  Force the value to
+ 	     be the tls base.  */
+ 	  if (r_symndx == 0
+ 	      && (r_type == R_ALPHA_TLSLDM
+ 		  || r_type == R_ALPHA_GOTTPREL
+ 		  || r_type == R_ALPHA_TPREL64
+ 		  || r_type == R_ALPHA_TPRELHI
+ 		  || r_type == R_ALPHA_TPRELLO
+ 		  || r_type == R_ALPHA_TPREL16))
+ 	    value = tp_base;
  
  	  if (local_got_entries)
  	    gotent = local_got_entries[r_symndx];



More information about the Binutils mailing list