Consolidate Thumb-1/Thumb-2 ISA detection
[deliverable/binutils-gdb.git] / gas / write.c
index 22e68c5ec8fe0474d9b2df97701298b5f06c5ee4..a76813dac1127d468db5bbbb32421bb4f21feeae 100644 (file)
@@ -1,7 +1,5 @@
 /* write.c - emit .o file
-   Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1986-2015 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -722,9 +720,10 @@ resolve_reloc_expr_symbols (void)
                 unless it has enough bits to cover the whole address
                 space.  */
              if (S_IS_LOCAL (sym) && !symbol_section_p (sym)
-                 && !(howto->partial_inplace
-                      && howto->pc_relative
-                      && howto->src_mask != addr_mask))
+                 && (sec->use_rela_p
+                     || (howto->partial_inplace
+                         && (!howto->pc_relative
+                             || howto->src_mask == addr_mask))))
                {
                  asection *symsec = S_GET_SEGMENT (sym);
                  if (!(((symsec->flags & SEC_MERGE) != 0
@@ -837,7 +836,8 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
        if (symsec == NULL)
          abort ();
 
-       if (bfd_is_abs_section (symsec))
+       if (bfd_is_abs_section (symsec)
+           || symsec == reg_section)
          {
            /* The fixup_segment routine normally will not use this
               symbol in a relocation.  */
@@ -1184,6 +1184,11 @@ get_frag_for_reloc (fragS *last_frag,
        && r->u.b.r.address < f->fr_address + f->fr_fix)
       return f;
 
+  for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next)
+    if (f->fr_address <= r->u.b.r.address
+       && r->u.b.r.address <= f->fr_address + f->fr_fix)
+      return f;
+
   as_bad_where (r->file, r->line,
                _("reloc not within (fixed part of) section"));
   return NULL;
@@ -1408,6 +1413,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
@@ -1422,27 +1428,32 @@ 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)
+    {
+      stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI;
+      compression_header_size
+       = bfd_get_compression_header_size (stdoutput, NULL);
+      header_size = compression_header_size;
+    }
+  else
+    {
+      stdoutput->flags |= BFD_COMPRESS;
+      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 (_("can't extend frag %u chars"), 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.  */
@@ -1521,18 +1532,27 @@ 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 = (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;
+    }
 }
 
 static void
@@ -1565,7 +1585,9 @@ 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 (_("can't write %ld bytes to section %s of %s because: '%s'"),
+                     (long) f->fr_fix, sec->name,
+                     stdoutput->filename,
                      bfd_errmsg (bfd_get_error ()));
          offset += f->fr_fix;
        }
@@ -1586,7 +1608,9 @@ 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 (_("can't fill %ld bytes in section %s of %s because '%s'"),
+                             (long) fill_size, sec->name,
+                             stdoutput->filename,
                              bfd_errmsg (bfd_get_error ()));
                  offset += fill_size;
                }
@@ -1616,7 +1640,8 @@ 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"),
+                   as_fatal (_("cannot fill %ld bytes in section %s of %s because: '%s'"),
+                             (long)(n_per_buf * fill_size), sec->name,
                              stdoutput->filename,
                              bfd_errmsg (bfd_get_error ()));
                  offset += n_per_buf * fill_size;
@@ -1687,70 +1712,107 @@ set_symtab (void)
    of the section.  This allows proper nop-filling at the end of
    code-bearing sections.  */
 #define SUB_SEGMENT_ALIGN(SEG, FRCHAIN)                                        \
-  (!(FRCHAIN)->frch_next ? get_recorded_alignment (SEG) : 0)
+  (!(FRCHAIN)->frch_next && subseg_text_p (SEG)                                \
+   ? get_recorded_alignment (SEG)                                      \
+   : 0)
 #else
 #define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0
 #endif
 #endif
 
-void
-subsegs_finish (void)
+static void
+subsegs_finish_section (asection *s)
 {
   struct frchain *frchainP;
-  asection *s;
+  segment_info_type *seginfo = seg_info (s);
+  if (!seginfo)
+    return;
 
-  for (s = stdoutput->sections; s; s = s->next)
+  for (frchainP = seginfo->frchainP;
+       frchainP != NULL;
+       frchainP = frchainP->frch_next)
     {
-      segment_info_type *seginfo = seg_info (s);
-      if (!seginfo)
-       continue;
-
-      for (frchainP = seginfo->frchainP;
-          frchainP != NULL;
-          frchainP = frchainP->frch_next)
-       {
-         int alignment = 0;
+      int alignment = 0;
 
-         subseg_set (s, frchainP->frch_subseg);
+      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 ())
+      /* 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)
            {
-             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;
+             unsigned int entsize = now_seg->entsize;
+             int entalign = 0;
 
-                 while ((entsize & 1) == 0)
-                   {
-                     ++entalign;
-                     entsize >>= 1;
-                   }
-                 if (entalign > alignment)
-                   alignment = entalign;
+             while ((entsize & 1) == 0)
+               {
+                 ++entalign;
+                 entsize >>= 1;
                }
+
+             if (entalign > alignment)
+               alignment = entalign;
            }
+       }
 
-         if (subseg_text_p (now_seg))
-           frag_align_code (alignment, 0);
-         else
-           frag_align (alignment, 0, 0);
+      if (subseg_text_p (now_seg))
+       frag_align_code (alignment, 0);
+      else
+       frag_align (alignment, 0, 0);
 
-         /* frag_align will have left a new frag.
-            Use this last frag for an empty ".fill".
+      /* frag_align will have left a new frag.
+        Use this last frag for an empty ".fill".
 
-            For this segment ...
-            Create a last frag. Do not leave a "being filled in frag".  */
-         frag_wane (frag_now);
-         frag_now->fr_fix = 0;
-         know (frag_now->fr_next == NULL);
-       }
+        For this segment ...
+        Create a last frag. Do not leave a "being filled in frag".  */
+      frag_wane (frag_now);
+      frag_now->fr_fix = 0;
+      know (frag_now->fr_next == NULL);
+    }
+}
+
+static void
+subsegs_finish (void)
+{
+  asection *s;
+
+  for (s = stdoutput->sections; s; s = s->next)
+    subsegs_finish_section (s);
+}
+
+#ifdef OBJ_ELF
+static void
+create_obj_attrs_section (void)
+{
+  segT s;
+  char *p;
+  offsetT size;
+  const char *name;
+
+  size = bfd_elf_obj_attr_size (stdoutput);
+  if (size)
+    {
+      name = get_elf_backend_data (stdoutput)->obj_attrs_section;
+      if (!name)
+       name = ".gnu.attributes";
+      s = subseg_new (name, 0);
+      elf_section_type (s)
+       = get_elf_backend_data (stdoutput)->obj_attrs_section_type;
+      bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA);
+      frag_now_fix ();
+      p = frag_more (size);
+      bfd_elf_set_obj_attr_contents (stdoutput, (bfd_byte *)p, size);
+
+      subsegs_finish_section (s);
+      relax_segment (seg_info (s)->frchainP->frch_root, s, 0);
+      size_seg (stdoutput, s, NULL);
     }
 }
+#endif
 
 /* Write the object file.  */
 
@@ -1762,33 +1824,12 @@ write_object_file (void)
   fragS *fragP;                        /* Track along all frags.  */
 #endif
 
+  subsegs_finish ();
+
 #ifdef md_pre_output_hook
   md_pre_output_hook;
 #endif
 
-  /* Do we really want to write it?  */
-  {
-    int n_warns, n_errs;
-    n_warns = had_warnings ();
-    n_errs = had_errors ();
-    /* The -Z flag indicates that an object file should be generated,
-       regardless of warnings and errors.  */
-    if (flag_always_generate_output)
-      {
-       if (n_warns || n_errs)
-         as_warn (_("%d error%s, %d warning%s, generating bad object file"),
-                  n_errs, n_errs == 1 ? "" : "s",
-                  n_warns, n_warns == 1 ? "" : "s");
-      }
-    else
-      {
-       if (n_errs)
-         as_fatal (_("%d error%s, %d warning%s, no object file generated"),
-                   n_errs, n_errs == 1 ? "" : "s",
-                   n_warns, n_warns == 1 ? "" : "s");
-      }
-  }
-
 #ifdef md_pre_relax_hook
   md_pre_relax_hook;
 #endif
@@ -1865,6 +1906,11 @@ write_object_file (void)
   md_post_relax_hook;
 #endif
 
+#ifdef OBJ_ELF
+  if (IS_ELF)
+    create_obj_attrs_section ();
+#endif
+
 #ifndef WORKING_DOT_WORD
   {
     struct broken_word *lie;
@@ -1884,7 +1930,7 @@ write_object_file (void)
 #ifdef TC_CONS_FIX_NEW
          TC_CONS_FIX_NEW (lie->frag,
                           lie->word_goes_here - lie->frag->fr_literal,
-                          2, &exp);
+                          2, &exp, TC_PARSE_CONS_RETURN_NONE);
 #else
          fix_new_exp (lie->frag,
                       lie->word_goes_here - lie->frag->fr_literal,
@@ -2285,13 +2331,13 @@ relax_frag (segT segment, fragS *fragP, long stretch)
 /* Relax_align. Advance location counter to next address that has 'alignment'
    lowest order bits all 0s, return size of adjustment made.  */
 static relax_addressT
-relax_align (register relax_addressT address,  /* Address now.  */
-            register int alignment     /* Alignment (binary).  */)
+relax_align (relax_addressT address,   /* Address now.  */
+            int alignment      /* Alignment (binary).  */)
 {
   relax_addressT mask;
   relax_addressT new_address;
 
-  mask = ~((~0) << alignment);
+  mask = ~((relax_addressT) ~0 << alignment);
   new_address = (address + mask) & (~mask);
 #ifdef LINKER_RELAXING_SHRINKS_ONLY
   if (linkrelax)
This page took 0.030369 seconds and 4 git commands to generate.