Fix copyright notices
[deliverable/binutils-gdb.git] / gas / config / obj-elf.c
index 4e7f3a36d0682352ca8a15882532b3cff3991419..162f02fa290a97b7277bc9e0470867c910ad92ce 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF object file format
-   Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000
+   Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -1107,14 +1107,6 @@ obj_elf_symver (ignore)
 
   *input_line_pointer = c;
 
-  if (symbol_get_obj (sym)->versioned_name != NULL)
-    {
-      as_bad (_("multiple .symver directives for symbol `%s'"),
-             S_GET_NAME (sym));
-      ignore_rest_of_line ();
-      return;
-    }
-
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
@@ -1133,16 +1125,34 @@ obj_elf_symver (ignore)
       *input_line_pointer++ = c;
     }
 
-  symbol_get_obj (sym)->versioned_name = xstrdup (name);
+  if (symbol_get_obj (sym)->versioned_name == NULL)
+    {
+      symbol_get_obj (sym)->versioned_name = xstrdup (name);
 
-  *input_line_pointer = c;
+      *input_line_pointer = c;
 
-  if (strchr (symbol_get_obj (sym)->versioned_name, ELF_VER_CHR) == NULL)
+      if (strchr (symbol_get_obj (sym)->versioned_name,
+                 ELF_VER_CHR) == NULL)
+       {
+         as_bad (_("missing version name in `%s' for symbol `%s'"),
+                 symbol_get_obj (sym)->versioned_name,
+                 S_GET_NAME (sym));
+         ignore_rest_of_line ();
+         return;
+       }
+    }
+  else
     {
-      as_bad (_("missing version name in `%s' for symbol `%s'"),
-             symbol_get_obj (sym)->versioned_name, S_GET_NAME (sym));
-      ignore_rest_of_line ();
-      return;
+      if (strcmp (symbol_get_obj (sym)->versioned_name, name))
+       {
+         as_bad (_("multiple versions [`%s'|`%s'] for symbol `%s'"),
+                 name, symbol_get_obj (sym)->versioned_name,
+                 S_GET_NAME (sym));
+         ignore_rest_of_line ();
+         return;
+       }
+
+      *input_line_pointer = c;
     }
 
   demand_empty_rest_of_line ();
@@ -1644,6 +1654,11 @@ elf_frob_symbol (symp, puntp)
 
   if (sy_obj->versioned_name != NULL)
     {
+      char *p;
+
+      p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
+      know (p != NULL);
+
       /* This symbol was given a new name with the .symver directive.
 
          If this is an external reference, just rename the symbol to
@@ -1657,13 +1672,9 @@ elf_frob_symbol (symp, puntp)
 
       if (! S_IS_DEFINED (symp))
        {
-         char *p;
-
          /* Verify that the name isn't using the @@ syntax--this is
              reserved for definitions of the default version to link
              against.  */
-         p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
-         know (p != NULL);
          if (p[1] == ELF_VER_CHR)
            {
              as_bad (_("invalid attempt to declare external version name as default in symbol `%s'"),
@@ -1674,36 +1685,50 @@ elf_frob_symbol (symp, puntp)
        }
       else
        {
-         symbolS *symp2;
+         if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR)
+           {
+             size_t l;
 
-         /* FIXME: Creating a new symbol here is risky.  We're in the
-             final loop over the symbol table.  We can get away with
-             it only because the symbol goes to the end of the list,
-             where the loop will still see it.  It would probably be
-             better to do this in obj_frob_file_before_adjust.  */
+             /* The @@@ syntax is a special case. It renames the
+                symbol name to versioned_name with one `@' removed.  */
+             l = strlen (&p[3]) + 1;
+             memmove (&p [2], &p[3], l);
+             S_SET_NAME (symp, sy_obj->versioned_name);
+           }
+         else
+           {
+             symbolS *symp2;
+
+             /* FIXME: Creating a new symbol here is risky.  We're
+                in the final loop over the symbol table.  We can
+                get away with it only because the symbol goes to
+                the end of the list, where the loop will still see
+                it.  It would probably be better to do this in
+                obj_frob_file_before_adjust.  */
 
-         symp2 = symbol_find_or_make (sy_obj->versioned_name);
+             symp2 = symbol_find_or_make (sy_obj->versioned_name);
 
-         /* Now we act as though we saw symp2 = sym.  */
+             /* Now we act as though we saw symp2 = sym.  */
 
-         S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp));
+             S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp));
 
-         /* Subtracting out the frag address here is a hack because
-             we are in the middle of the final loop.  */
-         S_SET_VALUE (symp2,
-                      (S_GET_VALUE (symp)
-                       - symbol_get_frag (symp)->fr_address));
+             /* Subtracting out the frag address here is a hack
+                because we are in the middle of the final loop.  */
+             S_SET_VALUE (symp2,
+                          (S_GET_VALUE (symp)
+                           - symbol_get_frag (symp)->fr_address));
 
-         symbol_set_frag (symp2, symbol_get_frag (symp));
+             symbol_set_frag (symp2, symbol_get_frag (symp));
 
-         /* This will copy over the size information.  */
-         copy_symbol_attributes (symp2, symp);
+             /* This will copy over the size information.  */
+             copy_symbol_attributes (symp2, symp);
 
-         if (S_IS_WEAK (symp))
-           S_SET_WEAK (symp2);
+             if (S_IS_WEAK (symp))
+               S_SET_WEAK (symp2);
 
-         if (S_IS_EXTERNAL (symp))
-           S_SET_EXTERNAL (symp2);
+             if (S_IS_EXTERNAL (symp))
+               S_SET_EXTERNAL (symp2);
+           }
        }
     }
 
@@ -1754,6 +1779,42 @@ elf_frob_file ()
 #endif
 }
 
+/* It removes any unneeded versioned symbols from the symbol table.  */
+
+void
+elf_frob_file_before_adjust ()
+{
+  if (symbol_rootP)
+    {
+      symbolS *symp;
+
+      for (symp = symbol_rootP; symp; symp = symbol_next (symp))
+       if (symbol_get_obj (symp)->versioned_name)
+         {
+           if (!S_IS_DEFINED (symp))
+             {
+               char *p;
+
+               /* The @@@ syntax is a special case. If the symbol is
+                  not defined, 2 `@'s will be removed from the
+                  versioned_name.  */
+
+               p = strchr (symbol_get_obj (symp)->versioned_name,
+                           ELF_VER_CHR);
+               know (p != NULL);
+               if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR)
+                 {
+                   size_t l = strlen (&p[3]) + 1;
+                   memmove (&p [1], &p[3], l);
+                 }
+               if (symbol_used_p (symp) == 0
+                   && symbol_used_in_reloc_p (symp) == 0)
+                 symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+             }
+         }
+    }
+}
+
 /* It is required that we let write_relocs have the opportunity to
    optimize away fixups before output has begun, since it is possible
    to eliminate all fixups for a section and thus we never should
@@ -1958,6 +2019,7 @@ const struct format_ops elf_format_ops =
   elf_file_symbol,
   elf_frob_symbol,
   elf_frob_file,
+  elf_frob_file_before_adjust,
   elf_frob_file_after_relocs,
   elf_s_get_size, elf_s_set_size,
   elf_s_get_align, elf_s_set_align,
This page took 0.028805 seconds and 4 git commands to generate.