* NEWS: Announce Renesas RX support.
[deliverable/binutils-gdb.git] / gas / write.c
index 1c93d43a73a9525b009b07f3a5df9eba485878b9..8adb87b94a302c67d7874756e9688203289c70a0 100644 (file)
@@ -1,13 +1,13 @@
 /* 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
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
   (! SEG_NORMAL (SEG))
 #endif
 
+#ifndef md_register_arithmetic
+# define md_register_arithmetic 1
+#endif
+
 #ifndef TC_FORCE_RELOCATION_SUB_ABS
-#define TC_FORCE_RELOCATION_SUB_ABS(FIX)       0
+#define TC_FORCE_RELOCATION_SUB_ABS(FIX, SEG)  \
+  (!md_register_arithmetic && (SEG) == reg_section)
 #endif
 
 #ifndef TC_FORCE_RELOCATION_SUB_LOCAL
 #ifdef DIFF_EXPR_OK
-#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX)     0
+#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG)        \
+  (!md_register_arithmetic && (SEG) == reg_section)
 #else
-#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX)     1
+#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG)        1
 #endif
 #endif
 
 #ifndef TC_VALIDATE_FIX_SUB
 #ifdef UNDEFINED_DIFFERENCE_OK
 /* The PA needs this for PIC code generation.  */
-#define TC_VALIDATE_FIX_SUB(FIX) 1
+#define TC_VALIDATE_FIX_SUB(FIX, SEG)                  \
+  (md_register_arithmetic || (SEG) != reg_section)
 #else
-#define TC_VALIDATE_FIX_SUB(FIX)               \
-  ((FIX)->fx_r_type == BFD_RELOC_GPREL32       \
-   || (FIX)->fx_r_type == BFD_RELOC_GPREL16)
+#define TC_VALIDATE_FIX_SUB(FIX, SEG)                  \
+  ((md_register_arithmetic || (SEG) != reg_section)    \
+   && ((FIX)->fx_r_type == BFD_RELOC_GPREL32           \
+       || (FIX)->fx_r_type == BFD_RELOC_GPREL16))
 #endif
 #endif
 
 #define TC_FAKE_LABEL(NAME) (strcmp ((NAME), FAKE_LABEL_NAME) == 0)
 #endif
 
+/* Positive values of TC_FX_SIZE_SLACK allow a target to define
+   fixups that far past the end of a frag.  Having such fixups
+   is of course most most likely a bug in setting fx_size correctly.
+   A negative value disables the fixup check entirely, which is
+   appropriate for something like the Renesas / SuperH SH_COUNT
+   reloc.  */
+#ifndef TC_FX_SIZE_SLACK
+#define TC_FX_SIZE_SLACK(FIX) 0
+#endif
+
 /* Used to control final evaluation of expressions.  */
 int finalize_syms = 0;
 
@@ -107,6 +125,9 @@ symbolS *abs_section_sym;
 /* Remember the value of dot when parsing expressions.  */
 addressT dot_value;
 
+/* Relocs generated by ".reloc" pseudo.  */
+struct reloc_list* reloc_list;
+
 void print_fixup (fixS *);
 
 /* We generally attach relocs to frag chains.  However, after we have
@@ -135,7 +156,7 @@ fix_new_internal (fragS *frag,              /* Which frag?  */
 
   n_fixups++;
 
-  fixP = obstack_alloc (&notes, sizeof (fixS));
+  fixP = (fixS *) obstack_alloc (&notes, sizeof (fixS));
 
   fixP->fx_frag = frag;
   fixP->fx_where = where;
@@ -365,7 +386,7 @@ chain_frchains_together_1 (segT section, struct frchain *frchp)
     {
       prev_frag->fr_next = frchp->frch_root;
       prev_frag = frchp->frch_last;
-      assert (prev_frag->fr_type != 0);
+      gas_assert (prev_frag->fr_type != 0);
       if (frchp->fix_root != (fixS *) NULL)
        {
          if (seg_info (section)->fix_root == (fixS *) NULL)
@@ -375,8 +396,8 @@ chain_frchains_together_1 (segT section, struct frchain *frchp)
          prev_fix = frchp->fix_tail;
        }
     }
-  assert (prev_frag->fr_type != 0);
-  assert (prev_frag != &dummy);
+  gas_assert (prev_frag->fr_type != 0);
+  gas_assert (prev_frag != &dummy);
   prev_frag->fr_next = 0;
   return prev_frag;
 }
@@ -457,7 +478,7 @@ cvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP)
     case rs_machine_dependent:
       md_convert_frag (stdoutput, sec, fragP);
 
-      assert (fragP->fr_next == NULL
+      gas_assert (fragP->fr_next == NULL
              || ((offsetT) (fragP->fr_next->fr_address - fragP->fr_address)
                  == fragP->fr_fix));
 
@@ -539,25 +560,24 @@ size_seg (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
     size = 0;
 
   flags = bfd_get_section_flags (abfd, sec);
+  if (size == 0 && bfd_get_section_size (sec) != 0 &&
+    (flags & SEC_HAS_CONTENTS) != 0)
+    return;
 
   if (size > 0 && ! seginfo->bss)
     flags |= SEC_HAS_CONTENTS;
 
-  /* @@ This is just an approximation.  */
-  if (seginfo && seginfo->fix_root)
-    flags |= SEC_RELOC;
-  else
-    flags &= ~SEC_RELOC;
+  flags &= ~SEC_RELOC;
   x = bfd_set_section_flags (abfd, sec, flags);
-  assert (x);
+  gas_assert (x);
 
   newsize = md_section_align (sec, size);
   x = bfd_set_section_size (abfd, sec, newsize);
-  assert (x);
+  gas_assert (x);
 
   /* If the size had to be rounded up, add some padding in the last
      non-empty frag.  */
-  assert (newsize >= size);
+  gas_assert (newsize >= size);
   if (size != newsize)
     {
       fragS *last = seginfo->frchainP->frch_last;
@@ -618,6 +638,86 @@ dump_section_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, FILE *stream)
 #define EMIT_SECTION_SYMBOLS 1
 #endif
 
+/* Resolve U.A.OFFSET_SYM and U.A.SYM fields of RELOC_LIST entries,
+   and check for validity.  Convert RELOC_LIST from using U.A fields
+   to U.B fields.  */
+static void
+resolve_reloc_expr_symbols (void)
+{
+  struct reloc_list *r;
+
+  for (r = reloc_list; r; r = r->next)
+    {
+      expressionS *symval;
+      symbolS *sym;
+      bfd_vma offset, addend;
+      asection *sec;
+      reloc_howto_type *howto;
+
+      resolve_symbol_value (r->u.a.offset_sym);
+      symval = symbol_get_value_expression (r->u.a.offset_sym);
+
+      offset = 0;
+      sym = NULL;
+      if (symval->X_op == O_constant)
+       sym = r->u.a.offset_sym;
+      else if (symval->X_op == O_symbol)
+       {
+         sym = symval->X_add_symbol;
+         offset = symval->X_add_number;
+         symval = symbol_get_value_expression (symval->X_add_symbol);
+       }
+      if (sym == NULL
+         || symval->X_op != O_constant
+         || (sec = S_GET_SEGMENT (sym)) == NULL
+         || !SEG_NORMAL (sec))
+       {
+         as_bad_where (r->file, r->line, _("invalid offset expression"));
+         sec = NULL;
+       }
+      else
+       offset += S_GET_VALUE (sym);
+
+      sym = NULL;
+      addend = r->u.a.addend;
+      if (r->u.a.sym != NULL)
+       {
+         resolve_symbol_value (r->u.a.sym);
+         symval = symbol_get_value_expression (r->u.a.sym);
+         if (symval->X_op == O_constant)
+           sym = r->u.a.sym;
+         else if (symval->X_op == O_symbol)
+           {
+             sym = symval->X_add_symbol;
+             addend += symval->X_add_number;
+             symval = symbol_get_value_expression (symval->X_add_symbol);
+           }
+         if (symval->X_op != O_constant)
+           {
+             as_bad_where (r->file, r->line, _("invalid reloc expression"));
+             sec = NULL;
+           }
+         else if (sym != NULL)
+           symbol_mark_used_in_reloc (sym);
+       }
+      if (sym == NULL)
+       {
+         if (abs_section_sym == NULL)
+           abs_section_sym = section_symbol (absolute_section);
+         sym = abs_section_sym;
+       }
+
+      howto = r->u.a.howto;
+
+      r->u.b.sec = sec;
+      r->u.b.s = symbol_get_bfdsym (sym);
+      r->u.b.r.sym_ptr_ptr = &r->u.b.s;
+      r->u.b.r.address = offset;
+      r->u.b.r.addend = addend;
+      r->u.b.r.howto = howto;
+    }
+}
+
 /* This pass over fixups decides whether symbols can be replaced with
    section symbols.  */
 
@@ -661,17 +761,21 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
 
        /* If this symbol is equated to an undefined or common symbol,
           convert the fixup to being against that symbol.  */
-       if (symbol_equated_reloc_p (sym)
-           || S_IS_WEAKREFR (sym))
+       while (symbol_equated_reloc_p (sym)
+              || S_IS_WEAKREFR (sym))
          {
+           symbolS *newsym = symbol_get_value_expression (sym)->X_add_symbol;
+           if (sym == newsym)
+             break;
            fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number;
-           sym = symbol_get_value_expression (sym)->X_add_symbol;
-           fixp->fx_addsy = sym;
+           fixp->fx_addsy = newsym;
+           sym = newsym;
          }
 
        if (symbol_mri_common_p (sym))
          {
-           /* These symbols are handled specially in fixup_segment.  */
+           fixp->fx_offset += S_GET_VALUE (sym);
+           fixp->fx_addsy = symbol_get_value_expression (sym)->X_add_symbol;
            continue;
          }
 
@@ -700,14 +804,14 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
        if (bfd_is_abs_section (symsec))
          {
            /* The fixup_segment routine normally will not use this
-               symbol in a relocation.  */
+              symbol in a relocation.  */
            continue;
          }
 
        /* Don't try to reduce relocs which refer to non-local symbols
-           in .linkonce sections.  It can lead to confusion when a
-           debugging section refers to a .linkonce section.  I hope
-           this will always be correct.  */
+          in .linkonce sections.  It can lead to confusion when a
+          debugging section refers to a .linkonce section.  I hope
+          this will always be correct.  */
        if (symsec != sec && ! S_IS_LOCAL (sym))
          {
            if ((symsec->flags & SEC_LINK_ONCE) != 0
@@ -808,15 +912,6 @@ fixup_segment (fixS *fixP, segT this_segment)
 #endif
       add_number = fixP->fx_offset;
 
-      if (fixP->fx_addsy != NULL
-         && symbol_mri_common_p (fixP->fx_addsy))
-       {
-         add_number += S_GET_VALUE (fixP->fx_addsy);
-         fixP->fx_offset = add_number;
-         fixP->fx_addsy
-           = symbol_get_value_expression (fixP->fx_addsy)->X_add_symbol;
-       }
-
       if (fixP->fx_addsy != NULL)
        add_symbol_segment = S_GET_SEGMENT (fixP->fx_addsy);
 
@@ -840,14 +935,14 @@ fixup_segment (fixS *fixP, segT this_segment)
 #endif
            }
          else if (sub_symbol_segment == absolute_section
-                  && !TC_FORCE_RELOCATION_SUB_ABS (fixP))
+                  && !TC_FORCE_RELOCATION_SUB_ABS (fixP, add_symbol_segment))
            {
              add_number -= S_GET_VALUE (fixP->fx_subsy);
              fixP->fx_offset = add_number;
              fixP->fx_subsy = NULL;
            }
          else if (sub_symbol_segment == this_segment
-                  && !TC_FORCE_RELOCATION_SUB_LOCAL (fixP))
+                  && !TC_FORCE_RELOCATION_SUB_LOCAL (fixP, add_symbol_segment))
            {
              add_number -= S_GET_VALUE (fixP->fx_subsy);
              fixP->fx_offset = (add_number + fixP->fx_dot_value
@@ -869,14 +964,20 @@ fixup_segment (fixS *fixP, segT this_segment)
              fixP->fx_subsy = NULL;
              fixP->fx_pcrel = 1;
            }
-         else if (!TC_VALIDATE_FIX_SUB (fixP))
+         else if (!TC_VALIDATE_FIX_SUB (fixP, add_symbol_segment))
            {
-             as_bad_where (fixP->fx_file, fixP->fx_line,
-                           _("can't resolve `%s' {%s section} - `%s' {%s section}"),
-                           fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0",
-                           segment_name (add_symbol_segment),
-                           S_GET_NAME (fixP->fx_subsy),
-                           segment_name (sub_symbol_segment));
+             if (!md_register_arithmetic
+                 && (add_symbol_segment == reg_section
+                     || sub_symbol_segment == reg_section))
+               as_bad_where (fixP->fx_file, fixP->fx_line,
+                             _("register value used as expression"));
+             else
+               as_bad_where (fixP->fx_file, fixP->fx_line,
+                             _("can't resolve `%s' {%s section} - `%s' {%s section}"),
+                             fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0",
+                             segment_name (add_symbol_segment),
+                             S_GET_NAME (fixP->fx_subsy),
+                             segment_name (sub_symbol_segment));
            }
        }
 
@@ -994,15 +1095,50 @@ fix_segment (bfd *abfd ATTRIBUTE_UNUSED,
   fixup_segment (seginfo->fix_root, sec);
 }
 
+static void
+install_reloc (asection *sec, arelent *reloc, fragS *fragp,
+              char *file, unsigned int line)
+{
+  char *err;
+  bfd_reloc_status_type s;
+  asymbol *sym;
+
+  if (reloc->sym_ptr_ptr != NULL
+      && (sym = *reloc->sym_ptr_ptr) != NULL
+      && (sym->flags & BSF_KEEP) == 0
+      && ((sym->flags & BSF_SECTION_SYM) == 0
+         || (EMIT_SECTION_SYMBOLS
+             && !bfd_is_abs_section (sym->section))))
+    as_bad_where (file, line, _("redefined symbol cannot be used on reloc"));
+
+  s = bfd_install_relocation (stdoutput, reloc,
+                             fragp->fr_literal, fragp->fr_address,
+                             sec, &err);
+  switch (s)
+    {
+    case bfd_reloc_ok:
+      break;
+    case bfd_reloc_overflow:
+      as_bad_where (file, line, _("relocation overflow"));
+      break;
+    case bfd_reloc_outofrange:
+      as_bad_where (file, line, _("relocation out of range"));
+      break;
+    default:
+      as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
+               file, line, s);
+    }
+}
+
 static void
 write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 {
   segment_info_type *seginfo = seg_info (sec);
   unsigned int i;
   unsigned int n;
+  struct reloc_list *my_reloc_list, **rp, *r;
   arelent **relocs;
   fixS *fixp;
-  char *err;
 
   /* If seginfo is NULL, we did not create this section; don't do
      anything with it.  */
@@ -1011,153 +1147,73 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 
   n = 0;
   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
-    n++;
+    if (!fixp->fx_done)
+      n++;
 
-#ifndef RELOC_EXPANSION_POSSIBLE
-  /* Set up reloc information as well.  */
-  relocs = xcalloc (n, sizeof (arelent *));
+#ifdef RELOC_EXPANSION_POSSIBLE
+  n *= MAX_RELOC_EXPANSION;
+#endif
 
-  i = 0;
-  for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
+  /* Extract relocs for this section from reloc_list.  */
+  rp = &reloc_list;
+  my_reloc_list = NULL;
+  while ((r = *rp) != NULL)
     {
-      arelent *reloc;
-      bfd_reloc_status_type s;
-      symbolS *sym;
-
-      if (fixp->fx_done)
-       {
-         n--;
-         continue;
-       }
-
-      /* If this is an undefined symbol which was equated to another
-         symbol, then generate the reloc against the latter symbol
-         rather than the former.  */
-      sym = fixp->fx_addsy;
-      while (symbol_equated_reloc_p (sym))
+      if (r->u.b.sec == sec)
        {
-         symbolS *n;
-
-         /* We must avoid looping, as that can occur with a badly
-            written program.  */
-         n = symbol_get_value_expression (sym)->X_add_symbol;
-         if (n == sym)
-           break;
-         fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number;
-         sym = n;
-       }
-      fixp->fx_addsy = sym;
-
-      reloc = tc_gen_reloc (sec, fixp);
-      if (!reloc)
-       {
-         n--;
-         continue;
+         *rp = r->next;
+         r->next = my_reloc_list;
+         my_reloc_list = r;
+         n++;
        }
-
-      /*
-       This test is triggered inappropriately for the SH:
-         if (fixp->fx_where + fixp->fx_size
-            > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
-            abort ();
-      */
-
-      s = bfd_install_relocation (stdoutput, reloc,
-                                 fixp->fx_frag->fr_literal,
-                                 fixp->fx_frag->fr_address,
-                                 sec, &err);
-      switch (s)
-       {
-       case bfd_reloc_ok:
-         break;
-       case bfd_reloc_overflow:
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       _("relocation overflow"));
-         break;
-       case bfd_reloc_outofrange:
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       _("relocation out of range"));
-         break;
-       default:
-         as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
-                   fixp->fx_file, fixp->fx_line, s);
-       }
-      relocs[i++] = reloc;
+      else
+       rp = &r->next;
     }
-#else
-  n = n * MAX_RELOC_EXPANSION;
-  /* Set up reloc information as well.  */
-  relocs = xcalloc (n, sizeof (arelent *));
+
+  relocs = (arelent **) xcalloc (n, sizeof (arelent *));
 
   i = 0;
   for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
     {
-      arelent **reloc;
-      bfd_reloc_status_type s;
-      symbolS *sym;
       int j;
+      int fx_size, slack;
+      offsetT loc;
 
       if (fixp->fx_done)
-       {
-         n--;
-         continue;
-       }
+       continue;
 
-      /* If this is an undefined symbol which was equated to another
-         symbol, then generate the reloc against the latter symbol
-         rather than the former.  */
-      sym = fixp->fx_addsy;
-      while (symbol_equated_reloc_p (sym))
-       {
-         symbolS *n;
-
-         /* We must avoid looping, as that can occur with a badly
-            written program.  */
-         n = symbol_get_value_expression (sym)->X_add_symbol;
-         if (n == sym)
-           break;
-         fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number;
-         sym = n;
-       }
-      fixp->fx_addsy = sym;
+      fx_size = fixp->fx_size;
+      slack = TC_FX_SIZE_SLACK (fixp);
+      if (slack > 0)
+       fx_size = fx_size > slack ? fx_size - slack : 0;
+      loc = fixp->fx_where + fx_size;
+      if (slack >= 0 && loc > fixp->fx_frag->fr_fix)
+       as_bad_where (fixp->fx_file, fixp->fx_line,
+                     _("internal error: fixup not contained within frag"));
 
-      reloc = tc_gen_reloc (sec, fixp);
+#ifndef RELOC_EXPANSION_POSSIBLE
+      {
+       arelent *reloc = tc_gen_reloc (sec, fixp);
 
-      for (j = 0; reloc[j]; j++)
-       {
+       if (!reloc)
+         continue;
+       relocs[i++] = reloc;
+       j = 1;
+      }
+#else
+      {
+       arelent **reloc = tc_gen_reloc (sec, fixp);
+
+       for (j = 0; reloc[j]; j++)
          relocs[i++] = reloc[j];
-         assert (i <= n);
-       }
-      if (fixp->fx_where + fixp->fx_size
-         > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
-       as_bad_where (fixp->fx_file, fixp->fx_line,
-                     _("internal error: fixup not contained within frag"));
-      for (j = 0; reloc[j]; j++)
-       {
-         s = bfd_install_relocation (stdoutput, reloc[j],
-                                     fixp->fx_frag->fr_literal,
-                                     fixp->fx_frag->fr_address,
-                                     sec, &err);
-         switch (s)
-           {
-           case bfd_reloc_ok:
-             break;
-           case bfd_reloc_overflow:
-             as_bad_where (fixp->fx_file, fixp->fx_line,
-                           _("relocation overflow"));
-             break;
-           case bfd_reloc_outofrange:
-             as_bad_where (fixp->fx_file, fixp->fx_line,
-                           _("relocation out of range"));
-             break;
-           default:
-             as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
-                       fixp->fx_file, fixp->fx_line, s);
-           }
-       }
+      }
+#endif
+
+      for ( ; j != 0; --j)
+       install_reloc (sec, relocs[i - j], fixp->fx_frag,
+                      fixp->fx_file, fixp->fx_line);
     }
   n = i;
-#endif
 
 #ifdef DEBUG4
   {
@@ -1177,12 +1233,30 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   }
 #endif
 
+  for (r = my_reloc_list; r != NULL; r = r->next)
+    {
+      fragS *f;
+      for (f = seginfo->frchainP->frch_root; f; f = f->fr_next)
+       if (f->fr_address <= r->u.b.r.address
+           && r->u.b.r.address < f->fr_address + f->fr_fix)
+         break;
+      if (f == NULL)
+       as_bad_where (r->file, r->line,
+                     _("reloc not within (fixed part of) section"));
+      else
+       {
+         relocs[n++] = &r->u.b.r;
+         install_reloc (sec, &r->u.b.r, f, r->file, r->line);
+       }
+    }
+
   if (n)
-    bfd_set_reloc (stdoutput, sec, relocs, n);
-  else
-    bfd_set_section_flags (abfd, sec,
-                          (bfd_get_section_flags (abfd, sec)
-                           & (flagword) ~SEC_RELOC));
+    {
+      flagword flags = bfd_get_section_flags (abfd, sec);
+      flags |= SEC_RELOC;
+      bfd_set_section_flags (abfd, sec, flags);
+      bfd_set_reloc (stdoutput, sec, relocs, n);
+    }
 
 #ifdef SET_SECTION_RELOCS
   SET_SECTION_RELOCS (sec, relocs, n);
@@ -1228,7 +1302,7 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
       char *fill_literal;
       offsetT count;
 
-      assert (f->fr_type == rs_fill);
+      gas_assert (f->fr_type == rs_fill);
       if (f->fr_fix)
        {
          x = bfd_set_section_contents (stdoutput, sec,
@@ -1242,7 +1316,7 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
       fill_literal = f->fr_literal + f->fr_fix;
       fill_size = f->fr_var;
       count = f->fr_offset;
-      assert (count >= 0);
+      gas_assert (count >= 0);
       if (fill_size && count)
        {
          char buf[256];
@@ -1324,18 +1398,22 @@ set_symtab (void)
       int i;
       bfd_size_type amt = (bfd_size_type) nsyms * sizeof (asymbol *);
 
-      asympp = bfd_alloc (stdoutput, amt);
+      asympp = (asymbol **) bfd_alloc (stdoutput, amt);
       symp = symbol_rootP;
       for (i = 0; i < nsyms; i++, symp = symbol_next (symp))
        {
          asympp[i] = symbol_get_bfdsym (symp);
+         if (asympp[i]->flags != BSF_SECTION_SYM
+             || !(bfd_is_const_section (asympp[i]->section)
+                  && asympp[i]->section->symbol == asympp[i]))
+           asympp[i]->flags |= BSF_KEEP;
          symbol_mark_written (symp);
        }
     }
   else
     asympp = 0;
   result = bfd_set_symtab (stdoutput, asympp, nsyms);
-  assert (result);
+  gas_assert (result);
   symbol_table_frozen = 1;
 }
 
@@ -1596,18 +1674,22 @@ write_object_file (void)
            if (lie->added == 2)
              continue;
            /* Patch the jump table.  */
-           /* This is the offset from ??? to table_ptr+0.  */
-           to_addr = table_addr - S_GET_VALUE (lie->sub);
-#ifdef TC_CHECK_ADJUSTED_BROKEN_DOT_WORD
-           TC_CHECK_ADJUSTED_BROKEN_DOT_WORD (to_addr, lie);
-#endif
-           md_number_to_chars (lie->word_goes_here, to_addr, 2);
-           for (untruth = lie->next_broken_word;
+           for (untruth = (struct broken_word *) (fragP->fr_symbol);
                 untruth && untruth->dispfrag == fragP;
                 untruth = untruth->next_broken_word)
              {
                if (untruth->use_jump == lie)
-                 md_number_to_chars (untruth->word_goes_here, to_addr, 2);
+                 {
+                   /* This is the offset from ??? to table_ptr+0.
+                      The target is the same for all users of this
+                      md_long_jump, but the "sub" bases (and hence the
+                      offsets) may be different.  */
+                   addressT to_word = table_addr - S_GET_VALUE (untruth->sub);
+#ifdef TC_CHECK_ADJUSTED_BROKEN_DOT_WORD
+                   TC_CHECK_ADJUSTED_BROKEN_DOT_WORD (to_word, untruth);
+#endif
+                   md_number_to_chars (untruth->word_goes_here, to_word, 2);
+                 }
              }
 
            /* Install the long jump.  */
@@ -1633,6 +1715,7 @@ write_object_file (void)
        resolve_symbol_value (symp);
     }
   resolve_local_symbol_values ();
+  resolve_reloc_expr_symbols ();
 
   PROGRESS (1);
 
@@ -1700,7 +1783,7 @@ write_object_file (void)
          resolve_symbol_value (symp);
 
          /* Skip symbols which were equated to undefined or common
-             symbols.  */
+            symbols.  */
          if (symbol_equated_reloc_p (symp)
              || S_IS_WEAKREFR (symp))
            {
@@ -1714,6 +1797,13 @@ write_object_file (void)
                  as_bad (_("Local symbol `%s' can't be equated to common symbol `%s'"),
                          name, S_GET_NAME (e->X_add_symbol));
                }
+             if (S_GET_SEGMENT (symp) == reg_section)
+               {
+                 /* Report error only if we know the symbol name.  */
+                 if (S_GET_NAME (symp) != reg_section->name)
+                   as_bad (_("can't make global register symbol `%s'"),
+                           name);
+               }
              symbol_remove (symp, &symbol_rootP, &symbol_lastP);
              continue;
            }
@@ -1781,6 +1871,10 @@ write_object_file (void)
   obj_adjust_symtab ();
 #endif
 
+  /* Stop if there is an error.  */
+  if (had_errors ())
+    return;
+
   /* Now that all the sizes are known, and contents correct, we can
      start writing to the file.  */
   set_symtab ();
@@ -1795,7 +1889,9 @@ write_object_file (void)
 #ifdef obj_frob_file
   obj_frob_file ();
 #endif
-
+#ifdef obj_coff_generate_pdata
+  obj_coff_generate_pdata ();
+#endif
   bfd_map_over_sections (stdoutput, write_relocs, (char *) 0);
 
 #ifdef tc_frob_file_after_relocs
@@ -2029,23 +2125,48 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
   /* Do relax().  */
   {
     unsigned long max_iterations;
-    offsetT stretch;   /* May be any size, 0 or negative.  */
-    /* Cumulative number of addresses we have relaxed this pass.
-       We may have relaxed more than one address.  */
-    int stretched;     /* Have we stretched on this pass?  */
-    /* This is 'cuz stretch may be zero, when, in fact some piece of code
-       grew, and another shrank.  If a branch instruction doesn't fit anymore,
-       we could be scrod.  */
+
+    /* Cumulative address adjustment.  */
+    offsetT stretch;
+
+    /* Have we made any adjustment this pass?  We can't just test
+       stretch because one piece of code may have grown and another
+       shrank.  */
+    int stretched;
+
+    /* Most horrible, but gcc may give us some exception data that
+       is impossible to assemble, of the form
+
+       .align 4
+       .byte 0, 0
+       .uleb128 end - start
+       start:
+       .space 128*128 - 1
+       .align 4
+       end:
+
+       If the leb128 is two bytes in size, then end-start is 128*128,
+       which requires a three byte leb128.  If the leb128 is three
+       bytes in size, then end-start is 128*128-1, which requires a
+       two byte leb128.  We work around this dilemma by inserting
+       an extra 4 bytes of alignment just after the .align.  This
+       works because the data after the align is accessed relative to
+       the end label.
+
+       This counter is used in a tiny state machine to detect
+       whether a leb128 followed by an align is impossible to
+       relax.  */
+    int rs_leb128_fudge = 0;
 
     /* We want to prevent going into an infinite loop where one frag grows
        depending upon the location of a symbol which is in turn moved by
        the growing frag.  eg:
 
-         foo = .
-         .org foo+16
-         foo = .
+        foo = .
+        .org foo+16
+        foo = .
 
-       So we dictate that this algorithm can be at most O2.  */
+       So we dictate that this algorithm can be at most O2.  */
     max_iterations = frag_count * frag_count;
     /* Check for overflow.  */
     if (max_iterations < frag_count)
@@ -2114,13 +2235,17 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
                                             S_GET_NAME (lie->sub),
                                             buf);
                            }
-                         lie->added = 1;
                          if (fragP->fr_subtype == 0)
                            {
                              fragP->fr_subtype++;
                              growth += md_short_jump_size;
                            }
-                         for (untruth = lie->next_broken_word;
+
+                         /* Redirect *all* words of this table with the same
+                            target, lest we have to handle the case where the
+                            same target but with a offset that fits on this
+                            round overflows at the next relaxation round.  */
+                         for (untruth = (struct broken_word *) (fragP->fr_symbol);
                               untruth && untruth->dispfrag == lie->dispfrag;
                               untruth = untruth->next_broken_word)
                            if ((symbol_get_frag (untruth->add)
@@ -2131,6 +2256,8 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
                                untruth->added = 2;
                                untruth->use_jump = lie;
                              }
+
+                         lie->added = 1;
                          growth += md_long_jump_size;
                        }
                    }
@@ -2158,6 +2285,49 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
                    }
 
                  growth = newoff - oldoff;
+
+                 /* If this align happens to follow a leb128 and
+                    we have determined that the leb128 is bouncing
+                    in size, then break the cycle by inserting an
+                    extra alignment.  */
+                 if (growth < 0
+                     && (rs_leb128_fudge & 16) != 0
+                     && (rs_leb128_fudge & 15) >= 2)
+                   {
+                     segment_info_type *seginfo = seg_info (segment);
+                     struct obstack *ob = &seginfo->frchainP->frch_obstack;
+                     struct frag *newf;
+
+                     newf = frag_alloc (ob);
+                     obstack_blank_fast (ob, fragP->fr_var);
+                     obstack_finish (ob);
+                     memcpy (newf, fragP, SIZEOF_STRUCT_FRAG);
+                     memcpy (newf->fr_literal,
+                             fragP->fr_literal + fragP->fr_fix,
+                             fragP->fr_var);
+                     newf->fr_type = rs_fill;
+                     newf->fr_fix = 0;
+                     newf->fr_offset = (((offsetT) 1 << fragP->fr_offset)
+                                        / fragP->fr_var);
+                     if (newf->fr_offset * newf->fr_var
+                         != (offsetT) 1 << fragP->fr_offset)
+                       {
+                         newf->fr_offset = (offsetT) 1 << fragP->fr_offset;
+                         newf->fr_var = 1;
+                       }
+                     /* Include growth of new frag, because rs_fill
+                        frags don't normally grow.  */
+                     growth += newf->fr_offset * newf->fr_var;
+                     /* The new frag address is newoff.  Adjust this
+                        for the amount we'll add when we process the
+                        new frag.  */
+                     newf->fr_address = newoff - stretch - growth;
+                     newf->relax_marker ^= 1;
+                     fragP->fr_next = newf;
+#ifdef DEBUG
+                     as_warn (_("padding added"));
+#endif
+                   }
                }
                break;
 
@@ -2168,16 +2338,16 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 
                  if (symbolP)
                    {
-                      /* Convert from an actual address to an octet offset
-                         into the section.  Here it is assumed that the
-                         section's VMA is zero, and can omit subtracting it
-                         from the symbol's value to get the address offset.  */
-                      know (S_GET_SEGMENT (symbolP)->vma == 0);
+                     /* Convert from an actual address to an octet offset
+                        into the section.  Here it is assumed that the
+                        section's VMA is zero, and can omit subtracting it
+                        from the symbol's value to get the address offset.  */
+                     know (S_GET_SEGMENT (symbolP)->vma == 0);
                      target += S_GET_VALUE (symbolP) * OCTETS_PER_BYTE;
                    }
 
                  know (fragP->fr_next);
-                 after = fragP->fr_next->fr_address;
+                 after = fragP->fr_next->fr_address + stretch;
                  growth = target - after;
                  if (growth < 0)
                    {
@@ -2208,18 +2378,14 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
                                    _("attempt to move .org backwards"));
 
                      /* We've issued an error message.  Change the
-                         frag to avoid cascading errors.  */
+                        frag to avoid cascading errors.  */
                      fragP->fr_type = rs_align;
                      fragP->fr_subtype = 0;
                      fragP->fr_offset = 0;
-                     fragP->fr_fix = after - was_address;
-                     break;
+                     fragP->fr_fix = after - address;
                    }
-
-                 /* This is an absolute growth factor  */
-                 growth -= stretch;
-                 break;
                }
+               break;
 
              case rs_space:
                growth = 0;
@@ -2297,8 +2463,23 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
              {
                stretch += growth;
                stretched = 1;
+               if (fragP->fr_type == rs_leb128)
+                 rs_leb128_fudge += 16;
+               else if (fragP->fr_type == rs_align
+                        && (rs_leb128_fudge & 16) != 0
+                        && stretch == 0)
+                 rs_leb128_fudge += 16;
+               else
+                 rs_leb128_fudge = 0;
              }
          }
+
+       if (stretch == 0
+           && (rs_leb128_fudge & 16) == 0
+           && (rs_leb128_fudge & -16) != 0)
+         rs_leb128_fudge += 1;
+       else
+         rs_leb128_fudge = 0;
       }
     /* Until nothing further to relax.  */
     while (stretched && -- max_iterations);
@@ -2354,7 +2535,9 @@ void
 print_fixup (fixS *fixp)
 {
   indent_level = 1;
-  fprintf (stderr, "fix %lx %s:%d", (long) fixp, fixp->fx_file, fixp->fx_line);
+  fprintf (stderr, "fix ");
+  fprintf_vma (stderr, (bfd_vma)((bfd_hostptr_t) fixp));
+  fprintf (stderr, " %s:%d",fixp->fx_file, fixp->fx_line);
   if (fixp->fx_pcrel)
     fprintf (stderr, " pcrel");
   if (fixp->fx_pcrel_adjust)
@@ -2371,9 +2554,12 @@ print_fixup (fixS *fixp)
     fprintf (stderr, " tcbit");
   if (fixp->fx_done)
     fprintf (stderr, " done");
-  fprintf (stderr, "\n    size=%d frag=%lx where=%ld offset=%lx addnumber=%lx",
-          fixp->fx_size, (long) fixp->fx_frag, (long) fixp->fx_where,
-          (long) fixp->fx_offset, (long) fixp->fx_addnumber);
+  fprintf (stderr, "\n    size=%d frag=", fixp->fx_size);
+  fprintf_vma (stderr, (bfd_vma) ((bfd_hostptr_t) fixp->fx_frag));
+  fprintf (stderr, " where=%ld offset=%lx addnumber=%lx",
+          (long) fixp->fx_where,
+          (unsigned long) fixp->fx_offset,
+          (unsigned long) fixp->fx_addnumber);
   fprintf (stderr, "\n    %s (%d)", bfd_get_reloc_code_name (fixp->fx_r_type),
           fixp->fx_r_type);
   if (fixp->fx_addsy)
This page took 0.03904 seconds and 4 git commands to generate.