rx: Add target rx-*-linux.
[deliverable/binutils-gdb.git] / gas / config / tc-s390.c
index 97edcc3b69b87d69bd08484b8228a54f98f13539..6b58c4cb33a6890854e64215d89d080b6f072de5 100644 (file)
@@ -1,12 +1,12 @@
 /* tc-s390.c -- Assemble for the S390
 /* tc-s390.c -- Assemble for the S390
-   Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2000-2018 Free Software Foundation, Inc.
    Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the Free
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the Free
-   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 
-#include <stdio.h>
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
-#include "struc-symbol.h"
 #include "dwarf2dbg.h"
 #include "dwarf2dbg.h"
+#include "dw2gencfi.h"
 
 #include "opcode/s390.h"
 #include "elf/s390.h"
 
 #include "opcode/s390.h"
 #include "elf/s390.h"
 #ifndef DEFAULT_ARCH
 #define DEFAULT_ARCH "s390"
 #endif
 #ifndef DEFAULT_ARCH
 #define DEFAULT_ARCH "s390"
 #endif
-static char *default_arch = DEFAULT_ARCH;
+static const char *default_arch = DEFAULT_ARCH;
 /* Either 32 or 64, selects file format.  */
 static int s390_arch_size = 0;
 
 /* Either 32 or 64, selects file format.  */
 static int s390_arch_size = 0;
 
+/* If no -march option was given default to the highest available CPU.
+   Since with S/390 a newer CPU always supports everything from its
+   predecessors this will accept every valid asm input.  */
+static unsigned int current_cpu = S390_OPCODE_MAXCPU - 1;
+/* All facilities are enabled by default.  */
+static unsigned int current_flags = S390_INSTR_FLAG_FACILITY_MASK;
+/* The mode mask default is picked in init_default_arch depending on
+   the current cpu.  */
 static unsigned int current_mode_mask = 0;
 static unsigned int current_mode_mask = 0;
-static unsigned int current_cpu = -1U;
+
+/* Set to TRUE if the highgprs flag in the ELF header needs to be set
+   for the output file.  */
+static bfd_boolean set_highgprs_p = FALSE;
 
 /* Whether to use user friendly register names. Default is TRUE.  */
 #ifndef TARGET_REG_NAMES_P
 
 /* Whether to use user friendly register names. Default is TRUE.  */
 #ifndef TARGET_REG_NAMES_P
@@ -70,176 +80,67 @@ const char EXP_CHARS[] = "eE";
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
 
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
 
+/* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
+int s390_cie_data_alignment;
+
 /* The target specific pseudo-ops which we support.  */
 
 /* Define the prototypes for the pseudo-ops */
 /* The target specific pseudo-ops which we support.  */
 
 /* Define the prototypes for the pseudo-ops */
-static void s390_byte PARAMS ((int));
-static void s390_elf_cons PARAMS ((int));
-static void s390_bss PARAMS ((int));
-static void s390_insn PARAMS ((int));
-static void s390_literals PARAMS ((int));
+static void s390_byte (int);
+static void s390_elf_cons (int);
+static void s390_bss (int);
+static void s390_insn (int);
+static void s390_literals (int);
+static void s390_machine (int);
+static void s390_machinemode (int);
 
 const pseudo_typeS md_pseudo_table[] =
 {
 
 const pseudo_typeS md_pseudo_table[] =
 {
-  { "align", s_align_bytes, 0 },
+  { "align",        s_align_bytes,      0 },
   /* Pseudo-ops which must be defined.  */
   /* Pseudo-ops which must be defined.  */
-  { "bss",      s390_bss,       0 },
-  { "insn",     s390_insn,      0 },
+  { "bss",          s390_bss,           0 },
+  { "insn",         s390_insn,          0 },
   /* Pseudo-ops which must be overridden.  */
   /* Pseudo-ops which must be overridden.  */
-  { "byte",    s390_byte,      0 },
-  { "short",    s390_elf_cons,  2 },
-  { "long",    s390_elf_cons,  4 },
-  { "quad",     s390_elf_cons,  8 },
-  { "ltorg",    s390_literals,  0 },
-  { "string",   stringer,       2 },
-  { NULL,      NULL,           0 }
-};
-
-
-/* Structure to hold information about predefined registers.  */
-struct pd_reg
-  {
-    char *name;
-    int value;
-  };
-
-/* List of registers that are pre-defined:
-
-   Each access register has a predefined name of the form:
-     a<reg_num> which has the value <reg_num>.
-
-   Each control register has a predefined name of the form:
-     c<reg_num> which has the value <reg_num>.
-
-   Each general register has a predefined name of the form:
-     r<reg_num> which has the value <reg_num>.
-
-   Each floating point register a has predefined name of the form:
-     f<reg_num> which has the value <reg_num>.
-
-   There are individual registers as well:
-     sp     has the value 15
-     lit    has the value 12
-
-   The table is sorted. Suitable for searching by a binary search.  */
-
-static const struct pd_reg pre_defined_registers[] =
-{
-  { "a0", 0 },     /* Access registers */
-  { "a1", 1 },
-  { "a10", 10 },
-  { "a11", 11 },
-  { "a12", 12 },
-  { "a13", 13 },
-  { "a14", 14 },
-  { "a15", 15 },
-  { "a2", 2 },
-  { "a3", 3 },
-  { "a4", 4 },
-  { "a5", 5 },
-  { "a6", 6 },
-  { "a7", 7 },
-  { "a8", 8 },
-  { "a9", 9 },
-
-  { "c0", 0 },     /* Control registers */
-  { "c1", 1 },
-  { "c10", 10 },
-  { "c11", 11 },
-  { "c12", 12 },
-  { "c13", 13 },
-  { "c14", 14 },
-  { "c15", 15 },
-  { "c2", 2 },
-  { "c3", 3 },
-  { "c4", 4 },
-  { "c5", 5 },
-  { "c6", 6 },
-  { "c7", 7 },
-  { "c8", 8 },
-  { "c9", 9 },
-
-  { "f0", 0 },     /* Floating point registers */
-  { "f1", 1 },
-  { "f10", 10 },
-  { "f11", 11 },
-  { "f12", 12 },
-  { "f13", 13 },
-  { "f14", 14 },
-  { "f15", 15 },
-  { "f2", 2 },
-  { "f3", 3 },
-  { "f4", 4 },
-  { "f5", 5 },
-  { "f6", 6 },
-  { "f7", 7 },
-  { "f8", 8 },
-  { "f9", 9 },
-
-  { "lit", 13 },   /* Pointer to literal pool */
-
-  { "r0", 0 },     /* General purpose registers */
-  { "r1", 1 },
-  { "r10", 10 },
-  { "r11", 11 },
-  { "r12", 12 },
-  { "r13", 13 },
-  { "r14", 14 },
-  { "r15", 15 },
-  { "r2", 2 },
-  { "r3", 3 },
-  { "r4", 4 },
-  { "r5", 5 },
-  { "r6", 6 },
-  { "r7", 7 },
-  { "r8", 8 },
-  { "r9", 9 },
-
-  { "sp", 15 },   /* Stack pointer */
-
+  { "byte",        s390_byte,          0 },
+  { "short",        s390_elf_cons,      2 },
+  { "long",        s390_elf_cons,      4 },
+  { "quad",         s390_elf_cons,      8 },
+  { "ltorg",        s390_literals,      0 },
+  { "string",       stringer,           8 + 1 },
+  { "machine",      s390_machine,       0 },
+  { "machinemode",  s390_machinemode,   0 },
+  { NULL,          NULL,               0 }
 };
 
 };
 
-#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct pd_reg))
-
-static int reg_name_search
-  PARAMS ((const struct pd_reg *, int, const char *));
-static bfd_boolean register_name PARAMS ((expressionS *));
-static void init_default_arch PARAMS ((void));
-static void s390_insert_operand
-  PARAMS ((unsigned char *, const struct s390_operand *, offsetT, char *,
-          unsigned int));
-static char *md_gather_operands
-  PARAMS ((char *, unsigned char *, const struct s390_opcode *));
-
 /* Given NAME, find the register number associated with that name, return
    the integer value associated with the given name or -1 on failure.  */
 
 static int
 /* Given NAME, find the register number associated with that name, return
    the integer value associated with the given name or -1 on failure.  */
 
 static int
-reg_name_search (regs, regcount, name)
-     const struct pd_reg *regs;
-     int regcount;
-     const char *name;
+reg_name_search (const char *name)
 {
 {
-  int middle, low, high;
-  int cmp;
+  int val = -1;
 
 
-  low = 0;
-  high = regcount - 1;
+  if (strcasecmp (name, "lit") == 0)
+    return 13;
 
 
-  do
+  if (strcasecmp (name, "sp") == 0)
+    return 15;
+
+  if (name[0] != 'a' && name[0] != 'c' && name[0] != 'f'
+      && name[0] != 'r' && name[0] != 'v')
+    return -1;
+
+  if (ISDIGIT (name[1]))
     {
     {
-      middle = (low + high) / 2;
-      cmp = strcasecmp (name, regs[middle].name);
-      if (cmp < 0)
-       high = middle - 1;
-      else if (cmp > 0)
-       low = middle + 1;
-      else
-       return regs[middle].value;
+      val = name[1] - '0';
+      if (ISDIGIT (name[2]))
+       val = val * 10 + name[2] - '0';
     }
     }
-  while (low <= high);
 
 
-  return -1;
+  if ((name[0] != 'v' && val > 15) || val > 31)
+    val = -1;
+
+  return val;
 }
 
 
 }
 
 
@@ -256,8 +157,7 @@ reg_name_search (regs, regcount, name)
  */
 
 static bfd_boolean
  */
 
 static bfd_boolean
-register_name (expressionP)
-     expressionS *expressionP;
+register_name (expressionS *expressionP)
 {
   int reg_number;
   char *name;
 {
   int reg_number;
   char *name;
@@ -271,11 +171,11 @@ register_name (expressionP)
   else
     return FALSE;
 
   else
     return FALSE;
 
-  c = get_symbol_end ();
-  reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
+  c = get_symbol_name (&name);
+  reg_number = reg_name_search (name);
 
   /* Put back the delimiting char.  */
 
   /* Put back the delimiting char.  */
-  *input_line_pointer = c;
+  (void) restore_line_pointer (c);
 
   /* Look to see if it's in the register table.  */
   if (reg_number >= 0)
 
   /* Look to see if it's in the register table.  */
   if (reg_number >= 0)
@@ -300,7 +200,7 @@ register_name (expressionP)
 static struct hash_control *s390_opformat_hash;
 
 /* Opcode hash table.  */
 static struct hash_control *s390_opformat_hash;
 
 /* Opcode hash table.  */
-static struct hash_control *s390_opcode_hash;
+static struct hash_control *s390_opcode_hash = NULL;
 
 /* Flags to set in the elf header */
 static flagword s390_flags = 0;
 
 /* Flags to set in the elf header */
 static flagword s390_flags = 0;
@@ -308,8 +208,8 @@ static flagword s390_flags = 0;
 symbolS *GOT_symbol;           /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 
 #ifndef WORKING_DOT_WORD
 symbolS *GOT_symbol;           /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 
 #ifndef WORKING_DOT_WORD
-const int md_short_jump_size = 4;
-const int md_long_jump_size = 4;
+int md_short_jump_size = 4;
+int md_long_jump_size = 4;
 #endif
 
 const char *md_shortopts = "A:m:kVQ:";
 #endif
 
 const char *md_shortopts = "A:m:kVQ:";
@@ -321,33 +221,34 @@ size_t md_longopts_size = sizeof (md_longopts);
 /* Initialize the default opcode arch and word size from the default
    architecture name if not specified by an option.  */
 static void
 /* Initialize the default opcode arch and word size from the default
    architecture name if not specified by an option.  */
 static void
-init_default_arch ()
+init_default_arch (void)
 {
   if (strcmp (default_arch, "s390") == 0)
     {
       if (s390_arch_size == 0)
        s390_arch_size = 32;
 {
   if (strcmp (default_arch, "s390") == 0)
     {
       if (s390_arch_size == 0)
        s390_arch_size = 32;
-      if (current_mode_mask == 0)
-       current_mode_mask = 1 << S390_OPCODE_ESA;
-      if (current_cpu == -1U)
-       current_cpu = S390_OPCODE_G5;
     }
   else if (strcmp (default_arch, "s390x") == 0)
     {
       if (s390_arch_size == 0)
        s390_arch_size = 64;
     }
   else if (strcmp (default_arch, "s390x") == 0)
     {
       if (s390_arch_size == 0)
        s390_arch_size = 64;
-      if (current_mode_mask == 0)
-       current_mode_mask = 1 << S390_OPCODE_ZARCH;
-      if (current_cpu == -1U)
-       current_cpu = S390_OPCODE_Z900;
     }
   else
     }
   else
-    as_fatal ("Invalid default architecture, broken assembler.");
+    as_fatal (_("Invalid default architecture, broken assembler."));
+
+  if (current_mode_mask == 0)
+    {
+      /* Default to z/Architecture mode if the CPU supports it.  */
+      if (current_cpu < S390_OPCODE_Z900)
+       current_mode_mask = 1 << S390_OPCODE_ESA;
+      else
+       current_mode_mask = 1 << S390_OPCODE_ZARCH;
+    }
 }
 
 /* Called by TARGET_FORMAT.  */
 const char *
 }
 
 /* Called by TARGET_FORMAT.  */
 const char *
-s390_target_format ()
+s390_target_format (void)
 {
   /* We don't get a chance to initialize anything before we're called,
      so handle that now.  */
 {
   /* We don't get a chance to initialize anything before we're called,
      so handle that now.  */
@@ -356,10 +257,140 @@ s390_target_format ()
   return s390_arch_size == 64 ? "elf64-s390" : "elf32-s390";
 }
 
   return s390_arch_size == 64 ? "elf64-s390" : "elf32-s390";
 }
 
+/* Map a cpu string ARG as given with -march= or .machine to the respective
+   enum s390_opcode_cpu_val value.  If ALLOW_EXTENSIONS is TRUE, the cpu name
+   can be followed by a list of cpu facility flags each beginning with the
+   character '+'.  The active cpu flags are returned through *RET_FLAGS.
+   In case of an error, S390_OPCODE_MAXCPU is returned.  */
+
+static unsigned int
+s390_parse_cpu (const char *         arg,
+               unsigned int * ret_flags,
+               bfd_boolean    allow_extensions)
+{
+  static struct
+  {
+    const char * name;
+    unsigned int name_len;
+    const char * alt_name;
+    unsigned int alt_name_len;
+    unsigned int flags;
+  } cpu_table[S390_OPCODE_MAXCPU] =
+  {
+    { STRING_COMMA_LEN ("g5"), STRING_COMMA_LEN ("arch3"), 0 },
+    { STRING_COMMA_LEN ("g6"), STRING_COMMA_LEN (""), 0 },
+    { STRING_COMMA_LEN ("z900"), STRING_COMMA_LEN ("arch5"), 0 },
+    { STRING_COMMA_LEN ("z990"), STRING_COMMA_LEN ("arch6"), 0 },
+    { STRING_COMMA_LEN ("z9-109"), STRING_COMMA_LEN (""), 0 },
+    { STRING_COMMA_LEN ("z9-ec"), STRING_COMMA_LEN ("arch7"), 0 },
+    { STRING_COMMA_LEN ("z10"), STRING_COMMA_LEN ("arch8"), 0 },
+    { STRING_COMMA_LEN ("z196"), STRING_COMMA_LEN ("arch9"), 0 },
+    { STRING_COMMA_LEN ("zEC12"), STRING_COMMA_LEN ("arch10"),
+      S390_INSTR_FLAG_HTM },
+    { STRING_COMMA_LEN ("z13"), STRING_COMMA_LEN ("arch11"),
+      S390_INSTR_FLAG_HTM | S390_INSTR_FLAG_VX },
+    { STRING_COMMA_LEN ("z14"), STRING_COMMA_LEN ("arch12"),
+      S390_INSTR_FLAG_HTM | S390_INSTR_FLAG_VX }
+  };
+  static struct
+  {
+    const char * name;
+    unsigned int mask;
+    bfd_boolean  on;
+  } cpu_flags[] =
+  {
+    { "htm",   S390_INSTR_FLAG_HTM, TRUE },
+    { "nohtm", S390_INSTR_FLAG_HTM, FALSE },
+    { "vx",    S390_INSTR_FLAG_VX, TRUE },
+    { "novx",  S390_INSTR_FLAG_VX, FALSE }
+  };
+  unsigned int icpu;
+  char *ilp_bak;
+
+  icpu = S390_OPCODE_MAXCPU;
+  if (strncmp (arg, "all", 3) == 0 && (arg[3] == 0 || arg[3] == '+'))
+    {
+      icpu = S390_OPCODE_MAXCPU - 1;
+      arg += 3;
+    }
+  else
+    {
+      for (icpu = 0; icpu < S390_OPCODE_MAXCPU; icpu++)
+       {
+         unsigned int l, l_alt;
+
+         l = cpu_table[icpu].name_len;
+
+         if (strncmp (arg, cpu_table[icpu].name, l) == 0
+             && (arg[l] == 0 || arg[l] == '+'))
+           {
+             arg += l;
+             break;
+           }
+
+         l_alt = cpu_table[icpu].alt_name_len;
+
+         if (l_alt > 0
+             && strncmp (arg, cpu_table[icpu].alt_name, l_alt) == 0
+             && (arg[l_alt] == 0 || arg[l_alt] == '+'))
+           {
+             arg += l_alt;
+             break;
+           }
+       }
+    }
+
+  if (icpu == S390_OPCODE_MAXCPU)
+    return S390_OPCODE_MAXCPU;
+
+  ilp_bak = input_line_pointer;
+  if (icpu != S390_OPCODE_MAXCPU)
+    {
+      input_line_pointer = (char *) arg;
+      *ret_flags = (cpu_table[icpu].flags & S390_INSTR_FLAG_FACILITY_MASK);
+
+      while (*input_line_pointer == '+' && allow_extensions)
+       {
+         unsigned int iflag;
+         char *sym;
+         char c;
+
+         input_line_pointer++;
+         c = get_symbol_name (&sym);
+         for (iflag = 0; iflag < ARRAY_SIZE (cpu_flags); iflag++)
+           {
+             if (strcmp (sym, cpu_flags[iflag].name) == 0)
+               {
+                 if (cpu_flags[iflag].on)
+                   *ret_flags |= cpu_flags[iflag].mask;
+                 else
+                   *ret_flags &= ~cpu_flags[iflag].mask;
+                 break;
+               }
+           }
+         if (iflag == ARRAY_SIZE (cpu_flags))
+           as_bad (_("no such machine extension `%s'"), sym - 1);
+         *input_line_pointer = c;
+         if (iflag == ARRAY_SIZE (cpu_flags))
+           break;
+       }
+    }
+
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer != 0 && *input_line_pointer != '\n')
+    {
+      as_bad (_("junk at end of machine string, first unrecognized character"
+               " is `%c'"), *input_line_pointer);
+      icpu = S390_OPCODE_MAXCPU;
+    }
+  input_line_pointer = ilp_bak;
+
+  return icpu;
+}
+
 int
 int
-md_parse_option (c, arg)
-     int c;
-     char *arg;
+md_parse_option (int c, const char *arg)
 {
   switch (c)
     {
 {
   switch (c)
     {
@@ -386,17 +417,16 @@ md_parse_option (c, arg)
        current_mode_mask = 1 << S390_OPCODE_ESA;
 
       else if (arg != NULL && strcmp (arg, "zarch") == 0)
        current_mode_mask = 1 << S390_OPCODE_ESA;
 
       else if (arg != NULL && strcmp (arg, "zarch") == 0)
-       current_mode_mask = 1 << S390_OPCODE_ZARCH;
+       {
+         if (s390_arch_size == 32)
+           set_highgprs_p = TRUE;
+         current_mode_mask = 1 << S390_OPCODE_ZARCH;
+       }
 
       else if (arg != NULL && strncmp (arg, "arch=", 5) == 0)
        {
 
       else if (arg != NULL && strncmp (arg, "arch=", 5) == 0)
        {
-         if (strcmp (arg + 5, "g5") == 0)
-           current_cpu = S390_OPCODE_G5;
-         else if (strcmp (arg + 5, "g6") == 0)
-           current_cpu = S390_OPCODE_G6;
-         else if (strcmp (arg + 5, "z900") == 0)
-           current_cpu = S390_OPCODE_Z900;
-         else
+         current_cpu = s390_parse_cpu (arg + 5, &current_flags, FALSE);
+         if (current_cpu == S390_OPCODE_MAXCPU)
            {
              as_bad (_("invalid switch -m%s"), arg);
              return 0;
            {
              as_bad (_("invalid switch -m%s"), arg);
              return 0;
@@ -411,13 +441,13 @@ md_parse_option (c, arg)
       break;
 
     case 'A':
       break;
 
     case 'A':
-      /* Option -A is deprecated. Still available for compatability.  */
+      /* Option -A is deprecated. Still available for compatibility.  */
       if (arg != NULL && strcmp (arg, "esa") == 0)
        current_cpu = S390_OPCODE_G5;
       else if (arg != NULL && strcmp (arg, "esame") == 0)
        current_cpu = S390_OPCODE_Z900;
       else
       if (arg != NULL && strcmp (arg, "esa") == 0)
        current_cpu = S390_OPCODE_G5;
       else if (arg != NULL && strcmp (arg, "esame") == 0)
        current_cpu = S390_OPCODE_Z900;
       else
-       as_bad ("invalid architecture -A%s", arg);
+       as_bad (_("invalid architecture -A%s"), arg);
       break;
 
       /* -V: SVR4 argument to print version ID.  */
       break;
 
       /* -V: SVR4 argument to print version ID.  */
@@ -438,8 +468,7 @@ md_parse_option (c, arg)
 }
 
 void
 }
 
 void
-md_show_usage (stream)
-     FILE *stream;
+md_show_usage (FILE *stream)
 {
   fprintf (stream, _("\
         S390 options:\n\
 {
   fprintf (stream, _("\
         S390 options:\n\
@@ -453,21 +482,88 @@ md_show_usage (stream)
         -Qy, -Qn          ignored\n"));
 }
 
         -Qy, -Qn          ignored\n"));
 }
 
+/* Generate the hash table mapping mnemonics to struct s390_opcode.
+   This table is built at startup and whenever the CPU level is
+   changed using .machine.  */
+
+static void
+s390_setup_opcodes (void)
+{
+  const struct s390_opcode *op;
+  const struct s390_opcode *op_end;
+  bfd_boolean dup_insn = FALSE;
+  const char *retval;
+
+  if (s390_opcode_hash != NULL)
+    hash_die (s390_opcode_hash);
+
+  /* Insert the opcodes into a hash table.  */
+  s390_opcode_hash = hash_new ();
+
+  op_end = s390_opcodes + s390_num_opcodes;
+  for (op = s390_opcodes; op < op_end; op++)
+    {
+      int use_opcode;
+
+      while (op < op_end - 1 && strcmp(op->name, op[1].name) == 0)
+       {
+          if (op->min_cpu <= current_cpu && (op->modes & current_mode_mask))
+           break;
+         op++;
+        }
+
+      if ((op->modes & current_mode_mask) == 0)
+       use_opcode = 0;
+      else if ((op->flags & S390_INSTR_FLAG_FACILITY_MASK) == 0)
+       {
+         /* Opcodes that do not belong to a specific facility are enabled if
+            present in the selected cpu.  */
+         use_opcode = (op->min_cpu <= current_cpu);
+       }
+      else
+       {
+         unsigned int f;
+
+         /* Opcodes of a specific facility are enabled if the facility is
+            enabled.  Note: only some facilities are represented as flags.  */
+         f = (op->flags & S390_INSTR_FLAG_FACILITY_MASK);
+         use_opcode = ((f & current_flags) == f);
+       }
+      if (use_opcode)
+       {
+         retval = hash_insert (s390_opcode_hash, op->name, (void *) op);
+         if (retval != (const char *) NULL)
+           {
+             as_bad (_("Internal assembler error for instruction %s"),
+                     op->name);
+             dup_insn = TRUE;
+           }
+       }
+
+      while (op < op_end - 1 && strcmp (op->name, op[1].name) == 0)
+       op++;
+    }
+
+  if (dup_insn)
+    abort ();
+}
+
 /* This function is called when the assembler starts up.  It is called
    after the options have been parsed and the output file has been
    opened.  */
 
 void
 /* This function is called when the assembler starts up.  It is called
    after the options have been parsed and the output file has been
    opened.  */
 
 void
-md_begin ()
+md_begin (void)
 {
 {
-  register const struct s390_opcode *op;
+  const struct s390_opcode *op;
   const struct s390_opcode *op_end;
   const struct s390_opcode *op_end;
-  bfd_boolean dup_insn = FALSE;
   const char *retval;
 
   /* Give a warning if the combination -m64-bit and -Aesa is used.  */
   if (s390_arch_size == 64 && current_cpu < S390_OPCODE_Z900)
   const char *retval;
 
   /* Give a warning if the combination -m64-bit and -Aesa is used.  */
   if (s390_arch_size == 64 && current_cpu < S390_OPCODE_Z900)
-    as_warn ("The 64 bit file format is used without esame instructions.");
+    as_warn (_("The 64 bit file format is used without esame instructions."));
+
+  s390_cie_data_alignment = -s390_arch_size / 8;
 
   /* Set the ELF flags if desired.  */
   if (s390_flags)
 
   /* Set the ELF flags if desired.  */
   if (s390_flags)
@@ -479,41 +575,22 @@ md_begin ()
   op_end = s390_opformats + s390_num_opformats;
   for (op = s390_opformats; op < op_end; op++)
     {
   op_end = s390_opformats + s390_num_opformats;
   for (op = s390_opformats; op < op_end; op++)
     {
-      retval = hash_insert (s390_opformat_hash, op->name, (PTR) op);
-      if (retval != (const char *) NULL)
-       {
-         as_bad (_("Internal assembler error for instruction format %s"),
-                 op->name);
-         dup_insn = TRUE;
-       }
-    }
-
-  /* Insert the opcodes into a hash table.  */
-  s390_opcode_hash = hash_new ();
-
-  op_end = s390_opcodes + s390_num_opcodes;
-  for (op = s390_opcodes; op < op_end; op++)
-    {
-      retval = hash_insert (s390_opcode_hash, op->name, (PTR) op);
+      retval = hash_insert (s390_opformat_hash, op->name, (void *) op);
       if (retval != (const char *) NULL)
       if (retval != (const char *) NULL)
-       {
-         as_bad (_("Internal assembler error for instruction %s"), op->name);
-         dup_insn = TRUE;
-       }
+       as_bad (_("Internal assembler error for instruction format %s"),
+               op->name);
     }
 
     }
 
-  if (dup_insn)
-    abort ();
+  s390_setup_opcodes ();
 
   record_alignment (text_section, 2);
   record_alignment (data_section, 2);
   record_alignment (bss_section, 2);
 
   record_alignment (text_section, 2);
   record_alignment (data_section, 2);
   record_alignment (bss_section, 2);
-
 }
 
 /* Called after all assembly has been done.  */
 void
 }
 
 /* Called after all assembly has been done.  */
 void
-s390_md_end ()
+s390_md_end (void)
 {
   if (s390_arch_size == 64)
     bfd_set_arch_mach (stdoutput, bfd_arch_s390, bfd_mach_s390_64);
 {
   if (s390_arch_size == 64)
     bfd_set_arch_mach (stdoutput, bfd_arch_s390, bfd_mach_s390_64);
@@ -521,28 +598,14 @@ s390_md_end ()
     bfd_set_arch_mach (stdoutput, bfd_arch_s390, bfd_mach_s390_31);
 }
 
     bfd_set_arch_mach (stdoutput, bfd_arch_s390, bfd_mach_s390_31);
 }
 
-void
-s390_align_code (fragP, count)
-     fragS *fragP;
-     int count;
-{
-  /* We use nop pattern 0x0707.  */
-  if (count > 0)
-    {
-      memset (fragP->fr_literal + fragP->fr_fix, 0x07, count);
-      fragP->fr_var = count;
-    }
-}
-
 /* Insert an operand value into an instruction.  */
 
 static void
 /* Insert an operand value into an instruction.  */
 
 static void
-s390_insert_operand (insn, operand, val, file, line)
-     unsigned char *insn;
-     const struct s390_operand *operand;
-     offsetT val;
-     char *file;
-     unsigned int line;
+s390_insert_operand (unsigned char *insn,
+                    const struct s390_operand *operand,
+                    offsetT val,
+                    const char *file,
+                    unsigned int line)
 {
   addressT uval;
   int offset;
 {
   addressT uval;
   int offset;
@@ -560,7 +623,7 @@ s390_insert_operand (insn, operand, val, file, line)
       if (val < min || val > max)
        {
          const char *err =
       if (val < min || val > max)
        {
          const char *err =
-           "operand out of range (%s not between %ld and %ld)";
+           _("operand out of range (%s not between %ld and %ld)");
          char buf[100];
 
          if (operand->flags & S390_OPERAND_PCREL)
          char buf[100];
 
          if (operand->flags & S390_OPERAND_PCREL)
@@ -578,6 +641,9 @@ s390_insert_operand (insn, operand, val, file, line)
        }
       /* val is ok, now restrict it to operand->bits bits.  */
       uval = (addressT) val & ((((addressT) 1 << (operand->bits-1)) << 1) - 1);
        }
       /* val is ok, now restrict it to operand->bits bits.  */
       uval = (addressT) val & ((((addressT) 1 << (operand->bits-1)) << 1) - 1);
+      /* val is restrict, now check for special case.  */
+      if (operand->bits == 20 && operand->shift == 20)
+        uval = (uval >> 12) | ((uval & 0xfff) << 8);
     }
   else
     {
     }
   else
     {
@@ -586,31 +652,68 @@ s390_insert_operand (insn, operand, val, file, line)
       max = (((addressT) 1 << (operand->bits - 1)) << 1) - 1;
       min = (offsetT) 0;
       uval = (addressT) val;
       max = (((addressT) 1 << (operand->bits - 1)) << 1) - 1;
       min = (offsetT) 0;
       uval = (addressT) val;
+
+      /* Vector register operands have an additional bit in the RXB
+        field.  */
+      if (operand->flags & S390_OPERAND_VR)
+       max = (max << 1) | 1;
+
       /* Length x in an instructions has real length x+1.  */
       if (operand->flags & S390_OPERAND_LENGTH)
        uval--;
       /* Check for underflow / overflow.  */
       if (uval < min || uval > max)
        {
       /* Length x in an instructions has real length x+1.  */
       if (operand->flags & S390_OPERAND_LENGTH)
        uval--;
       /* Check for underflow / overflow.  */
       if (uval < min || uval > max)
        {
-         const char *err =
-           "operand out of range (%s not between %ld and %ld)";
-         char buf[100];
-
          if (operand->flags & S390_OPERAND_LENGTH)
            {
              uval++;
              min++;
              max++;
            }
          if (operand->flags & S390_OPERAND_LENGTH)
            {
              uval++;
              min++;
              max++;
            }
-         sprint_value (buf, uval);
-         if (file == (char *) NULL)
-           as_bad (err, buf, (int) min, (int) max);
-         else
-           as_bad_where (file, line, err, buf, (int) min, (int) max);
+
+         as_bad_value_out_of_range (_("operand"), uval, (offsetT) min, (offsetT) max, file, line);
+
          return;
        }
     }
 
          return;
        }
     }
 
+  if (operand->flags & S390_OPERAND_VR)
+    {
+      /* Insert the extra bit into the RXB field.  */
+      switch (operand->shift)
+       {
+       case 8:
+         insn[4] |= (uval & 0x10) >> 1;
+         break;
+       case 12:
+         insn[4] |= (uval & 0x10) >> 2;
+         break;
+       case 16:
+         insn[4] |= (uval & 0x10) >> 3;
+         break;
+       case 32:
+         insn[4] |= (uval & 0x10) >> 4;
+         break;
+       }
+      uval &= 0xf;
+    }
+
+  if (operand->flags & S390_OPERAND_OR1)
+    uval |= 1;
+  if (operand->flags & S390_OPERAND_OR2)
+    uval |= 2;
+  if (operand->flags & S390_OPERAND_OR8)
+    uval |= 8;
+
+  /* Duplicate the operand at bit pos 12 to 16.  */
+  if (operand->flags & S390_OPERAND_CP16)
+    {
+      /* Copy VR operand at bit pos 12 to bit pos 16.  */
+      insn[2] |= uval << 4;
+      /* Copy the flag in the RXB field.  */
+      insn[4] |= (insn[4] & 4) >> 1;
+    }
+
   /* Insert fragments of the operand byte for byte.  */
   offset = operand->shift + operand->bits;
   uval <<= (-offset) & 7;
   /* Insert fragments of the operand byte for byte.  */
   offset = operand->shift + operand->bits;
   uval <<= (-offset) & 7;
@@ -624,19 +727,14 @@ s390_insert_operand (insn, operand, val, file, line)
 
 struct map_tls
   {
 
 struct map_tls
   {
-    char *string;
+    const char *string;
     int length;
     bfd_reloc_code_real_type reloc;
   };
 
     int length;
     bfd_reloc_code_real_type reloc;
   };
 
-static bfd_reloc_code_real_type s390_tls_suffix
-  PARAMS ((char **, expressionS *));
-
 /* Parse tls marker and return the desired relocation.  */
 static bfd_reloc_code_real_type
 /* Parse tls marker and return the desired relocation.  */
 static bfd_reloc_code_real_type
-s390_tls_suffix (str_p, exp_p)
-     char **str_p;
-     expressionS *exp_p;
+s390_tls_suffix (char **str_p, expressionS *exp_p)
 {
   static struct map_tls mapping[] =
   {
 {
   static struct map_tls mapping[] =
   {
@@ -704,22 +802,15 @@ elf_suffix_type;
 
 struct map_bfd
   {
 
 struct map_bfd
   {
-    char *string;
+    const char *string;
     int length;
     elf_suffix_type suffix;
   };
 
     int length;
     elf_suffix_type suffix;
   };
 
-static elf_suffix_type s390_elf_suffix PARAMS ((char **, expressionS *));
-static int s390_exp_compare PARAMS ((expressionS *exp1, expressionS *exp2));
-static elf_suffix_type s390_lit_suffix
-  PARAMS ((char **, expressionS *, elf_suffix_type));
-
 
 /* Parse @got/@plt/@gotoff. and return the desired relocation.  */
 static elf_suffix_type
 
 /* Parse @got/@plt/@gotoff. and return the desired relocation.  */
 static elf_suffix_type
-s390_elf_suffix (str_p, exp_p)
-     char **str_p;
-     expressionS *exp_p;
+s390_elf_suffix (char **str_p, expressionS *exp_p)
 {
   static struct map_bfd mapping[] =
   {
 {
   static struct map_bfd mapping[] =
   {
@@ -826,9 +917,7 @@ static int lp_count = 0;
 static int lpe_count = 0;
 
 static int
 static int lpe_count = 0;
 
 static int
-s390_exp_compare (exp1, exp2)
-     expressionS *exp1;
-     expressionS *exp2;
+s390_exp_compare (expressionS *exp1, expressionS *exp2)
 {
   if (exp1->X_op != exp2->X_op)
     return 0;
 {
   if (exp1->X_op != exp2->X_op)
     return 0;
@@ -841,6 +930,7 @@ s390_exp_compare (exp1, exp2)
 
     case O_big:
       as_bad (_("Can't handle O_big in s390_exp_compare"));
 
     case O_big:
       as_bad (_("Can't handle O_big in s390_exp_compare"));
+      return 0;
 
     case O_symbol:     /* X_add_symbol & X_add_number must be equal.  */
     case O_symbol_rva:
 
     case O_symbol:     /* X_add_symbol & X_add_number must be equal.  */
     case O_symbol_rva:
@@ -877,13 +967,10 @@ s390_exp_compare (exp1, exp2)
     }
 }
 
     }
 }
 
-/* Test for @lit and if its present make an entry in the literal pool and
+/* Test for @lit and if it's present make an entry in the literal pool and
    modify the current expression to be an offset into the literal pool.  */
 static elf_suffix_type
    modify the current expression to be an offset into the literal pool.  */
 static elf_suffix_type
-s390_lit_suffix (str_p, exp_p, suffix)
-     char **str_p;
-     expressionS *exp_p;
-     elf_suffix_type suffix;
+s390_lit_suffix (char **str_p, expressionS *exp_p, elf_suffix_type suffix)
 {
   bfd_reloc_code_real_type reloc;
   char tmp_name[64];
 {
   bfd_reloc_code_real_type reloc;
   char tmp_name[64];
@@ -968,7 +1055,7 @@ s390_lit_suffix (str_p, exp_p, suffix)
        }
       else
        {
        }
       else
        {
-         lpe = (struct s390_lpe *) xmalloc (sizeof (struct s390_lpe));
+         lpe = XNEW (struct s390_lpe);
        }
 
       lpe->ex = *exp_p;
        }
 
       lpe->ex = *exp_p;
@@ -1010,7 +1097,7 @@ s390_lit_suffix (str_p, exp_p, suffix)
     }
 
   /* Now change exp_p to the offset into the literal pool.
     }
 
   /* Now change exp_p to the offset into the literal pool.
-     Thats the expression: .L^Ax^By-.L^Ax   */
+     That's the expression: .L^Ax^By-.L^Ax   */
   exp_p->X_add_symbol = lpe->sym;
   exp_p->X_op_symbol = lp_sym;
   exp_p->X_op = O_subtract;
   exp_p->X_add_symbol = lpe->sym;
   exp_p->X_op_symbol = lp_sym;
   exp_p->X_op = O_subtract;
@@ -1026,8 +1113,7 @@ s390_lit_suffix (str_p, exp_p, suffix)
 /* Like normal .long/.short/.word, except support @got, etc.
    clobbers input_line_pointer, checks end-of-line.  */
 static void
 /* Like normal .long/.short/.word, except support @got, etc.
    clobbers input_line_pointer, checks end-of-line.  */
 static void
-s390_elf_cons (nbytes)
-     register int nbytes;      /* 1=.byte, 2=.word, 4=.long */
+s390_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long */)
 {
   expressionS exp;
   elf_suffix_type suffix;
 {
   expressionS exp;
   elf_suffix_type suffix;
@@ -1119,7 +1205,9 @@ s390_elf_cons (nbytes)
            {
              size = bfd_get_reloc_size (reloc_howto);
              if (size > nbytes)
            {
              size = bfd_get_reloc_size (reloc_howto);
              if (size > nbytes)
-               as_bad (_("%s relocations do not fit in %d bytes"),
+               as_bad (ngettext ("%s relocations do not fit in %d byte",
+                                 "%s relocations do not fit in %d bytes",
+                                 nbytes),
                        reloc_howto->name, nbytes);
              where = frag_more (nbytes);
              md_number_to_chars (where, 0, size);
                        reloc_howto->name, nbytes);
              where = frag_more (nbytes);
              md_number_to_chars (where, 0, size);
@@ -1156,10 +1244,9 @@ struct s390_fixup
 /* This routine is called for each instruction to be assembled.  */
 
 static char *
 /* This routine is called for each instruction to be assembled.  */
 
 static char *
-md_gather_operands (str, insn, opcode)
-     char *str;
-     unsigned char *insn;
-     const struct s390_opcode *opcode;
+md_gather_operands (char *str,
+                   unsigned char *insn,
+                   const struct s390_opcode *opcode)
 {
   struct s390_fixup fixups[MAX_INSN_FIXUPS];
   const struct s390_operand *operand;
 {
   struct s390_fixup fixups[MAX_INSN_FIXUPS];
   const struct s390_operand *operand;
@@ -1168,14 +1255,12 @@ md_gather_operands (str, insn, opcode)
   elf_suffix_type suffix;
   bfd_reloc_code_real_type reloc;
   int skip_optional;
   elf_suffix_type suffix;
   bfd_reloc_code_real_type reloc;
   int skip_optional;
-  int parentheses;
   char *f;
   int fc, i;
 
   while (ISSPACE (*str))
     str++;
 
   char *f;
   int fc, i;
 
   while (ISSPACE (*str))
     str++;
 
-  parentheses = 0;
   skip_optional = 0;
 
   /* Gather the operands.  */
   skip_optional = 0;
 
   /* Gather the operands.  */
@@ -1186,6 +1271,15 @@ md_gather_operands (str, insn, opcode)
 
       operand = s390_operands + *opindex_ptr;
 
 
       operand = s390_operands + *opindex_ptr;
 
+      if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2))
+         && *str == '\0')
+       {
+         /* Optional parameters might need to be ORed with a
+            value so calling s390_insert_operand is needed.  */
+         s390_insert_operand (insn, operand, 0, NULL, 0);
+         break;
+       }
+
       if (skip_optional && (operand->flags & S390_OPERAND_INDEX))
        {
          /* We do an early skip. For D(X,B) constructions the index
       if (skip_optional && (operand->flags & S390_OPERAND_INDEX))
        {
          /* We do an early skip. For D(X,B) constructions the index
@@ -1211,7 +1305,11 @@ md_gather_operands (str, insn, opcode)
       if (ex.X_op == O_illegal)
        as_bad (_("illegal operand"));
       else if (ex.X_op == O_absent)
       if (ex.X_op == O_illegal)
        as_bad (_("illegal operand"));
       else if (ex.X_op == O_absent)
-       as_bad (_("missing operand"));
+       {
+         if (opindex_ptr[0] == '\0')
+           break;
+         as_bad (_("missing operand"));
+       }
       else if (ex.X_op == O_register || ex.X_op == O_constant)
        {
          s390_lit_suffix (&str, &ex, ELF_SUFFIX_NONE);
       else if (ex.X_op == O_register || ex.X_op == O_constant)
        {
          s390_lit_suffix (&str, &ex, ELF_SUFFIX_NONE);
@@ -1229,14 +1327,31 @@ md_gather_operands (str, insn, opcode)
            }
          else
            {
            }
          else
            {
+             if ((operand->flags & S390_OPERAND_LENGTH)
+                 && ex.X_op != O_constant)
+               as_fatal (_("invalid length field specified"));
              if ((operand->flags & S390_OPERAND_INDEX)
                  && ex.X_add_number == 0
                  && warn_areg_zero)
              if ((operand->flags & S390_OPERAND_INDEX)
                  && ex.X_add_number == 0
                  && warn_areg_zero)
-               as_warn ("index register specified but zero");
+               as_warn (_("index register specified but zero"));
              if ((operand->flags & S390_OPERAND_BASE)
                  && ex.X_add_number == 0
                  && warn_areg_zero)
              if ((operand->flags & S390_OPERAND_BASE)
                  && ex.X_add_number == 0
                  && warn_areg_zero)
-               as_warn ("base register specified but zero");
+               as_warn (_("base register specified but zero"));
+             if ((operand->flags & S390_OPERAND_GPR)
+                 && (operand->flags & S390_OPERAND_REG_PAIR)
+                 && (ex.X_add_number & 1))
+               as_fatal (_("odd numbered general purpose register specified as "
+                           "register pair"));
+             if ((operand->flags & S390_OPERAND_FPR)
+                 && (operand->flags & S390_OPERAND_REG_PAIR)
+                 && ex.X_add_number != 0 && ex.X_add_number != 1
+                 && ex.X_add_number != 4 && ex.X_add_number != 5
+                 && ex.X_add_number != 8 && ex.X_add_number != 9
+                 && ex.X_add_number != 12 && ex.X_add_number != 13)
+               as_fatal (_("invalid floating point register pair.  Valid fp "
+                           "register pair operands are 0, 1, 4, 5, 8, 9, "
+                           "12 or 13."));
              s390_insert_operand (insn, operand, ex.X_add_number, NULL, 0);
            }
        }
              s390_insert_operand (insn, operand, ex.X_add_number, NULL, 0);
            }
        }
@@ -1248,8 +1363,12 @@ md_gather_operands (str, insn, opcode)
 
          if (suffix == ELF_SUFFIX_GOT)
            {
 
          if (suffix == ELF_SUFFIX_GOT)
            {
-             if (operand->flags & S390_OPERAND_DISP)
+             if ((operand->flags & S390_OPERAND_DISP) &&
+                 (operand->bits == 12))
                reloc = BFD_RELOC_390_GOT12;
                reloc = BFD_RELOC_390_GOT12;
+             else if ((operand->flags & S390_OPERAND_DISP) &&
+                      (operand->bits == 20))
+               reloc = BFD_RELOC_390_GOT20;
              else if ((operand->flags & S390_OPERAND_SIGNED)
                       && (operand->bits == 16))
                reloc = BFD_RELOC_390_GOT16;
              else if ((operand->flags & S390_OPERAND_SIGNED)
                       && (operand->bits == 16))
                reloc = BFD_RELOC_390_GOT16;
@@ -1260,8 +1379,14 @@ md_gather_operands (str, insn, opcode)
          else if (suffix == ELF_SUFFIX_PLT)
            {
              if ((operand->flags & S390_OPERAND_PCREL)
          else if (suffix == ELF_SUFFIX_PLT)
            {
              if ((operand->flags & S390_OPERAND_PCREL)
-                 && (operand->bits == 16))
+                 && (operand->bits == 12))
+               reloc = BFD_RELOC_390_PLT12DBL;
+             else if ((operand->flags & S390_OPERAND_PCREL)
+                      && (operand->bits == 16))
                reloc = BFD_RELOC_390_PLT16DBL;
                reloc = BFD_RELOC_390_PLT16DBL;
+             else if ((operand->flags & S390_OPERAND_PCREL)
+                      && (operand->bits == 24))
+               reloc = BFD_RELOC_390_PLT24DBL;
              else if ((operand->flags & S390_OPERAND_PCREL)
                       && (operand->bits == 32))
                reloc = BFD_RELOC_390_PLT32DBL;
              else if ((operand->flags & S390_OPERAND_PCREL)
                       && (operand->bits == 32))
                reloc = BFD_RELOC_390_PLT32DBL;
@@ -1301,6 +1426,9 @@ md_gather_operands (str, insn, opcode)
              if ((operand->flags & S390_OPERAND_DISP)
                  && (operand->bits == 12))
                reloc = BFD_RELOC_390_TLS_GOTIE12;
              if ((operand->flags & S390_OPERAND_DISP)
                  && (operand->bits == 12))
                reloc = BFD_RELOC_390_TLS_GOTIE12;
+             else if ((operand->flags & S390_OPERAND_DISP)
+                      && (operand->bits == 20))
+               reloc = BFD_RELOC_390_TLS_GOTIE20;
            }
          else if (suffix == ELF_SUFFIX_TLS_IE)
            {
            }
          else if (suffix == ELF_SUFFIX_TLS_IE)
            {
@@ -1328,8 +1456,8 @@ md_gather_operands (str, insn, opcode)
          /* After a displacement a block in parentheses can start.  */
          if (*str != '(')
            {
          /* After a displacement a block in parentheses can start.  */
          if (*str != '(')
            {
-             /* Check if parethesed block can be skipped. If the next
-                operand is neiter an optional operand nor a base register
+             /* Check if parenthesized block can be skipped. If the next
+                operand is neither an optional operand nor a base register
                 then we have a syntax error.  */
              operand = s390_operands + *(++opindex_ptr);
              if (!(operand->flags & (S390_OPERAND_INDEX|S390_OPERAND_BASE)))
                 then we have a syntax error.  */
              operand = s390_operands + *(++opindex_ptr);
              if (!(operand->flags & (S390_OPERAND_INDEX|S390_OPERAND_BASE)))
@@ -1339,11 +1467,20 @@ md_gather_operands (str, insn, opcode)
              while (!(operand->flags & S390_OPERAND_BASE))
                operand = s390_operands + *(++opindex_ptr);
 
              while (!(operand->flags & S390_OPERAND_BASE))
                operand = s390_operands + *(++opindex_ptr);
 
-             /* If there is a next operand it must be seperated by a comma.  */
+             /* If there is a next operand it must be separated by a comma.  */
              if (opindex_ptr[1] != '\0')
                {
              if (opindex_ptr[1] != '\0')
                {
-                 if (*str++ != ',')
-                   as_bad (_("syntax error; expected ,"));
+                 if (*str != ',')
+                   {
+                     while (opindex_ptr[1] != '\0')
+                       {
+                         operand = s390_operands + *(++opindex_ptr);
+                         as_bad (_("syntax error; expected ','"));
+                         break;
+                       }
+                   }
+                 else
+                   str++;
                }
            }
          else
                }
            }
          else
@@ -1368,15 +1505,39 @@ md_gather_operands (str, insn, opcode)
        }
       else if (operand->flags & S390_OPERAND_BASE)
        {
        }
       else if (operand->flags & S390_OPERAND_BASE)
        {
-         /* After the base register the parenthesed block ends.  */
+         /* After the base register the parenthesised block ends.  */
          if (*str++ != ')')
            as_bad (_("syntax error; missing ')' after base register"));
          skip_optional = 0;
          if (*str++ != ')')
            as_bad (_("syntax error; missing ')' after base register"));
          skip_optional = 0;
-         /* If there is a next operand it must be seperated by a comma.  */
+
+         if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM
+                               | S390_INSTR_FLAG_OPTPARM2))
+             && opindex_ptr[1] != '\0'
+             && opindex_ptr[2] == '\0'
+             && *str == '\0')
+           continue;
+
+         if ((opcode->flags & S390_INSTR_FLAG_OPTPARM2)
+             && opindex_ptr[1] != '\0'
+             && opindex_ptr[2] != '\0'
+             && opindex_ptr[3] == '\0'
+             && *str == '\0')
+           continue;
+
+         /* If there is a next operand it must be separated by a comma.  */
          if (opindex_ptr[1] != '\0')
            {
          if (opindex_ptr[1] != '\0')
            {
-             if (*str++ != ',')
-               as_bad (_("syntax error; expected ,"));
+             if (*str != ',')
+               {
+                 while (opindex_ptr[1] != '\0')
+                   {
+                     operand = s390_operands + *(++opindex_ptr);
+                     as_bad (_("syntax error; expected ','"));
+                     break;
+                   }
+               }
+             else
+               str++;
            }
        }
       else
            }
        }
       else
@@ -1391,11 +1552,35 @@ md_gather_operands (str, insn, opcode)
                as_bad (_("syntax error; ')' not allowed here"));
              str++;
            }
                as_bad (_("syntax error; ')' not allowed here"));
              str++;
            }
-         /* If there is a next operand it must be seperated by a comma.  */
+
+         if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM
+                               | S390_INSTR_FLAG_OPTPARM2))
+             && opindex_ptr[1] != '\0'
+             && opindex_ptr[2] == '\0'
+             && *str == '\0')
+           continue;
+
+         if ((opcode->flags & S390_INSTR_FLAG_OPTPARM2)
+             && opindex_ptr[1] != '\0'
+             && opindex_ptr[2] != '\0'
+             && opindex_ptr[3] == '\0'
+             && *str == '\0')
+           continue;
+
+         /* If there is a next operand it must be separated by a comma.  */
          if (opindex_ptr[1] != '\0')
            {
          if (opindex_ptr[1] != '\0')
            {
-             if (*str++ != ',')
-               as_bad (_("syntax error; expected ,"));
+             if (*str != ',')
+               {
+                 while (opindex_ptr[1] != '\0')
+                   {
+                     operand = s390_operands + *(++opindex_ptr);
+                     as_bad (_("syntax error; expected ','"));
+                     break;
+                   }
+               }
+             else
+               str++;
            }
        }
     }
            }
        }
     }
@@ -1438,7 +1623,7 @@ md_gather_operands (str, insn, opcode)
      BFD_RELOC_UNUSED plus the operand index.  This lets us easily
      handle fixups for any operand type, although that is admittedly
      not a very exciting feature.  We pick a BFD reloc type in
      BFD_RELOC_UNUSED plus the operand index.  This lets us easily
      handle fixups for any operand type, although that is admittedly
      not a very exciting feature.  We pick a BFD reloc type in
-     md_apply_fix3.  */
+     md_apply_fix.  */
   for (i = 0; i < fc; i++)
     {
 
   for (i = 0; i < fc; i++)
     {
 
@@ -1462,7 +1647,7 @@ md_gather_operands (str, insn, opcode)
          if (!reloc_howto)
            abort ();
 
          if (!reloc_howto)
            abort ();
 
-         size = bfd_get_reloc_size (reloc_howto);
+         size = ((reloc_howto->bitsize - 1) / 8) + 1;
 
          if (size < 1 || size > 4)
            abort ();
 
          if (size < 1 || size > 4)
            abort ();
@@ -1475,8 +1660,12 @@ md_gather_operands (str, insn, opcode)
             because fixup_segment will signal an overflow for large 4 byte
             quantities for GOT12 relocations.  */
          if (   fixups[i].reloc == BFD_RELOC_390_GOT12
             because fixup_segment will signal an overflow for large 4 byte
             quantities for GOT12 relocations.  */
          if (   fixups[i].reloc == BFD_RELOC_390_GOT12
+             || fixups[i].reloc == BFD_RELOC_390_GOT20
              || fixups[i].reloc == BFD_RELOC_390_GOT16)
            fixP->fx_no_overflow = 1;
              || fixups[i].reloc == BFD_RELOC_390_GOT16)
            fixP->fx_no_overflow = 1;
+
+         if (operand->flags & S390_OPERAND_PCREL)
+           fixP->fx_pcrel_adjust = operand->shift / 8;
        }
       else
        fix_new_exp (frag_now, f - frag_now->fr_literal, 4, &fixups[i].exp,
        }
       else
        fix_new_exp (frag_now, f - frag_now->fr_literal, 4, &fixups[i].exp,
@@ -1490,8 +1679,7 @@ md_gather_operands (str, insn, opcode)
 /* This routine is called for each instruction to be assembled.  */
 
 void
 /* This routine is called for each instruction to be assembled.  */
 
 void
-md_assemble (str)
-     char *str;
+md_assemble (char *str)
 {
   const struct s390_opcode *opcode;
   unsigned char insn[6];
 {
   const struct s390_opcode *opcode;
   unsigned char insn[6];
@@ -1512,15 +1700,9 @@ md_assemble (str)
     }
   else if (!(opcode->modes & current_mode_mask))
     {
     }
   else if (!(opcode->modes & current_mode_mask))
     {
-      as_bad ("Opcode %s not available in this mode", str);
+      as_bad (_("Opcode %s not available in this mode"), str);
       return;
     }
       return;
     }
-  else if (opcode->min_cpu > current_cpu)
-    {
-      as_bad ("Opcode %s not available for this cpu", str);
-      return;
-    }
-
   memcpy (insn, opcode->opcode, sizeof (insn));
   md_gather_operands (s, insn, opcode);
 }
   memcpy (insn, opcode->opcode, sizeof (insn));
   md_gather_operands (s, insn, opcode);
 }
@@ -1549,8 +1731,7 @@ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
 #endif
 
 void
 #endif
 
 void
-s390_bss (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s390_bss (int ignore ATTRIBUTE_UNUSED)
 {
   /* We don't support putting frags in the BSS segment, we fake it
      by marking in_bss, then looking at s_skip for clues.  */
 {
   /* We don't support putting frags in the BSS segment, we fake it
      by marking in_bss, then looking at s_skip for clues.  */
@@ -1562,8 +1743,7 @@ s390_bss (ignore)
 /* Pseudo-op handling.  */
 
 void
 /* Pseudo-op handling.  */
 
 void
-s390_insn (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s390_insn (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS exp;
   const struct s390_opcode *opformat;
 {
   expressionS exp;
   const struct s390_opcode *opformat;
@@ -1590,10 +1770,13 @@ s390_insn (ignore)
   expression (&exp);
   if (exp.X_op == O_constant)
     {
   expression (&exp);
   if (exp.X_op == O_constant)
     {
-      if (   (opformat->oplen == 6 && exp.X_op > 0 && exp.X_op < (1ULL << 48))
-         || (opformat->oplen == 4 && exp.X_op > 0 && exp.X_op < (1ULL << 32))
-         || (opformat->oplen == 2 && exp.X_op > 0 && exp.X_op < (1ULL << 16)))
-       md_number_to_chars (insn, exp.X_add_number, opformat->oplen);
+      if (   (   opformat->oplen == 6
+             && (addressT) exp.X_add_number < (1ULL << 48))
+         || (   opformat->oplen == 4
+             && (addressT) exp.X_add_number < (1ULL << 32))
+         || (   opformat->oplen == 2
+             && (addressT) exp.X_add_number < (1ULL << 16)))
+       md_number_to_chars ((char *) insn, exp.X_add_number, opformat->oplen);
       else
        as_bad (_("Invalid .insn format\n"));
     }
       else
        as_bad (_("Invalid .insn format\n"));
     }
@@ -1603,9 +1786,9 @@ s390_insn (ignore)
          && opformat->oplen == 6
          && generic_bignum[3] == 0)
        {
          && opformat->oplen == 6
          && generic_bignum[3] == 0)
        {
-         md_number_to_chars (insn, generic_bignum[2], 2);
-         md_number_to_chars (&insn[2], generic_bignum[1], 2);
-         md_number_to_chars (&insn[4], generic_bignum[0], 2);
+         md_number_to_chars ((char *) insn, generic_bignum[2], 2);
+         md_number_to_chars ((char *) &insn[2], generic_bignum[1], 2);
+         md_number_to_chars ((char *) &insn[4], generic_bignum[0], 2);
        }
       else
        as_bad (_("Invalid .insn format\n"));
        }
       else
        as_bad (_("Invalid .insn format\n"));
@@ -1629,8 +1812,7 @@ s390_insn (ignore)
    pseudo-op, but it can also take a single ASCII string.  */
 
 static void
    pseudo-op, but it can also take a single ASCII string.  */
 
 static void
-s390_byte (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s390_byte (int ignore ATTRIBUTE_UNUSED)
 {
   if (*input_line_pointer != '\"')
     {
 {
   if (*input_line_pointer != '\"')
     {
@@ -1665,8 +1847,7 @@ s390_byte (ignore)
    @lit suffix.  */
 
 static void
    @lit suffix.  */
 
 static void
-s390_literals (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s390_literals (int ignore ATTRIBUTE_UNUSED)
 {
   struct s390_lpe *lpe;
 
 {
   struct s390_lpe *lpe;
 
@@ -1676,7 +1857,7 @@ s390_literals (ignore)
   /* Emit symbol for start of literal pool.  */
   S_SET_SEGMENT (lp_sym, now_seg);
   S_SET_VALUE (lp_sym, (valueT) frag_now_fix ());
   /* Emit symbol for start of literal pool.  */
   S_SET_SEGMENT (lp_sym, now_seg);
   S_SET_VALUE (lp_sym, (valueT) frag_now_fix ());
-  lp_sym->sy_frag = frag_now;
+  symbol_set_frag (lp_sym, frag_now);
 
   while (lpe_list)
     {
 
   while (lpe_list)
     {
@@ -1684,7 +1865,7 @@ s390_literals (ignore)
       lpe_list = lpe_list->next;
       S_SET_SEGMENT (lpe->sym, now_seg);
       S_SET_VALUE (lpe->sym, (valueT) frag_now_fix ());
       lpe_list = lpe_list->next;
       S_SET_SEGMENT (lpe->sym, now_seg);
       S_SET_VALUE (lpe->sym, (valueT) frag_now_fix ());
-      lpe->sym->sy_frag = frag_now;
+      symbol_set_frag (lpe->sym, frag_now);
 
       /* Emit literal pool entry.  */
       if (lpe->reloc != BFD_RELOC_UNUSED)
 
       /* Emit literal pool entry.  */
       if (lpe->reloc != BFD_RELOC_UNUSED)
@@ -1695,7 +1876,9 @@ s390_literals (ignore)
          char *where;
 
          if (size > lpe->nbytes)
          char *where;
 
          if (size > lpe->nbytes)
-           as_bad (_("%s relocations do not fit in %d bytes"),
+           as_bad (ngettext ("%s relocations do not fit in %d byte",
+                             "%s relocations do not fit in %d bytes",
+                             lpe->nbytes),
                    reloc_howto->name, lpe->nbytes);
          where = frag_more (lpe->nbytes);
          md_number_to_chars (where, 0, size);
                    reloc_howto->name, lpe->nbytes);
          where = frag_more (lpe->nbytes);
          md_number_to_chars (where, 0, size);
@@ -1724,70 +1907,192 @@ s390_literals (ignore)
   lpe_count = 0;
 }
 
   lpe_count = 0;
 }
 
-/* Turn a string in input_line_pointer into a floating point constant
-   of type type, and store the appropriate bytes in *litp.  The number
-   of LITTLENUMS emitted is stored in *sizep .  An error message is
-   returned, or NULL on OK.  */
+#define MAX_HISTORY 100
 
 
-char *
-md_atof (type, litp, sizep)
-     int type;
-     char *litp;
-     int *sizep;
+/* The .machine pseudo op allows to switch to a different CPU level in
+   the asm listing.  The current CPU setting can be stored on a stack
+   with .machine push and restored with .machine pop.  */
+
+static void
+s390_machine (int ignore ATTRIBUTE_UNUSED)
 {
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
+  char *cpu_string;
+  static struct cpu_history
+  {
+    unsigned int cpu;
+    unsigned int flags;
+  } *cpu_history;
+  static int curr_hist;
 
 
-  switch (type)
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer == '"')
     {
     {
-    case 'f':
-      prec = 2;
-      break;
+      int len;
+      cpu_string = demand_copy_C_string (&len);
+    }
+  else
+    {
+      char c;
 
 
-    case 'd':
-      prec = 4;
-      break;
+      cpu_string = input_line_pointer;
+      do
+       {
+         char * str;
 
 
-    default:
-      *sizep = 0;
-      return "bad call to md_atof";
+         c = get_symbol_name (&str);
+         c = restore_line_pointer (c);
+         if (c == '+')
+           ++ input_line_pointer;
+       }
+      while (c == '+');
+
+      c = *input_line_pointer;
+      *input_line_pointer = 0;
+      cpu_string = xstrdup (cpu_string);
+      (void) restore_line_pointer (c);
     }
 
     }
 
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
+  if (cpu_string != NULL)
+    {
+      unsigned int new_cpu = current_cpu;
+      unsigned int new_flags = current_flags;
+
+      if (strcmp (cpu_string, "push") == 0)
+       {
+         if (cpu_history == NULL)
+           cpu_history = XNEWVEC (struct cpu_history, MAX_HISTORY);
+
+         if (curr_hist >= MAX_HISTORY)
+           as_bad (_(".machine stack overflow"));
+         else
+           {
+             cpu_history[curr_hist].cpu = current_cpu;
+             cpu_history[curr_hist].flags = current_flags;
+             curr_hist++;
+           }
+       }
+      else if (strcmp (cpu_string, "pop") == 0)
+       {
+         if (curr_hist <= 0)
+           as_bad (_(".machine stack underflow"));
+         else
+           {
+             curr_hist--;
+             new_cpu = cpu_history[curr_hist].cpu;
+             new_flags = cpu_history[curr_hist].flags;
+           }
+       }
+      else
+       new_cpu = s390_parse_cpu (cpu_string, &new_flags, TRUE);
+
+      if (new_cpu == S390_OPCODE_MAXCPU)
+       as_bad (_("invalid machine `%s'"), cpu_string);
+
+      if (new_cpu != current_cpu || new_flags != current_flags)
+       {
+         current_cpu = new_cpu;
+         current_flags = new_flags;
+         s390_setup_opcodes ();
+       }
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* The .machinemode pseudo op allows to switch to a different
+   architecture mode in the asm listing.  The current architecture
+   mode setting can be stored on a stack with .machinemode push and
+   restored with .machinemode pop.  */
+
+static void
+s390_machinemode (int ignore ATTRIBUTE_UNUSED)
+{
+  char *mode_string;
+  static unsigned int *mode_history;
+  static int curr_hist;
+
+  SKIP_WHITESPACE ();
 
 
-  *sizep = prec * 2;
+  {
+    char c;
+
+    c = get_symbol_name (&mode_string);
+    mode_string = xstrdup (mode_string);
+    (void) restore_line_pointer (c);
+  }
 
 
-  for (i = 0; i < prec; i++)
+  if (mode_string != NULL)
     {
     {
-      md_number_to_chars (litp, (valueT) words[i], 2);
-      litp += 2;
+      unsigned int old_mode_mask = current_mode_mask;
+      char *p;
+
+      for (p = mode_string; *p != 0; p++)
+       *p = TOLOWER (*p);
+
+      if (strcmp (mode_string, "push") == 0)
+       {
+         if (mode_history == NULL)
+           mode_history = XNEWVEC (unsigned int, MAX_HISTORY);
+
+         if (curr_hist >= MAX_HISTORY)
+           as_bad (_(".machinemode stack overflow"));
+         else
+           mode_history[curr_hist++] = current_mode_mask;
+       }
+      else if (strcmp (mode_string, "pop") == 0)
+       {
+         if (curr_hist <= 0)
+           as_bad (_(".machinemode stack underflow"));
+         else
+           current_mode_mask = mode_history[--curr_hist];
+       }
+      else
+       {
+         if (strcmp (mode_string, "esa") == 0)
+           current_mode_mask = 1 << S390_OPCODE_ESA;
+         else if (strcmp (mode_string, "zarch") == 0)
+           {
+             if (s390_arch_size == 32)
+               set_highgprs_p = TRUE;
+             current_mode_mask = 1 << S390_OPCODE_ZARCH;
+           }
+         else if (strcmp (mode_string, "zarch_nohighgprs") == 0)
+           current_mode_mask = 1 << S390_OPCODE_ZARCH;
+         else
+           as_bad (_("invalid machine mode `%s'"), mode_string);
+       }
+
+      if (current_mode_mask != old_mode_mask)
+       s390_setup_opcodes ();
     }
 
     }
 
-  return NULL;
+  demand_empty_rest_of_line ();
+}
+
+#undef MAX_HISTORY
+
+const char *
+md_atof (int type, char *litp, int *sizep)
+{
+  return ieee_md_atof (type, litp, sizep, TRUE);
 }
 
 /* Align a section (I don't know why this is machine dependent).  */
 
 valueT
 }
 
 /* Align a section (I don't know why this is machine dependent).  */
 
 valueT
-md_section_align (seg, addr)
-     asection *seg;
-     valueT addr;
+md_section_align (asection *seg, valueT addr)
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
 
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
 
-  return ((addr + (1 << align) - 1) & (-1 << align));
+  return ((addr + (1 << align) - 1) & -(1 << align));
 }
 
 /* We don't have any form of relaxing.  */
 
 int
 }
 
 /* We don't have any form of relaxing.  */
 
 int
-md_estimate_size_before_relax (fragp, seg)
-     fragS *fragp ATTRIBUTE_UNUSED;
-     asection *seg ATTRIBUTE_UNUSED;
+md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
+                              asection *seg ATTRIBUTE_UNUSED)
 {
   abort ();
   return 0;
 {
   abort ();
   return 0;
@@ -1796,17 +2101,15 @@ md_estimate_size_before_relax (fragp, seg)
 /* Convert a machine dependent frag.  We never generate these.  */
 
 void
 /* Convert a machine dependent frag.  We never generate these.  */
 
 void
-md_convert_frag (abfd, sec, fragp)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     asection *sec ATTRIBUTE_UNUSED;
-     fragS *fragp ATTRIBUTE_UNUSED;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+                asection *sec ATTRIBUTE_UNUSED,
+                fragS *fragp ATTRIBUTE_UNUSED)
 {
   abort ();
 }
 
 symbolS *
 {
   abort ();
 }
 
 symbolS *
-md_undefined_symbol (name)
-     char *name;
+md_undefined_symbol (char *name)
 {
   if (*name == '_' && *(name + 1) == 'G'
       && strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
 {
   if (*name == '_' && *(name + 1) == 'G'
       && strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
@@ -1829,9 +2132,7 @@ md_undefined_symbol (name)
    given a PC relative reloc.  */
 
 long
    given a PC relative reloc.  */
 
 long
-md_pcrel_from_section (fixp, sec)
-     fixS *fixp;
-     segT sec ATTRIBUTE_UNUSED;
+md_pcrel_from_section (fixS *fixp, segT sec ATTRIBUTE_UNUSED)
 {
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
 {
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
@@ -1841,12 +2142,13 @@ md_pcrel_from_section (fixp, sec)
    to make sure that the dynamic relocations are done correctly, so in
    some cases we force the original symbol to be used.  */
 int
    to make sure that the dynamic relocations are done correctly, so in
    some cases we force the original symbol to be used.  */
 int
-tc_s390_fix_adjustable (fixP)
-     fixS *fixP;
+tc_s390_fix_adjustable (fixS *fixP)
 {
 {
-  /* Don't adjust references to merge sections.  */
-  if ((S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0)
+  /* Don't adjust pc-relative references to merge sections.  */
+  if (fixP->fx_pcrel
+      && (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0)
     return 0;
     return 0;
+
   /* adjust_reloc_syms doesn't know about the GOT.  */
   if (   fixP->fx_r_type == BFD_RELOC_16_GOTOFF
       || fixP->fx_r_type == BFD_RELOC_32_GOTOFF
   /* adjust_reloc_syms doesn't know about the GOT.  */
   if (   fixP->fx_r_type == BFD_RELOC_16_GOTOFF
       || fixP->fx_r_type == BFD_RELOC_32_GOTOFF
@@ -1854,17 +2156,21 @@ tc_s390_fix_adjustable (fixP)
       || fixP->fx_r_type == BFD_RELOC_390_PLTOFF16
       || fixP->fx_r_type == BFD_RELOC_390_PLTOFF32
       || fixP->fx_r_type == BFD_RELOC_390_PLTOFF64
       || fixP->fx_r_type == BFD_RELOC_390_PLTOFF16
       || fixP->fx_r_type == BFD_RELOC_390_PLTOFF32
       || fixP->fx_r_type == BFD_RELOC_390_PLTOFF64
+      || fixP->fx_r_type == BFD_RELOC_390_PLT12DBL
       || fixP->fx_r_type == BFD_RELOC_390_PLT16DBL
       || fixP->fx_r_type == BFD_RELOC_390_PLT16DBL
+      || fixP->fx_r_type == BFD_RELOC_390_PLT24DBL
       || fixP->fx_r_type == BFD_RELOC_390_PLT32
       || fixP->fx_r_type == BFD_RELOC_390_PLT32DBL
       || fixP->fx_r_type == BFD_RELOC_390_PLT64
       || fixP->fx_r_type == BFD_RELOC_390_GOT12
       || fixP->fx_r_type == BFD_RELOC_390_PLT32
       || fixP->fx_r_type == BFD_RELOC_390_PLT32DBL
       || fixP->fx_r_type == BFD_RELOC_390_PLT64
       || fixP->fx_r_type == BFD_RELOC_390_GOT12
+      || fixP->fx_r_type == BFD_RELOC_390_GOT20
       || fixP->fx_r_type == BFD_RELOC_390_GOT16
       || fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL
       || fixP->fx_r_type == BFD_RELOC_390_GOT64
       || fixP->fx_r_type == BFD_RELOC_390_GOTENT
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLT12
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLT16
       || fixP->fx_r_type == BFD_RELOC_390_GOT16
       || fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL
       || fixP->fx_r_type == BFD_RELOC_390_GOT64
       || fixP->fx_r_type == BFD_RELOC_390_GOTENT
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLT12
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLT16
+      || fixP->fx_r_type == BFD_RELOC_390_GOTPLT20
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLT32
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLT64
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLTENT
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLT32
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLT64
       || fixP->fx_r_type == BFD_RELOC_390_GOTPLTENT
@@ -1874,6 +2180,7 @@ tc_s390_fix_adjustable (fixP)
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GD32
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GD64
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE12
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GD32
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GD64
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE12
+      || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE20
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE32
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE64
       || fixP->fx_r_type == BFD_RELOC_390_TLS_LDM32
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE32
       || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE64
       || fixP->fx_r_type == BFD_RELOC_390_TLS_LDM32
@@ -1897,14 +2204,14 @@ tc_s390_fix_adjustable (fixP)
 /* Return true if we must always emit a reloc for a type and false if
    there is some hope of resolving it at assembly time.  */
 int
 /* Return true if we must always emit a reloc for a type and false if
    there is some hope of resolving it at assembly time.  */
 int
-tc_s390_force_relocation (fixp)
-     struct fix *fixp;
+tc_s390_force_relocation (struct fix *fixp)
 {
   /* Ensure we emit a relocation for every reference to the global
      offset table or to the procedure link table.  */
   switch (fixp->fx_r_type)
     {
     case BFD_RELOC_390_GOT12:
 {
   /* Ensure we emit a relocation for every reference to the global
      offset table or to the procedure link table.  */
   switch (fixp->fx_r_type)
     {
     case BFD_RELOC_390_GOT12:
+    case BFD_RELOC_390_GOT20:
     case BFD_RELOC_32_GOT_PCREL:
     case BFD_RELOC_32_GOTOFF:
     case BFD_RELOC_390_GOTOFF64:
     case BFD_RELOC_32_GOT_PCREL:
     case BFD_RELOC_32_GOTOFF:
     case BFD_RELOC_390_GOTOFF64:
@@ -1917,17 +2224,20 @@ tc_s390_force_relocation (fixp)
     case BFD_RELOC_390_GOT64:
     case BFD_RELOC_390_GOTENT:
     case BFD_RELOC_390_PLT32:
     case BFD_RELOC_390_GOT64:
     case BFD_RELOC_390_GOTENT:
     case BFD_RELOC_390_PLT32:
+    case BFD_RELOC_390_PLT12DBL:
     case BFD_RELOC_390_PLT16DBL:
     case BFD_RELOC_390_PLT16DBL:
+    case BFD_RELOC_390_PLT24DBL:
     case BFD_RELOC_390_PLT32DBL:
     case BFD_RELOC_390_PLT64:
     case BFD_RELOC_390_GOTPLT12:
     case BFD_RELOC_390_GOTPLT16:
     case BFD_RELOC_390_PLT32DBL:
     case BFD_RELOC_390_PLT64:
     case BFD_RELOC_390_GOTPLT12:
     case BFD_RELOC_390_GOTPLT16:
+    case BFD_RELOC_390_GOTPLT20:
     case BFD_RELOC_390_GOTPLT32:
     case BFD_RELOC_390_GOTPLT64:
     case BFD_RELOC_390_GOTPLTENT:
       return 1;
     default:
     case BFD_RELOC_390_GOTPLT32:
     case BFD_RELOC_390_GOTPLT64:
     case BFD_RELOC_390_GOTPLTENT:
       return 1;
     default:
-      break;;
+      break;
     }
 
   return generic_force_reloc (fixp);
     }
 
   return generic_force_reloc (fixp);
@@ -1943,10 +2253,7 @@ tc_s390_force_relocation (fixp)
    fixup.  */
 
 void
    fixup.  */
 
 void
-md_apply_fix3 (fixP, valP, seg)
-     fixS *fixP;
-     valueT *valP;
-     segT seg ATTRIBUTE_UNUSED;
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
   char *where;
   valueT value = *valP;
 {
   char *where;
   valueT value = *valP;
@@ -1955,7 +2262,7 @@ md_apply_fix3 (fixP, valP, seg)
 
   if (fixP->fx_subsy != NULL)
     as_bad_where (fixP->fx_file, fixP->fx_line,
 
   if (fixP->fx_subsy != NULL)
     as_bad_where (fixP->fx_file, fixP->fx_line,
-                 "cannot emit relocation %s against subsy symbol %s",
+                 _("cannot emit relocation %s against subsy symbol %s"),
                  bfd_get_reloc_code_name (fixP->fx_r_type),
                  S_GET_NAME (fixP->fx_subsy));
 
                  bfd_get_reloc_code_name (fixP->fx_r_type),
                  S_GET_NAME (fixP->fx_subsy));
 
@@ -1978,8 +2285,8 @@ md_apply_fix3 (fixP, valP, seg)
       if (fixP->fx_done)
        {
          /* Insert the fully resolved operand value.  */
       if (fixP->fx_done)
        {
          /* Insert the fully resolved operand value.  */
-         s390_insert_operand (where, operand, (offsetT) value,
-                              fixP->fx_file, fixP->fx_line);
+         s390_insert_operand ((unsigned char *) where, operand,
+                              (offsetT) value, fixP->fx_file, fixP->fx_line);
          return;
        }
 
          return;
        }
 
@@ -1999,12 +2306,27 @@ md_apply_fix3 (fixP, valP, seg)
          fixP->fx_where += 4;
          fixP->fx_r_type = BFD_RELOC_390_12;
        }
          fixP->fx_where += 4;
          fixP->fx_r_type = BFD_RELOC_390_12;
        }
+      else if (operand->bits == 20 && operand->shift == 20)
+       {
+         fixP->fx_size = 4;
+         fixP->fx_where += 2;
+         fixP->fx_r_type = BFD_RELOC_390_20;
+       }
       else if (operand->bits == 8 && operand->shift == 8)
        {
          fixP->fx_size = 1;
          fixP->fx_where += 1;
          fixP->fx_r_type = BFD_RELOC_8;
        }
       else if (operand->bits == 8 && operand->shift == 8)
        {
          fixP->fx_size = 1;
          fixP->fx_where += 1;
          fixP->fx_r_type = BFD_RELOC_8;
        }
+      else if (operand->bits == 12 && operand->shift == 12
+              && (operand->flags & S390_OPERAND_PCREL))
+       {
+         fixP->fx_size = 2;
+         fixP->fx_where += 1;
+         fixP->fx_offset += 1;
+         fixP->fx_pcrel_adjust = 1;
+         fixP->fx_r_type = BFD_RELOC_390_PC12DBL;
+       }
       else if (operand->bits == 16 && operand->shift == 16)
        {
          fixP->fx_size = 2;
       else if (operand->bits == 16 && operand->shift == 16)
        {
          fixP->fx_size = 2;
@@ -2013,21 +2335,41 @@ md_apply_fix3 (fixP, valP, seg)
            {
              fixP->fx_r_type = BFD_RELOC_390_PC16DBL;
              fixP->fx_offset += 2;
            {
              fixP->fx_r_type = BFD_RELOC_390_PC16DBL;
              fixP->fx_offset += 2;
+             fixP->fx_pcrel_adjust = 2;
            }
          else
            fixP->fx_r_type = BFD_RELOC_16;
        }
            }
          else
            fixP->fx_r_type = BFD_RELOC_16;
        }
+      else if (operand->bits == 16 && operand->shift == 32
+              && (operand->flags & S390_OPERAND_PCREL))
+       {
+         fixP->fx_size = 2;
+         fixP->fx_where += 4;
+         fixP->fx_offset += 4;
+         fixP->fx_pcrel_adjust = 4;
+         fixP->fx_r_type = BFD_RELOC_390_PC16DBL;
+       }
+      else if (operand->bits == 24 && operand->shift == 24
+              && (operand->flags & S390_OPERAND_PCREL))
+       {
+         fixP->fx_size = 3;
+         fixP->fx_where += 3;
+         fixP->fx_offset += 3;
+         fixP->fx_pcrel_adjust = 3;
+         fixP->fx_r_type = BFD_RELOC_390_PC24DBL;
+       }
       else if (operand->bits == 32 && operand->shift == 16
               && (operand->flags & S390_OPERAND_PCREL))
        {
          fixP->fx_size = 4;
          fixP->fx_where += 2;
          fixP->fx_offset += 2;
       else if (operand->bits == 32 && operand->shift == 16
               && (operand->flags & S390_OPERAND_PCREL))
        {
          fixP->fx_size = 4;
          fixP->fx_where += 2;
          fixP->fx_offset += 2;
+         fixP->fx_pcrel_adjust = 2;
          fixP->fx_r_type = BFD_RELOC_390_PC32DBL;
        }
       else
        {
          fixP->fx_r_type = BFD_RELOC_390_PC32DBL;
        }
       else
        {
-         char *sfile;
+         const char *sfile;
          unsigned int sline;
 
          /* Use expr_symbol_where to see if this is an expression
          unsigned int sline;
 
          /* Use expr_symbol_where to see if this is an expression
@@ -2055,23 +2397,44 @@ md_apply_fix3 (fixP, valP, seg)
        case BFD_RELOC_390_12:
        case BFD_RELOC_390_GOT12:
        case BFD_RELOC_390_GOTPLT12:
        case BFD_RELOC_390_12:
        case BFD_RELOC_390_GOT12:
        case BFD_RELOC_390_GOTPLT12:
+       case BFD_RELOC_390_PC12DBL:
+       case BFD_RELOC_390_PLT12DBL:
+         if (fixP->fx_pcrel)
+           value += fixP->fx_pcrel_adjust;
+
          if (fixP->fx_done)
            {
              unsigned short mop;
 
          if (fixP->fx_done)
            {
              unsigned short mop;
 
+             if (fixP->fx_pcrel)
+               value >>= 1;
+
              mop = bfd_getb16 ((unsigned char *) where);
              mop |= (unsigned short) (value & 0xfff);
              bfd_putb16 ((bfd_vma) mop, (unsigned char *) where);
            }
          break;
 
              mop = bfd_getb16 ((unsigned char *) where);
              mop |= (unsigned short) (value & 0xfff);
              bfd_putb16 ((bfd_vma) mop, (unsigned char *) where);
            }
          break;
 
+       case BFD_RELOC_390_20:
+       case BFD_RELOC_390_GOT20:
+       case BFD_RELOC_390_GOTPLT20:
+         if (fixP->fx_done)
+           {
+             unsigned int mop;
+             mop = bfd_getb32 ((unsigned char *) where);
+             mop |= (unsigned int) ((value & 0xfff) << 8 |
+                                    (value & 0xff000) >> 12);
+             bfd_putb32 ((bfd_vma) mop, (unsigned char *) where);
+           }
+         break;
+
        case BFD_RELOC_16:
        case BFD_RELOC_GPREL16:
        case BFD_RELOC_16_GOT_PCREL:
        case BFD_RELOC_16_GOTOFF:
          if (fixP->fx_pcrel)
            as_bad_where (fixP->fx_file, fixP->fx_line,
        case BFD_RELOC_16:
        case BFD_RELOC_GPREL16:
        case BFD_RELOC_16_GOT_PCREL:
        case BFD_RELOC_16_GOTOFF:
          if (fixP->fx_pcrel)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         "cannot emit PC relative %s relocation%s%s",
+                         _("cannot emit PC relative %s relocation%s%s"),
                          bfd_get_reloc_code_name (fixP->fx_r_type),
                          fixP->fx_addsy != NULL ? " against " : "",
                          (fixP->fx_addsy != NULL
                          bfd_get_reloc_code_name (fixP->fx_r_type),
                          fixP->fx_addsy != NULL ? " against " : "",
                          (fixP->fx_addsy != NULL
@@ -2088,11 +2451,25 @@ md_apply_fix3 (fixP, valP, seg)
          break;
        case BFD_RELOC_390_PC16DBL:
        case BFD_RELOC_390_PLT16DBL:
          break;
        case BFD_RELOC_390_PC16DBL:
        case BFD_RELOC_390_PLT16DBL:
-         value += 2;
+         value += fixP->fx_pcrel_adjust;
          if (fixP->fx_done)
            md_number_to_chars (where, (offsetT) value >> 1, 2);
          break;
 
          if (fixP->fx_done)
            md_number_to_chars (where, (offsetT) value >> 1, 2);
          break;
 
+       case BFD_RELOC_390_PC24DBL:
+       case BFD_RELOC_390_PLT24DBL:
+         value += fixP->fx_pcrel_adjust;
+         if (fixP->fx_done)
+           {
+             unsigned int mop;
+             value >>= 1;
+
+             mop = bfd_getb32 ((unsigned char *) where - 1);
+             mop |= (unsigned int) (value & 0xffffff);
+             bfd_putb32 ((bfd_vma) mop, (unsigned char *) where - 1);
+           }
+         break;
+
        case BFD_RELOC_32:
          if (fixP->fx_pcrel)
            fixP->fx_r_type = BFD_RELOC_32_PCREL;
        case BFD_RELOC_32:
          if (fixP->fx_pcrel)
            fixP->fx_r_type = BFD_RELOC_32_PCREL;
@@ -2119,7 +2496,7 @@ md_apply_fix3 (fixP, valP, seg)
        case BFD_RELOC_390_GOTPCDBL:
        case BFD_RELOC_390_GOTENT:
        case BFD_RELOC_390_GOTPLTENT:
        case BFD_RELOC_390_GOTPCDBL:
        case BFD_RELOC_390_GOTENT:
        case BFD_RELOC_390_GOTPLTENT:
-         value += 2;
+         value += fixP->fx_pcrel_adjust;
          if (fixP->fx_done)
            md_number_to_chars (where, (offsetT) value >> 1, 4);
          break;
          if (fixP->fx_done)
            md_number_to_chars (where, (offsetT) value >> 1, 4);
          break;
@@ -2168,6 +2545,7 @@ md_apply_fix3 (fixP, valP, seg)
        case BFD_RELOC_390_TLS_GD32:
        case BFD_RELOC_390_TLS_GD64:
        case BFD_RELOC_390_TLS_GOTIE12:
        case BFD_RELOC_390_TLS_GD32:
        case BFD_RELOC_390_TLS_GD64:
        case BFD_RELOC_390_TLS_GOTIE12:
+       case BFD_RELOC_390_TLS_GOTIE20:
        case BFD_RELOC_390_TLS_GOTIE32:
        case BFD_RELOC_390_TLS_GOTIE64:
        case BFD_RELOC_390_TLS_LDM32:
        case BFD_RELOC_390_TLS_GOTIE32:
        case BFD_RELOC_390_TLS_GOTIE64:
        case BFD_RELOC_390_TLS_LDM32:
@@ -2181,10 +2559,12 @@ md_apply_fix3 (fixP, valP, seg)
        case BFD_RELOC_390_TLS_DTPMOD:
        case BFD_RELOC_390_TLS_DTPOFF:
        case BFD_RELOC_390_TLS_TPOFF:
        case BFD_RELOC_390_TLS_DTPMOD:
        case BFD_RELOC_390_TLS_DTPOFF:
        case BFD_RELOC_390_TLS_TPOFF:
+         S_SET_THREAD_LOCAL (fixP->fx_addsy);
          /* Fully resolved at link time.  */
          break;
        case BFD_RELOC_390_TLS_IEENT:
          /* Fully resolved at link time.  */
          /* Fully resolved at link time.  */
          break;
        case BFD_RELOC_390_TLS_IEENT:
          /* Fully resolved at link time.  */
+         S_SET_THREAD_LOCAL (fixP->fx_addsy);
          value += 2;
          break;
 
          value += 2;
          break;
 
@@ -2193,11 +2573,9 @@ md_apply_fix3 (fixP, valP, seg)
            const char *reloc_name = bfd_get_reloc_code_name (fixP->fx_r_type);
 
            if (reloc_name != NULL)
            const char *reloc_name = bfd_get_reloc_code_name (fixP->fx_r_type);
 
            if (reloc_name != NULL)
-             fprintf (stderr, "Gas failure, reloc type %s\n", reloc_name);
+             as_fatal (_("Gas failure, reloc type %s\n"), reloc_name);
            else
            else
-             fprintf (stderr, "Gas failure, reloc type #%i\n", fixP->fx_r_type);
-           fflush (stderr);
-           abort ();
+             as_fatal (_("Gas failure, reloc type #%i\n"), fixP->fx_r_type);
          }
        }
 
          }
        }
 
@@ -2208,9 +2586,7 @@ md_apply_fix3 (fixP, valP, seg)
 /* Generate a reloc for a fixup.  */
 
 arelent *
 /* Generate a reloc for a fixup.  */
 
 arelent *
-tc_gen_reloc (seg, fixp)
-     asection *seg ATTRIBUTE_UNUSED;
-     fixS *fixp;
+tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 {
   bfd_reloc_code_real_type code;
   arelent *reloc;
 {
   bfd_reloc_code_real_type code;
   arelent *reloc;
@@ -2225,8 +2601,8 @@ tc_gen_reloc (seg, fixp)
        code = BFD_RELOC_390_GOTPCDBL;
     }
 
        code = BFD_RELOC_390_GOTPCDBL;
     }
 
-  reloc = (arelent *) xmalloc (sizeof (arelent));
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc = XNEW (arelent);
+  reloc->sym_ptr_ptr = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
@@ -2237,9 +2613,40 @@ tc_gen_reloc (seg, fixp)
                    bfd_get_reloc_code_name (code));
       /* Set howto to a garbage value so that we can keep going.  */
       reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
                    bfd_get_reloc_code_name (code));
       /* Set howto to a garbage value so that we can keep going.  */
       reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
-      assert (reloc->howto != NULL);
+      gas_assert (reloc->howto != NULL);
     }
   reloc->addend = fixp->fx_offset;
 
   return reloc;
 }
     }
   reloc->addend = fixp->fx_offset;
 
   return reloc;
 }
+
+void
+s390_cfi_frame_initial_instructions (void)
+{
+  cfi_add_CFA_def_cfa (15, s390_arch_size == 64 ? 160 : 96);
+}
+
+int
+tc_s390_regname_to_dw2regnum (char *regname)
+{
+  int regnum = -1;
+
+  if (regname[0] != 'c' && regname[0] != 'a')
+    {
+      regnum = reg_name_search (regname);
+      if (regname[0] == 'f' && regnum != -1)
+        regnum += 16;
+    }
+  else if (strcmp (regname, "ap") == 0)
+    regnum = 32;
+  else if (strcmp (regname, "cc") == 0)
+    regnum = 33;
+  return regnum;
+}
+
+void
+s390_elf_final_processing (void)
+{
+  if (set_highgprs_p)
+    elf_elfheader (stdoutput)->e_flags |= EF_S390_HIGH_GPRS;
+}
This page took 0.045235 seconds and 4 git commands to generate.