aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2020-06-08 08:37:47 +0200
committerJan Beulich <jbeulich@suse.com>2020-06-08 08:37:47 +0200
commit8a6fb3f9bb5105e58f6800de9089a4bdb0cc0cd6 (patch)
treeb4be5b526c1cb1048b525fa880b8315b643f34a1
parent334a017304f03fdc77a2d8893396ed9bfa40382f (diff)
downloadgdb-8a6fb3f9bb5105e58f6800de9089a4bdb0cc0cd6.zip
gdb-8a6fb3f9bb5105e58f6800de9089a4bdb0cc0cd6.tar.gz
gdb-8a6fb3f9bb5105e58f6800de9089a4bdb0cc0cd6.tar.bz2
x86: restrict use of register aliases
Register aliases (created e.g. via .set) check their target register at the time of creation of the alias. While this makes sense, it's not enough: The underlying register must also be "visible" at the time of use. Wrong use of such aliases would lead to internal errors in e.g. add_prefix() or build_modrm_byte(). Split the checking part of parse_real_register() into a new helper function and use it also from the latter part of parse_register() (at the same time replacing a minor open coded part of it). Since parse_register() returning NULL already has a meaning, a fake new "bad register" indicator gets added, which all callers need to check for.
-rw-r--r--gas/ChangeLog13
-rw-r--r--gas/config/tc-i386.c160
-rw-r--r--gas/testsuite/gas/i386/equ-bad.l3
-rw-r--r--gas/testsuite/gas/i386/equ-bad.s9
-rw-r--r--gas/testsuite/gas/i386/i386.exp2
-rw-r--r--gas/testsuite/gas/i386/x86-64-equ-bad.l8
-rw-r--r--gas/testsuite/gas/i386/x86-64-equ-bad.s19
-rw-r--r--opcodes/ChangeLog4
-rw-r--r--opcodes/i386-opc.h2
9 files changed, 154 insertions, 66 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index b532af9..d244ab4 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,16 @@
+2020-06-08 Jan Beulich <jbeulich@suse.com>
+
+ * config/tc-i386.c (bad_reg): New.
+ (check_VecOperations, i386_att_operand, i386_parse_name): Check
+ for it.
+ (check_register): New, broken out from ...
+ (parse_real_register): ... here. Call it.
+ (parse_register): Call it, and error upon failure.
+ * testsuite/gas/i386/equ-bad.s, testsuite/gas/i386/equ-bad.l,
+ testsuite/gas/i386/x86-64-equ-bad.s,
+ testsuite/gas/i386/x86-64-equ-bad.l: New.
+ * testsuite/gas/i386/i386.exp: Run new tests.
+
2020-06-06 Alan Modra <amodra@gmail.com>
* config/tc-ppc.c (md_show_usage): Mention -mpower10 and -mpwr10.
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index ae1bd0d..e34ff85 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -210,6 +210,10 @@ static unsigned int x86_used_note = DEFAULT_X86_USED_NOTE;
static const char *default_arch = DEFAULT_ARCH;
+/* parse_register() returns this when a register alias cannot be used. */
+static const reg_entry bad_reg = { "<bad>", OPERAND_TYPE_NONE, 0, 0,
+ { Dw2Inval, Dw2Inval } };
+
/* This struct describes rounding control and SAE in the instruction. */
struct RC_Operation
{
@@ -10176,6 +10180,9 @@ check_VecOperations (char *op_string, char *op_end)
/* Check masking operation. */
else if ((mask = parse_register (op_string, &end_op)) != NULL)
{
+ if (mask == &bad_reg)
+ return NULL;
+
/* k0 can't be used for write mask. */
if (mask->reg_type.bitfield.class != RegMask || !mask->reg_num)
{
@@ -11035,6 +11042,9 @@ i386_att_operand (char *operand_string)
{
i386_operand_type temp;
+ if (r == &bad_reg)
+ return 0;
+
/* Check for a segment override by searching for ':' after a
segment register. */
op_string = end_op;
@@ -11211,6 +11221,8 @@ i386_att_operand (char *operand_string)
if (i.base_reg)
{
+ if (i.base_reg == &bad_reg)
+ return 0;
base_string = end_op;
if (is_space_char (*base_string))
++base_string;
@@ -11226,6 +11238,8 @@ i386_att_operand (char *operand_string)
if ((i.index_reg = parse_register (base_string, &end_op))
!= NULL)
{
+ if (i.index_reg == &bad_reg)
+ return 0;
base_string = end_op;
if (is_space_char (*base_string))
++base_string;
@@ -12331,6 +12345,73 @@ output_invalid (int c)
return output_invalid_buf;
}
+/* Verify that @r can be used in the current context. */
+
+static bfd_boolean check_register (const reg_entry *r)
+{
+ if (allow_pseudo_reg)
+ return TRUE;
+
+ if (operand_type_all_zero (&r->reg_type))
+ return FALSE;
+
+ if ((r->reg_type.bitfield.dword
+ || (r->reg_type.bitfield.class == SReg && r->reg_num > 3)
+ || r->reg_type.bitfield.class == RegCR
+ || r->reg_type.bitfield.class == RegDR
+ || r->reg_type.bitfield.class == RegTR)
+ && !cpu_arch_flags.bitfield.cpui386)
+ return FALSE;
+
+ if (r->reg_type.bitfield.class == RegMMX && !cpu_arch_flags.bitfield.cpummx)
+ return FALSE;
+
+ if (!cpu_arch_flags.bitfield.cpuavx512f)
+ {
+ if (r->reg_type.bitfield.zmmword
+ || r->reg_type.bitfield.class == RegMask)
+ return FALSE;
+
+ if (!cpu_arch_flags.bitfield.cpuavx)
+ {
+ if (r->reg_type.bitfield.ymmword)
+ return FALSE;
+
+ if (!cpu_arch_flags.bitfield.cpusse && r->reg_type.bitfield.xmmword)
+ return FALSE;
+ }
+ }
+
+ if (r->reg_type.bitfield.class == RegBND && !cpu_arch_flags.bitfield.cpumpx)
+ return FALSE;
+
+ /* Don't allow fake index register unless allow_index_reg isn't 0. */
+ if (!allow_index_reg && r->reg_num == RegIZ)
+ return FALSE;
+
+ /* Upper 16 vector registers are only available with VREX in 64bit
+ mode, and require EVEX encoding. */
+ if (r->reg_flags & RegVRex)
+ {
+ if (!cpu_arch_flags.bitfield.cpuavx512f
+ || flag_code != CODE_64BIT)
+ return FALSE;
+
+ i.vec_encoding = vex_encoding_evex;
+ }
+
+ if (((r->reg_flags & (RegRex64 | RegRex)) || r->reg_type.bitfield.qword)
+ && (!cpu_arch_flags.bitfield.cpulm || r->reg_type.bitfield.class != RegCR)
+ && flag_code != CODE_64BIT)
+ return FALSE;
+
+ if (r->reg_type.bitfield.class == SReg && r->reg_num == RegFlat
+ && !intel_syntax)
+ return FALSE;
+
+ return TRUE;
+}
+
/* REG_STRING starts *before* REGISTER_PREFIX. */
static const reg_entry *
@@ -12400,67 +12481,7 @@ parse_real_register (char *reg_string, char **end_op)
}
}
- if (r == NULL || allow_pseudo_reg)
- return r;
-
- if (operand_type_all_zero (&r->reg_type))
- return (const reg_entry *) NULL;
-
- if ((r->reg_type.bitfield.dword
- || (r->reg_type.bitfield.class == SReg && r->reg_num > 3)
- || r->reg_type.bitfield.class == RegCR
- || r->reg_type.bitfield.class == RegDR
- || r->reg_type.bitfield.class == RegTR)
- && !cpu_arch_flags.bitfield.cpui386)
- return (const reg_entry *) NULL;
-
- if (r->reg_type.bitfield.class == RegMMX && !cpu_arch_flags.bitfield.cpummx)
- return (const reg_entry *) NULL;
-
- if (!cpu_arch_flags.bitfield.cpuavx512f)
- {
- if (r->reg_type.bitfield.zmmword
- || r->reg_type.bitfield.class == RegMask)
- return (const reg_entry *) NULL;
-
- if (!cpu_arch_flags.bitfield.cpuavx)
- {
- if (r->reg_type.bitfield.ymmword)
- return (const reg_entry *) NULL;
-
- if (!cpu_arch_flags.bitfield.cpusse && r->reg_type.bitfield.xmmword)
- return (const reg_entry *) NULL;
- }
- }
-
- if (r->reg_type.bitfield.class == RegBND && !cpu_arch_flags.bitfield.cpumpx)
- return (const reg_entry *) NULL;
-
- /* Don't allow fake index register unless allow_index_reg isn't 0. */
- if (!allow_index_reg && r->reg_num == RegIZ)
- return (const reg_entry *) NULL;
-
- /* Upper 16 vector registers are only available with VREX in 64bit
- mode, and require EVEX encoding. */
- if (r->reg_flags & RegVRex)
- {
- if (!cpu_arch_flags.bitfield.cpuavx512f
- || flag_code != CODE_64BIT)
- return (const reg_entry *) NULL;
-
- i.vec_encoding = vex_encoding_evex;
- }
-
- if (((r->reg_flags & (RegRex64 | RegRex)) || r->reg_type.bitfield.qword)
- && (!cpu_arch_flags.bitfield.cpulm || r->reg_type.bitfield.class != RegCR)
- && flag_code != CODE_64BIT)
- return (const reg_entry *) NULL;
-
- if (r->reg_type.bitfield.class == SReg && r->reg_num == RegFlat
- && !intel_syntax)
- return (const reg_entry *) NULL;
-
- return r;
+ return r && check_register (r) ? r : NULL;
}
/* REG_STRING starts *before* REGISTER_PREFIX. */
@@ -12491,8 +12512,12 @@ parse_register (char *reg_string, char **end_op)
know (e->X_add_number >= 0
&& (valueT) e->X_add_number < i386_regtab_size);
r = i386_regtab + e->X_add_number;
- if ((r->reg_flags & RegVRex))
- i.vec_encoding = vex_encoding_evex;
+ if (!check_register (r))
+ {
+ as_bad (_("register '%s%s' cannot be used here"),
+ register_prefix, r->reg_name);
+ r = &bad_reg;
+ }
*end_op = input_line_pointer;
}
*input_line_pointer = c;
@@ -12513,8 +12538,13 @@ i386_parse_name (char *name, expressionS *e, char *nextcharP)
{
*nextcharP = *input_line_pointer;
*input_line_pointer = 0;
- e->X_op = O_register;
- e->X_add_number = r - i386_regtab;
+ if (r != &bad_reg)
+ {
+ e->X_op = O_register;
+ e->X_add_number = r - i386_regtab;
+ }
+ else
+ e->X_op = O_illegal;
return 1;
}
input_line_pointer = end;
diff --git a/gas/testsuite/gas/i386/equ-bad.l b/gas/testsuite/gas/i386/equ-bad.l
new file mode 100644
index 0000000..47cda1a
--- /dev/null
+++ b/gas/testsuite/gas/i386/equ-bad.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:8: Error: .*%ebx.*
+.*:9: Error: .*%ebx.*
diff --git a/gas/testsuite/gas/i386/equ-bad.s b/gas/testsuite/gas/i386/equ-bad.s
new file mode 100644
index 0000000..ca79b26
--- /dev/null
+++ b/gas/testsuite/gas/i386/equ-bad.s
@@ -0,0 +1,9 @@
+ .text
+ .arch generic32
+equ:
+ .set xBX, %ebx
+
+ .code16
+ .arch i286
+ inc xBX
+ incb (xBX)
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index 3bacb80..86dc1e4 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -91,6 +91,7 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_32_check]]
run_list_test "suffix-bad"
run_dump_test "immed32"
run_dump_test "equ"
+ run_list_test "equ-bad"
run_dump_test "divide"
run_dump_test "padlock"
run_dump_test "crx"
@@ -924,6 +925,7 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t
run_dump_test "x86-64-prefetchwt1-intel"
run_dump_test "x86-64-se1"
run_dump_test "x86-64-equ"
+ run_list_test "x86-64-equ-bad"
run_dump_test "x86-64-avx512f_vl-intel"
run_dump_test "x86-64-avx512f_vl-opts-intel"
run_dump_test "x86-64-avx512f_vl-opts"
diff --git a/gas/testsuite/gas/i386/x86-64-equ-bad.l b/gas/testsuite/gas/i386/x86-64-equ-bad.l
new file mode 100644
index 0000000..cf44d05
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-equ-bad.l
@@ -0,0 +1,8 @@
+.*: Assembler messages:
+.*:11: Error: .*'%xmm18'.*
+.*:13: Error: .*'%dil'.*
+.*:14: Error: .*'%rdi'.*
+.*:15: Error: .*'%r8'.*
+.*:16: Error: .*'%r9d'.*
+.*:18: Error: .*'%r8'.*
+.*:19: Error: .*'%r9d'.*
diff --git a/gas/testsuite/gas/i386/x86-64-equ-bad.s b/gas/testsuite/gas/i386/x86-64-equ-bad.s
new file mode 100644
index 0000000..483a1cf
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-equ-bad.s
@@ -0,0 +1,19 @@
+ .text
+ .code64
+equ:
+ .set R18, %xmm18
+ .set lDI, %dil
+ .set xDI, %rdi
+ .set x8, %r8
+ .set x9, %r9d
+
+ .code32
+ vmovaps %xmm0, R18
+
+ inc lDI
+ incl (xDI)
+ inc x8
+ inc x9
+
+ shlx x8, x8, x8
+ shlx x9, x9, x9
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index f09d599..d405787 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,7 @@
+2020-06-08 Jan Beulich <jbeulich@suse.com>
+
+ * i386-opc.h (reg_entry): Const-qualify reg_name field.
+
2020-06-06 Alan Modra <amodra@gmail.com>
* ppc-dis.c (ppc_opts): Accept -mpwr10/-Mpwr10.
diff --git a/opcodes/i386-opc.h b/opcodes/i386-opc.h
index e5a5dcb..55726c1 100644
--- a/opcodes/i386-opc.h
+++ b/opcodes/i386-opc.h
@@ -906,7 +906,7 @@ extern const insn_template i386_optab[];
/* these are for register name --> number & type hash lookup */
typedef struct
{
- char *reg_name;
+ const char *reg_name;
i386_operand_type reg_type;
unsigned char reg_flags;
#define RegRex 0x1 /* Extended register. */