start writing functions for extracting and inserting unusual operands
[deliverable/binutils-gdb.git] / gas / read.c
index 62d783c6cafda8563e14e6a72406defb3f264f36..2bf064d5b428048eb5d193d06f9d05e5fbe0d18c 100644 (file)
@@ -202,7 +202,7 @@ symbolS *mri_common_symbol;
 static int mri_pending_align;
 
 static int scrub_from_string PARAMS ((char **));
-static void do_align PARAMS ((int, char *));
+static void do_align PARAMS ((int, char *, int));
 static int hex_float PARAMS ((int, char *));
 static void do_org PARAMS ((segT, expressionS *, int));
 char *demand_copy_string PARAMS ((int *lenP));
@@ -246,6 +246,8 @@ static const pseudo_typeS potable[] =
   {"ascii", stringer, 0},
   {"asciz", stringer, 1},
   {"balign", s_align_bytes, 0},
+  {"balignw", s_align_bytes, -2},
+  {"balignl", s_align_bytes, -4},
 /* block */
   {"byte", cons, 1},
   {"comm", s_comm, 0},
@@ -325,12 +327,15 @@ static const pseudo_typeS potable[] =
   {"irepc", s_irp, 1},
   {"lcomm", s_lcomm, 0},
   {"lflags", listing_flags, 0},        /* Listing flags */
+  {"linkonce", s_linkonce, 0},
   {"list", listing_list, 1},   /* Turn listing on */
   {"llen", listing_psize, 1},
   {"long", cons, 4},
   {"lsym", s_lsym, 0},
   {"macro", s_macro, 0},
   {"mexit", s_mexit, 0},
+  {"mri", s_mri, 0},
+  {".mri", s_mri, 0},  /* Special case so .mri works in MRI mode.  */
   {"name", s_ignore, 0},
   {"noformat", s_ignore, 0},
   {"nolist", listing_list, 0}, /* Turn listing off */
@@ -339,6 +344,8 @@ static const pseudo_typeS potable[] =
   {"offset", s_struct, 0},
   {"org", s_org, 0},
   {"p2align", s_align_ptwo, 0},
+  {"p2alignw", s_align_ptwo, -2},
+  {"p2alignl", s_align_ptwo, -4},
   {"page", listing_eject, 0},
   {"plen", listing_psize, 0},
   {"print", s_print, 0},
@@ -356,6 +363,7 @@ static const pseudo_typeS potable[] =
   {"single", float_cons, 'f'},
 /* size */
   {"space", s_space, 0},
+  {"skip", s_space, 0},
   {"spc", s_ignore, 0},
   {"stabd", s_stab, 'd'},
   {"stabn", s_stab, 'n'},
@@ -687,7 +695,7 @@ read_a_source_file (name)
                                    || (pop->poc_handler == s_space
                                        && pop->poc_val == 1))))
                        {
-                         do_align (1, (char *) NULL);
+                         do_align (1, (char *) NULL, 0);
                          mri_pending_align = 0;
                        }
 
@@ -724,7 +732,7 @@ read_a_source_file (name)
 
                      if (mri_pending_align)
                        {
-                         do_align (1, (char *) NULL);
+                         do_align (1, (char *) NULL, 0);
                          mri_pending_align = 0;
                        }
 
@@ -1039,12 +1047,13 @@ s_abort (ignore)
 
 /* Guts of .align directive.  */
 static void 
-do_align (n, fill)
+do_align (n, fill, len)
      int n;
      char *fill;
+     int len;
 {
 #ifdef md_do_align
-  md_do_align (n, fill, just_record_alignment);
+  md_do_align (n, fill, len, just_record_alignment);
 #endif
   if (!fill)
     {
@@ -1060,10 +1069,17 @@ do_align (n, fill)
        {
          fill = &zero;
        }
+      len = 1;
     }
+
   /* Only make a frag if we HAVE to. . . */
   if (n && !need_pass_2)
-    frag_align (n, *fill);
+    {
+      if (len <= 1)
+       frag_align (n, *fill);
+      else
+       frag_align_pattern (n, fill, len);
+    }
 
 #ifdef md_do_align
  just_record_alignment:
@@ -1088,7 +1104,12 @@ s_align_bytes (arg)
     stop = mri_comment_field (&stopc);
 
   if (is_end_of_line[(unsigned char) *input_line_pointer])
-    temp = arg;                        /* Default value from pseudo-op table */
+    {
+      if (arg < 0)
+       temp = 0;
+      else
+       temp = arg;     /* Default value from pseudo-op table */
+    }
   else
     temp = get_absolute_expression ();
 
@@ -1110,12 +1131,36 @@ s_align_bytes (arg)
   temp = i;
   if (*input_line_pointer == ',')
     {
+      offsetT fillval;
+      int len;
+
       input_line_pointer++;
-      temp_fill = get_absolute_expression ();
-      do_align (temp, &temp_fill);
+      fillval = get_absolute_expression ();
+      if (arg >= 0)
+       len = 1;
+      else
+       len = - arg;
+      if (len <= 1)
+       {
+         temp_fill = fillval;
+         do_align (temp, &temp_fill, len);
+       }
+      else
+       {
+         char ab[16];
+
+         if (len > sizeof ab)
+           abort ();
+         md_number_to_chars (ab, fillval, len);
+         do_align (temp, ab, len);
+       }
     }
   else
-    do_align (temp, (char *) 0);
+    {
+      if (arg < 0)
+       as_warn ("expected fill pattern missing");
+      do_align (temp, (char *) NULL, 0);
+    }
 
   if (flag_mri)
     mri_comment_end (stop, stopc);
@@ -1125,8 +1170,8 @@ s_align_bytes (arg)
 
 /* For machines where ".align 4" means align to 2**4 boundary. */
 void 
-s_align_ptwo (ignore)
-     int ignore;
+s_align_ptwo (arg)
+     int arg;
 {
   register int temp;
   char temp_fill;
@@ -1147,12 +1192,36 @@ s_align_ptwo (ignore)
     }
   if (*input_line_pointer == ',')
     {
+      offsetT fillval;
+      int len;
+
       input_line_pointer++;
-      temp_fill = get_absolute_expression ();
-      do_align (temp, &temp_fill);
+      fillval = get_absolute_expression ();
+      if (arg >= 0)
+       len = 1;
+      else
+       len = - arg;
+      if (len <= 1)
+       {
+         temp_fill = fillval;
+         do_align (temp, &temp_fill, len);
+       }
+      else
+       {
+         char ab[16];
+
+         if (len > sizeof ab)
+           abort ();
+         md_number_to_chars (ab, fillval, len);
+         do_align (temp, ab, len);
+       }
     }
   else
-    do_align (temp, (char *) 0);
+    {
+      if (arg < 0)
+       as_warn ("expected fill pattern missing");
+      do_align (temp, (char *) NULL, 0);
+    }
 
   if (flag_mri)
     mri_comment_end (stop, stopc);
@@ -1622,6 +1691,83 @@ s_irp (irpc)
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
 }
 
+/* Handle the .linkonce pseudo-op.  This tells the assembler to mark
+   the section to only be linked once.  However, this is not supported
+   by most object file formats.  This takes an optional argument,
+   which is what to do about duplicates.  */
+
+void
+s_linkonce (ignore)
+     int ignore;
+{
+  enum linkonce_type type;
+
+  SKIP_WHITESPACE ();
+
+  type = LINKONCE_DISCARD;
+
+  if (! is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      char *s;
+      char c;
+
+      s = input_line_pointer;
+      c = get_symbol_end ();
+      if (strcasecmp (s, "discard") == 0)
+       type = LINKONCE_DISCARD;
+      else if (strcasecmp (s, "one_only") == 0)
+       type = LINKONCE_ONE_ONLY;
+      else if (strcasecmp (s, "same_size") == 0)
+       type = LINKONCE_SAME_SIZE;
+      else if (strcasecmp (s, "same_contents") == 0)
+       type = LINKONCE_SAME_CONTENTS;
+      else
+       as_warn ("unrecognized .linkonce type `%s'", s);
+
+      *input_line_pointer = c;
+    }
+
+#ifdef obj_handle_link_once
+  obj_handle_link_once (type);
+#else /* ! defined (obj_handle_link_once) */
+#ifdef BFD_ASSEMBLER
+  {
+    flagword flags;
+
+    if ((bfd_applicable_section_flags (stdoutput) & SEC_LINK_ONCE) == 0)
+      as_warn (".linkonce is not supported for this object file format");
+
+    flags = bfd_get_section_flags (stdoutput, now_seg);
+    flags |= SEC_LINK_ONCE;
+    switch (type)
+      {
+      default:
+       abort ();
+      case LINKONCE_DISCARD:
+       flags |= SEC_LINK_DUPLICATES_DISCARD;
+       break;
+      case LINKONCE_ONE_ONLY:
+       flags |= SEC_LINK_DUPLICATES_ONE_ONLY;
+       break;
+      case LINKONCE_SAME_SIZE:
+       flags |= SEC_LINK_DUPLICATES_SAME_SIZE;
+       break;
+      case LINKONCE_SAME_CONTENTS:
+       flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS;
+       break;
+      }
+    if (! bfd_set_section_flags (stdoutput, now_seg, flags))
+      as_bad ("bfd_set_section_flags: %s",
+             bfd_errmsg (bfd_get_error ()));
+  }
+#else /* ! defined (BFD_ASSEMBLER) */
+  as_warn (".linkonce is not supported for this object file format");
+#endif /* ! defined (BFD_ASSEMBLER) */
+#endif /* ! defined (obj_handle_link_once) */
+
+  demand_empty_rest_of_line ();
+}
+
 void 
 s_lcomm (needs_align)
      /* 1 if this was a ".bss" directive, which may require a 3rd argument
@@ -1675,6 +1821,11 @@ s_lcomm (needs_align)
        {
          bss_seg = subseg_new (".sbss", 1);
          seg_info (bss_seg)->bss = 1;
+#ifdef BFD_ASSEMBLER
+         if (! bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC))
+           as_warn ("error setting flags for \".sbss\": %s",
+                    bfd_errmsg (bfd_get_error ()));
+#endif
        }
     }
 #endif
@@ -1856,6 +2007,9 @@ static int
 get_line_sb (line)
      sb *line;
 {
+  if (input_line_pointer[-1] == '\n')
+    bump_line_counters ();
+
   if (input_line_pointer >= buffer_limit)
     {
       buffer_limit = input_scrub_next_buffer (&input_line_pointer);
@@ -1868,11 +2022,8 @@ get_line_sb (line)
   while (input_line_pointer < buffer_limit
         && is_end_of_line[(unsigned char) *input_line_pointer])
     {
-      if (*input_line_pointer == '\n')
-       {
-         bump_line_counters ();
-         LISTING_NEWLINE ();
-       }
+      if (input_line_pointer[-1] == '\n')
+       bump_line_counters ();
       ++input_line_pointer;
     }
   return 1;
@@ -1901,8 +2052,6 @@ s_macro (ignore)
   if (line_label != NULL)
     sb_add_string (&label, S_GET_NAME (line_label));
 
-  demand_empty_rest_of_line ();
-
   err = define_macro (0, &s, &label, get_line_sb);
   if (err != NULL)
     as_bad_where (file, line, "%s", err);
@@ -1929,6 +2078,37 @@ s_mexit (ignore)
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
 }
 
+/* Switch in and out of MRI mode.  */
+
+void
+s_mri (ignore)
+     int ignore;
+{
+  int on, old_flag;
+
+  on = get_absolute_expression ();
+  old_flag = flag_mri;
+  if (on != 0)
+    {
+      flag_mri = 1;
+#ifdef TC_M68K
+      flag_m68k_mri = 1;
+#endif
+    }
+  else
+    {
+      flag_mri = 0;
+      flag_m68k_mri = 0;
+    }
+
+#ifdef MRI_MODE_CHANGE
+  if (on != old_flag)
+    MRI_MODE_CHANGE (on);
+#endif
+
+  demand_empty_rest_of_line ();
+}
+
 /* Handle changing the location counter.  */
 
 static void
@@ -2010,9 +2190,9 @@ s_org (ignore)
 /* Handle parsing for the MRI SECT/SECTION pseudo-op.  This should be
    called by the obj-format routine which handles section changing
    when in MRI mode.  It will create a new section, and return it.  It
-   will set *TYPE to the section type: one of '\0' (unspecified), 'C'
-   (code), 'D' (data), 'M' (mixed), or 'R' (romable).  If
-   BFD_ASSEMBLER is defined, the flags will be set in the section.  */
+   will set *TYPE to the section type: one of 'C' (code), 'D' (data),
+   'M' (mixed), or 'R' (romable).  If BFD_ASSEMBLER is defined, the
+   flags will be set in the section.  */
 
 void
 s_mri_sect (type)
@@ -2040,9 +2220,7 @@ s_mri_sect (type)
       *input_line_pointer = '\0';
     }
 
-  name = strdup (name);
-  if (name == NULL)
-    as_fatal ("virtual memory exhausted");
+  name = xstrdup (name);
 
   *input_line_pointer = c;
 
@@ -2057,7 +2235,7 @@ s_mri_sect (type)
       record_alignment (seg, align);
     }
 
-  *type = '\0';
+  *type = 'C';
   if (*input_line_pointer == ',')
     {
       c = *++input_line_pointer;
@@ -2074,11 +2252,11 @@ s_mri_sect (type)
 
        flags = SEC_NO_FLAGS;
        if (*type == 'C')
-         flags = SEC_CODE;
-       else if (*type == 'D')
-         flags = SEC_DATA;
+         flags = SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE;
+       else if (*type == 'D' || *type == 'M')
+         flags = SEC_ALLOC | SEC_LOAD | SEC_DATA;
        else if (*type == 'R')
-         flags = SEC_ROM;
+         flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY | SEC_ROM;
        if (flags != SEC_NO_FLAGS)
          {
            if (! bfd_set_section_flags (stdoutput, seg, flags))
@@ -2108,9 +2286,7 @@ s_mri_sect (type)
   name = input_line_pointer;
   c = get_symbol_end ();
 
-  name = strdup (name);
-  if (name == NULL)
-    as_fatal ("virtual memory exhausted");
+  name = xstrdup (name);
 
   *input_line_pointer = c;
 
@@ -2323,7 +2499,7 @@ s_space (mult)
      int mult;
 {
   expressionS exp;
-  long temp_fill;
+  expressionS val;
   char *p = 0;
   char *stop = NULL;
   char stopc;
@@ -2335,72 +2511,94 @@ s_space (mult)
   if (flag_mri)
     stop = mri_comment_field (&stopc);
 
-  /* Just like .fill, but temp_size = 1 */
   expression (&exp);
-  if (exp.X_op == O_constant)
-    {
-      long repeat;
 
-      repeat = exp.X_add_number;
-      if (mult)
-       repeat *= mult;
-      if (repeat <= 0)
-       {
-         if (! flag_mri || repeat < 0)
-           as_warn (".space repeat count is %s, ignored",
-                    repeat ? "negative" : "zero");
-         goto getout;
-       }
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == ',')
+    {
+      ++input_line_pointer;
+      expression (&val);
+    }
+  else
+    {
+      val.X_op = O_constant;
+      val.X_add_number = 0;
+    }
 
-      /* If we are in the absolute section, just bump the offset.  */
-      if (now_seg == absolute_section)
+  if (val.X_op != O_constant
+      || val.X_add_number < - 0x80
+      || val.X_add_number > 0xff
+      || (mult != 0 && mult != 1 && val.X_add_number != 0))
+    {
+      if (exp.X_op != O_constant)
+       as_bad ("Unsupported variable size or fill value");
+      else
        {
-         abs_section_offset += repeat;
-         goto getout;
-       }
+         offsetT i;
 
-      /* If we are secretly in an MRI common section, then creating
-         space just increases the size of the common symbol.  */
-      if (mri_common_symbol != NULL)
-       {
-         S_SET_VALUE (mri_common_symbol,
-                      S_GET_VALUE (mri_common_symbol) + repeat);
-         goto getout;
+         if (mult == 0)
+           mult = 1;
+         for (i = 0; i < exp.X_add_number; i++)
+           emit_expr (&val, mult);
        }
-
-      if (!need_pass_2)
-       p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
-                     repeat, (char *) 0);
     }
   else
     {
-      if (now_seg == absolute_section)
+      if (exp.X_op == O_constant)
        {
-         as_bad ("space allocation too complex in absolute section");
-         subseg_set (text_section, 0);
+         long repeat;
+
+         repeat = exp.X_add_number;
+         if (mult)
+           repeat *= mult;
+         if (repeat <= 0)
+           {
+             if (! flag_mri || repeat < 0)
+               as_warn (".space repeat count is %s, ignored",
+                        repeat ? "negative" : "zero");
+             goto getout;
+           }
+
+         /* If we are in the absolute section, just bump the offset.  */
+         if (now_seg == absolute_section)
+           {
+             abs_section_offset += repeat;
+             goto getout;
+           }
+
+         /* If we are secretly in an MRI common section, then
+            creating space just increases the size of the common
+            symbol.  */
+         if (mri_common_symbol != NULL)
+           {
+             S_SET_VALUE (mri_common_symbol,
+                          S_GET_VALUE (mri_common_symbol) + repeat);
+             goto getout;
+           }
+
+         if (!need_pass_2)
+           p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
+                         repeat, (char *) 0);
        }
-      if (mri_common_symbol != NULL)
+      else
        {
-         as_bad ("space allocation too complex in common section");
-         mri_common_symbol = NULL;
+         if (now_seg == absolute_section)
+           {
+             as_bad ("space allocation too complex in absolute section");
+             subseg_set (text_section, 0);
+           }
+         if (mri_common_symbol != NULL)
+           {
+             as_bad ("space allocation too complex in common section");
+             mri_common_symbol = NULL;
+           }
+         if (!need_pass_2)
+           p = frag_var (rs_space, 1, 1, (relax_substateT) 0,
+                         make_expr_symbol (&exp), 0L, (char *) 0);
        }
-      if (!need_pass_2)
-       p = frag_var (rs_space, 1, 1, (relax_substateT) 0,
-                     make_expr_symbol (&exp), 0L, (char *) 0);
-    }
-  SKIP_WHITESPACE ();
-  if (*input_line_pointer == ',')
-    {
-      input_line_pointer++;
-      temp_fill = get_absolute_expression ();
-    }
-  else
-    {
-      temp_fill = 0;
-    }
-  if (p)
-    {
-      *p = temp_fill;
+
+      if (p)
+       *p = val.X_add_number;
     }
 
  getout:
This page took 0.050269 seconds and 4 git commands to generate.