rl78: relaxation fixes
authorDJ Delorie <dj@redhat.com>
Tue, 8 Dec 2015 06:29:25 +0000 (01:29 -0500)
committerDJ Delorie <dj@redhat.com>
Tue, 8 Dec 2015 06:29:25 +0000 (01:29 -0500)
Various fixes to linker relaxation.  In general, we need to support
relaxing every branch, even if we don't relax it in the assembler,
so we can optionally defer relaxation to the linker.

* elf32-rl78.c (rl78_offset_for_reloc): Add more relocs.
(rl78_elf_relax_section): Add bc/bz/bnc/bnz/bh/bnh.  Fix reloc
choices.

* config/rl78-parse.y: Make all branches relaxable via
rl78_linkrelax_branch().
* config/tc-rl78.c (rl78_linkrelax_branch): Mark all relaxable
branches with relocs.
(options): Add OPTION_NORELAX.
(md_longopts): Add -mnorelax.
(md_parse_option): Support OPTION_NORELAX.
(op_type_T): Add bh, sk, call, and br.
(rl78_opcode_type): Likewise.
(rl78_relax_frag): Fix not-relaxing logic.  Add sk.
(md_convert_frag): Fix relocation handling.
(tc_gen_reloc): Strip relax relocs when not linker relaxing.
(md_apply_fix): Defer overflow handling for anything that needs a
PLT, to the linker.
* config/tc-rl78.h (TC_FORCE_RELOCATION): Force all relocations to
the linker when linker relaxing.
* doc/c-rl78.texi (norelax): Add.

bfd/ChangeLog
bfd/elf32-rl78.c
gas/ChangeLog
gas/config/rl78-parse.y
gas/config/tc-rl78.c
gas/config/tc-rl78.h
gas/doc/c-rl78.texi

index 180f363dc54dee6eabe6f4c458d61740d10a5bd9..2473d6ef3b1fcb2ca97886391712fa0dfdf903c4 100644 (file)
@@ -1,5 +1,9 @@
 2015-12-08  DJ Delorie  <dj@redhat.com>
 
+       * elf32-rl78.c (rl78_offset_for_reloc): Add more relocs.
+       (rl78_elf_relax_section): Add bc/bz/bnc/bnz/bh/bnh.  Fix reloc
+       choices.
+
        * elf32-rx.c (rx_elf_object_p): Ignore empty and nobits sections.
 
 2015-12-07  Nick Clifton  <nickc@redhat.com>
index 723cb4b07d4de8cdc5ca8e56e02d468a6b11a94f..cf192bf0e14b8b360843338aa421b8056b68183c 100644 (file)
@@ -1974,7 +1974,15 @@ rl78_offset_for_reloc (bfd *                    abfd,
 
        default:
        reloc_computes_value:
-         symval = rl78_compute_complex_reloc (r_type, 0, input_section);
+         symval = rl78_compute_complex_reloc (r_type, symval, input_section);
+       case R_RL78_DIR32:
+       case R_RL78_DIR24S:
+       case R_RL78_DIR16:
+       case R_RL78_DIR16U:
+       case R_RL78_DIR16S:
+       case R_RL78_DIR24S_PCREL:
+       case R_RL78_DIR16S_PCREL:
+       case R_RL78_DIR8S_PCREL:
          if (lrel)
            *lrel = rel;
          return symval;
@@ -2316,6 +2324,27 @@ rl78_elf_relax_section
 
          switch (insn[0])
            {
+           case 0xdc: /* BC */
+           case 0xdd: /* BZ */
+           case 0xde: /* BNC */
+           case 0xdf: /* BNZ */
+             if (insn[1] == 0x03 && insn[2] == 0xee /* BR */
+                 && (srel->r_offset - irel->r_offset) > 1) /* a B<c> without its own reloc */
+               {
+                 /* This is a "long" conditional as generated by gas:
+                    DC 03 EE ad.dr  */
+                 if (pcrel < 127
+                     && pcrel > -127)
+                   {
+                     insn[0] ^= 0x02; /* invert conditional */
+                     SNIPNR (4, 1);
+                     SNIP (1, 2, R_RL78_DIR8S_PCREL);
+                     insn[1] = pcrel;
+                     *again = TRUE;
+                   }
+               }
+             break;
+
            case 0xec: /* BR !!abs20 */
 
              if (pcrel < 127
@@ -2331,7 +2360,7 @@ rl78_elf_relax_section
                  insn[0] = 0xed;
                  insn[1] = symval & 0xff;
                  insn[2] = symval >> 8;
-                 SNIP (2, 1, R_RL78_DIR16S);
+                 SNIP (2, 1, R_RL78_DIR16U);
                  *again = TRUE;
                }
              else if (pcrel < 32767
@@ -2363,7 +2392,7 @@ rl78_elf_relax_section
                  insn[0] = 0xfd;
                  insn[1] = symval & 0xff;
                  insn[2] = symval >> 8;
-                 SNIP (2, 1, R_RL78_DIR16S);
+                 SNIP (2, 1, R_RL78_DIR16U);
                  *again = TRUE;
                }
              else if (pcrel < 32767
@@ -2386,6 +2415,25 @@ rl78_elf_relax_section
                 here anyway. */
              switch (insn[1])
                {
+               case 0xd3: /* BNH */
+               case 0xc3: /* BH */
+                 if (insn[2] == 0x03 && insn[3] == 0xee
+                     && (srel->r_offset - irel->r_offset) > 2) /* a B<c> without its own reloc */
+                   {
+                     /* Another long branch by gas:
+                        61 D3 03 EE ad.dr  */
+                     if (pcrel < 127
+                         && pcrel > -127)
+                       {
+                         insn[1] ^= 0x10; /* invert conditional */
+                         SNIPNR (5, 1);
+                         SNIP (2, 2, R_RL78_DIR8S_PCREL);
+                         insn[2] = pcrel;
+                         *again = TRUE;
+                       }
+                   }
+                 break;
+
                case 0xc8: /* SKC */
                  if (insn[2] == 0xef)
                    {
index 8a50708d67cda94eea63ca41e9c965b128b9bf67..6fb81a1acaf94a5988d20e9ba731f16dee805132 100644 (file)
@@ -1,3 +1,23 @@
+2015-12-08  DJ Delorie  <dj@redhat.com>
+
+       * config/rl78-parse.y: Make all branches relaxable via
+       rl78_linkrelax_branch().
+       * config/tc-rl78.c (rl78_linkrelax_branch): Mark all relaxable
+       branches with relocs.
+       (options): Add OPTION_NORELAX.
+       (md_longopts): Add -mnorelax.
+       (md_parse_option): Support OPTION_NORELAX.
+       (op_type_T): Add bh, sk, call, and br.
+       (rl78_opcode_type): Likewise.
+       (rl78_relax_frag): Fix not-relaxing logic.  Add sk.
+       (md_convert_frag): Fix relocation handling.
+       (tc_gen_reloc): Strip relax relocs when not linker relaxing.
+       (md_apply_fix): Defer overflow handling for anything that needs a
+       PLT, to the linker.
+       * config/tc-rl78.h (TC_FORCE_RELOCATION): Force all relocations to
+       the linker when linker relaxing.
+       * doc/c-rl78.texi (norelax): Add.
+
 2015-12-07  Alan Modra  <amodra@gmail.com>
 
        * config/tc-ppc.c (md_apply_fix): Localize variables.  Reduce casts.
index b8795815f7b533a61848dd6d4c23edebf8011dc3..ff017cfb1409b369bee42951c1c10af2bfdd80f7 100644 (file)
@@ -294,22 +294,22 @@ statement :
 /* ---------------------------------------------------------------------- */
 
        | BC '$' EXPR
-         { B1 (0xdc); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+         { B1 (0xdc); PC1 ($3); rl78_linkrelax_branch (); }
 
        | BNC '$' EXPR
-         { B1 (0xde); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+         { B1 (0xde); PC1 ($3); rl78_linkrelax_branch (); }
 
        | BZ '$' EXPR
-         { B1 (0xdd); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+         { B1 (0xdd); PC1 ($3); rl78_linkrelax_branch (); }
 
        | BNZ '$' EXPR
-         { B1 (0xdf); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+         { B1 (0xdf); PC1 ($3); rl78_linkrelax_branch (); }
 
        | BH '$' EXPR
-         { B2 (0x61, 0xc3); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+         { B2 (0x61, 0xc3); PC1 ($3); rl78_linkrelax_branch (); }
 
        | BNH '$' EXPR
-         { B2 (0x61, 0xd3); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+         { B2 (0x61, 0xd3); PC1 ($3); rl78_linkrelax_branch (); }
 
 /* ---------------------------------------------------------------------- */
 
@@ -337,7 +337,7 @@ statement :
          { B2 (0x61, 0xcb); }
 
        | BR '$' EXPR
-         { B1 (0xef); PC1 ($3); }
+         { B1 (0xef); PC1 ($3); rl78_linkrelax_branch (); }
 
        | BR '$' '!' EXPR
          { B1 (0xee); PC2 ($4); rl78_linkrelax_branch (); }
@@ -1022,22 +1022,22 @@ statement :
 /* ---------------------------------------------------------------------- */
 
        | SKC
-         { B2 (0x61, 0xc8); rl78_linkrelax_branch (); }
+         { B2 (0x61, 0xc8); rl78_relax (RL78_RELAX_BRANCH, 0); }
 
        | SKH
-         { B2 (0x61, 0xe3); rl78_linkrelax_branch (); }
+         { B2 (0x61, 0xe3); rl78_relax (RL78_RELAX_BRANCH, 0); }
 
        | SKNC
-         { B2 (0x61, 0xd8); rl78_linkrelax_branch (); }
+         { B2 (0x61, 0xd8); rl78_relax (RL78_RELAX_BRANCH, 0); }
 
        | SKNH
-         { B2 (0x61, 0xf3); rl78_linkrelax_branch (); }
+         { B2 (0x61, 0xf3); rl78_relax (RL78_RELAX_BRANCH, 0); }
 
        | SKNZ
-         { B2 (0x61, 0xf8); rl78_linkrelax_branch (); }
+         { B2 (0x61, 0xf8); rl78_relax (RL78_RELAX_BRANCH, 0); }
 
        | SKZ
-         { B2 (0x61, 0xe8); rl78_linkrelax_branch (); }
+         { B2 (0x61, 0xe8); rl78_relax (RL78_RELAX_BRANCH, 0); }
 
 /* ---------------------------------------------------------------------- */
 
@@ -1161,8 +1161,8 @@ andor1    : AND1 { $$ = 0x05; rl78_bit_insn = 1; }
        | XOR1 { $$ = 0x07; rl78_bit_insn = 1; }
        ;
 
-bt_bf  : BT { $$ = 0x02;    rl78_bit_insn = 1; rl78_relax (RL78_RELAX_BRANCH, 0); }
-       | BF { $$ = 0x04;    rl78_bit_insn = 1; rl78_relax (RL78_RELAX_BRANCH, 0); }
+bt_bf  : BT { $$ = 0x02;    rl78_bit_insn = 1; rl78_linkrelax_branch (); }
+       | BF { $$ = 0x04;    rl78_bit_insn = 1; rl78_linkrelax_branch (); }
        | BTCLR { $$ = 0x00; rl78_bit_insn = 1; }
        ;
 
index 9fbaa42b5a7bcbe259ac5d649b1f9c55999c85bd..ad04795c13cd1a5fb165dc17572c73dd11274b6b 100644 (file)
@@ -102,6 +102,7 @@ rl78_linkrelax_addr16 (void)
 void
 rl78_linkrelax_branch (void)
 {
+  rl78_relax (RL78_RELAX_BRANCH, 0);
   rl78_bytes.link_relax |= RL78_RELAXA_BRA;
 }
 
@@ -280,6 +281,7 @@ rl78_field (int val, int pos, int sz)
 enum options
 {
   OPTION_RELAX = OPTION_MD_BASE,
+  OPTION_NORELAX,
   OPTION_G10,
   OPTION_G13,
   OPTION_G14,
@@ -294,6 +296,7 @@ const char * md_shortopts = RL78_SHORTOPTS;
 struct option md_longopts[] =
 {
   {"relax", no_argument, NULL, OPTION_RELAX},
+  {"norelax", no_argument, NULL, OPTION_NORELAX},
   {"mg10", no_argument, NULL, OPTION_G10},
   {"mg13", no_argument, NULL, OPTION_G13},
   {"mg14", no_argument, NULL, OPTION_G14},
@@ -312,6 +315,9 @@ md_parse_option (int c, char * arg ATTRIBUTE_UNUSED)
     case OPTION_RELAX:
       linkrelax = 1;
       return 1;
+    case OPTION_NORELAX:
+      linkrelax = 0;
+      return 1;
 
     case OPTION_G10:
       elf_flags &= ~ E_FLAG_RL78_CPU_MASK;
@@ -757,7 +763,10 @@ typedef enum
   OT_bt_sfr,
   OT_bt_es,
   OT_bc,
-  OT_bh
+  OT_bh,
+  OT_sk,
+  OT_call,
+  OT_br,
 } op_type_T;
 
 /* We're looking for these types of relaxations:
@@ -780,8 +789,10 @@ typedef enum
    a different size later.  */
 
 static op_type_T
-rl78_opcode_type (char * op)
+rl78_opcode_type (char * ops)
 {
+  unsigned char *op = (unsigned char *)ops;
+
   if (op[0] == 0x31
       && ((op[1] & 0x0f) == 0x05
          || (op[1] & 0x0f) == 0x03))
@@ -805,6 +816,20 @@ rl78_opcode_type (char * op)
       && (op[1] & 0xef) == 0xc3)
     return OT_bh;
 
+  if (op[0] == 0x61
+      && (op[1] & 0xcf) == 0xc8)
+    return OT_sk;
+
+  if (op[0] == 0x61
+      && (op[1] & 0xef) == 0xe3)
+    return OT_sk;
+
+  if (op[0] == 0xfc)
+    return OT_call;
+
+  if ((op[0] & 0xec) == 0xec)
+    return OT_br;
+
   return OT_other;
 }
 
@@ -901,6 +926,11 @@ rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch)
                           fragP->tc_frag_data->relax[ri].type != RL78_RELAX_BRANCH,
                           & sym_addr))
     {
+      /* If we don't expect the linker to do relaxing, don't emit
+        expanded opcodes that only the linker will relax.  */
+      if (!linkrelax)
+       return newsize - oldsize;
+
       /* If we don't, we must use the maximum size for the linker.  */
       switch (fragP->tc_frag_data->relax[ri].type)
        {
@@ -920,7 +950,10 @@ rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch)
            case OT_bh:
              newsize = 6;
              break;
-           case OT_other:
+           case OT_sk:
+             newsize = 2;
+             break;
+           default:
              newsize = oldsize;
              break;
            }
@@ -967,7 +1000,10 @@ rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch)
          else
            newsize = 6;
          break;
-       case OT_other:
+       case OT_sk:
+         newsize = 2;
+         break;
+       default:
          newsize = oldsize;
          break;
        }
@@ -1062,6 +1098,7 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
        case OPCODE (OT_bt, 3): /* BT A,$ - no change.  */
          disp -= 3;
          op[2] = disp;
+         reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE;
          break;
 
        case OPCODE (OT_bt, 6): /* BT A,$ - long version.  */
@@ -1079,6 +1116,7 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
        case OPCODE (OT_bt_sfr, 4): /* BT PSW,$ - no change.  */
          disp -= 4;
          op[3] = disp;
+         reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE;
          break;
 
        case OPCODE (OT_bt_sfr, 7): /* BT PSW,$ - long version.  */
@@ -1096,6 +1134,7 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
        case OPCODE (OT_bt_es, 4): /* BT ES:[HL],$ - no change.  */
          disp -= 4;
          op[3] = disp;
+         reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE;
          break;
 
        case OPCODE (OT_bt_es, 7): /* BT PSW,$ - long version.  */
@@ -1113,6 +1152,7 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
        case OPCODE (OT_bc, 2): /* BC $ - no change.  */
          disp -= 2;
          op[1] = disp;
+         reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE;
          break;
 
        case OPCODE (OT_bc, 5): /* BC $ - long version.  */
@@ -1130,6 +1170,7 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
        case OPCODE (OT_bh, 3): /* BH $ - no change.  */
          disp -= 3;
          op[2] = disp;
+         reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE;
          break;
 
        case OPCODE (OT_bh, 6): /* BC $ - long version.  */
@@ -1144,11 +1185,13 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
          reloc_adjust = 2;
          break;
 
-       default:
-         fprintf(stderr, "Missed case %d %d at 0x%lx\n",
-                 rl78_opcode_type (fragP->fr_opcode), fragP->fr_subtype, mypc);
-         abort ();
+       case OPCODE (OT_sk, 2): /* SK<cond> - no change */
+         reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE;
+         break;
 
+       default:
+         reloc_type = fix ? fix->fx_r_type : BFD_RELOC_NONE;
+         break;
        }
       break;
 
@@ -1215,6 +1258,12 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
       return reloc;
     }
 
+  if (fixp->fx_r_type == BFD_RELOC_RL78_RELAX && !linkrelax)
+    {
+      reloc[0] = NULL;
+      return reloc;
+    }
+
   if (fixp->fx_subsy
       && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
     {
@@ -1376,6 +1425,11 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED,
   char * op;
   unsigned long val;
 
+  /* We always defer overflow checks for these to the linker, as it
+     needs to do PLT stuff.  */
+  if (f->fx_r_type == BFD_RELOC_RL78_CODE)
+    f->fx_no_overflow = 1;
+
   if (f->fx_addsy && S_FORCE_RELOC (f->fx_addsy, 1))
     return;
   if (f->fx_subsy && S_FORCE_RELOC (f->fx_subsy, 1))
@@ -1384,13 +1438,16 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED,
   op = f->fx_frag->fr_literal + f->fx_where;
   val = (unsigned long) * t;
 
+  if (f->fx_addsy == NULL)
+    f->fx_done = 1;
+
   switch (f->fx_r_type)
     {
     case BFD_RELOC_NONE:
       break;
 
     case BFD_RELOC_RL78_RELAX:
-      f->fx_done = 1;
+      f->fx_done = 0;
       break;
 
     case BFD_RELOC_8_PCREL:
@@ -1461,8 +1518,6 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED,
       break;
     }
 
-  if (f->fx_addsy == NULL)
-    f->fx_done = 1;
 }
 
 valueT
index b9ede61674c2ae608990d160955abdb85a42e752..82f798ec35016ffb54a62aeb17c19d6eb0efeb84 100644 (file)
@@ -99,3 +99,5 @@ extern void rl78_elf_final_processing (void);
    || TC_FORCE_RELOCATION (FIX))
 
 #define DWARF2_USE_FIXED_ADVANCE_PC 1
+
+#define TC_FORCE_RELOCATION(FIX) (linkrelax)
index 5cb568f3ec2874f229d9b1b6f864dab4ffb83231..49e4ee4173803b5ec6acdd5db4e3f1b2117ed9fc 100644 (file)
@@ -28,6 +28,9 @@
 @item relax
 Enable support for link-time relaxation.
 
+@item norelax
+Disable support for link-time relaxation (default).
+
 @item mg10
 Mark the generated binary as targeting the G10 variant of the RL78
 architecture.