gas reloc rewrite.
[binutils-gdb.git] / gas / config / tc-vax.c
index 8455fa94075f3872c9bcb6fd7ec411f75a4d5c00..a2bae67495799856684920bfb11f827d03e46ad4 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-vax.c - vax-specific -
-   Copyright (C) 1987, 91, 92, 93, 94, 95, 98, 99, 2000
+   Copyright 1987, 1991, 1992, 1993, 1994, 1995, 1998, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
 #include "vax-inst.h"
 #include "obstack.h"           /* For FRAG_APPEND_1_CHAR macro in "frags.h" */
+#include "subsegs.h"
+
+#ifdef OBJ_ELF
+#include "elf/vax.h"
+#endif
 
 /* These chars start a comment anywhere in a source file (except inside
    another comment */
@@ -58,10 +63,20 @@ LITTLENUM_TYPE big_operand_bits[VIT_MAX_OPERANDS][SIZE_OF_LARGE_NUMBER];
 FLONUM_TYPE float_operand[VIT_MAX_OPERANDS];
 /* Above is made to point into big_operand_bits by md_begin().  */
 
+#ifdef OBJ_ELF
+#define GLOBAL_OFFSET_TABLE_NAME       "_GLOBAL_OFFSET_TABLE_"
+#define PROCEDURE_LINKAGE_TABLE_NAME   "_PROCEDURE_LINKAGE_TABLE_"
+symbolS *GOT_symbol;           /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
+symbolS *PLT_symbol;           /* Pre-defined "_PROCEDURE_LINKAGE_TABLE_" */
+#endif
+
 int flag_hash_long_names;      /* -+ */
 int flag_one;                  /* -1 */
 int flag_show_after_trunc;     /* -H */
 int flag_no_hash_mixed_case;   /* -h NUM */
+#ifdef OBJ_ELF
+int flag_want_pic;             /* -k */
+#endif
 \f
 /*
  * For VAX, relative addresses of "just the right length" are easy.
@@ -113,8 +128,6 @@ int flag_no_hash_mixed_case;        /* -h NUM */
  bbcs          e3
  bbsc          e4
  bbcc          e5
- bbssi         e6
- bbcci         e7
  Always, you complement 0th bit to reverse condition.
  Always, 1-byte opcde, longword-address, byte-address, 1-byte-displacement
 
@@ -183,6 +196,8 @@ int flag_no_hash_mixed_case;        /* -h NUM */
 #define C(a,b) ENCODE_RELAX(a,b)
 /* This macro has no side-effects.  */
 #define ENCODE_RELAX(what,length) (((what) << 2) + (length))
+#define RELAX_STATE(s) ((s) >> 2)
+#define RELAX_LENGTH(s) ((s) & 3)
 
 const relax_typeS md_relax_table[] =
 {
@@ -190,25 +205,31 @@ const relax_typeS md_relax_table[] =
   {1, 1, 0, 0},                        /* unused           0,1 */
   {1, 1, 0, 0},                        /* unused           0,2 */
   {1, 1, 0, 0},                        /* unused           0,3 */
+
   {BF + 1, BB + 1, 2, C (1, 1)},/* B^"foo"         1,0 */
   {WF + 1, WB + 1, 3, C (1, 2)},/* W^"foo"         1,1 */
   {0, 0, 5, 0},                        /* L^"foo"          1,2 */
   {1, 1, 0, 0},                        /* unused           1,3 */
+
   {BF, BB, 1, C (2, 1)},       /* b<cond> B^"foo"  2,0 */
   {WF + 2, WB + 2, 4, C (2, 2)},/* br.+? brw X     2,1 */
   {0, 0, 7, 0},                        /* br.+? jmp X      2,2 */
   {1, 1, 0, 0},                        /* unused           2,3 */
+
   {BF, BB, 1, C (3, 1)},       /* brb B^foo        3,0 */
   {WF, WB, 2, C (3, 2)},       /* brw W^foo        3,1 */
   {0, 0, 5, 0},                        /* Jmp L^foo        3,2 */
   {1, 1, 0, 0},                        /* unused           3,3 */
+
   {1, 1, 0, 0},                        /* unused           4,0 */
   {WF, WB, 2, C (4, 2)},       /* acb_ ^Wfoo       4,1 */
   {0, 0, 10, 0},               /* acb_,br,jmp L^foo4,2 */
   {1, 1, 0, 0},                        /* unused           4,3 */
+
   {BF, BB, 1, C (5, 1)},       /* Xob___,,foo      5,0 */
   {WF + 4, WB + 4, 6, C (5, 2)},/* Xob.+2,brb.+3,brw5,1 */
   {0, 0, 9, 0},                        /* Xob.+2,brb.+6,jmp5,2 */
+  {1, 1, 0, 0},                        /* unused           5,3 */
 };
 
 #undef C
@@ -217,7 +238,7 @@ const relax_typeS md_relax_table[] =
 #undef WF
 #undef WB
 
-void float_cons ();
+void float_cons PARAMS ((int));
 
 const pseudo_typeS md_pseudo_table[] =
 {
@@ -225,7 +246,7 @@ const pseudo_typeS md_pseudo_table[] =
   {"ffloat", float_cons, 'f'},
   {"gfloat", float_cons, 'g'},
   {"hfloat", float_cons, 'h'},
-  {0},
+  {NULL, NULL, 0},
 };
 
 #define STATE_PC_RELATIVE              (1)
@@ -245,10 +266,13 @@ int flonum_gen2vax PARAMS ((char format_letter, FLONUM_TYPE * f,
                            LITTLENUM_TYPE * words));
 static const char *vip_begin PARAMS ((int, const char *, const char *,
                                      const char *));
+static void vip_op_1 PARAMS ((int, const char *));
 static void vip_op_defaults PARAMS ((const char *, const char *, const char *));
 static void vip_op PARAMS ((char *, struct vop *));
 static void vip PARAMS ((struct vit *, char *));
 
+static int vax_reg_parse PARAMS ((char, char, char, char));
+
 void
 md_begin ()
 {
@@ -283,12 +307,23 @@ md_number_to_chars (con, value, nbytes)
    that they reference.  */
 
 void                           /* Knows about order of bytes in address.  */
-md_apply_fix (fixP, value)
+md_apply_fix3 (fixP, valueP, seg)
      fixS *fixP;
-     long value;
+     valueT *valueP;
+     segT seg ATTRIBUTE_UNUSED;
 {
-  number_to_chars_littleendian (fixP->fx_where + fixP->fx_frag->fr_literal,
-                               (valueT) value, fixP->fx_size);
+  valueT value = * valueP;
+#ifdef BFD_ASSEMBLER
+  if (((fixP->fx_addsy == NULL && fixP->fx_subsy == NULL)
+       && fixP->fx_r_type != BFD_RELOC_32_PLT_PCREL
+       && fixP->fx_r_type != BFD_RELOC_32_GOT_PCREL)
+      || fixP->fx_r_type == NO_RELOC)
+#endif
+    number_to_chars_littleendian (fixP->fx_where + fixP->fx_frag->fr_literal,
+                                 value, fixP->fx_size);
+
+  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+    fixP->fx_done = 1;
 }
 
 long
@@ -313,6 +348,8 @@ md_assemble (instruction_string)
 {
   /* Non-zero if operand expression's segment is not known yet.  */
   int is_undefined;
+  /* Non-zero if operand expression's segment is absolute.  */
+  int is_absolute;
 
   int length_code;
   char *p;
@@ -363,7 +400,7 @@ md_assemble (instruction_string)
    */
   if ((goofed = (*v.vit_error)) != 0)
     {
-      as_warn (_("Ignoring statement due to \"%s\""), v.vit_error);
+      as_fatal (_("Ignoring statement due to \"%s\""), v.vit_error);
     }
   /*
    * We need to use expression() and friends, which require us to diddle
@@ -382,7 +419,7 @@ md_assemble (instruction_string)
     {                          /* for each operand */
       if (operandP->vop_error)
        {
-         as_warn (_("Ignoring statement because \"%s\""), operandP->vop_error);
+         as_fatal (_("Aborting because statement has \"%s\""), operandP->vop_error);
          goofed = 1;
        }
       else
@@ -429,7 +466,7 @@ md_assemble (instruction_string)
               * instruction operands.
               */
              need_pass_2 = 1;
-             as_warn (_("Can't relocate expression"));
+             as_fatal (_("Can't relocate expression"));
              break;
 
            case O_big:
@@ -607,7 +644,7 @@ md_assemble (instruction_string)
            }
          if (input_line_pointer != operandP->vop_expr_end + 1)
            {
-             as_warn ("Junk at end of expression \"%s\"", input_line_pointer);
+             as_fatal ("Junk at end of expression \"%s\"", input_line_pointer);
              goofed = 1;
            }
          operandP->vop_expr_end[1] = c_save;
@@ -650,7 +687,13 @@ md_assemble (instruction_string)
       this_add_number = expP->X_add_number;
       this_add_symbol = expP->X_add_symbol;
       to_seg = *segP;
+#ifdef BFD_ASSEMBLER
+      is_undefined = (to_seg == undefined_section);
+      is_absolute = (to_seg == absolute_section);
+#else
       is_undefined = (to_seg == SEG_UNKNOWN);
+      is_absolute = (to_seg == SEG_ABSOLUTE);
+#endif
       at = operandP->vop_mode & 1;
       length = (operandP->vop_short == 'b'
                ? 1 : (operandP->vop_short == 'w'
@@ -719,16 +762,20 @@ md_assemble (instruction_string)
              /*
               * --- SEG FLOAT MAY APPEAR HERE ----
               */
-             if (to_seg == SEG_ABSOLUTE)
+             if (is_absolute)
                {
                  if (nbytes)
                    {
                      know (!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
                      p = frag_more (nbytes);
                      /* Conventional relocation.  */
-                     fix_new (frag_now, p - frag_now->fr_literal,
-                              nbytes, &abs_symbol, this_add_number,
-                              1, NO_RELOC);
+                     fix_new (frag_now, p - frag_now->fr_literal, nbytes,
+#ifdef BFD_ASSEMBLER
+                              section_symbol (absolute_section),
+#else
+                              &abs_symbol,
+#endif
+                              this_add_number, 1, NO_RELOC);
                    }
                  else
                    {
@@ -804,15 +851,19 @@ md_assemble (instruction_string)
                }
              else
                {
-                 /* to_seg != now_seg && to_seg != SEG_UNKNOWN && to_Seg != SEG_ABSOLUTE */
+                 /* to_seg != now_seg && !is_undefinfed && !is_absolute */
                  if (nbytes > 0)
                    {
                      /* Pc-relative. Conventional relocation.  */
                      know (!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
                      p = frag_more (nbytes);
-                     fix_new (frag_now, p - frag_now->fr_literal,
-                              nbytes, &abs_symbol, this_add_number,
-                              1, NO_RELOC);
+                     fix_new (frag_now, p - frag_now->fr_literal, nbytes,
+#ifdef BFD_ASSEMBLER
+                              section_symbol (absolute_section),
+#else
+                              &abs_symbol,
+#endif
+                              this_add_number, 1, NO_RELOC);
                    }
                  else
                    {
@@ -903,7 +954,7 @@ md_assemble (instruction_string)
                || operandP->vop_access == 'w');
          if (operandP->vop_short == 's')
            {
-             if (to_seg == SEG_ABSOLUTE)
+             if (is_absolute)
                {
                  if (this_add_number >= 64)
                    {
@@ -942,8 +993,14 @@ md_assemble (instruction_string)
                      if (length == 0)
                        {
                          know (operandP->vop_short == ' ');
+                         length_code = STATE_BYTE;
+#ifdef OBJ_ELF
+                         if (S_IS_EXTERNAL (this_add_symbol)
+                             || S_IS_WEAK (this_add_symbol))
+                           length_code = STATE_UNDF;
+#endif
                          p = frag_var (rs_machine_dependent, 10, 2,
-                              ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE),
+                              ENCODE_RELAX (STATE_PC_RELATIVE, length_code),
                                        this_add_symbol, this_add_number,
                                        opcode_low_byteP);
                          know (operandP->vop_mode == 10 + at);
@@ -968,7 +1025,7 @@ md_assemble (instruction_string)
                    {           /* to_seg != now_seg */
                      if (this_add_symbol == NULL)
                        {
-                         know (to_seg == SEG_ABSOLUTE);
+                         know (is_absolute);
                          /* Do @#foo: simpler relocation than foo-.(pc) anyway.  */
                          p = frag_more (5);
                          p[0] = VAX_ABSOLUTE_MODE;     /* @#...  */
@@ -983,17 +1040,29 @@ md_assemble (instruction_string)
                          /* {@}{q^}other_seg */
                          know ((length == 0 && operandP->vop_short == ' ')
                             || (length > 0 && operandP->vop_short != ' '));
-                         if (is_undefined)
+                         if (is_undefined
+#ifdef OBJ_ELF
+                             || S_IS_WEAK(this_add_symbol)
+                             || S_IS_EXTERNAL(this_add_symbol)
+#endif
+                             )
                            {
+                             switch (length)
+                               {
+                               default: length_code = STATE_UNDF; break;
+                               case 1: length_code = STATE_BYTE; break;
+                               case 2: length_code = STATE_WORD; break;
+                               case 4: length_code = STATE_LONG; break;
+                               }
                              /*
                               * We have a SEG_UNKNOWN symbol. It might
                               * turn out to be in the same segment as
                               * the instruction, permitting relaxation.
                               */
                              p = frag_var (rs_machine_dependent, 5, 2,
-                              ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF),
+                              ENCODE_RELAX (STATE_PC_RELATIVE, length_code),
                                            this_add_symbol, this_add_number,
-                                           0);
+                                           opcode_low_byteP);
                              p[0] = at << 4;
                            }
                          else
@@ -1031,7 +1100,7 @@ md_assemble (instruction_string)
                             one case.  */
                        }
                      if (length == 0
-                         && to_seg == SEG_ABSOLUTE && (expP->X_op != O_big)
+                         && is_absolute && (expP->X_op != O_big)
                          && operandP->vop_mode == 8    /* No '@'.  */
                          && this_add_number < 64)
                        {
@@ -1047,8 +1116,15 @@ md_assemble (instruction_string)
                          know (nbytes);
                          p = frag_more (nbytes + 1);
                          know (operandP->vop_reg == 0xF);
+#ifdef OBJ_ELF
+                         if (flag_want_pic && operandP->vop_mode == 8
+                               && this_add_symbol != NULL)
+                           {
+                             as_warn (_("Symbol used as immediate operand in PIC mode."));
+                           }
+#endif
                          p[0] = (operandP->vop_mode << 4) | 0xF;
-                         if ((to_seg == SEG_ABSOLUTE) && (expP->X_op != O_big))
+                         if ((is_absolute) && (expP->X_op != O_big))
                            {
                              /*
                               * If nbytes > 4, then we are scrod. We
@@ -1103,7 +1179,7 @@ md_assemble (instruction_string)
                            || (length > 0 && operandP->vop_short != ' '));
                      if (length == 0)
                        {
-                         if (to_seg == SEG_ABSOLUTE)
+                         if (is_absolute)
                            {
                              long test;
 
@@ -1125,7 +1201,7 @@ md_assemble (instruction_string)
                      know (operandP->vop_reg >= 0);
                      p[0] = operandP->vop_reg
                        | ((at | "?\12\14?\16"[length]) << 4);
-                     if (to_seg == SEG_ABSOLUTE)
+                     if (is_absolute)
                        {
                          md_number_to_chars (p + 1, this_add_number, length);
                        }
@@ -1142,127 +1218,156 @@ md_assemble (instruction_string)
     }                          /* for(operandP) */
 }                              /* vax_assemble() */
 \f
-/*
- *                     md_estimate_size_before_relax()
- *
- * Called just before relax().
- * Any symbol that is now undefined will not become defined.
- * Return the correct fr_subtype in the frag.
- * Return the initial "guess for fr_var" to caller.
- * The guess for fr_var is ACTUALLY the growth beyond fr_fix.
- * Whatever we do to grow fr_fix or fr_var contributes to our returned value.
- * Although it may not be explicit in the frag, pretend fr_var starts with a
- * 0 value.
- */
+/* md_estimate_size_before_relax(), called just before relax().
+   Any symbol that is now undefined will not become defined.
+   Return the correct fr_subtype in the frag and the growth beyond
+   fr_fix.  */
 int
 md_estimate_size_before_relax (fragP, segment)
      fragS *fragP;
      segT segment;
 {
-  char *p;
-  int old_fr_fix;
-
-  old_fr_fix = fragP->fr_fix;
-  switch (fragP->fr_subtype)
+  if (RELAX_LENGTH (fragP->fr_subtype) == STATE_UNDF)
     {
-    case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF):
-      if (S_GET_SEGMENT (fragP->fr_symbol) == segment)
-       {                       /* A relaxable case.  */
-         fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE);
-       }
-      else
+      if (S_GET_SEGMENT (fragP->fr_symbol) != segment
+#ifdef OBJ_ELF
+         || S_IS_WEAK (fragP->fr_symbol)
+         || S_IS_EXTERNAL (fragP->fr_symbol)
+#endif
+         )
        {
-         p = fragP->fr_literal + old_fr_fix;
-         p[0] |= VAX_PC_RELATIVE_MODE; /* Preserve @ bit.  */
-         fragP->fr_fix += 1 + 4;
-         fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol,
-                  fragP->fr_offset, 1, NO_RELOC);
-         frag_wane (fragP);
-       }
-      break;
+         /* Non-relaxable cases.  */
+         int reloc_type = NO_RELOC;
+         char *p;
+         int old_fr_fix;
 
-    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF):
-      if (S_GET_SEGMENT (fragP->fr_symbol) == segment)
-       {
-         fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
-       }
-      else
-       {
+         old_fr_fix = fragP->fr_fix;
          p = fragP->fr_literal + old_fr_fix;
-         *fragP->fr_opcode ^= 1;       /* Reverse sense of branch.  */
-         p[0] = 6;
-         p[1] = VAX_JMP;
-         p[2] = VAX_PC_RELATIVE_MODE;  /* ...(PC) */
-         fragP->fr_fix += 1 + 1 + 1 + 4;
-         fix_new (fragP, old_fr_fix + 3, 4, fragP->fr_symbol,
-                  fragP->fr_offset, 1, NO_RELOC);
-         frag_wane (fragP);
-       }
-      break;
+#ifdef OBJ_ELF
+         /*
+          * If this is to undefined symbol, then if it's an indirect
+          * reference indicate that is can mutated into a GLOB_DAT
+          * by the loader.  We restrict ourselves to no offset due to
+          * a limitation in the NetBSD linker.
+          */
+         if (GOT_symbol == NULL)
+           GOT_symbol = symbol_find (GLOBAL_OFFSET_TABLE_NAME);
+         if (PLT_symbol == NULL)
+           PLT_symbol = symbol_find (PROCEDURE_LINKAGE_TABLE_NAME);
+         if ((GOT_symbol == NULL || fragP->fr_symbol != GOT_symbol)
+             && (PLT_symbol == NULL || fragP->fr_symbol != PLT_symbol)
+             && fragP->fr_symbol != NULL
+             && (!S_IS_DEFINED (fragP->fr_symbol)
+                 || S_IS_WEAK (fragP->fr_symbol)
+                 || S_IS_EXTERNAL (fragP->fr_symbol)))
+           {
+             if (p[0] & 0x10)
+               {
+                 if (flag_want_pic)
+                   as_fatal ("PIC reference to %s is indirect.\n",
+                             S_GET_NAME (fragP->fr_symbol));
+               }
+             else
+               {
+       
+                 if (((unsigned char *) fragP->fr_opcode)[0] == VAX_CALLS
+                     || ((unsigned char *) fragP->fr_opcode)[0] == VAX_CALLG
+                     || ((unsigned char *) fragP->fr_opcode)[0] == VAX_JSB
+                     || ((unsigned char *) fragP->fr_opcode)[0] == VAX_JMP
+                     || S_IS_FUNCTION (fragP->fr_symbol))
+                   reloc_type = BFD_RELOC_32_PLT_PCREL;
+                 else
+                   reloc_type = BFD_RELOC_32_GOT_PCREL;
+               }
+           }
+#endif
+         switch (RELAX_STATE (fragP->fr_subtype))
+           {
+           case STATE_PC_RELATIVE:
+             p[0] |= VAX_PC_RELATIVE_MODE;     /* Preserve @ bit.  */
+             fragP->fr_fix += 1 + 4;
+             fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol,
+                      fragP->fr_offset, 1, reloc_type);
+             break;
 
-    case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_UNDF):
-      if (S_GET_SEGMENT (fragP->fr_symbol) == segment)
-       {
-         fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD);
-       }
-      else
-       {
-         p = fragP->fr_literal + old_fr_fix;
-         p[0] = 2;
-         p[1] = 0;
-         p[2] = VAX_BRB;
-         p[3] = 6;
-         p[4] = VAX_JMP;
-         p[5] = VAX_PC_RELATIVE_MODE;  /* ...(pc) */
-         fragP->fr_fix += 2 + 2 + 1 + 1 + 4;
-         fix_new (fragP, old_fr_fix + 6, 4, fragP->fr_symbol,
-                  fragP->fr_offset, 1, NO_RELOC);
-         frag_wane (fragP);
-       }
-      break;
+           case STATE_CONDITIONAL_BRANCH:
+             *fragP->fr_opcode ^= 1;           /* Reverse sense of branch.  */
+             p[0] = 6;
+             p[1] = VAX_JMP;
+             p[2] = VAX_PC_RELATIVE_MODE;      /* ...(PC) */
+             fragP->fr_fix += 1 + 1 + 1 + 4;
+             fix_new (fragP, old_fr_fix + 3, 4, fragP->fr_symbol,
+                      fragP->fr_offset, 1, NO_RELOC);
+             break;
 
-    case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_UNDF):
-      if (S_GET_SEGMENT (fragP->fr_symbol) == segment)
-       {
-         fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE);
-       }
-      else
-       {
-         p = fragP->fr_literal + old_fr_fix;
-         p[0] = 2;
-         p[1] = VAX_BRB;
-         p[2] = 6;
-         p[3] = VAX_JMP;
-         p[4] = VAX_PC_RELATIVE_MODE;  /* ...(pc) */
-         fragP->fr_fix += 1 + 2 + 1 + 1 + 4;
-         fix_new (fragP, old_fr_fix + 5, 4, fragP->fr_symbol,
-                  fragP->fr_offset, 1, NO_RELOC);
+           case STATE_COMPLEX_BRANCH:
+             p[0] = 2;
+             p[1] = 0;
+             p[2] = VAX_BRB;
+             p[3] = 6;
+             p[4] = VAX_JMP;
+             p[5] = VAX_PC_RELATIVE_MODE;      /* ...(pc) */
+             fragP->fr_fix += 2 + 2 + 1 + 1 + 4;
+             fix_new (fragP, old_fr_fix + 6, 4, fragP->fr_symbol,
+                      fragP->fr_offset, 1, NO_RELOC);
+             break;
+
+           case STATE_COMPLEX_HOP:
+             p[0] = 2;
+             p[1] = VAX_BRB;
+             p[2] = 6;
+             p[3] = VAX_JMP;
+             p[4] = VAX_PC_RELATIVE_MODE;      /* ...(pc) */
+             fragP->fr_fix += 1 + 2 + 1 + 1 + 4;
+             fix_new (fragP, old_fr_fix + 5, 4, fragP->fr_symbol,
+                      fragP->fr_offset, 1, NO_RELOC);
+             break;
+
+           case STATE_ALWAYS_BRANCH:
+             *fragP->fr_opcode += VAX_WIDEN_LONG;
+             p[0] = VAX_PC_RELATIVE_MODE;      /* ...(PC) */
+             fragP->fr_fix += 1 + 4;
+             fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol,
+                      fragP->fr_offset, 1, NO_RELOC);
+             break;
+
+           default:
+             abort ();
+           }
          frag_wane (fragP);
+
+         /* Return the growth in the fixed part of the frag.  */
+         return fragP->fr_fix - old_fr_fix;
        }
-      break;
 
-    case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_UNDF):
-      if (S_GET_SEGMENT (fragP->fr_symbol) == segment)
+      /* Relaxable cases.  Set up the initial guess for the variable
+        part of the frag.  */
+      switch (RELAX_STATE (fragP->fr_subtype))
        {
+       case STATE_PC_RELATIVE:
+         fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE);
+         break;
+       case STATE_CONDITIONAL_BRANCH:
+         fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
+         break;
+       case STATE_COMPLEX_BRANCH:
+         fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD);
+         break;
+       case STATE_COMPLEX_HOP:
+         fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE);
+         break;
+       case STATE_ALWAYS_BRANCH:
          fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE);
+         break;
        }
-      else
-       {
-         p = fragP->fr_literal + old_fr_fix;
-         *fragP->fr_opcode += VAX_WIDEN_LONG;
-         p[0] = VAX_PC_RELATIVE_MODE;  /* ...(PC) */
-         fragP->fr_fix += 1 + 4;
-         fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol,
-                  fragP->fr_offset, 1, NO_RELOC);
-         frag_wane (fragP);
-       }
-      break;
-
-    default:
-      break;
     }
-  return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
-}                              /* md_estimate_size_before_relax() */
+
+  if (fragP->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
+    abort ();
+
+  /* Return the size of the variable part of the frag.  */
+  return md_relax_table[fragP->fr_subtype].rlx_length;
+}
 \f
 /*
  *                     md_convert_frag();
@@ -1275,69 +1380,73 @@ md_estimate_size_before_relax (fragP, segment)
  * Out:        Any fixSs and constants are set up.
  *     Caller will turn frag into a ".space 0".
  */
+#ifdef BFD_ASSEMBLER
 void
 md_convert_frag (headers, seg, fragP)
-     object_headers *headers;
-     segT seg;
+     bfd *headers ATTRIBUTE_UNUSED;
+     segT seg ATTRIBUTE_UNUSED;
      fragS *fragP;
+#else
+void
+md_convert_frag (headers, seg, fragP)
+     object_headers *headers ATTRIBUTE_UNUSED;
+     segT seg ATTRIBUTE_UNUSED;
+     fragS *fragP;
+#endif
 {
   char *addressP;              /* -> _var to change.  */
   char *opcodeP;               /* -> opcode char(s) to change.  */
-  short int length_code;       /* 2=long 1=word 0=byte */
   short int extension = 0;     /* Size of relaxed address.  */
   /* Added to fr_fix: incl. ALL var chars.  */
   symbolS *symbolP;
   long where;
-  long address_of_var;
-  /* Where, in file space, is _var of *fragP? */
-  long target_address = 0;
-  /* Where, in file space, does addr point? */
 
   know (fragP->fr_type == rs_machine_dependent);
-  length_code = fragP->fr_subtype & 3; /* depends on ENCODE_RELAX() */
-  know (length_code >= 0 && length_code < 3);
   where = fragP->fr_fix;
   addressP = fragP->fr_literal + where;
   opcodeP = fragP->fr_opcode;
   symbolP = fragP->fr_symbol;
   know (symbolP);
-  target_address = S_GET_VALUE (symbolP) + fragP->fr_offset;
-  address_of_var = fragP->fr_address + where;
 
   switch (fragP->fr_subtype)
     {
 
     case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE):
       know (*addressP == 0 || *addressP == 0x10);      /* '@' bit.  */
-      addressP[0] |= 0xAF;     /* Byte displacement.  */
-      addressP[1] = target_address - (address_of_var + 2);
+      addressP[0] |= 0xAF;     /* Byte displacement. */
+      fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 2;
       break;
 
     case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD):
       know (*addressP == 0 || *addressP == 0x10);      /* '@' bit.  */
-      addressP[0] |= 0xCF;     /* Word displacement.  */
-      md_number_to_chars (addressP + 1, target_address - (address_of_var + 3), 2);
+      addressP[0] |= 0xCF;     /* Word displacement. */
+      fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 3;
       break;
 
     case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_LONG):
       know (*addressP == 0 || *addressP == 0x10);      /* '@' bit.  */
-      addressP[0] |= 0xEF;     /* Long word displacement.  */
-      md_number_to_chars (addressP + 1, target_address - (address_of_var + 5), 4);
+      addressP[0] |= 0xEF;     /* Long word displacement. */
+      fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 5;
       break;
 
     case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
-      addressP[0] = target_address - (address_of_var + 1);
+      fix_new (fragP, fragP->fr_fix, 1, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 1;
       break;
 
     case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
       opcodeP[0] ^= 1;         /* Reverse sense of test.  */
       addressP[0] = 3;
-      addressP[1] = VAX_BRB + VAX_WIDEN_WORD;
-      md_number_to_chars (addressP + 2, target_address - (address_of_var + 4), 2);
+      addressP[1] = VAX_BRW;
+      fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 4;
       break;
 
@@ -1346,30 +1455,35 @@ md_convert_frag (headers, seg, fragP)
       addressP[0] = 6;
       addressP[1] = VAX_JMP;
       addressP[2] = VAX_PC_RELATIVE_MODE;
-      md_number_to_chars (addressP + 3, target_address - (address_of_var + 7), 4);
+      fix_new (fragP, fragP->fr_fix + 3, 4, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 7;
       break;
 
     case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE):
-      addressP[0] = target_address - (address_of_var + 1);
+      fix_new (fragP, fragP->fr_fix, 1, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 1;
       break;
 
     case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_WORD):
       opcodeP[0] += VAX_WIDEN_WORD;    /* brb -> brw, bsbb -> bsbw */
-      md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
+      fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
+              1, NO_RELOC);
       extension = 2;
       break;
 
     case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_LONG):
       opcodeP[0] += VAX_WIDEN_LONG;    /* brb -> jmp, bsbb -> jsb */
       addressP[0] = VAX_PC_RELATIVE_MODE;
-      md_number_to_chars (addressP + 1, target_address - (address_of_var + 5), 4);
+      fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 5;
       break;
 
     case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD):
-      md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
+      fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 2;
       break;
 
@@ -1380,12 +1494,14 @@ md_convert_frag (headers, seg, fragP)
       addressP[3] = 6;
       addressP[4] = VAX_JMP;
       addressP[5] = VAX_PC_RELATIVE_MODE;
-      md_number_to_chars (addressP + 6, target_address - (address_of_var + 10), 4);
+      fix_new (fragP, fragP->fr_fix + 6, 4, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 10;
       break;
 
     case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE):
-      addressP[0] = target_address - (address_of_var + 1);
+      fix_new (fragP, fragP->fr_fix, 1, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 1;
       break;
 
@@ -1394,7 +1510,8 @@ md_convert_frag (headers, seg, fragP)
       addressP[1] = VAX_BRB;
       addressP[2] = 3;
       addressP[3] = VAX_BRW;
-      md_number_to_chars (addressP + 4, target_address - (address_of_var + 6), 2);
+      fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 6;
       break;
 
@@ -1404,7 +1521,8 @@ md_convert_frag (headers, seg, fragP)
       addressP[2] = 6;
       addressP[3] = VAX_JMP;
       addressP[4] = VAX_PC_RELATIVE_MODE;
-      md_number_to_chars (addressP + 5, target_address - (address_of_var + 9), 4);
+      fix_new (fragP, fragP->fr_fix + 5, 4, fragP->fr_symbol,
+              fragP->fr_offset, 1, NO_RELOC);
       extension = 9;
       break;
 
@@ -1439,6 +1557,8 @@ md_ri_to_chars (the_bytes, ri)
 
 #endif /* comment */
 
+#ifdef OBJ_AOUT
+#ifndef BFD_ASSEMBLER
 void
 tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
      char *where;
@@ -1470,6 +1590,8 @@ tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
              | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06)
              | (((fixP->fx_pcrel << 0) & 0x01) & 0x0f));
 }
+#endif /* !BFD_ASSEMBLER */
+#endif /* OBJ_AOUT */
 
 /*
  *       BUGS, GRIPES,  APOLOGIA, etc.
@@ -1663,8 +1785,6 @@ static const struct vot
   {"jbcs",     {"rlvbb?", 0x800000e3}},
   {"jbsc",     {"rlvbb?", 0x800000e4}},
   {"jbcc",     {"rlvbb?", 0x800000e5}},
-  {"jbssi",    {"rlvbb?", 0x800000e6}},
-  {"jbcci",    {"rlvbb?", 0x800000e7}},
   {"jlbs",     {"rlb?", 0x800000e8}},
   {"jlbc",     {"rlb?", 0x800000e9}},
 
@@ -1979,28 +2099,48 @@ main ()
  *
  */
 
-#include <ctype.h>
+#include "safe-ctype.h"
 #define AP (12)
 #define FP (13)
 #define SP (14)
 #define PC (15)
 \f
 int                            /* return -1 or 0:15 */
-vax_reg_parse (c1, c2, c3)     /* 3 chars of register name */
-     char c1, c2, c3;          /* c3 == 0 if 2-character reg name */
+vax_reg_parse (c1, c2, c3, c4) /* 3 chars of register name */
+     char c1, c2, c3, c4;      /* c3 == 0 if 2-character reg name */
 {
   int retval;          /* return -1:15 */
 
   retval = -1;
 
-  if (isupper (c1))
-    c1 = tolower (c1);
-  if (isupper (c2))
-    c2 = tolower (c2);
-  if (isdigit (c2) && c1 == 'r')
+#ifdef OBJ_ELF
+  if (c1 != '%')       /* register prefixes are mandatory for ELF */
+    return retval;
+  c1 = c2;
+  c2 = c3;
+  c3 = c4;
+#endif
+#ifdef OBJ_VMS
+  if (c4 != 0)         /* register prefixes are not allowed under VMS */
+    return retval;
+#endif
+#ifdef OBJ_AOUT
+  if (c1 == '%')       /* register prefixes are optional under a.out */
+    {
+      c1 = c2;
+      c2 = c3;
+      c3 = c4;
+    }
+  else if (c3 && c4)   /* can't be 4 characters long.  */
+    return retval;
+#endif
+
+  c1 = TOLOWER (c1);
+  c2 = TOLOWER (c2);
+  if (ISDIGIT (c2) && c1 == 'r')
     {
       retval = c2 - '0';
-      if (isdigit (c3))
+      if (ISDIGIT (c3))
        {
          retval = retval * 10 + c3 - '0';
          retval = (retval > 15) ? -1 : retval;
@@ -2346,8 +2486,7 @@ vip_op (optext, vopP)
     char c;
 
     c = *p;
-    if (isupper (c))
-      c = tolower (c);
+    c = TOLOWER (c);
     if (DISPLENP (p[1]) && strchr ("bilws", len = c))
       p += 2;                  /* skip (letter) '^' */
     else                       /* no (letter) '^' seen */
@@ -2399,9 +2538,11 @@ vip_op (optext, vopP)
           * name error. So again we don't need to check for early '\0'.
           */
          if (q[3] == ']')
-           ndx = vax_reg_parse (q[1], q[2], 0);
+           ndx = vax_reg_parse (q[1], q[2], 0, 0);
          else if (q[4] == ']')
-           ndx = vax_reg_parse (q[1], q[2], q[3]);
+           ndx = vax_reg_parse (q[1], q[2], q[3], 0);
+         else if (q[5] == ']')
+           ndx = vax_reg_parse (q[1], q[2], q[3], q[4]);
          else
            ndx = -1;
          /*
@@ -2454,9 +2595,11 @@ vip_op (optext, vopP)
               * name error. So again we don't need to check for early '\0'.
               */
              if (q[3] == ')')
-               reg = vax_reg_parse (q[1], q[2], 0);
+               reg = vax_reg_parse (q[1], q[2], 0, 0);
              else if (q[4] == ')')
-               reg = vax_reg_parse (q[1], q[2], q[3]);
+               reg = vax_reg_parse (q[1], q[2], q[3], 0);
+             else if (q[5] == ')')
+               reg = vax_reg_parse (q[1], q[2], q[3], q[4]);
              else
                reg = -1;
              /*
@@ -2526,8 +2669,11 @@ vip_op (optext, vopP)
                q--;
              /* reverse over whitespace, but don't */
              /* run back over *p */
-             if (q > p && q < p + 3)   /* room for Rn or Rnn exactly? */
-               reg = vax_reg_parse (p[0], p[1], q < p + 2 ? 0 : p[2]);
+             /* room for Rn or Rnn (include prefix) exactly? */
+             if (q > p && q < p + 4)
+               reg = vax_reg_parse (p[0], p[1],
+                 q < p + 2 ? 0 : p[2],
+                 q < p + 3 ? 0 : p[3]);
              else
                reg = -1;       /* always comes here if no register at all */
              /*
@@ -3076,9 +3222,10 @@ const int md_reloc_size = 8;     /* Size of relocation record */
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
+     addressT from_addr;
+     addressT to_addr ATTRIBUTE_UNUSED;
+     fragS *frag ATTRIBUTE_UNUSED;
+     symbolS *to_symbol ATTRIBUTE_UNUSED;
 {
   valueT offset;
 
@@ -3094,7 +3241,8 @@ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
 void
 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     addressT from_addr, to_addr;
+     addressT from_addr ATTRIBUTE_UNUSED;
+     addressT to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
@@ -3108,14 +3256,16 @@ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
 }
 \f
 #ifdef OBJ_VMS
-CONST char *md_shortopts = "d:STt:V+1h:Hv::";
+const char *md_shortopts = "d:STt:V+1h:Hv::";
+#elif defined(OBJ_ELC)
+const char *md_shortopts = "d:STt:VkK";
 #else
-CONST char *md_shortopts = "d:STt:V";
+const char *md_shortopts = "d:STt:V";
 #endif
 struct option md_longopts[] = {
   {NULL, no_argument, NULL, 0}
 };
-size_t md_longopts_size = sizeof(md_longopts);
+size_t md_longopts_size = sizeof (md_longopts);
 
 int
 md_parse_option (c, arg)
@@ -3175,6 +3325,13 @@ md_parse_option (c, arg)
       break;
 #endif
 
+#ifdef OBJ_ELF
+    case 'K':
+    case 'k':
+      flag_want_pic = 1;
+      break;                   /* -pic, Position Independent Code */
+#endif
+
     default:
       return 0;
     }
@@ -3186,7 +3343,7 @@ void
 md_show_usage (stream)
      FILE *stream;
 {
-  fprintf(stream, _("\
+  fprintf (stream, _("\
 VAX options:\n\
 -d LENGTH              ignored\n\
 -J                     ignored\n\
@@ -3208,10 +3365,9 @@ VMS options:\n\
 \f
 /* We have no need to default values of symbols.  */
 
-/* ARGSUSED */
 symbolS *
 md_undefined_symbol (name)
-     char *name;
+     char *name ATTRIBUTE_UNUSED;
 {
   return 0;
 }
@@ -3219,7 +3375,7 @@ md_undefined_symbol (name)
 /* Round up a section size to the appropriate boundary.  */
 valueT
 md_section_align (segment, size)
-     segT segment;
+     segT segment ATTRIBUTE_UNUSED;
      valueT size;
 {
   return size;                 /* Byte alignment is fine */
@@ -3227,7 +3383,7 @@ md_section_align (segment, size)
 
 /* Exactly what point is a PC-relative offset relative TO?
    On the vax, they're relative to the address of the offset, plus
-   its size. (??? Is this right?  FIXME-SOON) */
+   its size. */
 long
 md_pcrel_from (fixP)
      fixS *fixP;
@@ -3235,4 +3391,96 @@ md_pcrel_from (fixP)
   return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
+#ifdef OBJ_AOUT
+#ifndef BFD_ASSEMBLER
+void
+tc_headers_hook(headers)
+     object_headers *headers;
+{
+#ifdef TE_NetBSD
+  N_SET_INFO(headers->header, OMAGIC, M_VAX4K_NETBSD, 0);
+  headers->header.a_info = htonl(headers->header.a_info);
+#endif
+}
+#endif /* !BFD_ASSEMBLER */
+#endif /* OBJ_AOUT */
+
+#ifdef BFD_ASSEMBLER
+arelent *
+tc_gen_reloc (section, fixp)
+     asection *section ATTRIBUTE_UNUSED;
+     fixS *fixp;
+{
+  arelent *reloc;
+  bfd_reloc_code_real_type code;
+
+  if (fixp->fx_tcbit)
+    abort();
+
+  if (fixp->fx_r_type != BFD_RELOC_NONE)
+    {
+      code = fixp->fx_r_type;
+
+      if (fixp->fx_pcrel)
+       {
+         switch (code)
+           {
+           case BFD_RELOC_8_PCREL:
+           case BFD_RELOC_16_PCREL:
+           case BFD_RELOC_32_PCREL:
+#ifdef OBJ_ELF
+           case BFD_RELOC_8_GOT_PCREL:
+           case BFD_RELOC_16_GOT_PCREL:
+           case BFD_RELOC_32_GOT_PCREL:
+           case BFD_RELOC_8_PLT_PCREL:
+           case BFD_RELOC_16_PLT_PCREL:
+           case BFD_RELOC_32_PLT_PCREL:
+#endif
+             break;
+           default:
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           _("Cannot make %s relocation PC relative"),
+                           bfd_get_reloc_code_name (code));
+           }
+       }
+    }
+  else
+    {
+#define F(SZ,PCREL)            (((SZ) << 1) + (PCREL))
+      switch (F (fixp->fx_size, fixp->fx_pcrel))
+       {
+#define MAP(SZ,PCREL,TYPE)     case F(SZ,PCREL): code = (TYPE); break
+         MAP (1, 0, BFD_RELOC_8);
+         MAP (2, 0, BFD_RELOC_16);
+         MAP (4, 0, BFD_RELOC_32);
+         MAP (1, 1, BFD_RELOC_8_PCREL);
+         MAP (2, 1, BFD_RELOC_16_PCREL);
+         MAP (4, 1, BFD_RELOC_32_PCREL);
+       default:
+         abort ();
+       }
+    }
+#undef F
+#undef MAP
+
+  reloc = (arelent *) xmalloc (sizeof (arelent));
+  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+#ifndef OBJ_ELF
+  if (fixp->fx_pcrel)
+    reloc->addend = fixp->fx_addnumber;
+  else
+    reloc->addend = 0;
+#else
+  reloc->addend = fixp->fx_offset;
+#endif
+
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+  assert (reloc->howto != 0);
+
+  return reloc;
+}
+#endif /* BFD_ASSEMBLER */
+
 /* end of tc-vax.c */