PR ld/1021
[external/binutils.git] / bfd / elflink.c
index 506897b..d030b92 100644 (file)
@@ -433,8 +433,7 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
    this in case some dynamic object refers to this symbol.  */
 
 bfd_boolean
-bfd_elf_record_link_assignment (bfd *output_bfd ATTRIBUTE_UNUSED,
-                               struct bfd_link_info *info,
+bfd_elf_record_link_assignment (struct bfd_link_info *info,
                                const char *name,
                                bfd_boolean provide)
 {
@@ -1188,8 +1187,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
   /* Handle the special case of an old common symbol merging with a
      new symbol which looks like a common symbol in a shared object.
      We change *PSEC and *PVALUE to make the new symbol look like a
-     common symbol, and let _bfd_generic_link_add_one_symbol will do
-     the right thing.  */
+     common symbol, and let _bfd_generic_link_add_one_symbol do the
+     right thing.  */
 
   if (newdyncommon
       && h->root.type == bfd_link_hash_common)
@@ -2362,8 +2361,8 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
 
   if (h->root.type == bfd_link_hash_warning)
     {
-      h->plt = elf_hash_table (eif->info)->init_offset;
-      h->got = elf_hash_table (eif->info)->init_offset;
+      h->got = elf_hash_table (eif->info)->init_got_offset;
+      h->plt = elf_hash_table (eif->info)->init_plt_offset;
 
       /* When warning symbols are created, they **replace** the "real"
         entry in the hash table, thus we never get to see the real
@@ -2392,7 +2391,7 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
          || (!h->ref_regular
              && (h->u.weakdef == NULL || h->u.weakdef->dynindx == -1))))
     {
-      h->plt = elf_hash_table (eif->info)->init_offset;
+      h->plt = elf_hash_table (eif->info)->init_plt_offset;
       return TRUE;
     }
 
@@ -3688,11 +3687,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 
          /* If this is a hidden symbol, or if it is not version
             1, we append the version name to the symbol name.
-            However, we do not modify a non-hidden absolute
-            symbol, because it might be the version symbol
-            itself.  FIXME: What if it isn't?  */
+            However, we do not modify a non-hidden absolute symbol
+            if it is not a function, because it might be the version
+            symbol itself.  FIXME: What if it isn't?  */
          if ((iver.vs_vers & VERSYM_HIDDEN) != 0
-             || (vernum > 1 && ! bfd_is_abs_section (sec)))
+             || (vernum > 1 && (! bfd_is_abs_section (sec)
+                                || ELF_ST_TYPE (isym->st_info) == STT_FUNC)))
            {
              const char *verstr;
              size_t namelen, verlen, newlen;
@@ -4986,7 +4986,10 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
   /* Any syms created from now on start with -1 in
      got.refcount/offset and plt.refcount/offset.  */
-  elf_hash_table (info)->init_refcount = elf_hash_table (info)->init_offset;
+  elf_hash_table (info)->init_got_refcount
+    = elf_hash_table (info)->init_got_offset;
+  elf_hash_table (info)->init_plt_refcount
+    = elf_hash_table (info)->init_plt_offset;
 
   /* The backend may have to create some sections regardless of whether
      we're dynamic or not.  */
@@ -5377,7 +5380,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
            {
              bfd_size_type indx;
 
-             name = basename (output_bfd->filename);
+             name = lbasename (output_bfd->filename);
              def.vd_hash = bfd_elf_hash (name);
              indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                          name, FALSE);
@@ -5600,7 +5603,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                            elf_dt_name (t->vn_bfd) != NULL
                                            ? elf_dt_name (t->vn_bfd)
-                                           : basename (t->vn_bfd->filename),
+                                           : lbasename (t->vn_bfd->filename),
                                            FALSE);
                if (indx == (bfd_size_type) -1)
                  return FALSE;
@@ -6379,7 +6382,9 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
     {
       (*_bfd_error_handler)
        (_("%B: %s symbol `%s' in %B is referenced by DSO"),
-        finfo->output_bfd, h->root.u.def.section->owner,
+        finfo->output_bfd,
+        h->root.u.def.section == bfd_abs_section_ptr
+        ? finfo->output_bfd : h->root.u.def.section->owner,
         ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
         ? "internal"
         : ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
@@ -7082,14 +7087,10 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                    {
                      BFD_ASSERT (r_symndx != 0);
                      if (action & COMPLAIN)
-                       {
-                         (*_bfd_error_handler)
-                           (_("`%s' referenced in section `%A' of %B: "
-                              "defined in discarded section `%A' of %B"),
-                            o, input_bfd, sec, sec->owner, sym_name);
-                         bfd_set_error (bfd_error_bad_value);
-                         return FALSE;
-                       }
+                       (*finfo->info->callbacks->einfo)
+                         (_("%X`%s' referenced in section `%A' of %B: "
+                            "defined in discarded section `%A' of %B"),
+                          sym_name, o, input_bfd, sec, sec->owner);
 
                      /* Try to do the best we can to support buggy old
                         versions of gcc.  If we've warned, or this is
@@ -8732,6 +8733,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
                  gc_mark_hook_fn gc_mark_hook)
 {
   bfd_boolean ret;
+  bfd_boolean is_eh;
   asection *group_sec;
 
   sec->gc_mark = 1;
@@ -8744,6 +8746,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
 
   /* Look through the section relocs.  */
   ret = TRUE;
+  is_eh = strcmp (sec->name, ".eh_frame") == 0;
   if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
     {
       Elf_Internal_Rela *relstart, *rel, *relend;
@@ -8820,6 +8823,8 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
            {
              if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
                rsec->gc_mark = 1;
+             else if (is_eh)
+               rsec->gc_mark_from_eh = 1;
              else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
                {
                  ret = FALSE;
@@ -8890,6 +8895,41 @@ elf_gc_sweep (struct bfd_link_info *info, gc_sweep_hook_fn gc_sweep_hook)
          if (o->gc_mark)
            continue;
 
+         /* Keep .gcc_except_table.* if the associated .text.* is
+            marked.  This isn't very nice, but the proper solution,
+            splitting .eh_frame up and using comdat doesn't pan out 
+            easily due to needing special relocs to handle the
+            difference of two symbols in separate sections.
+            Don't keep code sections referenced by .eh_frame.  */
+         if (o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0)
+           {
+             if (strncmp (o->name, ".gcc_except_table.", 18) == 0)
+               {
+                 unsigned long len;
+                 char *fn_name;
+                 asection *fn_text;
+
+                 len = strlen (o->name + 18) + 1;
+                 fn_name = bfd_malloc (len + 6);
+                 if (fn_name == NULL)
+                   return FALSE;
+                 memcpy (fn_name, ".text.", 6);
+                 memcpy (fn_name + 6, o->name + 18, len);
+                 fn_text = bfd_get_section_by_name (sub, fn_name);
+                 free (fn_name);
+                 if (fn_text != NULL && fn_text->gc_mark)
+                   o->gc_mark = 1;
+               }
+
+             /* If not using specially named exception table section,
+                then keep whatever we are using.  */
+             else
+               o->gc_mark = 1;
+
+             if (o->gc_mark)
+               continue;
+           }
+
          /* Skip sweeping sections already excluded.  */
          if (o->flags & SEC_EXCLUDE)
            continue;
@@ -8901,7 +8941,9 @@ elf_gc_sweep (struct bfd_link_info *info, gc_sweep_hook_fn gc_sweep_hook)
          /* But we also have to update some of the relocation
             info we collected before.  */
          if (gc_sweep_hook
-             && (o->flags & SEC_RELOC) && o->reloc_count > 0)
+             && (o->flags & SEC_RELOC) != 0
+             && o->reloc_count > 0
+             && !bfd_is_abs_section (o->output_section))
            {
              Elf_Internal_Rela *internal_relocs;
              bfd_boolean r;
@@ -9066,27 +9108,6 @@ elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h,
   return TRUE;
 }
 
-/* Mark sections containing global symbols.  This is called through
-   elf_link_hash_traverse.  */
-
-static bfd_boolean
-elf_mark_used_section (struct elf_link_hash_entry *h,
-                      void *data ATTRIBUTE_UNUSED)
-{
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  if (h->root.type == bfd_link_hash_defined
-      || h->root.type == bfd_link_hash_defweak)
-    {
-      asection *s = h->root.u.def.section;
-      if (s != NULL && s->output_section != NULL)
-       s->output_section->flags |= SEC_KEEP;
-    }
-
-  return TRUE;
-}
-
 /* Do mark and sweep of unused sections.  */
 
 bfd_boolean
@@ -9098,17 +9119,6 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
     (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
      struct elf_link_hash_entry *h, Elf_Internal_Sym *);
 
-  if (!info->gc_sections)
-    {
-      /* If we are called when info->gc_sections is 0, we will mark
-        all sections containing global symbols for non-relocatable
-        link.  */
-      if (!info->relocatable)
-       elf_link_hash_traverse (elf_hash_table (info),
-                               elf_mark_used_section, NULL);
-      return TRUE;
-    }
-
   if (!get_elf_backend_data (abfd)->can_gc_sections
       || info->relocatable
       || info->emitrelocations
@@ -9151,18 +9161,9 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
        continue;
 
       for (o = sub->sections; o != NULL; o = o->next)
-       {
-         if (o->flags & SEC_KEEP)
-           {
-             /* _bfd_elf_discard_section_eh_frame knows how to discard
-                orphaned FDEs so don't mark sections referenced by the
-                EH frame section.  */
-             if (strcmp (o->name, ".eh_frame") == 0)
-               o->gc_mark = 1;
-             else if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
-               return FALSE;
-           }
-       }
+       if ((o->flags & SEC_KEEP) != 0 && !o->gc_mark)
+         if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
+           return FALSE;
     }
 
   /* ... and mark SEC_EXCLUDE for those that go.  */
@@ -9820,10 +9821,11 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
 }
 
 static void
-bfd_elf_set_symbol (struct elf_link_hash_entry *h, bfd_vma val)
+bfd_elf_set_symbol (struct elf_link_hash_entry *h, bfd_vma val,
+                   struct bfd_section *s)
 {
   h->root.type = bfd_link_hash_defined;
-  h->root.u.def.section = bfd_abs_section_ptr;
+  h->root.u.def.section = s ? s : bfd_abs_section_ptr;
   h->root.u.def.value = val;
   h->def_regular = 1;
   h->type = STT_OBJECT;
@@ -9831,23 +9833,28 @@ bfd_elf_set_symbol (struct elf_link_hash_entry *h, bfd_vma val)
   h->forced_local = 1;
 }
 
-/* Set NAME to VAL if the symbol exists and is undefined.  */
+/* Set NAME to VAL if the symbol exists and is not defined in a regular
+   object file.  If S is NULL it is an absolute symbol, otherwise it is
+   relative to that section.  */
 
 void
 _bfd_elf_provide_symbol (struct bfd_link_info *info, const char *name,
-                        bfd_vma val)
+                        bfd_vma val, struct bfd_section *s)
 {
   struct elf_link_hash_entry *h;
 
-  h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE,
-                           FALSE);
-  if (h != NULL && (h->root.type == bfd_link_hash_undefined
-                   || h->root.type == bfd_link_hash_undefweak))
-    bfd_elf_set_symbol (h, val);
+  bfd_elf_record_link_assignment (info, name, TRUE);
+
+  h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
+  if (h != NULL
+      && !(h->root.type == bfd_link_hash_defined
+          && h->root.u.def.section != NULL
+          && h->root.u.def.section != h->root.u.def.section->output_section))
+    bfd_elf_set_symbol (h, val, s);
 }
 
-/* Set START and END to boundaries of SEC if they exist and are
-   undefined.  */
+/* Set START and END to boundaries of SEC if they exist and are not
+   defined in regular object files.  */
 
 void
 _bfd_elf_provide_section_bound_symbols (struct bfd_link_info *info,
@@ -9855,49 +9862,41 @@ _bfd_elf_provide_section_bound_symbols (struct bfd_link_info *info,
                                        const char *start,
                                        const char *end)
 {
-  struct elf_link_hash_entry *hs, *he;
-  bfd_vma start_val, end_val;
-  bfd_boolean do_start, do_end;
-
-  /* Check if we need them or not first.  */
-  hs = elf_link_hash_lookup (elf_hash_table (info), start, FALSE,
-                            FALSE, FALSE);
-  do_start = (hs != NULL
-             && (hs->root.type == bfd_link_hash_undefined
-                 || hs->root.type == bfd_link_hash_undefweak));
-
-  he = elf_link_hash_lookup (elf_hash_table (info), end, FALSE,
-                            FALSE, FALSE);
-  do_end = (he != NULL
-           && (he->root.type == bfd_link_hash_undefined
-               || he->root.type == bfd_link_hash_undefweak));
-
-  if (!do_start && !do_end)
-    return;
-
+  bfd_vma val = 0;
+  _bfd_elf_provide_symbol (info, start, val, sec);
   if (sec != NULL)
+    val = sec->size;
+  _bfd_elf_provide_symbol (info, end, val, sec);
+}
+
+/* Convert symbols in excluded output sections to absolute.  */
+
+static bfd_boolean
+fix_syms (struct bfd_link_hash_entry *h, void *data)
+{
+  bfd *obfd = (bfd *) data;
+
+  if (h->type == bfd_link_hash_warning)
+    h = h->u.i.link;
+
+  if (h->type == bfd_link_hash_defined
+      || h->type == bfd_link_hash_defweak)
     {
-      start_val = sec->vma;
-      end_val = start_val + sec->size;
-    }
-  else
-    {
-      /* We have to choose those values very carefully.  Some targets,
-        like alpha, may have relocation overflow with 0. "__bss_start"
-        should be defined in all cases.  */
-      struct elf_link_hash_entry *h
-       = elf_link_hash_lookup (elf_hash_table (info), "__bss_start",
-                               FALSE, FALSE, FALSE);
-      if (h != NULL && h->root.type == bfd_link_hash_defined)
-       start_val = h->root.u.def.value;
-      else
-       start_val = 0;
-      end_val = start_val;
+      asection *s = h->u.def.section;
+      if (s != NULL
+         && s == s->output_section
+         && bfd_section_removed_from_list (obfd, s))
+       {
+         h->u.def.value += s->vma;
+         h->u.def.section = bfd_abs_section_ptr;
+       }
     }
 
-  if (do_start)
-    bfd_elf_set_symbol (hs, start_val);
+  return TRUE;
+}
 
-  if (do_end)
-    bfd_elf_set_symbol (he, end_val);
+void
+_bfd_elf_fix_excluded_sec_syms (bfd *obfd, struct bfd_link_info *info)
+{
+  bfd_link_hash_traverse (info->hash, fix_syms, obfd);
 }