Avoid setting or recording negative alignments when the target stores multiple octets...
authorDan Gisselquist <dgisselq@verizon.net>
Thu, 18 Feb 2016 09:47:31 +0000 (09:47 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 18 Feb 2016 09:49:04 +0000 (09:49 +0000)
gas * read.c (finish_bundle): Avoid recording a negative alignment.
(do_align): Use unsigned values for n, len and max.  Only create
a frag if the alignment requirement is greater than the minimum
byte alignment.  Avoid recording a negative alignment.
(s_align): Use unsigned values where appropriate.
(bss_alloc): Use an unsigned value for the alignment.
(sizeof_sleb128): Add a comment noting that we encode one octet
per byte, regardless of the value of OCTETS_PER_BYTE_POWER.
(emit_leb129_expr): Abort if the emitted encoding was longer than
expected.
* read.h (output_leb128): Update prototype.
(sizeof_leb128): Update prototype.
(bss_alloc): Update prototype.
* write.c (record_alignment): Use an unsigned value for the
alignment.  Do not record alignments less than the minimum
alignment for a byte.
* write.h (record_alignment): Update prototype.

gas/ChangeLog
gas/read.c
gas/read.h
gas/write.c
gas/write.h

index 3688728f2a680f722bc1719c1a873c717396c639..7236c3ee82f169a2ec7d80986731ee2d5ca39f74 100644 (file)
@@ -1,3 +1,24 @@
+2016-02-18  Dan Gisselquist  <dgisselq@verizon.net>
+           Nick Clifton  <nickc@redhat.com>
+
+       * read.c (finish_bundle): Avoid recording a negative alignment.
+       (do_align): Use unsigned values for n, len and max.  Only create
+       a frag if the alignment requirement is greater than the minimum
+       byte alignment.  Avoid recording a negative alignment.
+       (s_align): Use unsigned values where appropriate.
+       (bss_alloc): Use an unsigned value for the alignment.
+       (sizeof_sleb128): Add a comment noting that we encode one octet
+       per byte, regardless of the value of OCTETS_PER_BYTE_POWER.
+       (emit_leb129_expr): Abort if the emitted encoding was longer than
+       expected.
+       * read.h (output_leb128): Update prototype.
+       (sizeof_leb128): Update prototype.
+       (bss_alloc): Update prototype.
+       * write.c (record_alignment): Use an unsigned value for the
+       alignment.  Do not record alignments less than the minimum
+       alignment for a byte.
+       * write.h (record_alignment): Update prototype.
+
 2016-02-17  Max Filippov  <jcmvbkbc@gmail.com>
 
        * config/tc-xtensa.c (xtensa_move_literals): Fix check for
index 5c0478997256ac5852856772311ac95d0e5f9db7..f8fff782e034c92c813e1b6f69278f3a92c6887a 100644 (file)
@@ -238,7 +238,6 @@ static unsigned int bundle_lock_depth;
 #endif
 
 static void do_s_func (int end_p, const char *default_prefix);
-static void do_align (int, char *, int, int);
 static void s_align (int, int);
 static void s_altmacro (int);
 static void s_bad_end (int);
@@ -487,6 +486,7 @@ static offsetT
 get_absolute_expr (expressionS *exp)
 {
   expression_and_evaluate (exp);
+
   if (exp->X_op != O_constant)
     {
       if (exp->X_op != O_absent)
@@ -685,7 +685,8 @@ finish_bundle (fragS *frag, unsigned int size)
   /* We do this every time rather than just in s_bundle_align_mode
      so that we catch any affected section without needing hooks all
      over for all paths that do section changes.  It's cheap enough.  */
-  record_alignment (now_seg, bundle_align_p2 - OCTETS_PER_BYTE_POWER);
+  if (bundle_align_p2 > OCTETS_PER_BYTE_POWER)
+    record_alignment (now_seg, bundle_align_p2 - OCTETS_PER_BYTE_POWER);
 }
 
 /* Assemble one instruction.  This takes care of the bundle features
@@ -736,6 +737,75 @@ single instruction is %u bytes long but .bundle_align_mode limit is %u"),
 
 #endif  /* HANDLE_BUNDLE */
 
+static bfd_boolean
+in_bss (void)
+{
+  flagword flags = bfd_get_section_flags (stdoutput, now_seg);
+
+  return (flags & SEC_ALLOC) && !(flags & (SEC_LOAD | SEC_HAS_CONTENTS));
+}
+
+/* Guts of .align directive:
+   N is the power of two to which to align.  A value of zero is accepted but
+    ignored: the default alignment of the section will be at least this.
+   FILL may be NULL, or it may point to the bytes of the fill pattern.
+   LEN is the length of whatever FILL points to, if anything.  If LEN is zero
+    but FILL is not NULL then LEN is treated as if it were one.
+   MAX is the maximum number of characters to skip when doing the alignment,
+    or 0 if there is no maximum.  */
+
+static void
+do_align (unsigned int n, char *fill, unsigned int len, unsigned int max)
+{
+  if (now_seg == absolute_section || in_bss ())
+    {
+      if (fill != NULL)
+       while (len-- > 0)
+         if (*fill++ != '\0')
+           {
+             if (now_seg == absolute_section)
+               as_warn (_("ignoring fill value in absolute section"));
+             else
+               as_warn (_("ignoring fill value in section `%s'"),
+                        segment_name (now_seg));
+             break;
+           }
+      fill = NULL;
+      len = 0;
+    }
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+#ifdef md_do_align
+  md_do_align (n, fill, len, max, just_record_alignment);
+#endif
+
+  /* Only make a frag if we HAVE to...  */
+  if ((n > OCTETS_PER_BYTE_POWER) && !need_pass_2)
+    {
+      if (fill == NULL)
+       {
+         if (subseg_text_p (now_seg))
+           frag_align_code (n, max);
+         else
+           frag_align (n, 0, max);
+       }
+      else if (len <= 1)
+       frag_align (n, *fill, max);
+      else
+       frag_align_pattern (n, fill, len, max);
+    }
+
+#ifdef md_do_align
+ just_record_alignment: ATTRIBUTE_UNUSED_LABEL
+#endif
+
+  if (n > OCTETS_PER_BYTE_POWER)
+    record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER);
+}
+
 /* We read the file, putting things into a web that represents what we
    have been reading.  */
 void
@@ -1337,14 +1407,6 @@ convert_to_bignum (expressionS *exp, int sign)
   exp->X_add_number = i;
 }
 
-static bfd_boolean
-in_bss (void)
-{
-  flagword flags = bfd_get_section_flags (stdoutput, now_seg);
-
-  return (flags & SEC_ALLOC) && !(flags & (SEC_LOAD | SEC_HAS_CONTENTS));
-}
-
 /* For most MRI pseudo-ops, the line actually ends at the first
    nonquoted space.  This function looks for that point, stuffs a null
    in, and sets *STOPCP to the character that used to be there, and
@@ -1401,62 +1463,6 @@ s_abort (int ignore ATTRIBUTE_UNUSED)
   as_fatal (_(".abort detected.  Abandoning ship."));
 }
 
-/* Guts of .align directive.  N is the power of two to which to align.
-   FILL may be NULL, or it may point to the bytes of the fill pattern.
-   LEN is the length of whatever FILL points to, if anything.  MAX is
-   the maximum number of characters to skip when doing the alignment,
-   or 0 if there is no maximum.  */
-
-static void
-do_align (int n, char *fill, int len, int max)
-{
-  if (now_seg == absolute_section || in_bss ())
-    {
-      if (fill != NULL)
-       while (len-- > 0)
-         if (*fill++ != '\0')
-           {
-             if (now_seg == absolute_section)
-               as_warn (_("ignoring fill value in absolute section"));
-             else
-               as_warn (_("ignoring fill value in section `%s'"),
-                        segment_name (now_seg));
-             break;
-           }
-      fill = NULL;
-      len = 0;
-    }
-
-#ifdef md_flush_pending_output
-  md_flush_pending_output ();
-#endif
-#ifdef md_do_align
-  md_do_align (n, fill, len, max, just_record_alignment);
-#endif
-
-  /* Only make a frag if we HAVE to...  */
-  if (n != 0 && !need_pass_2)
-    {
-      if (fill == NULL)
-       {
-         if (subseg_text_p (now_seg))
-           frag_align_code (n, max);
-         else
-           frag_align (n, 0, max);
-       }
-      else if (len <= 1)
-       frag_align (n, *fill, max);
-      else
-       frag_align_pattern (n, fill, len, max);
-    }
-
-#ifdef md_do_align
- just_record_alignment: ATTRIBUTE_UNUSED_LABEL
-#endif
-
-  record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER);
-}
-
 /* Handle the .align pseudo-op.  A positive ARG is a default alignment
    (in bytes).  A negative ARG is the negative of the length of the
    fill pattern.  BYTES_P is non-zero if the alignment value should be
@@ -1466,14 +1472,14 @@ do_align (int n, char *fill, int len, int max)
 #endif
 
 static void
-s_align (int arg, int bytes_p)
+s_align (signed int arg, int bytes_p)
 {
   unsigned int align_limit = TC_ALIGN_LIMIT;
   unsigned int align;
   char *stop = NULL;
   char stopc = 0;
   offsetT fill = 0;
-  int max;
+  unsigned int max;
   int fill_p;
 
   if (flag_mri)
@@ -1553,15 +1559,16 @@ s_align (int arg, int bytes_p)
     }
   else
     {
-      int fill_len;
+      unsigned int fill_len;
 
       if (arg >= 0)
        fill_len = 1;
       else
        fill_len = -arg;
+
       if (fill_len <= 1)
        {
-         char fill_char;
+         char fill_char = 0;
 
          fill_char = fill;
          do_align (align, &fill_char, fill_len, max);
@@ -1571,7 +1578,12 @@ s_align (int arg, int bytes_p)
          char ab[16];
 
          if ((size_t) fill_len > sizeof ab)
-           abort ();
+           {
+             as_warn (_("fill pattern too long, truncating to %u"),
+                      (unsigned) sizeof ab);
+             fill_len = sizeof ab;
+           }
+
          md_number_to_chars (ab, fill, fill_len);
          do_align (align, ab, fill_len, max);
        }
@@ -2429,7 +2441,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED)
 }
 
 void
-bss_alloc (symbolS *symbolP, addressT size, int align)
+bss_alloc (symbolS *symbolP, addressT size, unsigned int align)
 {
   char *pfrag;
   segT current_seg = now_seg;
@@ -2453,7 +2465,7 @@ bss_alloc (symbolS *symbolP, addressT size, int align)
 #endif
   subseg_set (bss_seg, 1);
 
-  if (align)
+  if (align > OCTETS_PER_BYTE_POWER)
     {
       record_alignment (bss_seg, align);
       frag_align (align, 0, 0);
@@ -2907,7 +2919,7 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED)
 
   if (c == ',')
     {
-      int align;
+      unsigned int align;
 
       ++input_line_pointer;
       align = get_absolute_expression ();
@@ -3006,7 +3018,7 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED)
        }
       else if (strcasecmp (seccmd, "align") == 0)
        {
-         int align;
+         unsigned int align;
 
          (void) restore_line_pointer (c);
          align = get_absolute_expression ();
@@ -4993,9 +5005,25 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line.  */
   demand_empty_rest_of_line ();
 }
 \f
-/* Return the size of a LEB128 value.  */
+/* LEB128 Encoding.
 
-static inline int
+   Note - we are using the DWARF standard's definition of LEB128 encoding
+   where each 7-bit value is a stored in a byte, *not* an octet.  This
+   means that on targets where a byte contains multiple octets there is
+   a *huge waste of space*.  (This also means that we do not have to
+   have special versions of these functions for when OCTETS_PER_BYTE_POWER
+   is non-zero).
+
+   If the 7-bit values were to be packed into N-bit bytes (where N > 8)
+   we would then have to consider whether multiple, successive LEB128
+   values should be packed into the bytes without padding (bad idea) or
+   whether each LEB128 number is padded out to a whole number of bytes.
+   Plus you have to decide on the endianness of packing octets into a
+   byte.  */
+
+/* Return the size of a LEB128 value in bytes.  */
+
+static inline unsigned int
 sizeof_sleb128 (offsetT value)
 {
   int size = 0;
@@ -5016,7 +5044,7 @@ sizeof_sleb128 (offsetT value)
   return size;
 }
 
-static inline int
+static inline unsigned int
 sizeof_uleb128 (valueT value)
 {
   int size = 0;
@@ -5031,7 +5059,7 @@ sizeof_uleb128 (valueT value)
   return size;
 }
 
-int
+unsigned int
 sizeof_leb128 (valueT value, int sign)
 {
   if (sign)
@@ -5040,9 +5068,9 @@ sizeof_leb128 (valueT value, int sign)
     return sizeof_uleb128 (value);
 }
 
-/* Output a LEB128 value.  */
+/* Output a LEB128 value.  Returns the number of bytes used.  */
 
-static inline int
+static inline unsigned int
 output_sleb128 (char *p, offsetT value)
 {
   char *orig = p;
@@ -5069,7 +5097,7 @@ output_sleb128 (char *p, offsetT value)
   return p - orig;
 }
 
-static inline int
+static inline unsigned int
 output_uleb128 (char *p, valueT value)
 {
   char *orig = p;
@@ -5077,6 +5105,7 @@ output_uleb128 (char *p, valueT value)
   do
     {
       unsigned byte = (value & 0x7f);
+
       value >>= 7;
       if (value != 0)
        /* More bytes to follow.  */
@@ -5089,7 +5118,7 @@ output_uleb128 (char *p, valueT value)
   return p - orig;
 }
 
-int
+unsigned int
 output_leb128 (char *p, valueT value, int sign)
 {
   if (sign)
@@ -5100,10 +5129,11 @@ output_leb128 (char *p, valueT value, int sign)
 
 /* Do the same for bignums.  We combine sizeof with output here in that
    we don't output for NULL values of P.  It isn't really as critical as
-   for "normal" values that this be streamlined.  */
+   for "normal" values that this be streamlined.  Returns the number of
+   bytes used.  */
 
-static inline int
-output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
+static inline unsigned int
+output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size)
 {
   char *orig = p;
   valueT val = 0;
@@ -5157,8 +5187,8 @@ output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
   return p - orig;
 }
 
-static inline int
-output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
+static inline unsigned int
+output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size)
 {
   char *orig = p;
   valueT val = 0;
@@ -5196,8 +5226,8 @@ output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
   return p - orig;
 }
 
-static int
-output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, int size, int sign)
+static unsigned int
+output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size, int sign)
 {
   if (sign)
     return output_big_sleb128 (p, bignum, size);
@@ -5270,23 +5300,25 @@ emit_leb128_expr (expressionS *exp, int sign)
       /* If we've got a constant, emit the thing directly right now.  */
 
       valueT value = exp->X_add_number;
-      int size;
+      unsigned int size;
       char *p;
 
       size = sizeof_leb128 (value, sign);
       p = frag_more (size);
-      output_leb128 (p, value, sign);
+      if (output_leb128 (p, value, sign) > size)
+       abort ();
     }
   else if (op == O_big)
     {
       /* O_big is a different sort of constant.  */
 
-      int size;
+      unsigned int size;
       char *p;
 
       size = output_big_leb128 (NULL, generic_bignum, exp->X_add_number, sign);
       p = frag_more (size);
-      output_big_leb128 (p, generic_bignum, exp->X_add_number, sign);
+      if (output_big_leb128 (p, generic_bignum, exp->X_add_number, sign) > size)
+       abort ();
     }
   else
     {
index c1b040a5d6763cd92f9e1b074f463e700cf12ca6..146dc3657c7c082a5a60a06b371fc7ea3e4bac02 100644 (file)
@@ -128,17 +128,17 @@ extern void emit_expr_with_reloc (expressionS *exp, unsigned int nbytes,
                                  TC_PARSE_CONS_RETURN_TYPE);
 extern void emit_expr_fix (expressionS *, unsigned int, fragS *, char *,
                           TC_PARSE_CONS_RETURN_TYPE);
-extern void equals (char *sym_name, int reassign);
-extern void float_cons (int float_type);
+extern void equals (char *, int);
+extern void float_cons (int);
 extern void ignore_rest_of_line (void);
 #define discard_rest_of_line ignore_rest_of_line
-extern int output_leb128 (char *, valueT, int sign);
+extern unsigned output_leb128 (char *, valueT, int);
 extern void pseudo_set (symbolS * symbolP);
 extern void read_a_source_file (char *name);
 extern void read_begin (void);
 extern void read_print_statistics (FILE *);
 extern char *read_symbol_name (void);
-extern int sizeof_leb128 (valueT, int sign);
+extern unsigned sizeof_leb128 (valueT, int);
 extern void stabs_generate_asm_file (void);
 extern void stabs_generate_asm_lineno (void);
 extern void stabs_generate_asm_func (const char *, const char *);
@@ -153,7 +153,7 @@ extern void generate_lineno_debug (void);
 extern void s_abort (int) ATTRIBUTE_NORETURN;
 extern void s_align_bytes (int arg);
 extern void s_align_ptwo (int);
-extern void bss_alloc (symbolS *, addressT, int);
+extern void bss_alloc (symbolS *, addressT, unsigned);
 extern offsetT parse_align (int);
 extern symbolS *s_comm_internal (int, symbolS *(*) (int, symbolS *, addressT));
 extern symbolS *s_lcomm_internal (int, symbolS *, addressT);
index f9d5da9c19199b9f8d0409489900c37132abff8b..46d8d96ab6946f01ed741fa881373598132842e3 100644 (file)
@@ -355,12 +355,15 @@ record_alignment (/* Segment to which alignment pertains.  */
                  segT seg,
                  /* Alignment, as a power of 2 (e.g., 1 => 2-byte
                     boundary, 2 => 4-byte boundary, etc.)  */
-                 int align)
+                 unsigned int align)
 {
   if (seg == absolute_section)
     return;
 
-  if ((unsigned int) align > bfd_get_section_alignment (stdoutput, seg))
+  if (align <= OCTETS_PER_BYTE_POWER)
+    return;
+
+  if (align > bfd_get_section_alignment (stdoutput, seg))
     bfd_set_section_alignment (stdoutput, seg, align);
 }
 
index b1bc778f745be628c19ed9c487d4e90e1734da13..4aee78d0398acba2e71b83812a1958c2c355f73e 100644 (file)
@@ -166,9 +166,9 @@ extern addressT dot_value;
 extern fragS *dot_frag;
 extern struct reloc_list* reloc_list;
 
-extern void append (char **charPP, char *fromP, unsigned long length);
-extern void record_alignment (segT seg, int align);
-extern int get_recorded_alignment (segT seg);
+extern void append (char **, char *, unsigned long);
+extern void record_alignment (segT, unsigned);
+extern int get_recorded_alignment (segT);
 extern void write_object_file (void);
 extern long relax_frag (segT, fragS *, long);
 extern int relax_segment (struct frag *, segT, int);