Mention PR ld/4701.
[deliverable/binutils-gdb.git] / bfd / linker.c
index 9e6199b835a5b40b682e751126f7a6fa0517b982..497b5c23556588a223a3ae1e9033b1b70ecfbf53 100644 (file)
@@ -1,6 +1,7 @@
 /* linker.c -- BFD linker routines
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
 /* linker.c -- BFD linker routines
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
 
    This file is part of BFD, the Binary File Descriptor library.
    Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -19,8 +20,8 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-#include "bfd.h"
 #include "sysdep.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "libbfd.h"
 #include "bfdlink.h"
 #include "genlink.h"
 #include "libbfd.h"
 #include "bfdlink.h"
 #include "genlink.h"
@@ -472,14 +473,15 @@ _bfd_link_hash_table_init
    bfd *abfd,
    struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
                                      struct bfd_hash_table *,
    bfd *abfd,
    struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
                                      struct bfd_hash_table *,
-                                     const char *))
+                                     const char *),
+   unsigned int entsize)
 {
   table->creator = abfd->xvec;
   table->undefs = NULL;
   table->undefs_tail = NULL;
   table->type = bfd_link_generic_hash_table;
 
 {
   table->creator = abfd->xvec;
   table->undefs = NULL;
   table->undefs_tail = NULL;
   table->type = bfd_link_generic_hash_table;
 
-  return bfd_hash_table_init (&table->table, newfunc);
+  return bfd_hash_table_init (&table->table, newfunc, entsize);
 }
 
 /* Look up a symbol in a link hash table.  If follow is TRUE, we
 }
 
 /* Look up a symbol in a link hash table.  If follow is TRUE, we
@@ -561,11 +563,11 @@ bfd_wrapped_link_hash_lookup (bfd *abfd,
 
 #undef WRAP
 
 
 #undef WRAP
 
-#undef REAL
+#undef  REAL
 #define REAL "__real_"
 
       if (*l == '_'
 #define REAL "__real_"
 
       if (*l == '_'
-         && strncmp (l, REAL, sizeof REAL - 1) == 0
+         && CONST_STRNEQ (l, REAL)
          && bfd_hash_lookup (info->wrap_hash, l + sizeof REAL - 1,
                              FALSE, FALSE) != NULL)
        {
          && bfd_hash_lookup (info->wrap_hash, l + sizeof REAL - 1,
                              FALSE, FALSE) != NULL)
        {
@@ -709,7 +711,8 @@ _bfd_generic_link_hash_table_create (bfd *abfd)
   if (ret == NULL)
     return NULL;
   if (! _bfd_link_hash_table_init (&ret->root, abfd,
   if (ret == NULL)
     return NULL;
   if (! _bfd_link_hash_table_init (&ret->root, abfd,
-                                  _bfd_generic_link_hash_newfunc))
+                                  _bfd_generic_link_hash_newfunc,
+                                  sizeof (struct generic_link_hash_entry)))
     {
       free (ret);
       return NULL;
     {
       free (ret);
       return NULL;
@@ -901,9 +904,10 @@ archive_hash_table_init
   (struct archive_hash_table *table,
    struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
                                      struct bfd_hash_table *,
   (struct archive_hash_table *table,
    struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
                                      struct bfd_hash_table *,
-                                     const char *))
+                                     const char *),
+   unsigned int entsize)
 {
 {
-  return bfd_hash_table_init (&table->table, newfunc);
+  return bfd_hash_table_init (&table->table, newfunc, entsize);
 }
 
 /* Look up an entry in an archive hash table.  */
 }
 
 /* Look up an entry in an archive hash table.  */
@@ -981,7 +985,8 @@ _bfd_generic_link_add_archive_symbols
 
   /* In order to quickly determine whether an symbol is defined in
      this archive, we build a hash table of the symbols.  */
 
   /* In order to quickly determine whether an symbol is defined in
      this archive, we build a hash table of the symbols.  */
-  if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc))
+  if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc,
+                                sizeof (struct archive_hash_entry)))
     return FALSE;
   for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
     {
     return FALSE;
   for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
     {
@@ -1655,8 +1660,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
                s = name + 1;
                while (*s == '_')
                  ++s;
                s = name + 1;
                while (*s == '_')
                  ++s;
-               if (s[0] == 'G'
-                   && strncmp (s, CONS_PREFIX, CONS_PREFIX_LEN - 1) == 0)
+               if (s[0] == 'G' && CONST_STRNEQ (s, CONS_PREFIX))
                  {
                    char c;
 
                  {
                    char c;
 
@@ -2717,11 +2721,10 @@ default_indirect_link_order (bfd *output_bfd,
 
   BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
 
 
   BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
 
-  if (link_order->size == 0)
-    return TRUE;
-
   input_section = link_order->u.indirect.section;
   input_bfd = input_section->owner;
   input_section = link_order->u.indirect.section;
   input_bfd = input_section->owner;
+  if (input_section->size == 0)
+    return TRUE;
 
   BFD_ASSERT (input_section->output_section == output_section);
   BFD_ASSERT (input_section->output_offset == link_order->offset);
 
   BFD_ASSERT (input_section->output_section == output_section);
   BFD_ASSERT (input_section->output_offset == link_order->offset);
@@ -2810,9 +2813,9 @@ default_indirect_link_order (bfd *output_bfd,
     goto error_return;
 
   /* Output the section contents.  */
     goto error_return;
 
   /* Output the section contents.  */
-  loc = link_order->offset * bfd_octets_per_byte (output_bfd);
+  loc = input_section->output_offset * bfd_octets_per_byte (output_bfd);
   if (! bfd_set_section_contents (output_bfd, output_section,
   if (! bfd_set_section_contents (output_bfd, output_section,
-                                 new_contents, loc, link_order->size))
+                                 new_contents, loc, input_section->size))
     goto error_return;
 
   if (contents != NULL)
     goto error_return;
 
   if (contents != NULL)
@@ -2874,14 +2877,15 @@ FUNCTION
        bfd_section_already_linked
 
 SYNOPSIS
        bfd_section_already_linked
 
 SYNOPSIS
-        void bfd_section_already_linked (bfd *abfd, asection *sec);
+        void bfd_section_already_linked (bfd *abfd, asection *sec,
+                                        struct bfd_link_info *info);
 
 DESCRIPTION
        Check if @var{sec} has been already linked during a reloceatable
        or final link.
 
 
 DESCRIPTION
        Check if @var{sec} has been already linked during a reloceatable
        or final link.
 
-.#define bfd_section_already_linked(abfd, sec) \
-.       BFD_SEND (abfd, _section_already_linked, (abfd, sec))
+.#define bfd_section_already_linked(abfd, sec, info) \
+.       BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
 .
 
 */
 .
 
 */
@@ -2953,7 +2957,9 @@ bfd_boolean
 bfd_section_already_linked_table_init (void)
 {
   return bfd_hash_table_init_n (&_bfd_section_already_linked_table,
 bfd_section_already_linked_table_init (void)
 {
   return bfd_hash_table_init_n (&_bfd_section_already_linked_table,
-                               already_linked_newfunc, 42);
+                               already_linked_newfunc,
+                               sizeof (struct bfd_section_already_linked_hash_entry),
+                               42);
 }
 
 void
 }
 
 void
@@ -2965,7 +2971,8 @@ bfd_section_already_linked_table_free (void)
 /* This is used on non-ELF inputs.  */
 
 void
 /* This is used on non-ELF inputs.  */
 
 void
-_bfd_generic_section_already_linked (bfd *abfd, asection *sec)
+_bfd_generic_section_already_linked (bfd *abfd, asection *sec,
+                                    struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   flagword flags;
   const char *name;
 {
   flagword flags;
   const char *name;
@@ -3069,7 +3076,7 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec)
   bfd_section_already_linked_table_insert (already_linked_list, sec);
 }
 
   bfd_section_already_linked_table_insert (already_linked_list, sec);
 }
 
-/* Convert symbols in excluded output sections to absolute.  */
+/* Convert symbols in excluded output sections to use a kept section.  */
 
 static bfd_boolean
 fix_syms (struct bfd_link_hash_entry *h, void *data)
 
 static bfd_boolean
 fix_syms (struct bfd_link_hash_entry *h, void *data)
@@ -3088,8 +3095,64 @@ fix_syms (struct bfd_link_hash_entry *h, void *data)
          && (s->output_section->flags & SEC_EXCLUDE) != 0
          && bfd_section_removed_from_list (obfd, s->output_section))
        {
          && (s->output_section->flags & SEC_EXCLUDE) != 0
          && bfd_section_removed_from_list (obfd, s->output_section))
        {
+         asection *op, *op1;
+
          h->u.def.value += s->output_offset + s->output_section->vma;
          h->u.def.value += s->output_offset + s->output_section->vma;
-         h->u.def.section = bfd_abs_section_ptr;
+
+         /* Find preceding kept section.  */
+         for (op1 = s->output_section->prev; op1 != NULL; op1 = op1->prev)
+           if ((op1->flags & SEC_EXCLUDE) == 0
+               && !bfd_section_removed_from_list (obfd, op1))
+             break;
+
+         /* Find following kept section.  Start at prev->next because
+            other sections may have been added after S was removed.  */
+         if (s->output_section->prev != NULL)
+           op = s->output_section->prev->next;
+         else
+           op = s->output_section->owner->sections;
+         for (; op != NULL; op = op->next)
+           if ((op->flags & SEC_EXCLUDE) == 0
+               && !bfd_section_removed_from_list (obfd, op))
+             break;
+
+         /* Choose better of two sections, based on flags.  The idea
+            is to choose a section that will be in the same segment
+            as S would have been if it was kept.  */
+         if (op1 == NULL)
+           {
+             if (op == NULL)
+               op = bfd_abs_section_ptr;
+           }
+         else if (op == NULL)
+           op = op1;
+         else if (((op1->flags ^ op->flags)
+                   & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0)
+           {
+             if (((op->flags ^ s->flags)
+                  & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0)
+               op = op1;
+           }
+         else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0)
+           {
+             if (((op->flags ^ s->flags) & SEC_READONLY) != 0)
+               op = op1;
+           }
+         else if (((op1->flags ^ op->flags) & SEC_CODE) != 0)
+           {
+             if (((op->flags ^ s->flags) & SEC_CODE) != 0)
+               op = op1;
+           }
+         else
+           {
+             /* Flags we care about are the same.  Prefer the following
+                section if that will result in a positive valued sym.  */
+             if (h->u.def.value < op->vma)
+               op = op1;
+           }
+
+         h->u.def.value -= op->vma;
+         h->u.def.section = op;
        }
     }
 
        }
     }
 
This page took 0.026409 seconds and 4 git commands to generate.