ChangeLog rotatation and copyright year update
[deliverable/binutils-gdb.git] / gas / config / tc-microblaze.c
index 86ac90bc2718ae92a7a3f4d483a2b84c18be16c9..bdf25c2c02e3ea3731f445ac909ba23e5e1a7e1c 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-microblaze.c -- Assemble code for Xilinx MicroBlaze
 
-   Copyright 2009, 2010, 2012 Free Software Foundation.
+   Copyright (C) 2009-2015 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -35,6 +35,9 @@
 #define streq(a,b) (strcmp (a, b) == 0)
 #endif
 
+#define OPTION_EB (OPTION_MD_BASE + 0)
+#define OPTION_EL (OPTION_MD_BASE + 1)
+
 void microblaze_generate_symbol (char *sym);
 static bfd_boolean check_spl_reg (unsigned *);
 
@@ -78,7 +81,12 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 #define GOT_OFFSET           8
 #define PLT_OFFSET           9
 #define GOTOFF_OFFSET        10
-
+#define TLSGD_OFFSET         11
+#define TLSLD_OFFSET         12
+#define TLSDTPMOD_OFFSET     13
+#define TLSDTPREL_OFFSET     14
+#define TLSGOTTPREL_OFFSET   15
+#define TLSTPREL_OFFSET      16
 
 /* Initialize the relax table.  */
 const relax_typeS md_relax_table[] =
@@ -94,6 +102,12 @@ const relax_typeS md_relax_table[] =
   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /*  8: GOT_OFFSET.  */
   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /*  9: PLT_OFFSET.  */
   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 10: GOTOFF_OFFSET.  */
+  { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 11: TLSGD_OFFSET.  */
+  { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 12: TLSLD_OFFSET.  */
+  { 0x7fffffff, 0x80000000, INST_WORD_SIZE*1, 0 },  /* 13: TLSDTPMOD_OFFSET.  */
+  { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 14: TLSDTPREL_OFFSET.  */
+  { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 15: TLSGOTTPREL_OFFSET.  */
+  { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }   /* 16: TLSTPREL_OFFSET.  */
 };
 
 static struct hash_control * opcode_hash_control;      /* Opcode mnemonics.  */
@@ -528,6 +542,17 @@ parse_reg (char * s, unsigned * reg)
        }
       return s;
     }
+  /* Stack protection registers.  */
+  else if (strncasecmp (s, "rshr", 4) == 0)
+    {
+      *reg = REG_SHR;
+      return s + 4;
+    }
+  else if (strncasecmp (s, "rslr", 4) == 0)
+    {
+      *reg = REG_SLR;
+      return s + 4;
+    }
   else
     {
       if (TOLOWER (s[0]) == 'r')
@@ -585,9 +610,75 @@ parse_exp (char *s, expressionS *e)
 }
 
 /* Symbol modifiers (@GOT, @PLT, @GOTOFF).  */
+#define IMM_NONE   0
 #define IMM_GOT    1
 #define IMM_PLT    2
 #define IMM_GOTOFF 3
+#define IMM_TLSGD  4
+#define IMM_TLSLD  5
+#define IMM_TLSDTPMOD 6
+#define IMM_TLSDTPREL 7
+#define IMM_TLSTPREL  8
+#define IMM_MAX    9
+
+struct imm_type {
+       char *isuffix;   /* Suffix String */
+       int itype;       /* Suffix Type */
+       int otype;       /* Offset Type */
+};
+
+/* These are NOT in assending order of type, GOTOFF is ahead to make
+   sure @GOTOFF does not get matched with @GOT  */
+static struct imm_type imm_types[] = {
+       { "NONE", IMM_NONE , 0 },
+       { "GOTOFF", IMM_GOTOFF , GOTOFF_OFFSET },
+       { "GOT", IMM_GOT , GOT_OFFSET },
+       { "PLT", IMM_PLT , PLT_OFFSET },
+       { "TLSGD", IMM_TLSGD , TLSGD_OFFSET },
+       { "TLSLDM", IMM_TLSLD, TLSLD_OFFSET },
+       { "TLSDTPMOD", IMM_TLSDTPMOD, TLSDTPMOD_OFFSET },
+       { "TLSDTPREL", IMM_TLSDTPREL, TLSDTPREL_OFFSET },
+       { "TLSTPREL", IMM_TLSTPREL, TLSTPREL_OFFSET }
+};
+
+static int
+match_imm (const char *s, int *ilen)
+{
+  int i;
+  int slen;
+
+  /* Check for matching suffix */
+  for (i = 1; i < IMM_MAX; i++)
+    {
+      slen = strlen (imm_types[i].isuffix);
+
+      if (strncmp (imm_types[i].isuffix, s, slen) == 0)
+        {
+          *ilen = slen;
+          return imm_types[i].itype;
+        }
+    } /* for */
+  *ilen = 0;
+  return 0;
+}
+
+static int
+get_imm_otype (int itype)
+{
+  int i, otype;
+
+  otype = 0;
+  /* Check for matching itype */
+  for (i = 1; i < IMM_MAX; i++)
+    {
+      if (imm_types[i].itype == itype)
+        {
+          otype = imm_types[i].otype;
+          break;
+        }
+    }
+  return otype;
+}
 
 static symbolS * GOT_symbol;
 
@@ -598,6 +689,9 @@ parse_imm (char * s, expressionS * e, int min, int max)
 {
   char *new_pointer;
   char *atp;
+  int itype, ilen;
+
+  ilen = 0;
 
   /* Find the start of "@GOT" or "@PLT" suffix (if any) */
   for (atp = s; *atp != '@'; atp++)
@@ -606,26 +700,18 @@ parse_imm (char * s, expressionS * e, int min, int max)
 
   if (*atp == '@')
     {
-      if (strncmp (atp + 1, "GOTOFF", 5) == 0)
-       {
-         *atp = 0;
-         e->X_md = IMM_GOTOFF;
-       }
-      else if (strncmp (atp + 1, "GOT", 3) == 0)
-       {
-         *atp = 0;
-         e->X_md = IMM_GOT;
-       }
-      else if (strncmp (atp + 1, "PLT", 3) == 0)
-       {
-         *atp = 0;
-         e->X_md = IMM_PLT;
-       }
+      itype = match_imm (atp + 1, &ilen);
+      if (itype != 0)
+        {
+          *atp = 0;
+          e->X_md = itype;
+        }
       else
-       {
-         atp = NULL;
-         e->X_md = 0;
-       }
+        {
+          atp = NULL;
+          e->X_md = 0;
+          ilen = 0;
+        }
       *atp = 0;
     }
   else
@@ -641,6 +727,11 @@ parse_imm (char * s, expressionS * e, int min, int max)
 
   new_pointer = parse_exp (s, e);
 
+  if (!GOT_symbol && ! strncmp (s, GOT_SYMBOL_NAME, 20))
+    {
+      GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME);
+    }
+
   if (e->X_op == O_absent)
     ; /* An error message has already been emitted.  */
   else if ((e->X_op != O_constant && e->X_op != O_symbol) )
@@ -656,9 +747,7 @@ parse_imm (char * s, expressionS * e, int min, int max)
     {
       *atp = '@'; /* restore back (needed?)  */
       if (new_pointer >= atp)
-        new_pointer += (e->X_md == IMM_GOTOFF)?7:4;
-      /* sizeof("@GOTOFF", "@GOT" or "@PLT") */
-
+        new_pointer += ilen + 1; /* sizeof (imm_suffix) + 1 for '@' */
     }
   return new_pointer;
 }
@@ -713,7 +802,7 @@ check_got (int * got_type, int * got_len)
   return tmpbuf;
 }
 
-extern void
+extern bfd_reloc_code_real_type
 parse_cons_expression_microblaze (expressionS *exp, int size)
 {
   if (size == 4)
@@ -739,6 +828,7 @@ parse_cons_expression_microblaze (expressionS *exp, int size)
     }
   else
     expression (exp);
+  return BFD_RELOC_NONE;
 }
 
 /* This is the guts of the machine-dependent assembler.  STR points to a
@@ -757,6 +847,7 @@ check_spl_reg (unsigned * reg)
       || (*reg == REG_PID)   || (*reg == REG_ZPR)
       || (*reg == REG_TLBX)  || (*reg == REG_TLBLO)
       || (*reg == REG_TLBHI) || (*reg == REG_TLBSX)
+      || (*reg == REG_SHR)   || (*reg == REG_SLR)
       || (*reg >= REG_PVR+MIN_PVR_REGNUM && *reg <= REG_PVR+MAX_PVR_REGNUM))
     return TRUE;
 
@@ -777,7 +868,14 @@ tc_microblaze_fix_adjustable (struct fix *fixP)
   if (fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOTOFF
       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_GOTOFF
       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOT
-      || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_PLT)
+      || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_PLT
+      || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGD
+      || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSLD
+      || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPMOD
+      || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPREL
+      || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSDTPREL
+      || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL
+      || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSTPREL)
     return 0;
 
   return 1;
@@ -925,12 +1023,8 @@ md_assemble (char * str)
            opc = str_microblaze_rw_anchor;
          else
            opc = NULL;
-         if (exp.X_md == IMM_GOT)
-           subtype = GOT_OFFSET;
-         else if (exp.X_md == IMM_PLT)
-           subtype = PLT_OFFSET;
-         else if (exp.X_md == IMM_GOTOFF)
-           subtype = GOTOFF_OFFSET;
+         if (exp.X_md != 0)
+           subtype = get_imm_otype(exp.X_md);
          else
            subtype = opcode->inst_offset_type;
 
@@ -1198,9 +1292,6 @@ md_assemble (char * str)
           as_fatal (_("Error in statement syntax"));
           immed = 0;
         }
-      /* Check for spl registers.  */
-      if (check_spl_reg (&reg1))
-        as_fatal (_("Cannot use special register with this instruction"));
       inst |= (immed << IMM_LOW) & RFSL_MASK;
       output = frag_more (isize);
       break;
@@ -1280,6 +1371,10 @@ md_assemble (char * str)
         immed = opcode->immval_mask | REG_TLBLO_MASK;
       else if (reg2 == REG_TLBHI)
         immed = opcode->immval_mask | REG_TLBHI_MASK;
+      else if (reg2 == REG_SHR)
+        immed = opcode->immval_mask | REG_SHR_MASK;
+      else if (reg2 == REG_SLR)
+        immed = opcode->immval_mask | REG_SLR_MASK;
       else if (reg2 >= (REG_PVR+MIN_PVR_REGNUM) && reg2 <= (REG_PVR+MAX_PVR_REGNUM))
        immed = opcode->immval_mask | REG_PVR_MASK | reg2;
       else
@@ -1331,6 +1426,10 @@ md_assemble (char * str)
         immed = opcode->immval_mask | REG_TLBHI_MASK;
       else if (reg1 == REG_TLBSX)
         immed = opcode->immval_mask | REG_TLBSX_MASK;
+      else if (reg1 == REG_SHR)
+        immed = opcode->immval_mask | REG_SHR_MASK;
+      else if (reg1 == REG_SLR)
+        immed = opcode->immval_mask | REG_SLR_MASK;
       else
         as_fatal (_("invalid value for special purpose register"));
       inst |= (reg2 << RA_LOW) & RA_MASK;
@@ -1338,16 +1437,16 @@ md_assemble (char * str)
       output = frag_more (isize);
       break;
 
-    case INST_TYPE_RD_R1_SPECIAL:
+    case INST_TYPE_R1_R2_SPECIAL:
       if (strcmp (op_end, ""))
-        op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
+        op_end = parse_reg (op_end + 1, &reg1);  /* Get r1.  */
       else
        {
           as_fatal (_("Error in statement syntax"));
           reg1 = 0;
         }
       if (strcmp (op_end, ""))
-        op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
+        op_end = parse_reg (op_end + 1, &reg2);  /* Get r2.  */
       else
        {
           as_fatal (_("Error in statement syntax"));
@@ -1361,7 +1460,6 @@ md_assemble (char * str)
         as_fatal (_("Cannot use special register with this instruction"));
 
       /* insn wic ra, rb => wic ra, ra, rb.  */
-      inst |= (reg1 << RD_LOW) & RD_MASK;
       inst |= (reg1 << RA_LOW) & RA_MASK;
       inst |= (reg2 << RB_LOW) & RB_MASK;
 
@@ -1417,12 +1515,11 @@ md_assemble (char * str)
           char *opc = NULL;
           relax_substateT subtype;
 
-         if (exp.X_md == IMM_GOT)
-           subtype = GOT_OFFSET;
-         else if (exp.X_md == IMM_PLT)
-           subtype = PLT_OFFSET;
+         if (exp.X_md != 0)
+           subtype = get_imm_otype(exp.X_md);
          else
            subtype = opcode->inst_offset_type;
+
          output = frag_var (rs_machine_dependent,
                             isize * 2, /* maxm of 2 words.  */
                             isize,     /* minm of 1 word.  */
@@ -1484,12 +1581,11 @@ md_assemble (char * str)
           char *opc = NULL;
           relax_substateT subtype;
 
-          if (exp.X_md == IMM_GOT)
-            subtype = GOT_OFFSET;
-          else if (exp.X_md == IMM_PLT)
-            subtype = PLT_OFFSET;
-          else
+         if (exp.X_md != 0)
+           subtype = get_imm_otype(exp.X_md);
+         else
            subtype = opcode->inst_offset_type;
+
           output = frag_var (rs_machine_dependent,
                             isize * 2, /* maxm of 2 words.  */
                             isize,     /* minm of 1 word.  */
@@ -1557,12 +1653,11 @@ md_assemble (char * str)
           char *opc = NULL;
           relax_substateT subtype;
 
-          if (exp.X_md == IMM_GOT)
-            subtype = GOT_OFFSET;
-          else if (exp.X_md == IMM_PLT)
-            subtype = PLT_OFFSET;
-          else
-            subtype = opcode->inst_offset_type;
+         if (exp.X_md != 0)
+           subtype = get_imm_otype(exp.X_md);
+         else
+           subtype = opcode->inst_offset_type;
+
           output = frag_var (rs_machine_dependent,
                             isize * 2, /* maxm of 2 words.  */
                             isize,     /* minm of 1 word.  */
@@ -1605,6 +1700,24 @@ md_assemble (char * str)
       output = frag_more (isize);
       break;
 
+    case INST_TYPE_IMM5:
+      if (strcmp(op_end, ""))
+        op_end = parse_imm (op_end + 1, & exp, MIN_IMM5, MAX_IMM5);
+      else
+        as_fatal(_("Error in statement syntax"));
+      if (exp.X_op != O_constant) {
+        as_warn(_("Symbol used as immediate for mbar instruction"));
+      } else {
+        output = frag_more (isize);
+        immed = exp.X_add_number;
+      }
+      if (immed != (immed % 32)) {
+        as_warn(_("Immediate value for mbar > 32. using <value %% 32>"));
+        immed = immed % 32;
+      }
+      inst |= (immed << IMM_MBAR);
+      break;
+
     default:
       as_fatal (_("unimplemented opcode \"%s\""), name);
     }
@@ -1710,6 +1823,8 @@ const char * md_shortopts = "";
 
 struct option md_longopts[] =
 {
+  {"EB", no_argument, NULL, OPTION_EB},
+  {"EL", no_argument, NULL, OPTION_EL},
   { NULL,          no_argument, NULL, 0}
 };
 
@@ -1808,6 +1923,24 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
       fragP->fr_fix += INST_WORD_SIZE * 2;
       fragP->fr_var = 0;
       break;
+    case TLSGD_OFFSET:
+      fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
+              fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_TLSGD);
+      fragP->fr_fix += INST_WORD_SIZE * 2;
+      fragP->fr_var = 0;
+      break;
+    case TLSLD_OFFSET:
+      fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
+              fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_TLSLD);
+      fragP->fr_fix += INST_WORD_SIZE * 2;
+      fragP->fr_var = 0;
+      break;
+    case TLSDTPREL_OFFSET:
+      fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
+              fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_TLSDTPREL);
+      fragP->fr_fix += INST_WORD_SIZE * 2;
+      fragP->fr_var = 0;
+      break;
 
     default:
       abort ();
@@ -1989,6 +2122,11 @@ md_apply_fix (fixS *   fixP,
        }
       break;
 
+    case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
+    case BFD_RELOC_MICROBLAZE_64_TLSGD:
+    case BFD_RELOC_MICROBLAZE_64_TLSLD:
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+
     case BFD_RELOC_MICROBLAZE_64_GOTPC:
     case BFD_RELOC_MICROBLAZE_64_GOT:
     case BFD_RELOC_MICROBLAZE_64_PLT:
@@ -2167,11 +2305,16 @@ md_estimate_size_before_relax (fragS * fragP,
     case GOT_OFFSET:
     case PLT_OFFSET:
     case GOTOFF_OFFSET:
+    case TLSGD_OFFSET:
+    case TLSLD_OFFSET:
+    case TLSTPREL_OFFSET:
+    case TLSDTPREL_OFFSET:
       fragP->fr_var = INST_WORD_SIZE*2;
       break;
     case DEFINED_RO_SEGMENT:
     case DEFINED_RW_SEGMENT:
     case DEFINED_PC_OFFSET:
+    case TLSDTPMOD_OFFSET:
       fragP->fr_var = INST_WORD_SIZE;
       break;
     default:
@@ -2255,6 +2398,13 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
     case BFD_RELOC_MICROBLAZE_64_PLT:
     case BFD_RELOC_MICROBLAZE_64_GOTOFF:
     case BFD_RELOC_MICROBLAZE_32_GOTOFF:
+    case BFD_RELOC_MICROBLAZE_64_TLSGD:
+    case BFD_RELOC_MICROBLAZE_64_TLSLD:
+    case BFD_RELOC_MICROBLAZE_32_TLSDTPMOD:
+    case BFD_RELOC_MICROBLAZE_32_TLSDTPREL:
+    case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
+    case BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL:
+    case BFD_RELOC_MICROBLAZE_64_TLSTPREL:
       code = fixp->fx_r_type;
       break;
 
@@ -2307,6 +2457,12 @@ md_parse_option (int c, char * arg ATTRIBUTE_UNUSED)
 {
   switch (c)
     {
+    case OPTION_EB:
+      target_big_endian = 1;
+      break;
+    case OPTION_EL:
+      target_big_endian = 0;
+      break;
     default:
       return 0;
     }
@@ -2330,11 +2486,9 @@ void
 cons_fix_new_microblaze (fragS * frag,
                         int where,
                         int size,
-                        expressionS *exp)
+                        expressionS *exp,
+                        bfd_reloc_code_real_type r)
 {
-
-  bfd_reloc_code_real_type r;
-
   if ((exp->X_op == O_subtract) && (exp->X_add_symbol) &&
       (exp->X_op_symbol) && (now_seg != absolute_section) && (size == 4)
       && (!S_IS_LOCAL (exp->X_op_symbol)))
This page took 0.04308 seconds and 4 git commands to generate.