Better reloc support
authorMichael Meissner <gnu@the-meissners.org>
Mon, 25 Sep 1995 20:15:13 +0000 (20:15 +0000)
committerMichael Meissner <gnu@the-meissners.org>
Mon, 25 Sep 1995 20:15:13 +0000 (20:15 +0000)
gas/ChangeLog
gas/config/tc-ppc.c

index ed3e4a711b15cb669b205286de9d99338071abdb..4e3798d62f81659e02012d5e92844a1049f52c50 100644 (file)
@@ -1,3 +1,12 @@
+Mon Sep 25 16:08:43 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
+
+       * config/tc-ppc.c (ppc_elf_suffix): Lower case reloc before
+       testing.
+       (md_assemble): Be more robust in terms of relocations.
+       (md_apply_fix3): Allow 14 bit relocs to be emitted for external
+       symbols in addition to 26 bit relocs.  Properly insert 26/14 bit
+       reloc value fields into the instruction stream. 
+
 Mon Sep 25 00:23:16 1995  Ian Lance Taylor  <ian@cygnus.com>
 
        * config/tc-arm.c (md_atof): Output little endian constants in
index 435d0fb0190d997758f63e282e80f2a8cbda0d95..6760b6135e170717675da42fdefc6129f50c3573 100644 (file)
@@ -560,26 +560,21 @@ ppc_elf_suffix (str_p)
     bfd_reloc_code_real_type reloc;
   };
 
+  char ident[20];
   char *str = *str_p;
+  char *str2;
   int ch;
+  int len;
   struct map_bfd *ptr;
 
   static struct map_bfd mapping[] = {
-    { "GOT",           3,      BFD_RELOC_PPC_TOC16 },
     { "got",           3,      BFD_RELOC_PPC_TOC16 },
-    { "L",             1,      BFD_RELOC_LO16 },
     { "l",             1,      BFD_RELOC_LO16 },
-    { "HA",            2,      BFD_RELOC_HI16_S },
     { "ha",            2,      BFD_RELOC_HI16_S },
-    { "H",             1,      BFD_RELOC_HI16 },
     { "h",             1,      BFD_RELOC_HI16 },
-    { "SDAREL",                6,      BFD_RELOC_GPREL16 },
     { "sdarel",                6,      BFD_RELOC_GPREL16 },
-    { "FIXUP",         5,      BFD_RELOC_CTOR },       /* synonym for BFD_RELOC_32 that doesn't get */
     { "fixup",         5,      BFD_RELOC_CTOR },       /* warnings with -mrelocatable */
-    { "BRTAKEN",       7,      BFD_RELOC_PPC_B16_BRTAKEN },
     { "brtaken",       7,      BFD_RELOC_PPC_B16_BRTAKEN },
-    { "BRNTAKEN",      8,      BFD_RELOC_PPC_B16_BRNTAKEN },
     { "brntaken",      8,      BFD_RELOC_PPC_B16_BRNTAKEN },
     { (char *)0,       0,      BFD_RELOC_UNUSED }
   };
@@ -587,11 +582,17 @@ ppc_elf_suffix (str_p)
   if (*str++ != '@')
     return BFD_RELOC_UNUSED;
 
-  ch = *str;
+  for (ch = *str, str2 = ident; str2 < ident + sizeof(ident) - 1 && isalpha (ch); ch = *++str)
+    *str2++ = (islower (ch)) ? ch : tolower (ch);
+
+  *str2 = '\0';
+  len = str2 - ident;
+
+  ch = ident[0];
   for (ptr = &mapping[0]; ptr->length > 0; ptr++)
-    if (ch == ptr->string[0] && strncmp (str, ptr->string, ptr->length) == 0)
+    if (ch == ptr->string[0] && len == ptr->length && memcmp (ident, ptr->string, ptr->length) == 0)
       {
-       *str_p = str + ptr->length;
+       *str_p = str;
        return ptr->reloc;
       }
 
@@ -935,15 +936,21 @@ md_assemble (str)
       if (fixups[i].reloc != BFD_RELOC_UNUSED)
        {
          reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
-         int size = (!reloc_howto) ? 0 : bfd_get_reloc_size (reloc_howto);
-         int offset = target_big_endian ? (4 - size) : 0;
+         int size;
+         int offset;
          fixS *fixP;
 
-         if (size > 4)
+         if (!reloc_howto)
+           abort ();
+
+         size = bfd_get_reloc_size (reloc_howto);
+         offset = target_big_endian ? (4 - size) : 0;
+
+         if (size < 1 || size > 4)
            abort();
 
          fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size,
-                             &fixups[i].exp, (reloc_howto && reloc_howto->pc_relative),
+                             &fixups[i].exp, reloc_howto->pc_relative,
                              fixups[i].reloc);
 
          /* Turn off complaints that the addend is too large for things like
@@ -2642,6 +2649,9 @@ md_apply_fix3 (fixp, valuep, seg)
      segT seg;
 {
   valueT value;
+  char *where;
+  unsigned long insn;
+  unsigned long mask;
 
   /* FIXME FIXME FIXME: The value we are passed in *valuep includes
      the symbol values.  Since we are using BFD_ASSEMBLER, if we are
@@ -2681,8 +2691,6 @@ md_apply_fix3 (fixp, valuep, seg)
     {
       int opindex;
       const struct powerpc_operand *operand;
-      char *where;
-      unsigned long insn;
 
       opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
 
@@ -2735,17 +2743,24 @@ md_apply_fix3 (fixp, valuep, seg)
         We are only prepared to turn a few of the operands into
         relocs.
         FIXME: We need to handle the DS field at the very least.
-        FIXME: Handling 16 bit branches would also be reasonable.
         FIXME: Selecting the reloc type is a bit haphazard; perhaps
         there should be a new field in the operand table.  */
       if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
          && operand->bits == 26
          && operand->shift == 0)
        fixp->fx_r_type = BFD_RELOC_PPC_B26;
+      else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
+         && operand->bits == 16
+         && operand->shift == 0)
+       fixp->fx_r_type = BFD_RELOC_PPC_B16;
       else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
               && operand->bits == 26
               && operand->shift == 0)
        fixp->fx_r_type = BFD_RELOC_PPC_BA26;
+      else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
+              && operand->bits == 26
+              && operand->shift == 0)
+       fixp->fx_r_type = BFD_RELOC_PPC_BA16;
       else if ((operand->flags & PPC_OPERAND_PARENS) != 0
               && operand->bits == 16
               && operand->shift == 0
@@ -2771,6 +2786,7 @@ md_apply_fix3 (fixp, valuep, seg)
 #ifdef OBJ_ELF
       ppc_elf_validate_fix (fixp, seg);
 #endif
+      mask = 0;
       switch (fixp->fx_r_type)
        {
        case BFD_RELOC_32:
@@ -2795,24 +2811,52 @@ md_apply_fix3 (fixp, valuep, seg)
          if (fixp->fx_pcrel)
            abort ();
 
-       case BFD_RELOC_PPC_B16_BRTAKEN:
-       case BFD_RELOC_PPC_B16_BRNTAKEN:
-         value <<= 2;
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
-                             value, 2);
+         mask = 0xffff;
          break;
 
        case BFD_RELOC_8:
          if (fixp->fx_pcrel)
            abort ();
 
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
-                             value, 1);
+         mask = 0xff;
+         break;
+
+       case BFD_RELOC_PPC_B16:
+       case BFD_RELOC_PPC_B16_BRTAKEN:
+       case BFD_RELOC_PPC_B16_BRNTAKEN:
+       case BFD_RELOC_PPC_BA16:
+       case BFD_RELOC_PPC_BA16_BRTAKEN:
+       case BFD_RELOC_PPC_BA16_BRNTAKEN:
+         mask = 0xfffc;
+         break;
+
+       case BFD_RELOC_PPC_B26:
+       case BFD_RELOC_PPC_BA26:
+         mask = 0x3fffffc;
          break;
 
        default:
          abort ();
        }
+
+         /* Fetch the instruction, insert the fully resolved operand
+            value, and stuff the instruction back again.  */
+      if (mask != 0)
+       {
+         where = fixp->fx_frag->fr_literal + fixp->fx_where;
+         if (target_big_endian)
+           insn = bfd_getb32 ((unsigned char *) where);
+         else
+           insn = bfd_getl32 ((unsigned char *) where);
+
+         insn = (insn & ~mask) | (value & mask);
+
+         if (target_big_endian)
+           bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
+         else
+           bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+       }
+
     }
 
 #ifdef OBJ_ELF