* elf64-alpha.c (elf64_alpha_gc_mark_hook): New.
[deliverable/binutils-gdb.git] / bfd / elf64-alpha.c
index 19326cf81b3dd840e1491828020a3200a2cc472d..2b15a81c082a2c2c513845654757ac7f649cef1c 100644 (file)
@@ -1,6 +1,6 @@
 /* Alpha specific support for 64-bit ELF
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
+   2006, 2007, 2008, 2009, 2010, 2011  Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@tamu.edu>.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -1866,8 +1866,8 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
        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;
+            reloc to the STN_UNDEF (0) symbol so that they all match.  */
+         r_symndx = STN_UNDEF;
          h = 0;
          maybe_dynamic = FALSE;
          /* FALLTHRU */
@@ -1988,6 +1988,93 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
   return TRUE;
 }
 
+/* Return the section that should be marked against GC for a given
+   relocation.  */
+
+static asection *
+elf64_alpha_gc_mark_hook (asection *sec, struct bfd_link_info *info,
+                         Elf_Internal_Rela *rel,
+                         struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)
+{
+  /* These relocations don't really reference a symbol.  Instead we store
+     extra data in their addend slot.  Ignore the symbol.  */
+  switch (ELF64_R_TYPE (rel->r_info))
+    {
+    case R_ALPHA_LITUSE:
+    case R_ALPHA_GPDISP:
+    case R_ALPHA_HINT:
+      return NULL;
+    }
+
+  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
+}
+
+/* Update the got entry reference counts for the section being removed.  */
+
+static bfd_boolean
+elf64_alpha_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
+                          asection *sec, const Elf_Internal_Rela *relocs)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct alpha_elf_link_hash_entry **sym_hashes;
+  const Elf_Internal_Rela *rel, *relend;
+
+  if (info->relocatable)
+    return TRUE;
+
+  symtab_hdr = &elf_symtab_hdr (abfd);
+  sym_hashes = alpha_elf_sym_hashes (abfd);
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    {
+      unsigned long r_symndx, r_type;
+      struct alpha_elf_link_hash_entry *h = NULL;
+      struct alpha_elf_got_entry *gotent;
+
+      r_symndx = ELF64_R_SYM (rel->r_info);
+      if (r_symndx >= symtab_hdr->sh_info)
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.root.type == bfd_link_hash_indirect
+                || h->root.root.type == bfd_link_hash_warning)
+           h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
+       }
+
+      r_type = ELF64_R_TYPE (rel->r_info);
+      switch (r_type)
+       {
+       case R_ALPHA_LITERAL:
+         /* ??? Ignore re-computation of gotent_flags.  We're not
+            carrying a use-count for each bit in that mask.  */
+
+       case R_ALPHA_TLSGD:
+       case R_ALPHA_GOTDTPREL:
+       case R_ALPHA_GOTTPREL:
+         /* Fetch the got entry from the tables.  */
+         gotent = get_got_entry (abfd, h, r_type, r_symndx, rel->r_addend);
+
+         /* The got entry *must* exist, since we should have created it
+            before during check_relocs.  Also note that get_got_entry
+            assumed this was going to be another use, and so incremented
+            the use count again.  Thus the use count must be at least the
+            one real use and the "use" we just added.  */
+         if (gotent == NULL || gotent->use_count < 2)
+           {
+             abort ();
+             return FALSE;
+           }
+         gotent->use_count -= 2;
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  return TRUE;
+}
+
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -3491,7 +3578,7 @@ elf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval,
      as appropriate.  */
 
   use_gottprel = FALSE;
-  new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : 0;
+  new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : STN_UNDEF;
 
   /* Beware of the compiler hoisting part of the sequence out a loop
      and adjusting the destination register for the TLSGD insn.  If this
@@ -3724,8 +3811,8 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
 
        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;
+             reloc to the STN_UNDEF (0) symbol so that they all match.  */
+         r_symndx = STN_UNDEF;
          break;
 
        default:
@@ -4025,16 +4112,10 @@ elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
        }
 
       if (sec != NULL && elf_discarded_section (sec))
-       {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  */
-         _bfd_clear_contents (elf64_alpha_howto_table + r_type,
-                              input_bfd, contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
-       }
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, relend,
+                                        elf64_alpha_howto_table + r_type,
+                                        contents);
 
       if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
        rel->r_addend += sec->output_offset;
@@ -4086,7 +4167,7 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       const char *section_name;
       section_name = (bfd_elf_string_from_elf_section
                      (input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
-                      elf_section_data(input_section)->rel_hdr.sh_name));
+                      _bfd_elf_single_rel_hdr (input_section)->sh_name));
       BFD_ASSERT(section_name != NULL);
       srel = bfd_get_section_by_name (dynobj, section_name);
     }
@@ -4154,9 +4235,9 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       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.  */
+        reloc to the STN_UNDEF (0) symbol so that they all match.  */
       if (r_type == R_ALPHA_TLSLDM)
-       r_symndx = 0;
+       r_symndx = STN_UNDEF;
 
       if (r_symndx < symtab_hdr->sh_info)
        {
@@ -4166,10 +4247,10 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          msec = sec;
          value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel);
 
-         /* If this is a tp-relative relocation against sym 0,
+         /* If this is a tp-relative relocation against sym STN_UNDEF (0),
             this is hackery from relax_section.  Force the value to
             be the tls module base.  */
-         if (r_symndx == 0
+         if (r_symndx == STN_UNDEF
              && (r_type == R_ALPHA_TLSLDM
                  || r_type == R_ALPHA_GOTTPREL
                  || r_type == R_ALPHA_TPREL64
@@ -4240,15 +4321,8 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        }
 
       if (sec != NULL && elf_discarded_section (sec))
-       {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  Avoid any special processing.  */
-         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
-       }
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, relend, howto, contents);
 
       addend = rel->r_addend;
       value += addend;
@@ -4455,7 +4529,7 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                dynaddend = value - dtp_base;
              }
            else if (info->shared
-                    && r_symndx != 0
+                    && r_symndx != STN_UNDEF
                     && (input_section->flags & SEC_ALLOC)
                     && !undef_weak_ref)
              {
@@ -4503,7 +4577,7 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          /* ??? .eh_frame references to discarded sections will be smashed
             to relocations against SHN_UNDEF.  The .eh_frame format allows
             NULL to be encoded as 0 in any format, so this works here.  */
-         if (r_symndx == 0)
+         if (r_symndx == STN_UNDEF)
            howto = (elf64_alpha_howto_table
                     + (r_type - R_ALPHA_SREL32 + R_ALPHA_REFLONG));
          goto default_reloc;
@@ -5397,6 +5471,10 @@ static const struct elf_size_info alpha_elf_size_info =
 #define elf_backend_reloc_type_class \
   elf64_alpha_reloc_type_class
 
+#define elf_backend_can_gc_sections    1
+#define elf_backend_gc_mark_hook       elf64_alpha_gc_mark_hook
+#define elf_backend_gc_sweep_hook      elf64_alpha_gc_sweep_hook
+
 #define elf_backend_ecoff_debug_swap \
   &elf64_alpha_ecoff_debug_swap
 
This page took 0.02697 seconds and 4 git commands to generate.