From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1386) id 7D683385AE4E; Fri, 1 Dec 2023 07:29:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7D683385AE4E Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Jan Beulich To: bfd-cvs@sourceware.org Subject: [binutils-gdb] x86: last-insn recording should be per-section X-Act-Checkin: binutils-gdb X-Git-Author: Jan Beulich X-Git-Refname: refs/heads/master X-Git-Oldrev: 1f865bae65db9588f6994c02a92355bfb4e3d955 X-Git-Newrev: b5482fe535884c9fdb5c45c5627ec99e54c0e9d9 Message-Id: <20231201072951.7D683385AE4E@sourceware.org> Date: Fri, 1 Dec 2023 07:29:51 +0000 (GMT) X-BeenThere: binutils-cvs@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Dec 2023 07:29:51 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Db5482fe53588= 4c9fdb5c45c5627ec99e54c0e9d9 commit b5482fe535884c9fdb5c45c5627ec99e54c0e9d9 Author: Jan Beulich Date: Fri Dec 1 08:27:22 2023 +0100 x86: last-insn recording should be per-section =20 Otherwise intermediate section switches result in inconsistent behavior. Note, however, that intermediate sub-section switches will continue to result in inconsistent or even inappropriate behavior. =20 While there also add recording of state to s_insn(). Diff: --- gas/config/tc-i386.c | 105 ++++++++++++++--------------= ---- gas/config/tc-i386.h | 17 ++++++ gas/testsuite/gas/i386/i386.exp | 11 ++++ gas/testsuite/gas/i386/lfence-section.d | 19 ++++++ gas/testsuite/gas/i386/lfence-section.e | 3 + gas/testsuite/gas/i386/lfence-section.s | 19 ++++++ 6 files changed, 116 insertions(+), 58 deletions(-) diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index b1cd0e4542f..059dd49feea 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -178,7 +178,7 @@ static int check_word_reg (void); static int finalize_imm (void); static int process_operands (void); static const reg_entry *build_modrm_byte (void); -static void output_insn (void); +static void output_insn (const struct last_insn *); static void output_imm (fragS *, offsetT); static void output_disp (fragS *, offsetT); #ifndef I386COFF @@ -677,21 +677,6 @@ static enum lfence_before_ret_kind } lfence_before_ret; =20 -/* Types of previous instruction is .byte or prefix. */ -static struct - { - segT seg; - const char *file; - const char *name; - unsigned int line; - enum last_insn_kind - { - last_insn_other =3D 0, - last_insn_directive, - last_insn_prefix - } kind; - } last_insn; - /* 1 if the assembler should generate relax relocations. */ =20 static int generate_relax_relocations @@ -4971,7 +4956,7 @@ insert_lfence_after (void) /* Output lfence, 0xfaee8, before instruction. */ =20 static void -insert_lfence_before (void) +insert_lfence_before (const struct last_insn *last_insn) { char *p; =20 @@ -5007,12 +4992,11 @@ insert_lfence_before (void) else return; =20 - if (last_insn.kind !=3D last_insn_other - && last_insn.seg =3D=3D now_seg) + if (last_insn->kind !=3D last_insn_other) { - as_warn_where (last_insn.file, last_insn.line, + as_warn_where (last_insn->file, last_insn->line, _("`%s` skips -mlfence-before-indirect-branch on `%s`"), - last_insn.name, insn_name (&i.tm)); + last_insn->name, insn_name (&i.tm)); return; } =20 @@ -5027,12 +5011,11 @@ insert_lfence_before (void) if (lfence_before_ret !=3D lfence_before_ret_none && (i.tm.base_opcode | 1) =3D=3D 0xc3) { - if (last_insn.kind !=3D last_insn_other - && last_insn.seg =3D=3D now_seg) + if (last_insn->kind !=3D last_insn_other) { - as_warn_where (last_insn.file, last_insn.line, + as_warn_where (last_insn->file, last_insn->line, _("`%s` skips -mlfence-before-ret on `%s`"), - last_insn.name, insn_name (&i.tm)); + last_insn->name, insn_name (&i.tm)); return; } =20 @@ -5129,6 +5112,8 @@ md_assemble (char *line) const char *end, *pass1_mnem =3D NULL; enum i386_error pass1_err =3D 0; const insn_template *t; + struct last_insn *last_insn + =3D &seg_info(now_seg)->tc_segment_info_data.last_insn; =20 /* Initialize globals. */ current_templates.end =3D current_templates.start =3D NULL; @@ -5682,23 +5667,21 @@ md_assemble (char *line) if (i.rex !=3D 0) add_prefix (REX_OPCODE | i.rex); =20 - insert_lfence_before (); + insert_lfence_before (last_insn); =20 /* We are ready to output the insn. */ - output_insn (); + output_insn (last_insn); =20 insert_lfence_after (); =20 - last_insn.seg =3D now_seg; - if (i.tm.opcode_modifier.isprefix) { - last_insn.kind =3D last_insn_prefix; - last_insn.name =3D insn_name (&i.tm); - last_insn.file =3D as_where (&last_insn.line); + last_insn->kind =3D last_insn_prefix; + last_insn->name =3D insn_name (&i.tm); + last_insn->file =3D as_where (&last_insn->line); } else - last_insn.kind =3D last_insn_other; + last_insn->kind =3D last_insn_other; } =20 /* The Q suffix is generally valid only in 64-bit mode, with very few @@ -9667,7 +9650,8 @@ maybe_fused_with_jcc_p (enum mf_cmp_kind* mf_cmp_p) /* Return 1 if a FUSED_JCC_PADDING frag should be generated. */ =20 static int -add_fused_jcc_padding_frag_p (enum mf_cmp_kind* mf_cmp_p) +add_fused_jcc_padding_frag_p (enum mf_cmp_kind *mf_cmp_p, + const struct last_insn *last_insn) { /* NB: Don't work with COND_JUMP86 without i386. */ if (!align_branch_power @@ -9678,13 +9662,12 @@ add_fused_jcc_padding_frag_p (enum mf_cmp_kind* mf_= cmp_p) =20 if (maybe_fused_with_jcc_p (mf_cmp_p)) { - if (last_insn.kind =3D=3D last_insn_other - || last_insn.seg !=3D now_seg) + if (last_insn->kind =3D=3D last_insn_other) return 1; if (flag_debug) - as_warn_where (last_insn.file, last_insn.line, + as_warn_where (last_insn->file, last_insn->line, _("`%s` skips -malign-branch-boundary on `%s`"), - last_insn.name, insn_name (&i.tm)); + last_insn->name, insn_name (&i.tm)); } =20 return 0; @@ -9693,7 +9676,7 @@ add_fused_jcc_padding_frag_p (enum mf_cmp_kind* mf_cm= p_p) /* Return 1 if a BRANCH_PREFIX frag should be generated. */ =20 static int -add_branch_prefix_frag_p (void) +add_branch_prefix_frag_p (const struct last_insn *last_insn) { /* NB: Don't work with COND_JUMP86 without i386. Don't add prefix to PadLock instructions since they include prefixes in opcode. */ @@ -9709,14 +9692,13 @@ add_branch_prefix_frag_p (void) if (!i.operands || i.tm.opcode_modifier.isprefix) return 0; =20 - if (last_insn.kind =3D=3D last_insn_other - || last_insn.seg !=3D now_seg) + if (last_insn->kind =3D=3D last_insn_other) return 1; =20 if (flag_debug) - as_warn_where (last_insn.file, last_insn.line, + as_warn_where (last_insn->file, last_insn->line, _("`%s` skips -malign-branch-boundary on `%s`"), - last_insn.name, insn_name (&i.tm)); + last_insn->name, insn_name (&i.tm)); =20 return 0; } @@ -9725,7 +9707,8 @@ add_branch_prefix_frag_p (void) =20 static int add_branch_padding_frag_p (enum align_branch_kind *branch_p, - enum mf_jcc_kind *mf_jcc_p) + enum mf_jcc_kind *mf_jcc_p, + const struct last_insn *last_insn) { int add_padding; =20 @@ -9799,13 +9782,12 @@ add_branch_padding_frag_p (enum align_branch_kind *= branch_p, } =20 if (add_padding - && last_insn.kind !=3D last_insn_other - && last_insn.seg =3D=3D now_seg) + && last_insn->kind !=3D last_insn_other) { if (flag_debug) - as_warn_where (last_insn.file, last_insn.line, + as_warn_where (last_insn->file, last_insn->line, _("`%s` skips -malign-branch-boundary on `%s`"), - last_insn.name, insn_name (&i.tm)); + last_insn->name, insn_name (&i.tm)); return 0; } =20 @@ -9813,7 +9795,7 @@ add_branch_padding_frag_p (enum align_branch_kind *br= anch_p, } =20 static void -output_insn (void) +output_insn (const struct last_insn *last_insn) { fragS *insn_start_frag; offsetT insn_start_off; @@ -9943,7 +9925,7 @@ output_insn (void) insn_start_frag =3D frag_now; insn_start_off =3D frag_now_fix (); =20 - if (add_branch_padding_frag_p (&branch, &mf_jcc)) + if (add_branch_padding_frag_p (&branch, &mf_jcc, last_insn)) { char *p; /* Branch can be 8 bytes. Leave some room for prefixes. */ @@ -10029,7 +10011,7 @@ output_insn (void) if (branch) /* Skip if this is a branch. */ ; - else if (add_fused_jcc_padding_frag_p (&mf_cmp)) + else if (add_fused_jcc_padding_frag_p (&mf_cmp, last_insn)) { /* Make room for padding. */ frag_grow (MAX_FUSED_JCC_PADDING_SIZE); @@ -10045,7 +10027,7 @@ output_insn (void) fragP->tc_frag_data.branch_type =3D align_branch_fused; fragP->tc_frag_data.max_bytes =3D MAX_FUSED_JCC_PADDING_SIZE; } - else if (add_branch_prefix_frag_p ()) + else if (add_branch_prefix_frag_p (last_insn)) { unsigned int max_prefix_size =3D align_branch_prefix_size; =20 @@ -10948,6 +10930,7 @@ s_insn (int dummy ATTRIBUTE_UNUSED) unsigned int j; valueT val; bool vex =3D false, xop =3D false, evex =3D false; + struct last_insn *last_insn; =20 init_globals (); =20 @@ -11701,7 +11684,11 @@ s_insn (int dummy ATTRIBUTE_UNUSED) else if (i.rex !=3D 0) add_prefix (REX_OPCODE | i.rex); =20 - output_insn (); + last_insn =3D &seg_info(now_seg)->tc_segment_info_data.last_insn; + output_insn (last_insn); + last_insn->kind =3D last_insn_directive; + last_insn->name =3D ".insn directive"; + last_insn->file =3D as_where (&last_insn->line); =20 done: *saved_ilp =3D saved_char; @@ -15496,13 +15483,15 @@ s_bss (int ignore ATTRIBUTE_UNUSED) void i386_cons_align (int ignore ATTRIBUTE_UNUSED) { - if (last_insn.kind !=3D last_insn_directive + struct last_insn *last_insn + =3D &seg_info(now_seg)->tc_segment_info_data.last_insn; + + if (last_insn->kind !=3D last_insn_directive && (bfd_section_flags (now_seg) & SEC_CODE)) { - last_insn.seg =3D now_seg; - last_insn.kind =3D last_insn_directive; - last_insn.name =3D "constant directive"; - last_insn.file =3D as_where (&last_insn.line); + last_insn->kind =3D last_insn_directive; + last_insn->name =3D "constant directive"; + last_insn->file =3D as_where (&last_insn->line); if (lfence_before_ret !=3D lfence_before_ret_none) { if (lfence_before_indirect_branch !=3D lfence_branch_none) diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h index 5db25087290..c3022149fbe 100644 --- a/gas/config/tc-i386.h +++ b/gas/config/tc-i386.h @@ -281,6 +281,23 @@ extern enum i386_flag_code { CODE_64BIT } i386_flag_code; =20 +struct i386_segment_info { + /* Type of previous "instruction", e.g. .byte or stand-alone prefix. */ + struct last_insn { + const char *file; + const char *name; + unsigned int line; + enum last_insn_kind + { + last_insn_other =3D 0, + last_insn_directive, + last_insn_prefix + } kind; + } last_insn; +}; + +#define TC_SEGMENT_INFO_TYPE struct i386_segment_info + struct i386_tc_frag_data { union diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.= exp index 6ab197089ee..2c2543daa14 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -642,6 +642,17 @@ if [gas_32_check] then { run_dump_test "lfence-ret-c" run_dump_test "lfence-ret-d" run_dump_test "lfence-byte" + # This test uses the .section directive, which only ELF and COFF/PE su= pport. + if {[is_elf_format] + || [istarget "*-*-vxworks*"] + || [istarget "*-*-coff*"] + || [istarget "*-*-pe*"] + || [istarget "*-*-cygwin*"] + || [istarget "*-*-mingw*"] + } then { + run_dump_test "lfence-section" + } + run_dump_test "branch" =20 # These tests require support for 8 and 16 bit relocs, diff --git a/gas/testsuite/gas/i386/lfence-section.d b/gas/testsuite/gas/i3= 86/lfence-section.d new file mode 100644 index 00000000000..830851c3fc7 --- /dev/null +++ b/gas/testsuite/gas/i386/lfence-section.d @@ -0,0 +1,19 @@ +#as: -mlfence-before-indirect-branch=3Dall +#warning_output: lfence-section.e +#objdump: -dw +#name: -mlfence-before-indirect-branch=3Dall w/ section switches + +.*: +file format .* + + +Disassembly of section .text: + +0+ <_start>: + +[a-f0-9]+: f3 ff d0 repz call \*%eax + +[a-f0-9]+: f3 c3 repz ret + +[a-f0-9]+: cc int3 + +[a-f0-9]+: cc int3 + +[a-f0-9]+: cc int3 + +Disassembly of section \.text2: +#pass diff --git a/gas/testsuite/gas/i386/lfence-section.e b/gas/testsuite/gas/i3= 86/lfence-section.e new file mode 100644 index 00000000000..47f5b2b91c0 --- /dev/null +++ b/gas/testsuite/gas/i386/lfence-section.e @@ -0,0 +1,3 @@ +.*: Assembler messages: +.*:3: Warning: `rep` skips -mlfence-before-indirect-branch on `call` +.*:11: Warning: `rep` skips -mlfence-before-ret on `ret` diff --git a/gas/testsuite/gas/i386/lfence-section.s b/gas/testsuite/gas/i3= 86/lfence-section.s new file mode 100644 index 00000000000..bc3dd0bc7cc --- /dev/null +++ b/gas/testsuite/gas/i386/lfence-section.s @@ -0,0 +1,19 @@ + .text +_start: + rep + + .section .text2, "ax" +aux1: + nop + + .text + call *%eax + rep + + .section .text2, "ax" +aux2: + nop + + .text + ret + .p2align 2, 0xcc