Give Palmer co-credit for last patch.
[deliverable/binutils-gdb.git] / gas / write.c
index 949ae921dfe39c364795f4d5f3b307941f44841c..690852c6ba270755cc4a6006b0d9626419350632 100644 (file)
@@ -1,5 +1,5 @@
 /* write.c - emit .o file
-   Copyright (C) 1986-2015 Free Software Foundation, Inc.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
-/* This thing should be set up to do byteordering correctly.  But...  */
+/* This thing should be set up to do byte ordering correctly.  But...  */
 
 #include "as.h"
 #include "subsegs.h"
 #include "obstack.h"
 #include "output-file.h"
 #include "dwarf2dbg.h"
-#include "libbfd.h"
 #include "compress-debug.h"
 
 #ifndef TC_FORCE_RELOCATION
   (TC_FORCE_RELOCATION (FIX))
 #endif
 
-#ifndef TC_FORCE_RELOCATION_LOCAL
-#define TC_FORCE_RELOCATION_LOCAL(FIX)         \
+#define GENERIC_FORCE_RELOCATION_LOCAL(FIX)    \
   (!(FIX)->fx_pcrel                            \
    || TC_FORCE_RELOCATION (FIX))
+#ifndef TC_FORCE_RELOCATION_LOCAL
+#define TC_FORCE_RELOCATION_LOCAL GENERIC_FORCE_RELOCATION_LOCAL
 #endif
 
+#define GENERIC_FORCE_RELOCATION_SUB_SAME(FIX, SEG)    \
+  (!SEG_NORMAL (SEG))
 #ifndef TC_FORCE_RELOCATION_SUB_SAME
-#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) \
-  (! SEG_NORMAL (SEG))
+#define TC_FORCE_RELOCATION_SUB_SAME GENERIC_FORCE_RELOCATION_SUB_SAME
 #endif
 
 #ifndef md_register_arithmetic
@@ -192,7 +193,7 @@ fix_new_internal (fragS *frag,              /* Which frag?  */
   TC_INIT_FIX_DATA (fixP);
 #endif
 
-  as_where (&fixP->fx_file, &fixP->fx_line);
+  fixP->fx_file = as_where (&fixP->fx_line);
 
   {
 
@@ -355,12 +356,12 @@ 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 > bfd_get_section_alignment (stdoutput, seg))
     bfd_set_section_alignment (stdoutput, seg, align);
 }
 
@@ -464,6 +465,13 @@ cvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP)
        valueT value = S_GET_VALUE (fragP->fr_symbol);
        int size;
 
+       if (!S_IS_DEFINED (fragP->fr_symbol))
+         {
+           as_bad_where (fragP->fr_file, fragP->fr_line,
+                         _("leb128 operand is an undefined symbol: %s"),
+                         S_GET_NAME (fragP->fr_symbol));
+         }
+
        size = output_leb128 (fragP->fr_literal + fragP->fr_fix, value,
                              fragP->fr_subtype);
 
@@ -579,7 +587,12 @@ size_seg (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   x = bfd_set_section_flags (abfd, sec, flags);
   gas_assert (x);
 
-  newsize = md_section_align (sec, size);
+  /* If permitted, allow the backend to pad out the section
+     to some alignment boundary.  */
+  if (do_not_pad_sections_to_alignment)
+    newsize = size;
+  else
+    newsize = md_section_align (sec, size);
   x = bfd_set_section_size (abfd, sec, newsize);
   gas_assert (x);
 
@@ -711,7 +724,7 @@ resolve_reloc_expr_symbols (void)
              as_bad_where (r->file, r->line, _("invalid reloc expression"));
              sec = NULL;
            }
-         else if (sym != NULL)
+         else if (sym != NULL && sec != NULL)
            {
              /* Convert relocs against local symbols to refer to the
                 corresponding section symbol plus offset instead.  Keep
@@ -1093,7 +1106,11 @@ fixup_segment (fixS *fixP, segT this_segment)
                  else
                    sprintf (buf2, "%ld", (long) add_number);
                  as_bad_where (fixP->fx_file, fixP->fx_line,
-                               _("value of %s too large for field of %d bytes at %s"),
+                               ngettext ("value of %s too large for field "
+                                         "of %d byte at %s",
+                                         "value of %s too large for field "
+                                         "of %d bytes at %s",
+                                         fixP->fx_size),
                                buf2, fixP->fx_size, buf);
                } /* Generic error checking.  */
            }
@@ -1134,7 +1151,7 @@ fix_segment (bfd *abfd ATTRIBUTE_UNUSED,
 
 static void
 install_reloc (asection *sec, arelent *reloc, fragS *fragp,
-              char *file, unsigned int line)
+              const char *file, unsigned int line)
 {
   char *err;
   bfd_reloc_status_type s;
@@ -1234,7 +1251,7 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
        rp = &r->next;
     }
 
-  relocs = (arelent **) xcalloc (n, sizeof (arelent *));
+  relocs = XCNEWVEC (arelent *, n);
 
   n = 0;
   r = my_reloc_list;
@@ -1413,6 +1430,7 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   struct z_stream_s *strm;
   int x;
   flagword flags = bfd_get_section_flags (abfd, sec);
+  unsigned int header_size, compression_header_size;
 
   if (seginfo == NULL
       || sec->size < 32
@@ -1427,30 +1445,36 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   if (strm == NULL)
     return;
 
-  /* Create a new frag to contain the "ZLIB" header.  */
+  if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
+    {
+      compression_header_size
+       = bfd_get_compression_header_size (stdoutput, NULL);
+      header_size = compression_header_size;
+    }
+  else
+    {
+      compression_header_size = 0;
+      header_size = 12;
+    }
+
+  /* Create a new frag to contain the compression header.  */
   first_newf = frag_alloc (ob);
-  if (obstack_room (ob) < 12)
+  if (obstack_room (ob) < header_size)
     first_newf = frag_alloc (ob);
-  if (obstack_room (ob) < 12)
-    as_fatal (_("can't extend frag %u chars"), 12);
+  if (obstack_room (ob) < header_size)
+    as_fatal (ngettext ("can't extend frag %lu char",
+                       "can't extend frag %lu chars",
+                       (unsigned long) header_size),
+             (unsigned long) header_size);
   last_newf = first_newf;
-  obstack_blank_fast (ob, 12);
+  obstack_blank_fast (ob, header_size);
   last_newf->fr_type = rs_fill;
-  last_newf->fr_fix = 12;
+  last_newf->fr_fix = header_size;
   header = last_newf->fr_literal;
-  memcpy (header, "ZLIB", 4);
-  header[11] = uncompressed_size; uncompressed_size >>= 8;
-  header[10] = uncompressed_size; uncompressed_size >>= 8;
-  header[9] = uncompressed_size; uncompressed_size >>= 8;
-  header[8] = uncompressed_size; uncompressed_size >>= 8;
-  header[7] = uncompressed_size; uncompressed_size >>= 8;
-  header[6] = uncompressed_size; uncompressed_size >>= 8;
-  header[5] = uncompressed_size; uncompressed_size >>= 8;
-  header[4] = uncompressed_size;
-  compressed_size = 12;
+  compressed_size = header_size;
 
   /* Stream the frags through the compression engine, adding new frags
-     as necessary to accomodate the compressed output.  */
+     as necessary to accommodate the compressed output.  */
   for (f = seginfo->frchainP->frch_root;
        f;
        f = f->fr_next)
@@ -1526,18 +1550,24 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
        break;
     }
 
+  /* PR binutils/18087: If compression didn't make the section smaller,
+     just keep it uncompressed.  */
+  if (compressed_size >= uncompressed_size)
+    return;
+
   /* Replace the uncompressed frag list with the compressed frag list.  */
   seginfo->frchainP->frch_root = first_newf;
   seginfo->frchainP->frch_last = last_newf;
 
   /* Update the section size and its name.  */
+  bfd_update_compression_header (abfd, (bfd_byte *) header, sec);
   x = bfd_set_section_size (abfd, sec, compressed_size);
   gas_assert (x);
-  compressed_name = (char *) xmalloc (strlen (section_name) + 2);
-  compressed_name[0] = '.';
-  compressed_name[1] = 'z';
-  strcpy (compressed_name + 2, section_name + 1);
-  bfd_section_name (stdoutput, sec) = compressed_name;
+  if (!compression_header_size)
+    {
+      compressed_name = concat (".z", section_name + 1, (char *) NULL);
+      bfd_section_name (stdoutput, sec) = compressed_name;
+    }
 }
 
 static void
@@ -1570,7 +1600,13 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
                                        f->fr_literal, (file_ptr) offset,
                                        (bfd_size_type) f->fr_fix);
          if (!x)
-           as_fatal (_("can't write %s: %s"), stdoutput->filename,
+           as_fatal (ngettext ("can't write %ld byte "
+                               "to section %s of %s: '%s'",
+                               "can't write %ld bytes "
+                               "to section %s of %s: '%s'",
+                               (long) f->fr_fix),
+                     (long) f->fr_fix,
+                     sec->name, stdoutput->filename,
                      bfd_errmsg (bfd_get_error ()));
          offset += f->fr_fix;
        }
@@ -1591,7 +1627,13 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
                                                (file_ptr) offset,
                                                (bfd_size_type) fill_size);
                  if (!x)
-                   as_fatal (_("can't write %s: %s"), stdoutput->filename,
+                   as_fatal (ngettext ("can't fill %ld byte "
+                                       "in section %s of %s: '%s'",
+                                       "can't fill %ld bytes "
+                                       "in section %s of %s: '%s'",
+                                       (long) fill_size),
+                             (long) fill_size,
+                             sec->name, stdoutput->filename,
                              bfd_errmsg (bfd_get_error ()));
                  offset += fill_size;
                }
@@ -1621,8 +1663,13 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
                    (stdoutput, sec, buf, (file_ptr) offset,
                     (bfd_size_type) n_per_buf * fill_size);
                  if (!x)
-                   as_fatal (_("cannot write to output file '%s': %s"),
-                             stdoutput->filename,
+                   as_fatal (ngettext ("can't fill %ld byte "
+                                       "in section %s of %s: '%s'",
+                                       "can't fill %ld bytes "
+                                       "in section %s of %s: '%s'",
+                                       (long) (n_per_buf * fill_size)),
+                             (long) (n_per_buf * fill_size),
+                             sec->name, stdoutput->filename,
                              bfd_errmsg (bfd_get_error ()));
                  offset += n_per_buf * fill_size;
                }
@@ -1681,7 +1728,7 @@ set_symtab (void)
 }
 
 /* Finish the subsegments.  After every sub-segment, we fake an
-   ".align ...".  This conforms to BSD4.2 brane-damage.  We then fake
+   ".align ...".  This conforms to BSD4.2 brain-damage.  We then fake
    ".fill 0" because that is the kind of frag that requires least
    thought.  ".align" frags like to have a following frag since that
    makes calculating their intended length trivial.  */
@@ -1693,6 +1740,7 @@ set_symtab (void)
    code-bearing sections.  */
 #define SUB_SEGMENT_ALIGN(SEG, FRCHAIN)                                        \
   (!(FRCHAIN)->frch_next && subseg_text_p (SEG)                                \
+   && !do_not_pad_sections_to_alignment                                        \
    ? get_recorded_alignment (SEG)                                      \
    : 0)
 #else
@@ -1712,31 +1760,31 @@ subsegs_finish_section (asection *s)
        frchainP != NULL;
        frchainP = frchainP->frch_next)
     {
-      int alignment = 0;
+      int alignment;
 
       subseg_set (s, frchainP->frch_subseg);
 
       /* This now gets called even if we had errors.  In that case,
         any alignment is meaningless, and, moreover, will look weird
         if we are generating a listing.  */
-      if (!had_errors ())
-       {
-         alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
-         if ((bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE)
-             && now_seg->entsize)
-           {
-             unsigned int entsize = now_seg->entsize;
-             int entalign = 0;
+      if (had_errors ())
+       do_not_pad_sections_to_alignment = 1;
 
-             while ((entsize & 1) == 0)
-               {
-                 ++entalign;
-                 entsize >>= 1;
-               }
+      alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
+      if ((bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE)
+         && now_seg->entsize)
+       {
+         unsigned int entsize = now_seg->entsize;
+         int entalign = 0;
 
-             if (entalign > alignment)
-               alignment = entalign;
+         while ((entsize & 1) == 0)
+           {
+             ++entalign;
+             entsize >>= 1;
            }
+
+         if (entalign > alignment)
+           alignment = entalign;
        }
 
       if (subseg_text_p (now_seg))
@@ -1815,7 +1863,7 @@ write_object_file (void)
 #endif
 
   /* From now on, we don't care about sub-segments.  Build one frag chain
-     for each segment. Linked thru fr_next.  */
+     for each segment. Linked through fr_next.  */
 
   /* Remove the sections created by gas for its own purposes.  */
   {
@@ -1882,6 +1930,8 @@ write_object_file (void)
   /* Relaxation has completed.  Freeze all syms.  */
   finalize_syms = 1;
 
+  dwarf2dbg_final_check ();
+
 #ifdef md_post_relax_hook
   md_post_relax_hook;
 #endif
@@ -2076,12 +2126,11 @@ write_object_file (void)
 
              if (S_IS_COMMON (symp)
                  && !TC_FAKE_LABEL (sname)
-                 && !S_IS_WEAKREFR (symp)
-                 && (!S_IS_EXTERNAL (symp) || S_IS_LOCAL (symp)))
+                 && !S_IS_WEAKREFR (symp))
                {
                  expressionS *e = symbol_get_value_expression (symp);
 
-                 as_bad (_("Local symbol `%s' can't be equated to common symbol `%s'"),
+                 as_bad (_("`%s' can't be equated to common symbol `%s'"),
                          sname, S_GET_NAME (e->X_add_symbol));
                }
              if (S_GET_SEGMENT (symp) == reg_section)
@@ -2188,12 +2237,23 @@ write_object_file (void)
   obj_frob_file_after_relocs ();
 #endif
 
+#if defined OBJ_ELF || defined OBJ_MAYBE_ELF
+  if (IS_ELF && flag_use_elf_stt_common)
+    stdoutput->flags |= BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON;
+#endif
+
   /* Once all relocations have been written, we can compress the
      contents of the debug sections.  This needs to be done before
      we start writing any sections, because it will affect the file
      layout, which is fixed once we start writing contents.  */
   if (flag_compress_debug)
-    bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
+    {
+      if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
+       stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI;
+      else
+       stdoutput->flags |= BFD_COMPRESS;
+      bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
+    }
 
   bfd_map_over_sections (stdoutput, write_contents, (char *) 0);
 }
@@ -2381,7 +2441,11 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
            if (offset % fragP->fr_var != 0)
              {
                as_bad_where (fragP->fr_file, fragP->fr_line,
-                             _("alignment padding (%lu bytes) not a multiple of %ld"),
+                             ngettext ("alignment padding (%lu byte) "
+                                       "not a multiple of %ld",
+                                       "alignment padding (%lu bytes) "
+                                       "not a multiple of %ld",
+                                       (unsigned long) offset),
                              (unsigned long) offset, (long) fragP->fr_var);
                offset -= (offset % fragP->fr_var);
              }
@@ -2661,7 +2725,11 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
                  know (fragP->fr_next);
                  after = fragP->fr_next->fr_address + stretch;
                  growth = target - after;
-                 if (growth < 0)
+
+                 /* Growth may be negative, but variable part of frag
+                    cannot have fewer than 0 chars.  That is, we can't
+                    .org backwards.  */
+                 if (address + fragP->fr_fix > target)
                    {
                      growth = 0;
 
@@ -2683,9 +2751,6 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
                          break;
                        }
 
-                     /* Growth may be negative, but variable part of frag
-                        cannot have fewer than 0 chars.  That is, we can't
-                        .org backwards.  */
                      as_bad_where (fragP->fr_file, fragP->fr_line,
                                    _("attempt to move .org backwards"));
 
This page took 0.030457 seconds and 4 git commands to generate.