checkpoint
authorDoug Evans <dje@google.com>
Wed, 21 Jan 1998 00:30:46 +0000 (00:30 +0000)
committerDoug Evans <dje@google.com>
Wed, 21 Jan 1998 00:30:46 +0000 (00:30 +0000)
gas/config/tc-txvu.c
gas/config/tc-txvu.h

index 183a83313902177b5ee4500b715d6e6027cd2fc8..ac7ca12edec329009f83e550543a966bd7c772f2 100644 (file)
 #include "opcode/txvu.h"
 #include "elf/txvu.h"
 
+static TXVU_INSN txvu_insert_operand
+     PARAMS ((TXVU_INSN, const struct txvu_operand *, int, offsetT,
+             char *, unsigned int));
+
 const char comment_chars[] = ";";
 const char line_comment_chars[] = "#";
 const char line_separator_chars[] = "!";
@@ -103,12 +107,17 @@ struct txvu_fixup
 
 #define MAX_FIXUPS 5
 
-static char * assemble_insn PARAMS ((char *, int));
+static char * assemble_insn PARAMS ((char *, int, char *));
 
 void
 md_assemble (str)
      char *str;
 {
+  /* The lower instruction has the lower address.
+     Handle this by grabbing 8 bytes now, and then filling each word
+     as appropriate.  */
+  char *f = frag_more (8);
+
 #ifdef VERTICAL_BAR_SEPARATOR
   char *p = strchr (str, '|');
 
@@ -119,27 +128,29 @@ md_assemble (str)
     }
 
   *p = 0;
-  assemble_insn (str, 0);
+  assemble_insn (str, 0, f + 4);
   *p = '|';
-  assemble_insn (p + 1, 1);
+  assemble_insn (p + 1, 1, f);
 #else
-  str = assemble_insn (str, 0);
+  str = assemble_insn (str, 0, f + 4);
   /* Don't assemble next one if we couldn't assemble the first.  */
   if (str)
-    assemble_insn (str, 1);
+    assemble_insn (str, 1, f);
 #endif
 }
 
 /* Assemble one instruction.
    LOWER_P is non-zero if assembling in the lower insn slot.
-   The result is a pointer to beyond the end of the scanned insn.
+   The result is a pointer to beyond the end of the scanned insn
+   or NULL if an error occured.
    If this is the upper insn, the caller can pass back to result to us
    parse the lower insn.  */
 
 static char *
-assemble_insn (str, lower_p)
+assemble_insn (str, lower_p, buf)
      char *str;
      int lower_p;
+     char *buf;
 {
   const struct txvu_opcode *opcode;
   char *start;
@@ -368,7 +379,6 @@ assemble_insn (str, lower_p)
       if (*syn == '\0')
        {
          int i;
-         char *f;
 
          /* For the moment we assume a valid `str' can only contain blanks
             now.  IE: We needn't try again with a longer version of the
@@ -386,11 +396,10 @@ assemble_insn (str, lower_p)
            as_bad ("junk at end of line: `%s'", str);
 
          /* Write out the instruction.
-            It is important to fetch enough space in one call to `frag_more'.
-            We use (f - frag_now->fr_literal) to compute where we are and we
-            don't want frag_now to change between calls.  */
-         f = frag_more (4);
-         md_number_to_chars (f, insn, 4);
+            Reminder: it is important to fetch enough space in one call to
+            `frag_more'.  We use (f - frag_now->fr_literal) to compute where
+            we are and we don't want frag_now to change between calls.  */
+         md_number_to_chars (buf, insn, 4);
 
          /* Create any fixups.  */
          for (i = 0; i < fc; ++i)
@@ -408,9 +417,7 @@ assemble_insn (str, lower_p)
              op_type = fixups[i].opindex;
              reloc_type = op_type + (int) BFD_RELOC_UNUSED;
              operand = &txvu_operands[op_type];
-             fix_new_exp (frag_now,
-                          ((f - frag_now->fr_literal)
-                           + (operand->flags & TXVU_OPERAND_LIMM ? 4 : 0)), 4,
+             fix_new_exp (frag_now, buf - frag_now->fr_literal, 4,
                           &fixups[i].exp,
                           (operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0,
                           (bfd_reloc_code_real_type) reloc_type);
@@ -469,7 +476,7 @@ md_pcrel_from_section (fixP, sec)
     }
 
   /* FIXME: `& -16L'? */
-  return (fixP->fx_frag->fr_address + fixP->fx_where) & -4L;
+  return (fixP->fx_frag->fr_address + fixP->fx_where) & -8L;
 }
 
 /* Apply a fixup to the object code.  This is called for all the
@@ -487,19 +494,137 @@ md_apply_fix3 (fixP, valueP, seg)
   char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
   valueT value;
 
-  as_fatal ("txvu md_apply_fix3\n");
+  /* 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
+     bfd_perform_relocation, which is also going to use the symbol
+     value.  That means that if the reloc is fully resolved we want to
+     use *valueP since bfd_perform_relocation is not being used.
+     However, if the reloc is not fully resolved we do not want to use
+     *valueP, and must use fx_offset instead.  However, if the reloc
+     is PC relative, we do want to use *valueP since it includes the
+     result of md_pcrel_from.  This is confusing.  */
+
+  if (fixP->fx_addsy == (symbolS *) NULL)
+    {
+      value = *valueP;
+      fixP->fx_done = 1;
+    }
+  else if (fixP->fx_pcrel)
+    {
+      value = *valueP;
+    }
+  else
+    {
+      value = fixP->fx_offset;
+      if (fixP->fx_subsy != (symbolS *) NULL)
+       {
+         if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
+           value -= S_GET_VALUE (fixP->fx_subsy);
+         else
+           {
+             /* We can't actually support subtracting a symbol.  */
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                           "expression too complex");
+           }
+       }
+    }
+
+  /* Check for txvu_operand's.  These are indicated with a reloc value
+     >= BFD_RELOC_UNUSED.  */
+
+  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
+    {
+      int opindex;
+      const struct txvu_operand *operand;
+      TXVU_INSN insn;
+
+      opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
+
+      operand = &txvu_operands[opindex];
+
+      /* Fetch the instruction, insert the fully resolved operand
+        value, and stuff the instruction back again.  */
+      insn = bfd_getl32 ((unsigned char *) where);
+      insn = txvu_insert_operand (insn, operand, -1, (offsetT) value,
+                                 fixP->fx_file, fixP->fx_line);
+      bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+
+      if (fixP->fx_done)
+       {
+         /* Nothing else to do here.  */
+         return 1;
+       }
+
+      /* Determine a BFD reloc value based on the operand information.
+        We are only prepared to turn a few of the operands into relocs.  */
+      /* FIXME: This test is a hack.  */
+      if ((operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0)
+       {
+         assert ((operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0
+                 && operand->bits == 11
+                 && operand->shift == 0);
+         fixP->fx_r_type = BFD_RELOC_TXVU_11_PCREL;
+       }
+      else
+       {
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       "unresolved expression that must be resolved");
+         fixP->fx_done = 1;
+         return 1;
+       }
+    }
+  else
+    {
+      switch (fixP->fx_r_type)
+       {
+       case BFD_RELOC_8:
+         md_number_to_chars (where, value, 1);
+         break;
+       case BFD_RELOC_16:
+         md_number_to_chars (where, value, 2);
+         break;
+       case BFD_RELOC_32:
+         md_number_to_chars (where, value, 4);
+         break;
+       default:
+         abort ();
+       }
+    }
+
+  fixP->fx_addnumber = value;
+
+  return 1;
 }
 
 /* Translate internal representation of relocation info to BFD target
    format.  */
 
 arelent *
-tc_gen_reloc (section, fixp)
+tc_gen_reloc (section, fixP)
      asection *section;
-     fixS *fixp;
+     fixS *fixP;
 {
-  /* relocs not handled yet */
-  as_fatal ("txvu tc_gen_reloc\n");
+  arelent *reloc;
+
+  reloc = (arelent *) xmalloc (sizeof (arelent));
+
+  reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym;
+  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
+  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')",
+                   fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
+      return NULL;
+    }
+
+  assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+
+  reloc->addend = fixP->fx_addnumber;
+
+  return reloc;
 }
 \f
 /* Write a value out to the object file, using the appropriate endianness.  */
@@ -583,3 +708,80 @@ md_atof (type, litP, sizeP)
      
   return 0;
 }
+\f
+/* Insert an operand value into an instruction.  */
+
+static TXVU_INSN
+txvu_insert_operand (insn, operand, mods, val, file, line)
+     TXVU_INSN insn;
+     const struct txvu_operand *operand;
+     int mods;
+     offsetT val;
+     char *file;
+     unsigned int line;
+{
+  if (operand->bits != 32)
+    {
+      long min, max;
+      offsetT test;
+
+      if ((operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0)
+       {
+         if ((val & 7) != 0)
+           {
+             if (file == (char *) NULL)
+               as_warn ("branch to misaligned address");
+             else
+               as_warn_where (file, line, "branch to misaligned address");
+           }
+         val >>= 3;
+       }
+
+      if ((operand->flags & TXVU_OPERAND_SIGNED) != 0)
+       {
+         if ((operand->flags & TXVU_OPERAND_SIGNOPT) != 0)
+           max = (1 << operand->bits) - 1;
+         else
+           max = (1 << (operand->bits - 1)) - 1;
+         min = - (1 << (operand->bits - 1));
+       }
+      else
+       {
+         max = (1 << operand->bits) - 1;
+         min = 0;
+       }
+
+      if ((operand->flags & TXVU_OPERAND_NEGATIVE) != 0)
+       test = - val;
+      else
+       test = val;
+
+      if (test < (offsetT) min || test > (offsetT) max)
+       {
+         const char *err =
+           "operand out of range (%s not between %ld and %ld)";
+         char buf[100];
+
+         sprint_value (buf, test);
+         if (file == (char *) NULL)
+           as_warn (err, buf, min, max);
+         else
+           as_warn_where (file, line, err, buf, min, max);
+       }
+    }
+
+  if (operand->insert)
+    {
+      const char *errmsg;
+
+      errmsg = NULL;
+      insn = (*operand->insert) (insn, operand, mods, (long) val, &errmsg);
+      if (errmsg != (const char *) NULL)
+       as_warn (errmsg);
+    }
+  else
+    insn |= (((long) val & ((1 << operand->bits) - 1))
+            << operand->shift);
+
+  return insn;
+}
index 5f8dafea907906b6bd64e3ebb215c26e19353a59..cdde90cec584c6f32d6dab07994a96b0dd2627a8 100644 (file)
@@ -50,7 +50,5 @@
                        (as_fatal("estimate_size_before_relax called"),1)
 
 #define MD_APPLY_FIX3
-extern int txvu_md_apply_fix3 ();
-#define md_apply_fix3 txvu_md_apply_fix3
 
 #define TC_HANDLES_FX_DONE