2001-07-10 John Healy <jhealy@redhat.com>
[binutils-gdb.git] / gas / config / obj-elf.c
index bad62594d3a8c831fa0b61e28007ffafbeb7ba8a..9498c1884359d46b6686e3f85be2187c8310a6a5 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.
@@ -620,9 +620,9 @@ static struct special_section const special_sections[] =
 };
 
 void
-obj_elf_change_section (name, type, attr, push)
+obj_elf_change_section (name, type, attr, entsize, push)
      char *name;
-     int type, attr, push;
+     int type, attr, entsize, push;
 {
   asection *old_sec;
   segT sec;
@@ -690,7 +690,9 @@ obj_elf_change_section (name, type, attr, push)
           | ((attr & SHF_WRITE) ? 0 : SEC_READONLY)
           | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0)
           | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0)
-          | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0));
+          | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0)
+          | ((attr & SHF_MERGE) ? SEC_MERGE : 0)
+          | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0));
 #ifdef md_elf_section_flags
   flags = md_elf_section_flags (flags, attr, type);
 #endif
@@ -704,6 +706,8 @@ obj_elf_change_section (name, type, attr, push)
         seg_info (sec)->bss = 1;
 
       bfd_set_section_flags (stdoutput, sec, flags);
+      if (flags & SEC_MERGE)
+       sec->entsize = entsize;
 
       /* Add a symbol for this section to the symbol table.  */
       secsym = symbol_find (name);
@@ -719,8 +723,10 @@ obj_elf_change_section (name, type, attr, push)
         saw the first time.  */
       if ((old_sec->flags ^ flags)
          & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
-            | SEC_EXCLUDE | SEC_SORT_ENTRIES))
+            | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS))
        as_warn (_("Ignoring changed section attributes for %s"), name);
+      else if ((flags & SEC_MERGE) && old_sec->entsize != entsize)
+       as_warn (_("Ignoring changed section entity size for %s"), name);
     }
 
 #ifdef md_elf_section_change_hook
@@ -748,9 +754,15 @@ obj_elf_parse_section_letters (str, len)
        case 'x':
          attr |= SHF_EXECINSTR;
          break;
+       case 'm':
+         attr |= SHF_MERGE;
+         break;
+       case 's':
+         attr |= SHF_STRINGS;
+         break;
        default:
          {
-           char *bad_msg = _("Unrecognized .section attribute: want a,w,x");
+           char *bad_msg = _("Unrecognized .section attribute: want a,m,s,w,x");
 #ifdef md_elf_section_letter
            int md_attr = md_elf_section_letter (*str, &bad_msg);
            if (md_attr >= 0)
@@ -822,6 +834,7 @@ obj_elf_section (push)
 {
   char *name, *beg, *end;
   int type, attr, dummy;
+  int entsize;
 
 #ifndef TC_I370
   if (flag_mri)
@@ -877,6 +890,7 @@ obj_elf_section (push)
 
   type = SHT_NULL;
   attr = 0;
+  entsize = 0;
 
   if (*input_line_pointer == ',')
     {
@@ -919,6 +933,20 @@ obj_elf_section (push)
                  type = obj_elf_section_type (beg, input_line_pointer - beg);
                }
            }
+
+         SKIP_WHITESPACE ();
+         if ((attr & SHF_MERGE) && *input_line_pointer == ',')
+           {
+             ++input_line_pointer;
+             SKIP_WHITESPACE ();
+             entsize = get_absolute_expression ();
+             if (entsize < 0)
+               {
+                 as_warn (_("Bad .section directive - invalid merge entity size"));
+                 attr &= ~SHF_MERGE;
+                 entsize = 0;
+               }
+           }
        }
       else
        {
@@ -948,7 +976,17 @@ obj_elf_section (push)
 
   demand_empty_rest_of_line ();
 
-  obj_elf_change_section (name, type, attr, push);
+  if ((attr & SHF_MERGE) && entsize == 0)
+    {
+      as_warn (_("Entity size for SHF_MERGE not specified.\nSpecify entity size as 4th argument"));
+      attr &= SHF_MERGE;
+    }
+
+#ifdef md_elf_section_change_data_hook
+      md_elf_section_change_data_hook (name, type, attr, entsize, push);
+#endif
+
+  obj_elf_change_section (name, type, attr, entsize, push);
 }
 
 /* Change to the .data section.  */
@@ -1132,7 +1170,7 @@ obj_elf_symver (ignore)
       *input_line_pointer = c;
 
       if (strchr (symbol_get_obj (sym)->versioned_name,
-                                 ELF_VER_CHR) == NULL)
+                 ELF_VER_CHR) == NULL)
        {
          as_bad (_("missing version name in `%s' for symbol `%s'"),
                  symbol_get_obj (sym)->versioned_name,
@@ -1654,6 +1692,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
@@ -1667,13 +1710,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'"),
@@ -1684,36 +1723,50 @@ elf_frob_symbol (symp, puntp)
        }
       else
        {
-         symbolS *symp2;
+         if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR)
+           {
+             size_t l;
+
+             /* 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.  */
+             /* 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);
+           }
        }
     }
 
@@ -1764,7 +1817,7 @@ elf_frob_file ()
 #endif
 }
 
-/* It removes any unneeded versioned symbols from the symbol table. */
+/* It removes any unneeded versioned symbols from the symbol table.  */
 
 void
 elf_frob_file_before_adjust ()
@@ -1774,11 +1827,29 @@ elf_frob_file_before_adjust ()
       symbolS *symp;
 
       for (symp = symbol_rootP; symp; symp = symbol_next (symp))
-       if (symbol_get_obj (symp)->versioned_name
-           && !S_IS_DEFINED (symp)
-           && symbol_used_p (symp) == 0
-           && symbol_used_in_reloc_p (symp) == 0)
-         symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+       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);
+             }
+         }
     }
 }