]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-hppa.c
daily update
[thirdparty/binutils-gdb.git] / gas / config / tc-hppa.c
index d31d527a68c59eaf75b562d4f98ce9e7c7f2aafd..e688f71fba7ea8a2b2b32e03bb9ea38550adfa6d 100644 (file)
@@ -1,6 +1,7 @@
 /* tc-hppa.c -- Assemble for the PA
-   Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -948,8 +949,8 @@ static const struct selector_entry selector_table[] =
 #ifdef OBJ_SOM
 /* default space and subspace dictionaries */
 
-#define GDB_SYMBOLS          GDB_SYMBOLS_SUBSPACE_NAME
-#define GDB_STRINGS          GDB_STRINGS_SUBSPACE_NAME
+#define GDB_SYMBOLS    GDB_SYMBOLS_SUBSPACE_NAME
+#define GDB_STRINGS    GDB_STRINGS_SUBSPACE_NAME
 
 /* pre-defined subsegments (subspaces) for the HPPA.  */
 #define SUBSEG_CODE   0
@@ -995,6 +996,19 @@ static struct default_space_dict pa_def_spaces[] =
 #define IS_R_SELECT(S)   (*(S) == 'R' || *(S) == 'r')
 #define IS_L_SELECT(S)   (*(S) == 'L' || *(S) == 'l')
 
+/* Store immediate values of shift/deposit/extract functions.  */
+
+#define SAVE_IMMEDIATE(VALUE) \
+  { \
+    if (immediate_check) \
+      { \
+       if (pos == -1) \
+         pos = (VALUE); \
+       else if (len == -1) \
+         len = (VALUE); \
+      } \
+  }
+
 /* Insert FIELD into OPCODE starting at bit START.  Continue pa_ip
    main loop after insertion.  */
 
@@ -1012,9 +1026,9 @@ static struct default_space_dict pa_def_spaces[] =
     if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
       { \
        if (! IGNORE) \
-          as_bad (_("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
+         as_bad (_("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
                  (int) (FIELD));\
-        break; \
+       break; \
       } \
   }
 
@@ -1025,10 +1039,10 @@ static struct default_space_dict pa_def_spaces[] =
   { \
     if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
       { \
-        as_bad_where ((FILENAME), (LINE), \
+       as_bad_where ((FILENAME), (LINE), \
                      _("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
                      (int) (FIELD));\
-        break; \
+       break; \
       } \
   }
 
@@ -1040,9 +1054,9 @@ static struct default_space_dict pa_def_spaces[] =
     if ((FIELD) & ((ALIGN) - 1)) \
       { \
        if (! IGNORE) \
-          as_bad (_("Field not properly aligned [%d] (%d)."), (ALIGN), \
+         as_bad (_("Field not properly aligned [%d] (%d)."), (ALIGN), \
                  (int) (FIELD));\
-        break; \
+       break; \
       } \
   }
 
@@ -1050,6 +1064,10 @@ static struct default_space_dict pa_def_spaces[] =
   ((exp).X_op == O_subtract                    \
    && strcmp (S_GET_NAME ((exp).X_op_symbol), "$global$") == 0)
 
+#define is_SB_relative(exp)                    \
+  ((exp).X_op == O_subtract                    \
+   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$segrel$") == 0)
+
 #define is_PC_relative(exp)                    \
   ((exp).X_op == O_subtract                    \
    && strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0)
@@ -1233,6 +1251,7 @@ fix_new_hppa (fragS *frag,
      it now so as not to confuse write.c.  Ditto for $PIC_pcrel$0.  */
   if (new_fix->fx_subsy
       && (strcmp (S_GET_NAME (new_fix->fx_subsy), "$global$") == 0
+         || strcmp (S_GET_NAME (new_fix->fx_subsy), "$segrel$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$PIC_pcrel$0") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_gdidx$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ldidx$") == 0
@@ -1256,6 +1275,8 @@ cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp)
   else if (is_PC_relative (*exp))
     rel_type = R_HPPA_PCREL_CALL;
 #ifdef OBJ_ELF
+  else if (is_SB_relative (*exp))
+    rel_type = R_PARISC_SEGREL32;
   else if (is_tls_gdidx (*exp))
     rel_type = R_PARISC_TLS_GD21L;
   else if (is_tls_ldidx (*exp))
@@ -1368,13 +1389,26 @@ tc_gen_reloc (asection *section, fixS *fixp)
   if (fixp->fx_addsy == 0)
     return &no_relocs;
 
-  assert (hppa_fixp != 0);
-  assert (section != 0);
+  gas_assert (hppa_fixp != 0);
+  gas_assert (section != 0);
 
   reloc = xmalloc (sizeof (arelent));
 
   reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+
+  /* Allow fixup_segment to recognize hand-written pc-relative relocations.
+     When we went through cons_fix_new_hppa, we classified them as complex.  */
+  /* ??? It might be better to hide this +8 stuff in tc_cfi_emit_pcrel_expr,
+     undefine DIFF_EXPR_OK, and let these sorts of complex expressions fail
+     when R_HPPA_COMPLEX == R_PARISC_UNIMPLEMENTED.  */
+  if (fixp->fx_r_type == (bfd_reloc_code_real_type) R_HPPA_COMPLEX
+      && fixp->fx_pcrel)
+    {
+      fixp->fx_r_type = R_HPPA_PCREL_CALL;
+      fixp->fx_offset += 8;
+    }
+
   codes = hppa_gen_reloc_type (stdoutput,
                               fixp->fx_r_type,
                               hppa_fixp->fx_r_format,
@@ -1402,7 +1436,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
   switch (fixp->fx_r_type)
     {
     default:
-      assert (n_relocs == 1);
+      gas_assert (n_relocs == 1);
 
       code = *codes[0];
 
@@ -1456,7 +1490,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
                                            (bfd_reloc_code_real_type) code);
       reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
-      assert (reloc->howto && (unsigned int) code == reloc->howto->type);
+      gas_assert (reloc->howto && (unsigned int) code == reloc->howto->type);
       break;
     }
 #else /* OBJ_SOM */
@@ -1479,7 +1513,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
          /* The only time we ever use a R_COMP2 fixup is for the difference
             of two symbols.  With that in mind we fill in all four
             relocs now and break out of the loop.  */
-         assert (i == 1);
+         gas_assert (i == 1);
          relocs[0]->sym_ptr_ptr
            = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
          relocs[0]->howto
@@ -1946,7 +1980,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       case R_PARISC_TLS_LE14R:
       case R_PARISC_TLS_IE21L:
       case R_PARISC_TLS_IE14R:
-        if (fixP->fx_addsy)
+       if (fixP->fx_addsy)
          S_SET_THREAD_LOCAL (fixP->fx_addsy);
        break;
       default:
@@ -2099,8 +2133,8 @@ pa_parse_number (char **s, int is_float)
       p++;
       c = *p;
       /* Tege hack: Special case for general registers as the general
-         code makes a binary search with case translation, and is VERY
-         slow.  */
+        code makes a binary search with case translation, and is VERY
+        slow.  */
       if (c == 'r')
        {
          p++;
@@ -2155,7 +2189,7 @@ pa_parse_number (char **s, int is_float)
   else
     {
       /* And finally, it could be a symbol in the absolute section which
-         is effectively a constant, or a register alias symbol.  */
+        is effectively a constant, or a register alias symbol.  */
       name = p;
       c = *p;
       while (is_part_of_name (c))
@@ -2529,7 +2563,6 @@ pa_get_absolute_expression (struct pa_it *insn, char **strp)
   if (insn->exp.X_op == O_modulus)
     {
       char *s, c;
-      int retval;
 
       input_line_pointer = *strp;
       s = *strp;
@@ -2539,7 +2572,7 @@ pa_get_absolute_expression (struct pa_it *insn, char **strp)
       c = *s;
       *s = 0;
 
-      retval = pa_get_absolute_expression (insn, strp);
+      pa_get_absolute_expression (insn, strp);
 
       input_line_pointer = save_in;
       *s = c;
@@ -2666,7 +2699,7 @@ pa_parse_nonneg_cmpsub_cmpltr (char **s)
          cmpltr = 7;
        }
       /* If we have something like addb,n then there is no condition
-         completer.  */
+        completer.  */
       else if (strcasecmp (name, "n") == 0)
        {
          cmpltr = 0;
@@ -2740,7 +2773,7 @@ pa_parse_neg_cmpsub_cmpltr (char **s)
          cmpltr = 7;
        }
       /* If we have something like addb,n then there is no condition
-         completer.  */
+        completer.  */
       else if (strcasecmp (name, "n") == 0)
        {
          cmpltr = 0;
@@ -2966,7 +2999,7 @@ pa_parse_nonneg_add_cmpltr (char **s)
          cmpltr = 7;
        }
       /* If we have something like addb,n then there is no condition
-         completer.  */
+        completer.  */
       else if (strcasecmp (name, "n") == 0)
        {
          cmpltr = 0;
@@ -3039,7 +3072,7 @@ pa_parse_neg_add_cmpltr (char **s)
          cmpltr = 7;
        }
       /* If we have something like addb,n then there is no condition
-         completer.  */
+        completer.  */
       else if (strcasecmp (name, "n") == 0)
        {
          cmpltr = 0;
@@ -3140,7 +3173,7 @@ pa_parse_addb_64_cmpltr (char **s)
          cmpltr = 15;
        }
       /* If we have something like addb,n then there is no condition
-         completer.  */
+        completer.  */
       else if (strcasecmp (name, "n") == 0)
        {
          cmpltr = 0;
@@ -3171,7 +3204,8 @@ pa_ip (char *str)
   const char *args;
   int match = FALSE;
   int comma = 0;
-  int cmpltr, nullif, flag, cond, num;
+  int cmpltr, nullif, flag, cond, need_cond, num;
+  int immediate_check = 0, pos = -1, len = -1;
   unsigned long opcode;
   struct pa_opcode *insn;
 
@@ -3214,7 +3248,7 @@ pa_ip (char *str)
   /* Look up the opcode in the hash table.  */
   if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
     {
-      as_bad ("Unknown opcode: `%s'", str);
+      as_bad (_("Unknown opcode: `%s'"), str);
       return;
     }
 
@@ -3230,6 +3264,7 @@ pa_ip (char *str)
       opcode = insn->match;
       strict = (insn->flags & FLAG_STRICT);
       memset (&the_insn, 0, sizeof (the_insn));
+      need_cond = 1;
 
       the_insn.reloc = R_HPPA_NONE;
 
@@ -3238,7 +3273,7 @@ pa_ip (char *str)
        goto failed;
 
       /* Build the opcode, checking as we go to make
-         sure that the operands match.  */
+        sure that the operands match.  */
       for (args = insn->args;; ++args)
        {
          /* Absorb white space in instruction.  */
@@ -3289,12 +3324,12 @@ pa_ip (char *str)
                s = s + 1;
 
              if (!strncasecmp (s, "%sar", 4))
-               {
+               {
                  s += 4;
                  continue;
                }
              else if (!strncasecmp (s, "%cr11", 5))
-               {
+               {
                  s += 5;
                  continue;
                }
@@ -3332,6 +3367,7 @@ pa_ip (char *str)
                break;
              s = expr_end;
              CHECK_FIELD (num, 32, 1, 0);
+             SAVE_IMMEDIATE(num);
              INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
 
            /* Handle a 5 bit immediate at 15.  */
@@ -3498,7 +3534,7 @@ pa_ip (char *str)
                      }
                    else if (*args == 'J')
                      {
-                       /* M bit is explicit in the major opcode.  */
+                       /* M bit is explicit in the major opcode.  */
                        INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
                      }
                    else if (*args == 'e')
@@ -3723,6 +3759,8 @@ pa_ip (char *str)
                  else
                    break;
 
+                 /* Condition is not required with "dc".  */
+                 need_cond = 0;
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
                /* Handle 32 bit carry for ADD.  */
@@ -3791,6 +3829,8 @@ pa_ip (char *str)
                  else
                    break;
 
+                 /* Condition is not required with "db".  */
+                 need_cond = 0;
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
                /* Handle 32 bit borrow for SUB.  */
@@ -3890,7 +3930,7 @@ pa_ip (char *str)
                      permloc[2] = 8;
                      permloc[3] = 6;
                      for (; i < 4; i++)
-                       {
+                       {
                          switch (*s++)
                            {
                            case '0':
@@ -4016,6 +4056,11 @@ pa_ip (char *str)
                          as_bad (_("Invalid Add Condition: %s"), name);
                        *s = c;
                      }
+                   /* Except with "dc", we have a match failure with
+                      'A' if we don't have a doubleword condition.  */
+                   else if (*args == 'A' && need_cond)
+                     break;
+
                    opcode |= cmpltr << 13;
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
@@ -4095,8 +4140,11 @@ pa_ip (char *str)
                            s += 2;
                          }
                        else
-                         as_bad (_("Invalid Bit Branch Condition: %c"), *s);
+                         as_bad (_("Invalid Branch On Bit Condition: %c"), *s);
                      }
+                   else
+                     as_bad (_("Missing Branch On Bit Condition"));
+
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
 
                  /* Handle a compare/subtract condition.  */
@@ -4184,6 +4232,11 @@ pa_ip (char *str)
                                  name);
                        *s = c;
                      }
+                   /* Except with "db", we have a match failure with
+                      'S' if we don't have a doubleword condition.  */
+                   else if (*args == 'S' && need_cond)
+                     break;
+
                    opcode |= cmpltr << 13;
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
@@ -4242,7 +4295,7 @@ pa_ip (char *str)
 
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
-                   /* Handle a logical instruction condition.  */
+                 /* Handle a logical instruction condition.  */
                  case 'L':
                  case 'l':
                    cmpltr = 0;
@@ -4306,6 +4359,10 @@ pa_ip (char *str)
                          as_bad (_("Invalid Logical Instruction Condition."));
                        *s = c;
                      }
+                   /* 32-bit is default for no condition.  */
+                   else if (*args == 'L')
+                     break;
+
                    opcode |= cmpltr << 13;
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
@@ -4314,6 +4371,9 @@ pa_ip (char *str)
                  case 'x':
                  case 'y':
                    cmpltr = 0;
+                   /* Check immediate values in shift/extract/deposit
+                    * instructions if they will give undefined behaviour.  */
+                   immediate_check = 1;
                    if (*s == ',')
                      {
                        save_s = s++;
@@ -4361,6 +4421,7 @@ pa_ip (char *str)
                          as_bad (_("Invalid Shift/Extract/Deposit Condition."));
                        *s = c;
                      }
+
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
                  /* Handle a unit instruction condition.  */
@@ -4472,6 +4533,10 @@ pa_ip (char *str)
                        else if (*args != 'U' || (*s != ' ' && *s != '\t'))
                          as_bad (_("Invalid Unit Instruction Condition."));
                      }
+                   /* 32-bit is default for no condition.  */
+                   else if (*args == 'U')
+                     break;
+
                    opcode |= cmpltr << 13;
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
@@ -5065,7 +5130,7 @@ pa_ip (char *str)
                  continue;
                }
              else
-               break;
+               break;
 
            /* Handle '%sr0,%r31' implicit operand of be,l instruction.  */
            case 'Y':
@@ -5106,6 +5171,7 @@ pa_ip (char *str)
                break;
              s = expr_end;
              CHECK_FIELD (num, 31, 0, strict);
+             SAVE_IMMEDIATE(num);
              INSERT_FIELD_AND_CONTINUE (opcode, 31 - num, 5);
 
            /* Handle a 6 bit shift count at 20,22:26.  */
@@ -5115,6 +5181,7 @@ pa_ip (char *str)
                break;
              s = expr_end;
              CHECK_FIELD (num, 63, 0, strict);
+             SAVE_IMMEDIATE(num);
              num = 63 - num;
              opcode |= (num & 0x20) << 6;
              INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
@@ -5127,6 +5194,7 @@ pa_ip (char *str)
                break;
              s = expr_end;
              CHECK_FIELD (num, 64, 1, strict);
+             SAVE_IMMEDIATE(num);
              num--;
              opcode |= (num & 0x20) << 3;
              num = 31 - (num & 0x1f);
@@ -5139,6 +5207,7 @@ pa_ip (char *str)
                break;
              s = expr_end;
              CHECK_FIELD (num, 64, 1, strict);
+             SAVE_IMMEDIATE(num);
              num--;
              opcode |= (num & 0x20) << 7;
              num = 31 - (num & 0x1f);
@@ -5151,6 +5220,7 @@ pa_ip (char *str)
                break;
              s = expr_end;
              CHECK_FIELD (num, 31, 0, strict);
+             SAVE_IMMEDIATE(num);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 5);
 
            /* Handle a 6 bit bit position at 20,22:26.  */
@@ -5160,6 +5230,7 @@ pa_ip (char *str)
                break;
              s = expr_end;
              CHECK_FIELD (num, 63, 0, strict);
+             SAVE_IMMEDIATE(num);
              opcode |= (num & 0x20) << 6;
              INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
 
@@ -5402,7 +5473,7 @@ pa_ip (char *str)
            /* Handle all floating point registers.  */
            case 'f':
              switch (*++args)
-               {
+               {
                /* Float target register.  */
                case 't':
                  if (!pa_parse_number (&s, 3))
@@ -5530,13 +5601,13 @@ pa_ip (char *str)
                    CHECK_FIELD (num, 31, 0, 0);
                    if (the_insn.fpof1 == SGL)
                      {
-                       if (num < 16)
-                         {
+                       if (num < 16)
+                         {
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            break;
-                         }
-                       num &= 0xF;
-                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
+                         }
+                       num &= 0xF;
+                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
                  }
@@ -5550,13 +5621,13 @@ pa_ip (char *str)
                    CHECK_FIELD (num, 31, 0, 0);
                    if (the_insn.fpof1 == SGL)
                      {
-                       if (num < 16)
-                         {
+                       if (num < 16)
+                         {
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            break;
-                         }
-                       num &= 0xF;
-                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
+                         }
+                       num &= 0xF;
+                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                  }
@@ -5570,13 +5641,13 @@ pa_ip (char *str)
                    CHECK_FIELD (num, 31, 0, 0);
                    if (the_insn.fpof1 == SGL)
                      {
-                       if (num < 16)
-                         {
+                       if (num < 16)
+                         {
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            break;
-                         }
-                       num &= 0xF;
-                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
+                         }
+                       num &= 0xF;
+                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
                  }
@@ -5590,13 +5661,13 @@ pa_ip (char *str)
                    CHECK_FIELD (num, 31, 0, 0);
                    if (the_insn.fpof1 == SGL)
                      {
-                       if (num < 16)
-                         {
+                       if (num < 16)
+                         {
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            break;
-                         }
-                       num &= 0xF;
-                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
+                         }
+                       num &= 0xF;
+                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
                  }
@@ -5667,6 +5738,13 @@ pa_ip (char *str)
       break;
     }
 
+  if (immediate_check)
+    {
+      if (pos != -1 && len != -1 && pos < len - 1)
+        as_warn (_("Immediates %d and %d will give undefined behavior."),
+                       pos, len);
+    }
+
   the_insn.opcode = opcode;
 }
 
@@ -5678,7 +5756,7 @@ md_assemble (char *str)
   char *to;
 
   /* The had better be something to assemble.  */
-  assert (str);
+  gas_assert (str);
 
   /* If we are within a procedure definition, make sure we've
      defined a label for the procedure; handle case where the
@@ -5911,13 +5989,45 @@ pa_build_unwind_subspace (struct call_info *call_info)
   subsegT save_subseg;
   unsigned int unwind;
   int reloc;
-  char *p;
+  char *name, *p;
+  symbolS *symbolP;
 
   if ((bfd_get_section_flags (stdoutput, now_seg)
        & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
       != (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
     return;
 
+  if (call_info->start_symbol == NULL)
+    /* This can happen if there were errors earlier on in the assembly.  */
+    return;
+
+  /* Replace the start symbol with a local symbol that will be reduced
+     to a section offset.  This avoids problems with weak functions with
+     multiple definitions, etc.  */
+  name = xmalloc (strlen ("L$\001start_")
+                 + strlen (S_GET_NAME (call_info->start_symbol))
+                 + 1);
+  strcpy (name, "L$\001start_");
+  strcat (name, S_GET_NAME (call_info->start_symbol));
+
+  /* If we have a .procend preceded by a .exit, then the symbol will have
+     already been defined.  In that case, we don't want another unwind
+     entry.  */
+  symbolP = symbol_find (name);
+  if (symbolP)
+    {
+      xfree (name);
+      return;
+    }
+  else
+    {
+      symbolP = symbol_new (name, now_seg,
+                           S_GET_VALUE (call_info->start_symbol), frag_now);
+      gas_assert (symbolP);
+      S_CLEAR_EXTERNAL (symbolP);
+      symbol_table_insert (symbolP);
+    }
+
   reloc = R_PARISC_SEGREL32;
   save_seg = now_seg;
   save_subseg = now_subseg;
@@ -5943,7 +6053,7 @@ pa_build_unwind_subspace (struct call_info *call_info)
   /* Relocation info. for start offset of the function.  */
   md_number_to_chars (p, 0, 4);
   fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
-               call_info->start_symbol, (offsetT) 0,
+               symbolP, (offsetT) 0,
                (expressionS *) NULL, 0, reloc,
                e_fsel, 32, 0, 0);
 
@@ -6079,7 +6189,7 @@ pa_callinfo (int unused ATTRIBUTE_UNUSED)
          last_call_info->ci_unwind.descriptor.save_sp = 1;
        }
       /* Is this an unwindable procedure.  If so mark it so
-         in the unwind descriptor.  */
+        in the unwind descriptor.  */
       else if ((strncasecmp (name, "no_unwind", 9) == 0))
        {
          p = input_line_pointer;
@@ -6087,7 +6197,7 @@ pa_callinfo (int unused ATTRIBUTE_UNUSED)
          last_call_info->ci_unwind.descriptor.cannot_unwind = 1;
        }
       /* Is this an interrupt routine.  If so mark it in the
-         unwind descriptor.  */
+        unwind descriptor.  */
       else if ((strncasecmp (name, "hpux_int", 7) == 0))
        {
          p = input_line_pointer;
@@ -6190,8 +6300,8 @@ pa_comm (int unused ATTRIBUTE_UNUSED)
       S_SET_EXTERNAL (symbol);
 
       /* colon() has already set the frag to the current location in the
-         current subspace; we need to reset the fragment to the zero address
-         fragment.  We also need to reset the segment pointer.  */
+        current subspace; we need to reset the fragment to the zero address
+        fragment.  We also need to reset the segment pointer.  */
       symbol_set_frag (symbol, &zero_address_frag);
     }
   demand_empty_rest_of_line ();
@@ -6383,7 +6493,7 @@ hppa_elf_mark_end_of_function (void)
          symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
                                frag_now);
 
-         assert (symbolP);
+         gas_assert (symbolP);
          S_CLEAR_EXTERNAL (symbolP);
          symbol_table_insert (symbolP);
        }
@@ -6414,6 +6524,7 @@ process_exit (void)
   /* Mark the end of the function, stuff away the location of the frag
      for the end of the function, and finally call pa_build_unwind_subspace
      to add an entry in the unwind table.  */
+  (void) where;
   hppa_elf_mark_end_of_function ();
   pa_build_unwind_subspace (last_call_info);
 #else
@@ -6484,11 +6595,11 @@ pa_type_args (symbolS *symbolP, int is_export)
     {
       input_line_pointer += 4;
       /* IMPORTing/EXPORTing CODE types for functions is meaningless for SOM,
-         instead one should be IMPORTing/EXPORTing ENTRY types.
+        instead one should be IMPORTing/EXPORTing ENTRY types.
 
-         Complain if one tries to EXPORT a CODE type since that's never
-         done.  Both GCC and HP C still try to IMPORT CODE types, so
-         silently fix them to be ENTRY types.  */
+        Complain if one tries to EXPORT a CODE type since that's never
+        done.  Both GCC and HP C still try to IMPORT CODE types, so
+        silently fix them to be ENTRY types.  */
       if (S_IS_FUNCTION (symbolP))
        {
          if (is_export)
@@ -6555,6 +6666,8 @@ pa_type_args (symbolS *symbolP, int is_export)
      to the SOM BFD backend.  */
 #ifdef obj_set_symbol_type
   obj_set_symbol_type (bfdsym, (int) type);
+#else
+  (void) type;
 #endif
 
   /* Now that the type of the exported symbol has been handled,
@@ -6577,6 +6690,8 @@ pa_type_args (symbolS *symbolP, int is_export)
          arg_reloc = pa_align_arg_reloc (temp, pa_build_arg_reloc (name));
 #if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
          symbol_arg_reloc_info (symbolP) |= arg_reloc;
+#else
+         (void) arg_reloc;
 #endif
          *input_line_pointer = c;
        }
@@ -6591,6 +6706,8 @@ pa_type_args (symbolS *symbolP, int is_export)
          arg_reloc = pa_build_arg_reloc (name);
 #if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
          symbol_arg_reloc_info (symbolP) |= arg_reloc;
+#else
+         (void) arg_reloc;
 #endif
          *input_line_pointer = c;
        }
@@ -6641,10 +6758,10 @@ pa_export (int unused ATTRIBUTE_UNUSED)
   else
     {
       /* OK.  Set the external bits and process argument relocations.
-         For the HP, weak and global are not mutually exclusive.
-         S_SET_EXTERNAL will not set BSF_GLOBAL if WEAK is set.
-         Call S_SET_EXTERNAL to get the other processing.  Manually
-         set BSF_GLOBAL when we get back.  */
+        For the HP, weak and global are not mutually exclusive.
+        S_SET_EXTERNAL will not set BSF_GLOBAL if WEAK is set.
+        Call S_SET_EXTERNAL to get the other processing.  Manually
+        set BSF_GLOBAL when we get back.  */
       S_SET_EXTERNAL (symbol);
       symbol_get_bfdsym (symbol)->flags |= BSF_GLOBAL;
       p = input_line_pointer;
@@ -7055,8 +7172,8 @@ pa_parse_space_stmt (char *space_name, int create_flag)
       print_errors = FALSE;
       ptemp = input_line_pointer + 1;
       /* First see if the space was specified as a number rather than
-         as a name.  According to the PA assembly manual the rest of
-         the line should be ignored.  */
+        as a name.  According to the PA assembly manual the rest of
+        the line should be ignored.  */
       strict = 0;
       pa_parse_number (&ptemp, 0);
       if (pa_number >= 0)
@@ -7152,8 +7269,8 @@ pa_space (int unused ATTRIBUTE_UNUSED)
   else
     {
       /* Check for some of the predefined spaces.   FIXME: most of the code
-         below is repeated several times, can we extract the common parts
-         and place them into a subroutine or something similar?  */
+        below is repeated several times, can we extract the common parts
+        and place them into a subroutine or something similar?  */
       /* FIXME Is this (and the next IF stmt) really right?
         What if INPUT_LINE_POINTER points to "$TEXT$FOO"?  */
       if (strncmp (input_line_pointer, "$TEXT$", 6) == 0)
@@ -7291,7 +7408,7 @@ pa_subspace (int create_new)
 {
   char *name, *ss_name, c;
   char loadable, code_only, comdat, common, dup_common, zero, sort;
-  int i, access, space_index, alignment, quadrant, applicable, flags;
+  int i, access_ctr, space_index, alignment, quadrant, applicable, flags;
   sd_chain_struct *space;
   ssd_chain_struct *ssd;
   asection *section;
@@ -7314,7 +7431,7 @@ pa_subspace (int create_new)
 
       /* Load default values.  */
       sort = 0;
-      access = 0x7f;
+      access_ctr = 0x7f;
       loadable = 1;
       comdat = 0;
       common = 0;
@@ -7331,7 +7448,7 @@ pa_subspace (int create_new)
       else
        ssd = is_defined_subspace (ss_name);
       /* Allow user to override the builtin attributes of subspaces.  But
-         only allow the attributes to be changed once!  */
+        only allow the attributes to be changed once!  */
       if (ssd && SUBSPACE_DEFINED (ssd))
        {
          subseg_set (ssd->ssd_seg, ssd->ssd_subseg);
@@ -7359,7 +7476,7 @@ pa_subspace (int create_new)
                  space_index = pa_def_subspaces[i].space_index;
                  alignment = pa_def_subspaces[i].alignment;
                  quadrant = pa_def_subspaces[i].quadrant;
-                 access = pa_def_subspaces[i].access;
+                 access_ctr = pa_def_subspaces[i].access;
                  sort = pa_def_subspaces[i].sort;
                  break;
                }
@@ -7368,7 +7485,7 @@ pa_subspace (int create_new)
        }
 
       /* We should be working with a new subspace now.  Fill in
-         any information as specified by the user.  */
+        any information as specified by the user.  */
       if (!is_end_of_statement ())
        {
          input_line_pointer++;
@@ -7397,7 +7514,7 @@ pa_subspace (int create_new)
                {
                  *input_line_pointer = c;
                  input_line_pointer++;
-                 access = get_absolute_expression ();
+                 access_ctr = get_absolute_expression ();
                }
              else if ((strncasecmp (name, "sort", 4) == 0))
                {
@@ -7445,7 +7562,7 @@ pa_subspace (int create_new)
        }
 
       /* Compute a reasonable set of BFD flags based on the information
-         in the .subspace directive.  */
+        in the .subspace directive.  */
       applicable = bfd_applicable_section_flags (stdoutput);
       flags = 0;
       if (loadable)
@@ -7473,12 +7590,12 @@ pa_subspace (int create_new)
       applicable &= flags;
 
       /* If this is an existing subspace, then we want to use the
-         segment already associated with the subspace.
+        segment already associated with the subspace.
 
-         FIXME NOW!  ELF BFD doesn't appear to be ready to deal with
-         lots of sections.  It might be a problem in the PA ELF
-         code, I do not know yet.  For now avoid creating anything
-         but the "standard" sections for ELF.  */
+        FIXME NOW!  ELF BFD doesn't appear to be ready to deal with
+        lots of sections.  It might be a problem in the PA ELF
+        code, I do not know yet.  For now avoid creating anything
+        but the "standard" sections for ELF.  */
       if (create_new)
        section = subseg_force_new (ss_name, 0);
       else if (ssd)
@@ -7500,19 +7617,19 @@ pa_subspace (int create_new)
                           pa_subspace_start (space, quadrant));
 
       /* Now that all the flags are set, update an existing subspace,
-         or create a new one.  */
+        or create a new one.  */
       if (ssd)
 
        current_subspace = update_subspace (space, ss_name, loadable,
                                            code_only, comdat, common,
-                                           dup_common, sort, zero, access,
+                                           dup_common, sort, zero, access_ctr,
                                            space_index, alignment, quadrant,
                                            section);
       else
        current_subspace = create_new_subspace (space, ss_name, loadable,
                                                code_only, comdat, common,
                                                dup_common, zero, sort,
-                                               access, space_index,
+                                               access_ctr, space_index,
                                                alignment, quadrant, section);
 
       demand_empty_rest_of_line ();
@@ -7557,7 +7674,7 @@ pa_spaces_begin (void)
       sd_chain_struct *space;
 
       /* Pick the right name for the new section and pick the right
-         subsegment number.  */
+        subsegment number.  */
       name = pa_def_subspaces[i].name;
       subsegment = 0;
 
@@ -7565,7 +7682,7 @@ pa_spaces_begin (void)
       segment = subseg_new (name, subsegment);
 
       /* For SOM we want to replace the standard .text, .data, and .bss
-         sections with our own.   We also want to set BFD flags for
+        sections with our own.   We also want to set BFD flags for
         all the built-in subspaces.  */
       if (!strcmp (pa_def_subspaces[i].name, "$CODE$"))
        {
@@ -7700,7 +7817,7 @@ create_new_space (char *name,
        }
 
       /* At this point we've found the correct place to add the new
-         entry.  So add it and update the linked lists as appropriate.  */
+        entry.  So add it and update the linked lists as appropriate.  */
       if (prev_chain_pointer)
        {
          chain_entry->sd_next = chain_pointer;
@@ -7743,7 +7860,7 @@ create_new_subspace (sd_chain_struct *space,
                     int dup_common,
                     int is_zero ATTRIBUTE_UNUSED,
                     int sort,
-                    int access,
+                    int access_ctr,
                     int space_index ATTRIBUTE_UNUSED,
                     int alignment ATTRIBUTE_UNUSED,
                     int quadrant,
@@ -7784,7 +7901,7 @@ create_new_subspace (sd_chain_struct *space,
        }
 
       /* Now we have somewhere to put the new entry.  Insert it and update
-         the links.  */
+        the links.  */
       if (prev_chain_pointer)
        {
          chain_entry->ssd_next = chain_pointer;
@@ -7798,7 +7915,7 @@ create_new_subspace (sd_chain_struct *space,
     }
 
 #ifdef obj_set_subsection_attributes
-  obj_set_subsection_attributes (seg, space->sd_seg, access, sort,
+  obj_set_subsection_attributes (seg, space->sd_seg, access_ctr, sort,
                                 quadrant, comdat, common, dup_common);
 #endif
 
@@ -7818,7 +7935,7 @@ update_subspace (sd_chain_struct *space,
                 int dup_common,
                 int sort,
                 int zero ATTRIBUTE_UNUSED,
-                int access,
+                int access_ctr,
                 int space_index ATTRIBUTE_UNUSED,
                 int alignment ATTRIBUTE_UNUSED,
                 int quadrant,
@@ -7829,7 +7946,7 @@ update_subspace (sd_chain_struct *space,
   chain_entry = is_defined_subspace (name);
 
 #ifdef obj_set_subsection_attributes
-  obj_set_subsection_attributes (section, space->sd_seg, access, sort,
+  obj_set_subsection_attributes (section, space->sd_seg, access_ctr, sort,
                                 quadrant, comdat, common, dup_common);
 #endif
 
@@ -8246,7 +8363,7 @@ md_begin (void)
   dummy_symbol = symbol_find_or_make ("L$dummy");
   S_SET_SEGMENT (dummy_symbol, text_section);
   /* Force the symbol to be converted to a real symbol.  */
-  (void) symbol_get_bfdsym (dummy_symbol);
+  symbol_get_bfdsym (dummy_symbol)->flags |= BSF_KEEP;
 #endif
 }
 
@@ -8415,7 +8532,7 @@ hppa_force_relocation (struct fix *fixp)
     return 1;
 #endif
 
-  assert (fixp->fx_addsy != NULL);
+  gas_assert (fixp->fx_addsy != NULL);
 
   /* Ensure we emit a relocation for global symbols so that dynamic
      linking works.  */
@@ -8657,9 +8774,19 @@ hppa_regname_to_dw2regnum (char *regname)
     {
       p = regname + 2;
       regnum = strtoul (p, &q, 10);
+#if TARGET_ARCH_SIZE == 64
       if (p == q || *q || regnum <= 4 || regnum >= 32)
        return -1;
       regnum += 32 - 4;
+#else
+      if (p == q
+         || (*q  && ((*q != 'L' && *q != 'R') || *(q + 1)))
+         || regnum <= 4 || regnum >= 32)
+       return -1;
+      regnum = (regnum - 4) * 2 + 32;
+      if (*q == 'R')
+       regnum++;
+#endif
     }
   return regnum;
 }