]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - ld/ldlang.c
bfd/
[thirdparty/binutils-gdb.git] / ld / ldlang.c
index 8bd0eea58330006ff15e8e26545d8009a4d84c62..dbe0697d0c87d17bdfcb5b0bc16c503a8cda149e 100644 (file)
@@ -1,5 +1,6 @@
 /* Linker command language support.
-   Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001
    Free Software Foundation, Inc.
 
 This file is part of GLD, the Gnu Linker.
@@ -43,7 +44,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 /* FORWARDS */
 static lang_statement_union_type *new_statement PARAMS ((enum statement_enum,
                                                         size_t,
-                                                        lang_statement_list_type*));
+                                                        lang_statement_list_type *));
 
 /* LOCALS */
 static struct obstack stat_obstack;
@@ -120,15 +121,14 @@ static void print_statement_list
   PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *));
 static void print_statements PARAMS ((void));
 static bfd_vma insert_pad
-  PARAMS ((lang_statement_union_type **this_ptr, fill_type fill,
-          unsigned int power, asection *output_section_statement,
-          bfd_vma dot));
+  PARAMS ((lang_statement_union_type **, fill_type,
+          unsigned int, asection *, bfd_vma));
 static bfd_vma size_input_section
-  PARAMS ((lang_statement_union_type **this_ptr,
-          lang_output_section_statement_type *output_section_statement,
-          fill_type fill, bfd_vma dot, boolean relax));
+  PARAMS ((lang_statement_union_type **, lang_output_section_statement_type *,
+          fill_type, bfd_vma, boolean));
 static void lang_finish PARAMS ((void));
 static void ignore_bfd_errors PARAMS ((const char *, ...));
+static void record_bfd_errors PARAMS ((const char *, ...));
 static void lang_check PARAMS ((void));
 static void lang_common PARAMS ((void));
 static boolean lang_one_common PARAMS ((struct bfd_link_hash_entry *, PTR));
@@ -188,6 +188,7 @@ boolean had_output_filename = false;
 boolean lang_float_flag = false;
 boolean delete_output_file_on_failure = false;
 struct lang_nocrossrefs *nocrossref_list;
+struct unique_sections *unique_section_list;
 
 etree_type *base; /* Relocation base - or null */
 
@@ -197,11 +198,12 @@ etree_type *base; /* Relocation base - or null */
 #define cat(a,b) a/**/b
 #endif
 
-#define new_stat(x,y) (cat(x,_type)*) new_statement(cat(x,_enum), sizeof(cat(x,_type)),y)
+/* Don't beautify the line below with "innocent" whitespace, it breaks the K&R C preprocessor!  */
+#define new_stat(x, y) (cat (x,_type)*) new_statement (cat (x,_enum), sizeof (cat (x,_type)), y)
 
 #define outside_section_address(q) ((q)->output_offset + (q)->output_section->vma)
 
-#define outside_symbol_address(q) ((q)->value + outside_section_address(q->section))
+#define outside_symbol_address(q) ((q)->value + outside_section_address (q->section))
 
 #define SECTION_NAME_MAP_LENGTH (16)
 
@@ -212,6 +214,23 @@ stat_alloc (size)
   return obstack_alloc (&stat_obstack, size);
 }
 
+boolean
+unique_section_p (secnam)
+     const char *secnam;
+{
+  struct unique_sections *unam;
+
+  for (unam = unique_section_list; unam; unam = unam->next)
+    if (wildcardp (unam->name)
+       ? fnmatch (unam->name, secnam, 0) == 0
+       : strcmp (unam->name, secnam) == 0)
+      {
+       return true;
+      }
+
+  return false;
+}
+
 /* Generic traversal routines for finding matching sections.  */
 
 static void
@@ -243,31 +262,26 @@ walk_wild_section (ptr, section, file, callback, data)
   if (file->just_syms_flag == false)
     {
       register asection *s;
-      boolean wildcard;
+      boolean wildcard = false;
 
-      if (section == NULL)
-       wildcard = false;
-      else
+      if (section != NULL)
        wildcard = wildcardp (section);
 
       for (s = file->the_bfd->sections; s != NULL; s = s->next)
        {
          boolean match;
+         const char *sname = bfd_get_section_name (file->the_bfd, s);
 
          if (section == NULL)
            match = true;
+         else if (wildcard)
+           match = fnmatch (section, sname, 0) == 0 ? true : false;
          else
-           {
-             const char *name;
+           match = strcmp (section, sname) == 0 ? true : false;
 
-             name = bfd_get_section_name (file->the_bfd, s);
-             if (wildcard)
-               match = fnmatch (section, name, 0) == 0 ? true : false;
-             else
-               match = strcmp (section, name) == 0 ? true : false;
-           }
-
-         if (match)
+         /* If this is a wild-card output section statement, exclude
+            sections that match UNIQUE_SECTION_LIST.  */
+         if (match && (data == NULL || !unique_section_p (sname)))
            (*callback) (ptr, s, file, data);
        }
     }
@@ -926,20 +940,20 @@ section_already_linked (abfd, sec, data)
   if ((flags & SEC_LINK_ONCE) == 0)
     return;
 
-  /* FIXME: When doing a relocateable link, we may have trouble
+  /* FIXME: When doing a relocatable link, we may have trouble
      copying relocations in other sections that refer to local symbols
      in the section being discarded.  Those relocations will have to
      be converted somehow; as of this writing I'm not sure that any of
      the backends handle that correctly.
 
      It is tempting to instead not discard link once sections when
-     doing a relocateable link (technically, they should be discarded
+     doing a relocatable link (technically, they should be discarded
      whenever we are building constructors).  However, that fails,
      because the linker winds up combining all the link once sections
      into a single large link once section, which defeats the purpose
      of having link once sections in the first place.
 
-     Also, not merging link once sections in a relocateable link
+     Also, not merging link once sections in a relocatable link
      causes trouble for MIPS ELF, which relies in link once semantics
      to handle the .reginfo section correctly.  */
 
@@ -995,8 +1009,7 @@ section_already_linked (abfd, sec, data)
             discarded, we must retain a pointer to the section which
             we are really going to use.  */
          sec->output_section = bfd_abs_section_ptr;
-         if (sec->comdat != NULL)
-           sec->comdat->sec = l->sec;
+         sec->kept_section = l->sec;
 
          return;
        }
@@ -1163,8 +1176,22 @@ wild_doit (ptr, section, output, file)
       if (! first && (section->output_section->flags & SEC_READONLY) == 0)
        flags &= ~ SEC_READONLY;
 
+      /* Keep SEC_MERGE and SEC_STRINGS only if they are the same.  */
+      if (! first
+         && ((section->output_section->flags & (SEC_MERGE | SEC_STRINGS))
+             != (flags & (SEC_MERGE | SEC_STRINGS))
+             || ((flags & SEC_MERGE)
+                 && section->output_section->entsize != section->entsize)))
+       {
+         section->output_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
+         flags &= ~ (SEC_MERGE | SEC_STRINGS);
+       }
+
       section->output_section->flags |= flags;
 
+      if (flags & SEC_MERGE)
+       section->output_section->entsize = section->entsize;
+
       /* If SEC_READONLY is not set in the input section, then clear
          it from the output section.  */
       if ((section->flags & SEC_READONLY) == 0)
@@ -1883,6 +1910,7 @@ open_input_bfds (s, force)
          if (s->input_statement.real)
            {
              lang_statement_list_type add;
+             bfd_error_handler_type pfn;
 
              s->input_statement.target = current_target;
 
@@ -1897,10 +1925,17 @@ open_input_bfds (s, force)
                                       bfd_archive))
                s->input_statement.loaded = false;
 
-             lang_list_init (&add);
+             lang_list_init (& add);
+
+             /* We need to know if an error occurs whilst loading the 
+                symbols, since this means that a valid executable can
+                not be produced.  */
+             pfn = bfd_set_error_handler (record_bfd_errors);
 
              load_symbols (&s->input_statement, &add);
 
+             bfd_set_error_handler (pfn);
+
              if (add.head != NULL)
                {
                  *add.tail = s->next;
@@ -2655,7 +2690,6 @@ size_input_section (this_ptr, output_section_statement, fill, dot, relax)
 #define IGNORE_SECTION(bfd, s) \
   (((bfd_get_section_flags (bfd, s) & (SEC_ALLOC | SEC_LOAD)) != (SEC_ALLOC | SEC_LOAD)) \
    || bfd_section_size (bfd, s) == 0)
-
 /* Check to see if any allocated sections overlap with other allocated
    sections.  This can happen when the linker script specifically specifies
    the output section addresses of the two sections.  */
@@ -2666,6 +2700,7 @@ lang_check_section_addresses ()
   asection *s;
   unsigned opb = bfd_octets_per_byte (output_bfd);
 
+
   /* Scan all sections in the output list.  */
   for (s = output_bfd->sections; s != NULL; s = s->next)
     {
@@ -3424,6 +3459,53 @@ lang_finish ()
     }
 }
 
+
+/* This is the routine to handle BFD error messages.  */
+
+#ifdef ANSI_PROTOTYPES
+
+static void
+record_bfd_errors (const char *s, ...)
+{
+  va_list p;
+
+  einfo ("%P: ");
+
+  va_start (p, s);
+
+  vfprintf (stderr, s, p);
+
+  va_end (p);
+
+  fprintf (stderr, "\n");
+
+  einfo ("%X");
+}
+
+#else /* ! defined (ANSI_PROTOTYPES) */
+
+static void
+record_bfd_errors (va_alist)
+     va_dcl
+{
+  va_list p;
+  const char *s;
+
+  einfo ("%P: ");
+
+  va_start (p);
+
+  s = va_arg (p, const char *);
+  vfprintf (stderr, s, p);
+
+  va_end (p);
+
+  fprintf (stderr, "\n");
+
+  einfo ("%X");
+}
+
+#endif /* ! defined (ANSI_PROTOTYPES) */
 /* This is a small function used when we want to ignore errors from
    BFD.  */
 
@@ -3463,8 +3545,11 @@ lang_check ()
                   bfd_printable_name (input_bfd), input_bfd,
                   bfd_printable_name (output_bfd));
        }
-      else
+      else if (bfd_count_sections (input_bfd))
        {
+         /* If the input bfd has no contents, it shouldn't set the
+            private data of the output bfd. */
+
          bfd_error_handler_type pfn = NULL;
 
          /* If we aren't supposed to warn about mismatched input
@@ -4622,8 +4707,7 @@ static etree_type *overlay_max;
 
 /* A list of all the sections in this overlay.  */
 
-struct overlay_list
-{
+struct overlay_list {
   struct overlay_list *next;
   lang_output_section_statement_type *os;
 };
@@ -4767,7 +4851,14 @@ lang_leave_overlay (fill, memspec, phdrs, lma_memspec)
        l->os->fill = fill;
       if (region != NULL && l->os->region == NULL)
        l->os->region = region;
-      if (lma_region != NULL && l->os->lma_region == NULL)
+      /* We only set lma_region for the first overlay section, as
+        subsequent overlay sections will have load_base set relative
+        to the first section.  Also, don't set lma_region if
+        load_base is specified.  FIXME:  There should really be a test
+        that `AT ( LDADDR )' doesn't conflict with `AT >LMA_REGION'
+        rather than letting LDADDR simply override LMA_REGION.  */
+      if (lma_region != NULL && l->os->lma_region == NULL
+         && l->next == NULL && l->os->load_base == NULL)
        l->os->lma_region = lma_region;
       if (phdrs != NULL && l->os->phdrs == NULL)
        l->os->phdrs = phdrs;
@@ -5030,7 +5121,7 @@ lang_do_version_exports_section ()
        einfo (_("%X%P: unable to read .exports section contents"), sec);
 
       p = contents;
-      while (p < contents+len)
+      while (p < contents + len)
        {
          greg = lang_new_vers_regex (greg, p, NULL);
          p = strchr (p, '\0') + 1;
@@ -5047,3 +5138,19 @@ lang_do_version_exports_section ()
   lang_register_vers_node (command_line.version_exports_section,
                           lang_new_vers_node (greg, lreg), NULL);
 }
+
+void
+lang_add_unique (name)
+     const char *name;
+{
+  struct unique_sections *ent;
+
+  for (ent = unique_section_list; ent; ent = ent->next)
+    if (strcmp (ent->name, name) == 0)
+      return;
+
+  ent = (struct unique_sections *) xmalloc (sizeof *ent);
+  ent->name = xstrdup (name);
+  ent->next = unique_section_list;
+  unique_section_list = ent;
+}