Correctly check gcc version.
[platform/upstream/binutils.git] / gas / cgen.c
index 0e5c33c..e15e1b6 100644 (file)
@@ -1,5 +1,5 @@
 /* GAS interface for targets using CGEN: Cpu tools GENerator.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
 
 This file is part of GAS, the GNU Assembler.
 
@@ -19,10 +19,17 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
 
 #include <setjmp.h>
 #include "ansidecl.h"
+#include "libiberty.h"
 #include "bfd.h"
-#include "cgen-opc.h"
+#include "symcat.h"
+#include "cgen-desc.h"
 #include "as.h"
 #include "subsegs.h"
+#include "cgen.h"
+
+/* Opcode table descriptor, must be set by md_begin.  */
+
+CGEN_CPU_DESC gas_cgen_cpu_desc;
 
 /* Callback to insert a register into the symbol table.
    A target may choose to let GAS parse the registers.
@@ -30,13 +37,13 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
 
 void
 cgen_asm_record_register (name, number)
-     char *name;
+     char * name;
      int number;
 {
   /* Use symbol_create here instead of symbol_new so we don't try to
      output registers into the object file's symbol table.  */
   symbol_table_insert (symbol_create (name, reg_section,
-                                     number, &zero_address_frag));
+                                     number, & zero_address_frag));
 }
 
 /* We need to keep a list of fixups.  We can't simply generate them as
@@ -57,34 +64,91 @@ struct fixup
   expressionS exp;
 };
 
-#define MAX_FIXUPS 5
-
-static struct fixup fixups[MAX_FIXUPS];
+static struct fixup fixups [GAS_CGEN_MAX_FIXUPS];
 static int num_fixups;
 
 /* Prepare to parse an instruction.
    ??? May wish to make this static and delete calls in md_assemble.  */
 
 void
-cgen_asm_init_parse ()
+gas_cgen_init_parse ()
 {
   num_fixups = 0;
 }
 
 /* Queue a fixup.  */
 
-void
-cgen_queue_fixup (opindex, opinfo, expP)
-     int opindex;
-     expressionS *expP;
+static void
+queue_fixup (opindex, opinfo, expP)
+     int           opindex;
+     expressionS * expP;
 {
   /* We need to generate a fixup for this expression.  */
-  if (num_fixups >= MAX_FIXUPS)
-    as_fatal ("too many fixups");
-  fixups[num_fixups].exp = *expP;
+  if (num_fixups >= GAS_CGEN_MAX_FIXUPS)
+    as_fatal (_("too many fixups"));
+  fixups[num_fixups].exp     = * expP;
   fixups[num_fixups].opindex = opindex;
-  fixups[num_fixups].opinfo = opinfo;
-  ++num_fixups;
+  fixups[num_fixups].opinfo  = opinfo;
+  ++ num_fixups;
+}
+
+/* The following three functions allow a backup of the fixup chain to be made,
+   and to have this backup be swapped with the current chain.  This allows
+   certain ports, eg the m32r, to swap two instructions and swap their fixups
+   at the same time.  */
+/* ??? I think with cgen_asm_finish_insn (or something else) there is no
+   more need for this.  */
+
+static struct fixup saved_fixups [GAS_CGEN_MAX_FIXUPS];
+static int saved_num_fixups;
+
+void
+gas_cgen_save_fixups ()
+{
+  saved_num_fixups = num_fixups;
+  
+  memcpy (saved_fixups, fixups, sizeof (fixups[0]) * num_fixups);
+
+  num_fixups = 0;
+}
+
+void
+gas_cgen_restore_fixups ()
+{
+  num_fixups = saved_num_fixups;
+  
+  memcpy (fixups, saved_fixups, sizeof (fixups[0]) * num_fixups);
+
+  saved_num_fixups = 0;
+}
+
+void
+gas_cgen_swap_fixups ()
+{
+  int tmp;
+  struct fixup tmp_fixup;
+
+  if (num_fixups == 0)
+    {
+      gas_cgen_restore_fixups ();
+    }
+  else if (saved_num_fixups == 0)
+    {
+      gas_cgen_save_fixups ();
+    }
+  else
+    {
+      tmp = saved_num_fixups;
+      saved_num_fixups = num_fixups;
+      num_fixups = tmp;
+      
+      for (tmp = GAS_CGEN_MAX_FIXUPS; tmp--;)
+       {
+         tmp_fixup          = saved_fixups [tmp];
+         saved_fixups [tmp] = fixups [tmp];
+         fixups [tmp]       = tmp_fixup;
+       }
+    }
 }
 
 /* Default routine to record a fixup.
@@ -101,26 +165,28 @@ cgen_queue_fixup (opindex, opinfo, expP)
    operand type.  We pick a BFD reloc type in md_apply_fix.  */
 
 fixS *
-cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset)
-     fragS *frag;
-     int where;
-     const CGEN_INSN *insn;
-     int length;
-     const CGEN_OPERAND *operand;
-     int opinfo;
-     symbolS *symbol;
-     offsetT offset;
+gas_cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset)
+     fragS *              frag;
+     int                  where;
+     const CGEN_INSN *    insn;
+     int                  length;
+     const CGEN_OPERAND * operand;
+     int                  opinfo;
+     symbolS *            symbol;
+     offsetT              offset;
 {
-  fixS *fixP;
+  fixS * fixP;
 
   /* It may seem strange to use operand->attrs and not insn->attrs here,
      but it is the operand that has a pc relative relocation.  */
 
   fixP = fix_new (frag, where, length / 8, symbol, offset,
-                 CGEN_OPERAND_ATTR (operand, CGEN_OPERAND_PCREL_ADDR) != 0,
-                 (bfd_reloc_code_real_type) ((int) BFD_RELOC_UNUSED + CGEN_OPERAND_INDEX (operand)));
-  fixP->tc_fix_data.insn = (PTR) insn;
-  fixP->tc_fix_data.opinfo = opinfo;
+                 CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR),
+                 (bfd_reloc_code_real_type)
+                   ((int) BFD_RELOC_UNUSED
+                    + (int) operand->type));
+  fixP->fx_cgen.insn = insn;
+  fixP->fx_cgen.opinfo = opinfo;
 
   return fixP;
 }
@@ -139,25 +205,27 @@ cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset)
    operand type.  We pick a BFD reloc type in md_apply_fix.  */
 
 fixS *
-cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
-     fragS *frag;
-     int where;
-     const CGEN_INSN *insn;
-     int length;
-     const CGEN_OPERAND *operand;
-     int opinfo;
-     expressionS *exp;
+gas_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
+     fragS *              frag;
+     int                  where;
+     const CGEN_INSN *    insn;
+     int                  length;
+     const CGEN_OPERAND * operand;
+     int                  opinfo;
+     expressionS *        exp;
 {
-  fixS *fixP;
+  fixS * fixP;
 
   /* It may seem strange to use operand->attrs and not insn->attrs here,
      but it is the operand that has a pc relative relocation.  */
 
   fixP = fix_new_exp (frag, where, length / 8, exp,
-                     CGEN_OPERAND_ATTR (operand, CGEN_OPERAND_PCREL_ADDR) != 0,
-                     (bfd_reloc_code_real_type) ((int) BFD_RELOC_UNUSED + CGEN_OPERAND_INDEX (operand)));
-  fixP->tc_fix_data.insn = (PTR) insn;
-  fixP->tc_fix_data.opinfo = opinfo;
+                     CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR),
+                     (bfd_reloc_code_real_type)
+                       ((int) BFD_RELOC_UNUSED
+                        + (int) operand->type));
+  fixP->fx_cgen.insn = insn;
+  fixP->fx_cgen.opinfo = opinfo;
 
   return fixP;
 }
@@ -177,47 +245,48 @@ static jmp_buf expr_jmp_buf;
    The resulting value is stored in VALUEP.  */
 
 const char *
-cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP)
+gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP)
+     CGEN_CPU_DESC cd;
      enum cgen_parse_operand_type want;
-     const char **strP;
+     const char ** strP;
      int opindex;
      int opinfo;
-     enum cgen_parse_operand_result *resultP;
-     bfd_vma *valueP;
+     enum cgen_parse_operand_result * resultP;
+     bfd_vma * valueP;
 {
 #ifdef __STDC__
-  /* These is volatile to survive the setjmp.  */
+  /* These are volatile to survive the setjmp.  */
   char * volatile hold;
   enum cgen_parse_operand_result * volatile resultP_1;
 #else
-  static char *hold;
-  static enum cgen_parse_operand_result *resultP_1;
+  static char * hold;
+  static enum cgen_parse_operand_result * resultP_1;
 #endif
-  const char *errmsg = NULL;
+  const char * errmsg = NULL;
   expressionS exp;
 
   if (want == CGEN_PARSE_OPERAND_INIT)
     {
-      cgen_asm_init_parse ();
+      gas_cgen_init_parse ();
       return NULL;
     }
 
   resultP_1 = resultP;
   hold = input_line_pointer;
-  input_line_pointer = (char *) *strP;
+  input_line_pointer = (char *) * strP;
 
   /* We rely on md_operand to longjmp back to us.
-     This is done via cgen_md_operand.  */
+     This is done via gas_cgen_md_operand.  */
   if (setjmp (expr_jmp_buf) != 0)
     {
       input_line_pointer = (char *) hold;
-      *resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR;
+      * resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR;
       return "illegal operand";
     }
 
-  expression (&exp);
+  expression (& exp);
 
-  *strP = input_line_pointer;
+  * strP = input_line_pointer;
   input_line_pointer = hold;
 
   /* FIXME: Need to check `want'.  */
@@ -225,25 +294,25 @@ cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP)
   switch (exp.X_op)
     {
     case O_illegal :
-      errmsg = "illegal operand";
-      *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
+      errmsg = _("illegal operand");
+      * resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
       break;
     case O_absent :
-      errmsg = "missing operand";
-      *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
+      errmsg = _("missing operand");
+      * resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
       break;
     case O_constant :
-      *valueP = exp.X_add_number;
-      *resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER;
+      * valueP = exp.X_add_number;
+      * resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER;
       break;
     case O_register :
-      *valueP = exp.X_add_number;
-      *resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER;
+      * valueP = exp.X_add_number;
+      * resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER;
       break;
     default :
-      cgen_queue_fixup (opindex, opinfo, &exp);
-      *valueP = 0;
-      *resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED;
+      queue_fixup (opindex, opinfo, & exp);
+      * valueP = 0;
+      * resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED;
       break;
     }
 
@@ -256,24 +325,30 @@ cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP)
    ??? This could be done differently by adding code to `expression'.  */
 
 void
-cgen_md_operand (expressionP)
-     expressionS *expressionP;
+gas_cgen_md_operand (expressionP)
+     expressionS * expressionP;
 {
   longjmp (expr_jmp_buf, 1);
 }
 
 /* Finish assembling instruction INSN.
    BUF contains what we've built up so far.
-   LENGTH is the size of the insn in bits.  */
+   LENGTH is the size of the insn in bits.
+   RELAX_P is non-zero if relaxable insns should be emitted as such.
+   Otherwise they're emitted in non-relaxable forms.
+   The "result" is stored in RESULT if non-NULL.  */
 
 void
-cgen_asm_finish_insn (insn, buf, length)
-     const CGEN_INSN *insn;
-     cgen_insn_t *buf;
+gas_cgen_finish_insn (insn, buf, length, relax_p, result)
+     const CGEN_INSN * insn;
+     CGEN_INSN_BYTES_PTR buf;
      unsigned int length;
+     int relax_p;
+     finished_insnS * result;
 {
-  int i, relax_operand;
-  char *f;
+  int i;
+  int relax_operand;
+  char * f;
   unsigned int byte_len = length / 8;
 
   /* ??? Target foo issues various warnings here, so one might want to provide
@@ -288,21 +363,21 @@ cgen_asm_finish_insn (insn, buf, length)
      Relaxable instructions: We need to ensure we allocate enough
      space for the largest insn.  */
 
-  if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX) != 0)
+  if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAX))
     abort (); /* These currently shouldn't get here.  */
 
   /* Is there a relaxable insn with the relaxable operand needing a fixup?  */
 
   relax_operand = -1;
-  if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0)
+  if (relax_p && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXABLE))
     {
       /* Scan the fixups for the operand affected by relaxing
         (i.e. the branch address).  */
 
-      for (i = 0; i < num_fixups; ++i)
+      for (i = 0; i < num_fixups; ++ i)
        {
-         if (CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex],
-                                CGEN_OPERAND_RELAX) != 0)
+         if (CGEN_OPERAND_ATTR_VALUE (cgen_operand_lookup_by_num (gas_cgen_cpu_desc, fixups[i].opindex),
+                                      CGEN_OPERAND_RELAX))
            {
              relax_operand = i;
              break;
@@ -313,7 +388,7 @@ cgen_asm_finish_insn (insn, buf, length)
   if (relax_operand != -1)
     {
       int max_len;
-      fragS *old_frag;
+      fragS * old_frag;
 
 #ifdef TC_CGEN_MAX_RELAX
       max_len = TC_CGEN_MAX_RELAX (insn, byte_len);
@@ -323,10 +398,13 @@ cgen_asm_finish_insn (insn, buf, length)
       /* Ensure variable part and fixed part are in same fragment.  */
       /* FIXME: Having to do this seems like a hack.  */
       frag_grow (max_len);
+
       /* Allocate space for the fixed part.  */
       f = frag_more (byte_len);
+
       /* Create a relaxable fragment for this instruction.  */
       old_frag = frag_now;
+
       frag_var (rs_machine_dependent,
                max_len - byte_len /* max chars */,
                0 /* variable part already allocated */,
@@ -336,35 +414,26 @@ cgen_asm_finish_insn (insn, buf, length)
                fixups[relax_operand].exp.X_add_symbol,
                fixups[relax_operand].exp.X_add_number,
                f);
+
       /* Record the operand number with the fragment so md_convert_frag
-        can use cgen_md_record_fixup to record the appropriate reloc.  */
-      old_frag->fr_cgen.insn = insn;
+        can use gas_cgen_md_record_fixup to record the appropriate reloc.  */
+      old_frag->fr_cgen.insn    = insn;
       old_frag->fr_cgen.opindex = fixups[relax_operand].opindex;
-      old_frag->fr_cgen.opinfo = fixups[relax_operand].opinfo;
+      old_frag->fr_cgen.opinfo  = fixups[relax_operand].opinfo;
+      if (result)
+       result->frag = old_frag;
     }
   else
-    f = frag_more (byte_len);
+    {
+      f = frag_more (byte_len);
+      if (result)
+       result->frag = frag_now;
+    }
 
   /* If we're recording insns as numbers (rather than a string of bytes),
      target byte order handling is deferred until now.  */
-#if 0 /*def CGEN_INT_INSN*/
-  switch (length)
-    {
-    case 16:
-      if (cgen_big_endian_p)
-       bfd_putb16 ((bfd_vma) *buf, f);
-      else
-       bfd_putl16 ((bfd_vma) *buf, f);
-      break;
-    case 32:
-      if (cgen_big_endian_p)
-       bfd_putb32 ((bfd_vma) *buf, f);
-      else
-       bfd_putl32 ((bfd_vma) *buf, f);
-      break;
-    default:
-      abort ();
-    }
+#if CGEN_INT_INSN_P
+  cgen_put_insn_value (gas_cgen_cpu_desc, f, length, *buf);
 #else
   memcpy (f, buf, byte_len);
 #endif
@@ -372,23 +441,34 @@ cgen_asm_finish_insn (insn, buf, length)
   /* Create any fixups.  */
   for (i = 0; i < num_fixups; ++i)
     {
+      fixS *fixP;
+      const CGEN_OPERAND *operand =
+       cgen_operand_lookup_by_num (gas_cgen_cpu_desc, fixups[i].opindex);
+
       /* Don't create fixups for these.  That's done during relaxation.
         We don't need to test for CGEN_INSN_RELAX as they can't get here
         (see above).  */
-      if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0
-         && CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex],
-                               CGEN_OPERAND_RELAX) != 0)
+      if (relax_p
+         && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXABLE)
+         && CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_RELAX))
        continue;
 
 #ifndef md_cgen_record_fixup_exp
-#define md_cgen_record_fixup_exp cgen_record_fixup_exp
+#define md_cgen_record_fixup_exp gas_cgen_record_fixup_exp
 #endif
 
-      md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal,
-                               insn, length,
-                               & CGEN_SYM (operand_table) [fixups[i].opindex],
-                               fixups[i].opinfo,
-                               &fixups[i].exp);
+       fixP = md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal,
+                                        insn, length, operand,
+                                        fixups[i].opinfo,
+                                        & fixups[i].exp);
+       if (result)
+         result->fixups[i] = fixP;
+    }
+
+  if (result)
+    {
+      result->num_fixups = num_fixups;
+      result->addr = f;
     }
 }
 
@@ -405,14 +485,16 @@ cgen_asm_finish_insn (insn, buf, length)
    should handle them all.  */
 
 int
-cgen_md_apply_fix3 (fixP, valueP, seg)
-     fixS *fixP;
-     valueT *valueP;
-     segT seg;
+gas_cgen_md_apply_fix3 (fixP, valueP, seg)
+     fixS *   fixP;
+     valueT * valueP;
+     segT     seg;
 {
-  char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
+  char * where = fixP->fx_frag->fr_literal + fixP->fx_where;
   valueT value;
-
+  /* canonical name, since used a lot */
+  CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
+  
   /* FIXME FIXME FIXME: The value we are passed in *valuep includes
      the symbol values.  Since we are using BFD_ASSEMBLER, if we are
      doing this relocation the code in write.c is going to call
@@ -426,11 +508,11 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
 
   if (fixP->fx_addsy == (symbolS *) NULL)
     {
-      value = *valueP;
+      value = * valueP;
       fixP->fx_done = 1;
     }
   else if (fixP->fx_pcrel)
-    value = *valueP;
+    value = * valueP;
   else
     {
       value = fixP->fx_offset;
@@ -442,7 +524,7 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
            {
              /* We don't actually support subtracting a symbol.  */
              as_bad_where (fixP->fx_file, fixP->fx_line,
-                           "expression too complex");
+                           _("expression too complex"));
            }
        }
     }
@@ -450,11 +532,11 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
-      const CGEN_OPERAND *operand = & CGEN_SYM (operand_table) [opindex];
+      const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex);
       const char *errmsg;
       bfd_reloc_code_real_type reloc_type;
-      CGEN_FIELDS fields;
-      const CGEN_INSN *insn = (CGEN_INSN *) fixP->tc_fix_data.insn;
+      CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
+      const CGEN_INSN *insn = fixP->fx_cgen.insn;
 
       /* If the reloc has been fully resolved finish the operand here.  */
       /* FIXME: This duplicates the capabilities of code in BFD.  */
@@ -463,14 +545,27 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
             finish the job.  Testing for pcrel is a temporary hack.  */
          || fixP->fx_pcrel)
        {
-         /* This may seem like overkill, and using bfd_install_relocation or
-            some such may be preferable, but this is simple.  */
-         CGEN_FIELDS_BITSIZE (&fields) = CGEN_INSN_BITSIZE (insn);
-         CGEN_SYM (set_operand) (opindex, &value, &fields);
-         errmsg = CGEN_SYM (validate_operand) (opindex, &fields);
+         CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn));
+         CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value);
+
+#if CGEN_INT_INSN_P
+         {
+           CGEN_INSN_INT insn_value =
+             cgen_get_insn_value (cd, where, CGEN_INSN_BITSIZE (insn));
+
+           /* ??? 0 is passed for `pc' */
+           errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
+                                                  &insn_value, (bfd_vma) 0);
+           cgen_put_insn_value (cd, where, CGEN_INSN_BITSIZE (insn),
+                                insn_value);
+         }
+#else
+           /* ??? 0 is passed for `pc' */
+           errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields, where,
+                                                  (bfd_vma) 0);
+#endif
          if (errmsg)
-           as_warn_where (fixP->fx_file, fixP->fx_line, "%s\n", errmsg);
-         CGEN_SYM (insert_operand) (opindex, &fields, where);
+           as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg);
        }
 
       if (fixP->fx_done)
@@ -481,7 +576,7 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
         bfd_install_relocation.  Note that this doesn't work when
         partial_inplace == false.  */
 
-      reloc_type = CGEN_SYM (lookup_reloc) (insn, operand, fixP);
+      reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
       if (reloc_type != BFD_RELOC_NONE)
        {
          fixP->fx_r_type = reloc_type;
@@ -489,7 +584,7 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
       else
        {
          as_bad_where (fixP->fx_file, fixP->fx_line,
-                       "unresolved expression that must be resolved");
+                       _("unresolved expression that must be resolved"));
          fixP->fx_done = 1;
          return 1;
        }
@@ -511,7 +606,10 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
          break;
        /* FIXME: later add support for 64 bits.  */
        default:
-         abort ();
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("internal error: can't install fix for reloc type %d (`%s')"),
+                       fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
+         break;
        }
     }
   else
@@ -532,28 +630,35 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
    FIXME: To what extent can we get all relevant targets to use this?  */
 
 arelent *
-cgen_tc_gen_reloc (section, fixP)
-     asection *section;
-     fixS *fixP;
+gas_cgen_tc_gen_reloc (section, fixP)
+     asection * section;
+     fixS *     fixP;
 {
-  arelent *reloc;
+  arelent * reloc;
 
-  reloc = (arelent *) bfd_alloc (stdoutput, sizeof (arelent));
+  reloc = (arelent *) xmalloc (sizeof (arelent));
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
   if (reloc->howto == (reloc_howto_type *) NULL)
     {
       as_bad_where (fixP->fx_file, fixP->fx_line,
-                   "internal error: can't export reloc type %d (`%s')",
+                   _("internal error: can't export reloc type %d (`%s')"),
                    fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
       return NULL;
     }
 
   assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
 
-  reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym;
-  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
-  reloc->addend = fixP->fx_addnumber;
+  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
 
+  /* Use fx_offset for these cases */
+  if (   fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+      || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
+    reloc->addend  = fixP->fx_offset;
+  else
+    reloc->addend  = fixP->fx_addnumber;
+
+  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
   return reloc;
 }