Extend .reloc to accept some BFD_RELOCs
[deliverable/binutils-gdb.git] / gas / write.c
index 56ebb6c565bea35df43565b53206156270a41b66..aefed29ba3382075287f651cad95e474659f8851 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.
 
 #include "libbfd.h"
 #include "compress-debug.h"
 
-#ifndef TC_ADJUST_RELOC_COUNT
-#define TC_ADJUST_RELOC_COUNT(FIX, COUNT)
-#endif
-
 #ifndef TC_FORCE_RELOCATION
 #define TC_FORCE_RELOCATION(FIX)               \
   (generic_force_reloc (FIX))
@@ -126,6 +120,9 @@ symbolS *abs_section_sym;
 /* Remember the value of dot when parsing expressions.  */
 addressT dot_value;
 
+/* The frag that dot_value is based from.  */
+fragS *dot_frag;
+
 /* Relocs generated by ".reloc" pseudo.  */
 struct reloc_list* reloc_list;
 
@@ -173,6 +170,7 @@ fix_new_internal (fragS *frag,              /* Which frag?  */
   fixP->fx_subsy = sub_symbol;
   fixP->fx_offset = offset;
   fixP->fx_dot_value = dot_value;
+  fixP->fx_dot_frag = dot_frag;
   fixP->fx_pcrel = pcrel;
   fixP->fx_r_type = r_type;
   fixP->fx_im_disp = 0;
@@ -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.  */
@@ -890,15 +890,12 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
    handled now.  (These consist of fixS where we have since discovered
    the value of a symbol, or the address of the frag involved.)
    For each one, call md_apply_fix to put the fix into the frag data.
+   Ones that we couldn't completely handle here will be output later
+   by emit_relocations.  */
 
-   Result is a count of how many relocation structs will be needed to
-   handle the remaining fixS's that we couldn't completely handle here.
-   These will be output later by emit_relocations().  */
-
-static long
+static void
 fixup_segment (fixS *fixP, segT this_segment)
 {
-  long seg_reloc_count = 0;
   valueT add_number;
   fragS *fragP;
   segT add_symbol_segment = absolute_section;
@@ -928,10 +925,8 @@ fixup_segment (fixS *fixP, segT this_segment)
            symbol_mark_used_in_reloc (fixP->fx_addsy);
            if (fixP->fx_subsy != NULL)
              symbol_mark_used_in_reloc (fixP->fx_subsy);
-           seg_reloc_count++;
          }
-      TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count);
-      return seg_reloc_count;
+      return;
     }
 
   for (; fixP; fixP = fixP->fx_next)
@@ -986,7 +981,7 @@ fixup_segment (fixS *fixP, segT this_segment)
            {
              add_number -= S_GET_VALUE (fixP->fx_subsy);
              fixP->fx_offset = (add_number + fixP->fx_dot_value
-                                + fixP->fx_frag->fr_address);
+                                + fixP->fx_dot_frag->fr_address);
 
              /* Make it pc-relative.  If the back-end code has not
                 selected a pc-relative reloc, cancel the adjustment
@@ -1073,7 +1068,6 @@ fixup_segment (fixS *fixP, segT this_segment)
 
       if (!fixP->fx_done)
        {
-         ++seg_reloc_count;
          if (fixP->fx_addsy == NULL)
            fixP->fx_addsy = abs_section_sym;
          symbol_mark_used_in_reloc (fixP->fx_addsy);
@@ -1126,9 +1120,6 @@ fixup_segment (fixS *fixP, segT this_segment)
       print_fixup (fixP);
 #endif
     }                          /* For each fixS in this segment.  */
-
-  TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count);
-  return seg_reloc_count;
 }
 
 static void
@@ -1182,7 +1173,7 @@ get_frag_for_reloc (fragS *last_frag,
                    const struct reloc_list *r)
 {
   fragS *f;
-  
+
   for (f = last_frag; 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)
@@ -1193,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;
@@ -1702,64 +1698,99 @@ set_symtab (void)
 #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;
+      int alignment = 0;
 
-      for (frchainP = seginfo->frchainP;
-          frchainP != NULL;
-          frchainP = frchainP->frch_next)
-       {
-         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.  */
 
@@ -1771,33 +1802,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
@@ -1874,6 +1884,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;
@@ -1893,7 +1908,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,
@@ -2294,13 +2309,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.029918 seconds and 4 git commands to generate.