binutils:e593ec3bee996af0d129eb53b2039d409e6e1d42 2012-09-06 Andreas Krebbel * 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