gas reloc rewrite.
[binutils-gdb.git] / gas / config / tc-m68hc11.c
index d5707845089da51bb7d104ddbb638b4d9ce1bf1b..254bf1eac0f3811fd5e984547f75467cbdfb87c2 100644 (file)
@@ -182,6 +182,9 @@ static void build_insn
   PARAMS ((struct m68hc11_opcode *, operand *, int));
 static int relaxable_symbol PARAMS ((symbolS *));
 
+/* Pseudo op to indicate a relax group.  */
+static void s_m68hc11_relax PARAMS((int));
+
 /* Pseudo op to control the ELF flags.  */
 static void s_m68hc11_mode PARAMS ((int));
 
@@ -258,12 +261,15 @@ const pseudo_typeS md_pseudo_table[] = {
   {"rmb", s_space, 0},
 
   /* Dwarf2 support for Gcc.  */
-  {"file", dwarf2_directive_file, 0},
+  {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
   {"loc", dwarf2_directive_loc, 0},
 
   /* Motorola ALIS.  */
   {"xrefb", s_ignore, 0}, /* Same as xref  */
 
+  /* Gcc driven relaxation.  */
+  {"relax", s_m68hc11_relax, 0},
+
   /* .mode instruction (ala SH).  */
   {"mode", s_m68hc11_mode, 0},
 
@@ -1516,6 +1522,8 @@ build_jump_insn (opcode, operands, nb_operands, jmp_mode)
   unsigned char code;
   char *f;
   unsigned long n;
+  fragS *frag;
+  int where;
 
   /* The relative branch convertion is not supported for
      brclr and brset.  */
@@ -1536,6 +1544,12 @@ build_jump_insn (opcode, operands, nb_operands, jmp_mode)
          && (!check_range (n, opcode->format) &&
              (jmp_mode == 1 || flag_fixed_branchs == 0))))
     {
+      frag = frag_now;
+      where = frag_now_fix ();
+
+      fix_new (frag_now, frag_now_fix (), 1,
+               &abs_symbol, 0, 1, BFD_RELOC_M68HC11_RL_JUMP);
+
       if (code == M6811_BSR || code == M6811_BRA || code == M6812_BSR)
        {
          code = convert_branch (code);
@@ -1590,6 +1604,12 @@ build_jump_insn (opcode, operands, nb_operands, jmp_mode)
     }
   else if (opcode->format & M6812_OP_JUMP_REL16)
     {
+      frag = frag_now;
+      where = frag_now_fix ();
+
+      fix_new (frag_now, frag_now_fix (), 1,
+               &abs_symbol, 0, 1, BFD_RELOC_M68HC11_RL_JUMP);
+
       f = m68hc11_new_insn (2);
       number_to_chars_bigendian (f, M6811_OPCODE_PAGE2, 1);
       number_to_chars_bigendian (f + 1, code, 1);
@@ -1599,6 +1619,12 @@ build_jump_insn (opcode, operands, nb_operands, jmp_mode)
     {
       char *opcode;
 
+      frag = frag_now;
+      where = frag_now_fix ();
+      
+      fix_new (frag_now, frag_now_fix (), 1,
+               &abs_symbol, 0, 1, BFD_RELOC_M68HC11_RL_JUMP);
+
       /* Branch offset must fit in 8-bits, don't do some relax.  */
       if (jmp_mode == 0 && flag_fixed_branchs)
        {
@@ -2002,9 +2028,19 @@ build_insn (opcode, operands, nb_operands)
   char *f;
   long format;
   int move_insn = 0;
+  fragS *frag;
+  int where;
 
   /* Put the page code instruction if there is one.  */
   format = opcode->format;
+
+  frag = frag_now;
+  where = frag_now_fix ();
+
+  if (format & M6811_OP_BRANCH)
+    fix_new (frag, where, 1,
+             &abs_symbol, 0, 1, BFD_RELOC_M68HC11_RL_JUMP);
+
   if (format & OP_EXTENDED)
     {
       int page_code;
@@ -2592,21 +2628,42 @@ s_m68hc11_mark_symbol (mark)
 
   demand_empty_rest_of_line ();
 }
+
+static void
+s_m68hc11_relax (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  expressionS ex;
+
+  expression (&ex);
+
+  if (ex.X_op != O_symbol || ex.X_add_number != 0)
+    {
+      as_bad (_("bad .relax format"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  fix_new_exp (frag_now, frag_now_fix (), 1, &ex, 1,
+               BFD_RELOC_M68HC11_RL_GROUP);
+
+  demand_empty_rest_of_line ();
+}
+
 \f
 /* Relocation, relaxation and frag conversions.  */
+
+/* PC-relative offsets are relative to the start of the
+   next instruction.  That is, the address of the offset, plus its
+   size, since the offset is always the last part of the insn.  */
 long
-md_pcrel_from_section (fixp, sec)
-     fixS *fixp;
-     segT sec;
+md_pcrel_from (fixP)
+     fixS *fixP;
 {
-  int adjust;
-  if (fixp->fx_addsy != (symbolS *) NULL
-      && (!S_IS_DEFINED (fixp->fx_addsy)
-         || (S_GET_SEGMENT (fixp->fx_addsy) != sec)))
+  if (fixP->fx_r_type == BFD_RELOC_M68HC11_RL_JUMP)
     return 0;
 
-  adjust = fixp->fx_pcrel_adjust;
-  return fixp->fx_frag->fr_address + fixp->fx_where + adjust;
+  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
 /* If while processing a fixup, a reloc really needs to be created
@@ -2634,14 +2691,12 @@ tc_gen_reloc (section, fixp)
       return NULL;
     }
 
-  if (!fixp->fx_pcrel)
-    reloc->addend = fixp->fx_addnumber;
-  else
-    reloc->addend = (section->vma
-                    + (fixp->fx_pcrel_adjust == 64
-                       ? -1 : fixp->fx_pcrel_adjust)
-                    + fixp->fx_addnumber
-                    + md_pcrel_from_section (fixp, section));
+  /* Since we use Rel instead of Rela, encode the vtable entry to be
+     used in the relocation's section offset.  */
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    reloc->address = fixp->fx_offset;
+
+  reloc->addend = 0;
   return reloc;
 }
 
@@ -2873,7 +2928,7 @@ md_estimate_size_before_relax (fragP, segment)
              fragP->fr_opcode[0] = M6811_OPCODE_PAGE2;
 
              fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-                      fragP->fr_offset, 0, BFD_RELOC_16_PCREL);
+                       fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
              fragP->fr_fix += 2;
              break;
 
@@ -2934,6 +2989,52 @@ md_estimate_size_before_relax (fragP, segment)
   return md_relax_table[fragP->fr_subtype].rlx_length;
 }
 
+/* See whether we need to force a relocation into the output file.  */
+int
+tc_m68hc11_force_relocation (fixP)
+     fixS * fixP;
+{
+  switch (fixP->fx_r_type)
+    {
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+    case BFD_RELOC_M68HC11_RL_GROUP:
+      return 1;
+
+    default:
+      break;
+    }
+
+  return S_FORCE_RELOC (fixP->fx_addsy);
+}
+
+/* Here we decide which fixups can be adjusted to make them relative
+   to the beginning of the section instead of the symbol.  Basically
+   we need to make sure that the linker relaxation is done
+   correctly, so in some cases we force the original symbol to be
+   used.  */
+int
+tc_m68hc11_fix_adjustable (fixP)
+     fixS *fixP;
+{
+  switch (fixP->fx_r_type)
+    {
+      /* For the linker relaxation to work correctly, these relocs
+         need to be on the symbol itself.  */
+    case BFD_RELOC_16:
+    case BFD_RELOC_LO16:
+    case BFD_RELOC_M68HC11_RL_JUMP:
+    case BFD_RELOC_M68HC11_RL_GROUP:
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      return 0;
+
+    case BFD_RELOC_32:
+    default:
+      return 1;
+    }
+}
+
 void
 md_apply_fix3 (fixP, valP, seg)
      fixS *fixP;
@@ -2947,23 +3048,9 @@ md_apply_fix3 (fixP, valP, seg)
   if (fixP->fx_addsy == (symbolS *) NULL)
     fixP->fx_done = 1;
 
-  else if (fixP->fx_pcrel)
-    ;
-
-  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 don't actually support subtracting a symbol.  */
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("Expression too complex."));
-       }
-    }
+  /* We don't actually support subtracting a symbol.  */
+  if (fixP->fx_subsy != (symbolS *) NULL)
+    as_bad_where (fixP->fx_file, fixP->fx_line, _("Expression too complex."));
 
   op_type = fixP->fx_r_type;
 
@@ -3037,6 +3124,13 @@ md_apply_fix3 (fixP, valP, seg)
       where[0] = where[0] | (value & 0x07);
       break;
 
+    case BFD_RELOC_M68HC11_RL_JUMP:
+    case BFD_RELOC_M68HC11_RL_GROUP:
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      fixP->fx_done = 0;
+      return;
+
     default:
       as_fatal (_("Line %d: unknown relocation type: 0x%x."),
                fixP->fx_line, fixP->fx_r_type);