File s390-machinemode.patch of Package binutils

binutils:e593ec3bee996af0d129eb53b2039d409e6e1d42

2012-09-06  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* config/tc-s390.c (set_highgprs_p): New variable.
	(s390_machinemode): New function.
	(md_pseudo_table): Add new pseudo command machinemode.
	(md_parse_option): Set set_highgprs_p to TRUE if -mzarch was
	specified on command line.
	(s390_elf_final_processing): Set the highgprs flag in the ELF
	header depending on set_highgprs_p.

	* doc/c-s390.texi: Document new pseudo machinemode.

diff --git a/gas/config/tc-s390.c b/gas/config/tc-s390.c
index 9bc582f..47ec175 100644
--- a/gas/config/tc-s390.c
+++ b/gas/config/tc-s390.c
@@ -44,6 +44,10 @@ static int s390_arch_size = 0;
 static unsigned int current_cpu = S390_OPCODE_MAXCPU - 1;
 static unsigned int current_mode_mask = 0;
 
+/* 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
 #define TARGET_REG_NAMES_P TRUE
@@ -86,22 +90,24 @@ 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[] =
 {
-  { "align", s_align_bytes, 0 },
+  { "align",        s_align_bytes,      0 },
   /* 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.  */
-  { "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 },
-  { NULL,	NULL,		0 }
+  { "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 }
 };
 
 
@@ -409,7 +415,11 @@ md_parse_option (int c, char *arg)
 	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)
 	{
@@ -1799,7 +1809,7 @@ s390_literals (int ignore ATTRIBUTE_UNUSED)
 
 /* 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 .machined pop.  */
+   with .machine push and restored with .machine pop.  */
 
 static void
 s390_machine (int ignore ATTRIBUTE_UNUSED)
@@ -1863,6 +1873,83 @@ s390_machine (int ignore ATTRIBUTE_UNUSED)
   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;
+#define MAX_HISTORY 100
+  static unsigned int *mode_history;
+  static int curr_hist;
+
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer == '"')
+    {
+      int len;
+      mode_string = demand_copy_C_string (&len);
+    }
+  else
+    {
+      char c;
+      mode_string = input_line_pointer;
+      c = get_symbol_end ();
+      mode_string = xstrdup (mode_string);
+      *input_line_pointer = c;
+    }
+
+  if (mode_string != NULL)
+    {
+      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 = xmalloc (MAX_HISTORY * sizeof (*mode_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 `%s'"), mode_string);
+	}
+
+      if (current_mode_mask != old_mode_mask)
+	s390_setup_opcodes ();
+    }
+
+  demand_empty_rest_of_line ();
+}
+
 char *
 md_atof (int type, char *litp, int *sizep)
 {
@@ -2381,6 +2468,6 @@ tc_s390_regname_to_dw2regnum (char *regname)
 void
 s390_elf_final_processing (void)
 {
-  if (s390_arch_size == 32 && (current_mode_mask & (1 << S390_OPCODE_ZARCH)))
+  if (set_highgprs_p)
     elf_elfheader (stdoutput)->e_flags |= EF_S390_HIGH_GPRS;
 }
diff --git a/gas/doc/c-s390.texi b/gas/doc/c-s390.texi
index 7971327..76dc144 100644
--- a/gas/doc/c-s390.texi
+++ b/gas/doc/c-s390.texi
@@ -873,6 +873,19 @@ restored with @code{.machine pop}.  Be aware that the cpu string has
 to be put into double quotes in case it contains characters not
 appropriate for identifiers.  So you have to write @code{"z9-109"}
 instead of just @code{z9-109}.
+
+@cindex @code{.machinemode} directive, s390
+@item .machinemode string
+This directive allows to change the architecture mode for which code
+is being generated.  @code{string} may be @code{esa}, @code{zarch},
+@code{zarch_nohighgprs}, @code{push}, or @code{pop}.
+@code{.machinemode zarch_nohighgprs} can be used to prevent the
+@code{highgprs} flag from being set in the ELF header of the output
+file.  This is useful in situations where the code is gated with a
+runtime check which makes sure that the code is only executed on
+kernels providing the @code{highgprs} feature.
+@code{.machinemode push} saves the currently selected mode, which may
+be restored with @code{.machinemode pop}.
 @end table
 
 @node s390 Floating Point
openSUSE Build Service is sponsored by