mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-02-23 13:21:43 +08:00
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.
This commit is contained in:
parent
334a017304
commit
8a6fb3f9bb
@ -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.
|
||||
|
@ -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;
|
||||
|
3
gas/testsuite/gas/i386/equ-bad.l
Normal file
3
gas/testsuite/gas/i386/equ-bad.l
Normal file
@ -0,0 +1,3 @@
|
||||
.*: Assembler messages:
|
||||
.*:8: Error: .*%ebx.*
|
||||
.*:9: Error: .*%ebx.*
|
9
gas/testsuite/gas/i386/equ-bad.s
Normal file
9
gas/testsuite/gas/i386/equ-bad.s
Normal file
@ -0,0 +1,9 @@
|
||||
.text
|
||||
.arch generic32
|
||||
equ:
|
||||
.set xBX, %ebx
|
||||
|
||||
.code16
|
||||
.arch i286
|
||||
inc xBX
|
||||
incb (xBX)
|
@ -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"
|
||||
|
8
gas/testsuite/gas/i386/x86-64-equ-bad.l
Normal file
8
gas/testsuite/gas/i386/x86-64-equ-bad.l
Normal file
@ -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'.*
|
19
gas/testsuite/gas/i386/x86-64-equ-bad.s
Normal file
19
gas/testsuite/gas/i386/x86-64-equ-bad.s
Normal file
@ -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
|
@ -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.
|
||||
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user