Fix PR 8255
[deliverable/binutils-gdb.git] / gas / write.c
index df8f66e984d04f1788b7b7c8e24ff3a664c934f5..91871da548ee4ee06766e22e1b8afc4b3eea4e05 100644 (file)
 #define TC_FORCE_RELOCATION(FIXP) 0
 #endif
 
+#ifndef TC_FORCE_RELOCATION_SECTION
+#define TC_FORCE_RELOCATION_SECTION(FIXP,SEG) TC_FORCE_RELOCATION(FIXP)
+#endif
+
+#ifndef        MD_PCREL_FROM_SECTION
+#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from(FIXP)
+#endif
+
 #ifndef WORKING_DOT_WORD
 extern CONST int md_short_jump_size;
 extern CONST int md_long_jump_size;
@@ -130,6 +138,12 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
   fixP->fx_frag = frag;
   fixP->fx_where = where;
   fixP->fx_size = size;
+  /* We've made fx_size a narrow field; check that it's wide enough.  */
+  if (fixP->fx_size != size)
+    {
+      as_bad ("field fx_size too small to hold %d", size);
+      abort ();
+    }
   fixP->fx_addsy = add_symbol;
   fixP->fx_subsy = sub_symbol;
   fixP->fx_offset = offset;
@@ -142,12 +156,11 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
   fixP->fx_pcrel_adjust = 0;
   fixP->fx_bit_fixP = 0;
   fixP->fx_addnumber = 0;
-  fixP->tc_fix_data = NULL;
   fixP->fx_tcbit = 0;
   fixP->fx_done = 0;
 
-#if defined (TC_I960) || defined (TC_NS32K)
-  fixP->fx_bsr = 0;
+#ifdef TC_FIX_TYPE
+  TC_INIT_FIX_DATA(fixP);
 #endif
 
   as_where (&fixP->fx_file, &fixP->fx_line);
@@ -230,7 +243,7 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type)
   symbolS *add = NULL;
   symbolS *sub = NULL;
   offsetT off = 0;
-  
+
   switch (exp->X_op)
     {
     case O_absent:
@@ -249,6 +262,19 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type)
        return fix_new_exp (frag, where, size, exp, pcrel, r_type);
       }
 
+    case O_symbol_rva:
+      add = exp->X_add_symbol;
+      off = exp->X_add_number;
+
+#if defined(BFD_ASSEMBLER)
+      r_type = BFD_RELOC_RVA;
+#elif defined(TC_RVA_RELOC)
+      r_type = TC_RVA_RELOC;
+#else
+      as_fatal("rva not supported");
+#endif
+      break;
+
     case O_uminus:
       sub = exp->X_add_symbol;
       off = exp->X_add_number;
@@ -305,6 +331,8 @@ record_alignment (seg, align)
        boundary, etc.)  */
      int align;
 {
+  if (seg == absolute_section)
+    return;
 #ifdef BFD_ASSEMBLER
   if (align > bfd_get_section_alignment (stdoutput, seg))
     bfd_set_section_alignment (stdoutput, seg, align);
@@ -348,6 +376,7 @@ chain_frchains_together_1 (section, frchp)
     {
       prev_frag->fr_next = frchp->frch_root;
       prev_frag = frchp->frch_last;
+      assert (prev_frag->fr_type != 0);
 #ifdef BFD_ASSEMBLER
       if (frchp->fix_root != (fixS *) NULL)
        {
@@ -359,6 +388,7 @@ chain_frchains_together_1 (section, frchp)
        }
 #endif
     }
+  assert (prev_frag->fr_type != 0);
   prev_frag->fr_next = 0;
   return prev_frag;
 }
@@ -500,6 +530,8 @@ relax_and_size_seg (abfd, sec, xxx)
   int x;
   valueT size, newsize;
 
+  subseg_change (sec, 0);
+
   flags = bfd_get_section_flags (abfd, sec);
 
   seginfo = seg_info (sec);
@@ -630,6 +662,12 @@ adjust_reloc_syms (abfd, sec, xxx)
        sym = fixp->fx_addsy;
        symsec = sym->bsym->section;
 
+       if (sym != NULL && sym->sy_mri_common)
+         {
+           /* These symbols are handled specially in fixup_segment.  */
+           goto done;
+         }
+
        /* If it's one of these sections, assume the symbol is
           definitely going to be output.  The code in
           md_estimate_size_before_relax in tc-mips.c uses this test
@@ -932,66 +970,56 @@ write_contents (abfd, sec, xxx)
       count = f->fr_offset;
       assert (count >= 0);
       if (fill_size && count)
-#ifdef BFD_FAST_SECTION_FILL
        {
          char buf[256];
-         if (fill_size > sizeof(buf)) {
-           /* Do it the old way. Can this ever happen? */
-       while (count--)
-         {
-           x = bfd_set_section_contents (stdoutput, sec,
-                                         fill_literal, (file_ptr) offset,
-                                         (bfd_size_type) fill_size);
-           if (x == false)
-             {
-               bfd_perror (stdoutput->filename);
-               as_perror ("FATAL: Can't write %s", stdoutput->filename);
-               exit (EXIT_FAILURE);
-             }
-           offset += fill_size;
-         }
-    }
-         else {
-           /* Build a buffer full of fill objects and output it as
-            * often as necessary. This saves on the overhead of potentially
-            * lots of bfd_set_section_contents calls.
-            */
-           int n_per_buf, i;
-           if (fill_size == 1)
-             {
-               n_per_buf = sizeof (buf);
-               memset (buf, *fill_literal, n_per_buf);
-             }
-           else
-             {
-               char *bufp;
-               n_per_buf = sizeof(buf)/fill_size;
-               for (i = n_per_buf, bufp = buf; i; i--, bufp += fill_size)
-                 memcpy(bufp, fill_literal, fill_size);
-             }
-           for (; count > 0; count -= n_per_buf)
-             {
-               n_per_buf = n_per_buf > count ? count : n_per_buf;
-               x = bfd_set_section_contents (stdoutput, sec,
-                                             buf, (file_ptr) offset,
-                                             (bfd_size_type) n_per_buf * fill_size);
-               if (x != true)
-                 as_fatal ("Cannot write to output file.");
-               offset += n_per_buf * fill_size;
-             }
-         }
+         if (fill_size > sizeof(buf))
+           {
+             /* Do it the old way. Can this ever happen? */
+             while (count--)
+               {
+                 x = bfd_set_section_contents (stdoutput, sec,
+                                               fill_literal,
+                                               (file_ptr) offset,
+                                               (bfd_size_type) fill_size);
+                 if (x == false)
+                   {
+                     bfd_perror (stdoutput->filename);
+                     as_perror ("FATAL: Can't write %s", stdoutput->filename);
+                     exit (EXIT_FAILURE);
+                   }
+                 offset += fill_size;
+               }
+           }
+         else
+           {
+             /* Build a buffer full of fill objects and output it as
+                often as necessary. This saves on the overhead of
+                potentially lots of bfd_set_section_contents calls.  */
+             int n_per_buf, i;
+             if (fill_size == 1)
+               {
+                 n_per_buf = sizeof (buf);
+                 memset (buf, *fill_literal, n_per_buf);
+               }
+             else
+               {
+                 char *bufp;
+                 n_per_buf = sizeof(buf)/fill_size;
+                 for (i = n_per_buf, bufp = buf; i; i--, bufp += fill_size)
+                   memcpy(bufp, fill_literal, fill_size);
+               }
+             for (; count > 0; count -= n_per_buf)
+               {
+                 n_per_buf = n_per_buf > count ? count : n_per_buf;
+                 x = bfd_set_section_contents (stdoutput, sec,
+                                               buf, (file_ptr) offset,
+                                               (bfd_size_type) n_per_buf * fill_size);
+                 if (x != true)
+                   as_fatal ("Cannot write to output file.");
+                 offset += n_per_buf * fill_size;
+               }
+           }
        }
-#else
-       while (count--)
-         {
-           x = bfd_set_section_contents (stdoutput, sec,
-                                         fill_literal, (file_ptr) offset,
-                                         (bfd_size_type) fill_size);
-           if (x != true)
-             as_fatal ("Cannot write to output file.");
-           offset += fill_size;
-         }
-#endif
     }
 }
 #endif
@@ -1578,6 +1606,15 @@ write_object_file ()
          int punt = 0;
          const char *name;
 
+         if (symp->sy_mri_common)
+           {
+             if (S_IS_EXTERNAL (symp))
+               as_bad ("%s: global symbols not supported in common sections",
+                       S_GET_NAME (symp));
+             symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+             continue;
+           }
+
          name = S_GET_NAME (symp);
          if (name)
            {
@@ -2154,17 +2191,36 @@ fixup_segment (fixP, this_segment_type)
       pcrel = fixP->fx_pcrel;
       plt = fixP->fx_plt;
 
+      if (add_symbolP != NULL
+         && add_symbolP->sy_mri_common)
+       {
+         know (add_symbolP->sy_value.X_op == O_symbol);
+         add_number += S_GET_VALUE (add_symbolP);
+         fixP->fx_offset = add_number;
+         add_symbolP = fixP->fx_addsy = add_symbolP->sy_value.X_add_symbol;
+       }
+
       if (add_symbolP)
        add_symbol_segment = S_GET_SEGMENT (add_symbolP);
       
       if (sub_symbolP)
        {
          resolve_symbol_value (sub_symbolP);
-         if (!add_symbolP)
+         if (add_symbolP == NULL || add_symbol_segment == absolute_section)
            {
-             /* Its just -sym */
+             if (add_symbolP != NULL)
+               {
+                 add_number += S_GET_VALUE (add_symbolP);
+                 add_symbolP = NULL;
+                 fixP->fx_addsy = NULL;
+               }
+
+             /* It's just -sym */
              if (S_GET_SEGMENT (sub_symbolP) == absolute_section)
-               add_number -= S_GET_VALUE (sub_symbolP);
+               {
+                 add_number -= S_GET_VALUE (sub_symbolP);
+                 fixP->fx_subsy = NULL;
+               }
              else if (pcrel
                       && S_GET_SEGMENT (sub_symbolP) == this_segment_type)
                {
@@ -2177,9 +2233,8 @@ fixup_segment (fixP, this_segment_type)
                              "Negative of non-absolute symbol %s",
                              S_GET_NAME (sub_symbolP));
            }
-         else if ((S_GET_SEGMENT (sub_symbolP) == add_symbol_segment)
-                  && (SEG_NORMAL (add_symbol_segment)
-                      || (add_symbol_segment == absolute_section)))
+         else if (S_GET_SEGMENT (sub_symbolP) == add_symbol_segment
+                  && SEG_NORMAL (add_symbol_segment))
            {
              /* Difference of 2 symbols from same segment.
                 Can't make difference of 2 undefineds: 'value' means
@@ -2200,10 +2255,11 @@ fixup_segment (fixP, this_segment_type)
              /* Let the target machine make the final determination
                 as to whether or not a relocation will be needed to
                 handle this fixup.  */
-             if (!TC_FORCE_RELOCATION (fixP))
+             if (!TC_FORCE_RELOCATION_SECTION (fixP, this_segment_type))
                {
                  fixP->fx_pcrel = 0;
                  fixP->fx_addsy = NULL;
+                 fixP->fx_subsy = NULL;
                }
            }
          else
@@ -2225,7 +2281,7 @@ fixup_segment (fixP, this_segment_type)
                       )
                {
                  /* Make it pc-relative.  */
-                 add_number += (md_pcrel_from (fixP)
+                 add_number += (MD_PCREL_FROM_SECTION (fixP, this_segment_type)
                                 - S_GET_VALUE (sub_symbolP));
                  pcrel = 1;
                  fixP->fx_pcrel = 1;
@@ -2281,7 +2337,7 @@ fixup_segment (fixP, this_segment_type)
 #endif /* TC_I960 */
 
              add_number += S_GET_VALUE (add_symbolP);
-             add_number -= md_pcrel_from (fixP);
+             add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type);
              pcrel = 0;        /* Lie. Don't want further pcrel processing. */
              
              /* Let the target machine make the final determination
@@ -2306,6 +2362,7 @@ fixup_segment (fixP, this_segment_type)
                  /* Let the target machine make the final determination
                     as to whether or not a relocation will be needed to
                     handle this fixup.  */
+                 
                  if (!TC_FORCE_RELOCATION (fixP))
                    {
                      fixP->fx_addsy = NULL;
@@ -2354,7 +2411,7 @@ fixup_segment (fixP, this_segment_type)
 
       if (pcrel)
        {
-         add_number -= md_pcrel_from (fixP);
+         add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type);
          if (add_symbolP == 0)
            {
 #ifndef BFD_ASSEMBLER
@@ -2367,7 +2424,7 @@ fixup_segment (fixP, this_segment_type)
            }
        }
 
-      if (!fixP->fx_bit_fixP && size > 0)
+      if (!fixP->fx_bit_fixP && !fixP->fx_no_overflow && size > 0)
        {
          valueT mask = 0;
          if (size < sizeof (mask))
This page took 0.028565 seconds and 4 git commands to generate.