diff options
author | Jan Beulich <jbeulich@suse.com> | 2020-01-21 08:28:25 +0100 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2020-01-21 08:28:25 +0100 |
commit | c006a730e9a35489cc8d081f422a7ea1b62ada56 (patch) | |
tree | 9905562c0967d901d2bd6307483a00754ceed174 /gas/config | |
parent | c906a69a1f30c12074165f5be0027249c643e904 (diff) | |
download | gdb-c006a730e9a35489cc8d081f422a7ea1b62ada56.zip gdb-c006a730e9a35489cc8d081f422a7ea1b62ada56.tar.gz gdb-c006a730e9a35489cc8d081f422a7ea1b62ada56.tar.bz2 |
x86: improve handling of insns with ambiguous operand sizes
Commit b76bc5d54e ("x86: don't default variable shift count insns to
8-bit operand size") pointed out a very bad case, but the underlying
problem is, as mentioned on various occasions, much larger: Silently
selecting a (nowhere documented afaict) certain default operand size
when there's no "sizing" suffix and no suitable register operand(s) is
simply dangerous (for the programmer to make mistakes).
While in Intel syntax mode such mistakes already lead to an error (which
is going to remain that way), AT&T syntax mode now gains warnings in
such cases by default, which can be suppressed or promoted to an error
if so desired by the programmer. Furthermore at least general purpose
insns now consistently have a default applied (alongside the warning
emission), rather than accepting some and refusing others.
No warnings are (as before) to be generated for "DefaultSize" insns as
well as ones acting on selector and other fixed-width values. For
SYSRET, however, the DefaultSize needs to be dropped - it had been
wrongly put there in the first place, as it's unrelated to .code16gcc
(no stack accesses involved).
As set forth as a prereq when I first mentioned this intended change a
few years back, Linux as well as gcc have meanwhile been patched to
avoid (emission of) ambiguous operands (and hence triggering of the new
warning).
Note that I think that in 64-bit mode IRET and far RET would better get
a diagnostic too, as it's reasonably likely that a suffix-less instance
really is meant to be a 64-bit one. But I guess I better make this a
separate follow-on patch.
Note further that floating point operations with integer operands are an
exception for now: They continue to use short (16-bit) operands by
default even in 32- and 64-bit modes.
Finally note that while {,V}PCMPESTR{I,M} would, strictly speaking, also
need to be diagnosed, with their 64-bit forms not being very useful I
think it is better to continue to avoid warning about them (by way of
them carrying IgnoreSize attributes).
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-i386.c | 70 |
1 files changed, 37 insertions, 33 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 87ab43b..0b7542f 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -6395,9 +6395,7 @@ process_suffix (void) else if (i.tm.opcode_modifier.defaultsize && !i.suffix /* exclude fldenv/frstor/fsave/fstenv */ - && i.tm.opcode_modifier.no_ssuf - /* exclude sysret */ - && i.tm.base_opcode != 0x0f07) + && i.tm.opcode_modifier.no_ssuf) { i.suffix = stackop_size; if (stackop_size == LONG_MNEM_SUFFIX) @@ -6418,8 +6416,7 @@ process_suffix (void) i.tm.name); } } - else if (intel_syntax - && !i.suffix + else if (!i.suffix && (i.tm.opcode_modifier.jump == JUMP_ABSOLUTE || i.tm.opcode_modifier.jump == JUMP_BYTE || i.tm.opcode_modifier.jump == JUMP_INTERSEGMENT @@ -6446,42 +6443,49 @@ process_suffix (void) } } - if (!i.suffix) + if (!i.suffix + && !i.tm.opcode_modifier.defaultsize + && !i.tm.opcode_modifier.ignoresize) { - if (!intel_syntax) + unsigned int suffixes; + + suffixes = !i.tm.opcode_modifier.no_bsuf; + if (!i.tm.opcode_modifier.no_wsuf) + suffixes |= 1 << 1; + if (!i.tm.opcode_modifier.no_lsuf) + suffixes |= 1 << 2; + if (!i.tm.opcode_modifier.no_ldsuf) + suffixes |= 1 << 3; + if (!i.tm.opcode_modifier.no_ssuf) + suffixes |= 1 << 4; + if (flag_code == CODE_64BIT && !i.tm.opcode_modifier.no_qsuf) + suffixes |= 1 << 5; + + /* Are multiple suffixes allowed? */ + if (suffixes & (suffixes - 1)) { - if (i.tm.opcode_modifier.w) + if (intel_syntax) { - as_bad (_("no instruction mnemonic suffix given and " - "no register operands; can't size instruction")); + as_bad (_("ambiguous operand size for `%s'"), i.tm.name); return 0; } - } - else - { - unsigned int suffixes; - - suffixes = !i.tm.opcode_modifier.no_bsuf; - if (!i.tm.opcode_modifier.no_wsuf) - suffixes |= 1 << 1; - if (!i.tm.opcode_modifier.no_lsuf) - suffixes |= 1 << 2; - if (!i.tm.opcode_modifier.no_ldsuf) - suffixes |= 1 << 3; - if (!i.tm.opcode_modifier.no_ssuf) - suffixes |= 1 << 4; - if (flag_code == CODE_64BIT && !i.tm.opcode_modifier.no_qsuf) - suffixes |= 1 << 5; - - /* There are more than suffix matches. */ - if (i.tm.opcode_modifier.w - || ((suffixes & (suffixes - 1)) - && !i.tm.opcode_modifier.defaultsize - && !i.tm.opcode_modifier.ignoresize)) + if (operand_check == check_error) { - as_bad (_("ambiguous operand size for `%s'"), i.tm.name); + as_bad (_("no instruction mnemonic suffix given and " + "no register operands; can't size `%s'"), i.tm.name); return 0; } + if (operand_check == check_warning) + as_warn (_("no instruction mnemonic suffix given and " + "no register operands; using default for `%s'"), + i.tm.name); + + if (i.tm.opcode_modifier.floatmf) + i.suffix = SHORT_MNEM_SUFFIX; + else if (flag_code == CODE_16BIT) + i.suffix = WORD_MNEM_SUFFIX; + else + i.suffix = LONG_MNEM_SUFFIX; } } |