diff options
author | Jan Beulich <jbeulich@suse.com> | 2019-07-01 08:24:57 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2019-07-01 08:24:57 +0200 |
commit | 9c33702be70a7db648414775faa4850e7cf53034 (patch) | |
tree | 98134d3f024fc2aace411ec6e89a32d50116aa23 /gas/config | |
parent | 36cc073ef40f2cb9cb834cdb5d543fbb284f2b32 (diff) | |
download | gdb-9c33702be70a7db648414775faa4850e7cf53034.zip gdb-9c33702be70a7db648414775faa4850e7cf53034.tar.gz gdb-9c33702be70a7db648414775faa4850e7cf53034.tar.bz2 |
x86: warn about insns exceeding the 15-byte limit
Such insns will cause #UD when an attempt to execute them is made.
See also http://www.sandpile.org/x86/opc_enc.htm.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-i386.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 4e55188..84c4bc5 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -8123,6 +8123,25 @@ x86_cleanup (void) } #endif +static unsigned int +encoding_length (const fragS *start_frag, offsetT start_off, + const char *frag_now_ptr) +{ + unsigned int len = 0; + + if (start_frag != frag_now) + { + const fragS *fr = start_frag; + + do { + len += fr->fr_fix; + fr = fr->fr_next; + } while (fr && fr != frag_now); + } + + return len - start_off + (frag_now_ptr - frag_now->fr_literal); +} + static void output_insn (void) { @@ -8400,6 +8419,19 @@ output_insn (void) if (i.imm_operands) output_imm (insn_start_frag, insn_start_off); + + /* + * frag_now_fix () returning plain abs_section_offset when we're in the + * absolute section, and abs_section_offset not getting updated as data + * gets added to the frag breaks the logic below. + */ + if (now_seg != absolute_section) + { + j = encoding_length (insn_start_frag, insn_start_off, frag_more (0)); + if (j > 15) + as_warn (_("instruction length of %u bytes exceeds the limit of 15"), + j); + } } #ifdef DEBUG386 |