From da374e940857fed398acccf4202b37b8a5bc8c38 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 15 Dec 2023 12:42:43 +0100 Subject: x86: last-insn recording should be per-subsection Otherwise intermediate subsection switches result in inconsistent behavior. Leverage ELF's section change hook to switch state as necessary, limiting overhead to the bare minimum when subsections aren't used. --- gas/config/tc-i386.c | 33 +++++++++++++++++++++++++++++++++ gas/config/tc-i386.h | 5 +++++ gas/testsuite/gas/i386/i386.exp | 2 ++ gas/testsuite/gas/i386/lfence-subsect.d | 18 ++++++++++++++++++ gas/testsuite/gas/i386/lfence-subsect.s | 19 +++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 gas/testsuite/gas/i386/lfence-subsect.d create mode 100644 gas/testsuite/gas/i386/lfence-subsect.s (limited to 'gas') diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 6a349f2..aa26f5c 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -15922,6 +15922,39 @@ i386_elf_section_type (const char *str, size_t len) return -1; } +void +i386_elf_section_change_hook (void) +{ + struct i386_segment_info *info = &seg_info(now_seg)->tc_segment_info_data; + struct i386_segment_info *curr, *prev; + + if (info->subseg == now_subseg) + return; + + /* Find the (or make a) list entry to save state into. */ + for (prev = info; (curr = prev->next) != NULL; prev = curr) + if (curr->subseg == info->subseg) + break; + if (!curr) + { + curr = XNEW (struct i386_segment_info); + curr->subseg = info->subseg; + curr->next = NULL; + prev->next = curr; + } + curr->last_insn = info->last_insn; + + /* Find the list entry to load state from. */ + for (curr = info->next; curr; curr = curr->next) + if (curr->subseg == now_subseg) + break; + if (curr) + info->last_insn = curr->last_insn; + else + memset (&info->last_insn, 0, sizeof (info->last_insn)); + info->subseg = now_subseg; +} + #ifdef TE_SOLARIS void i386_solaris_fix_up_eh_frame (segT sec) diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h index 6d6f0b9..3cb0c78 100644 --- a/gas/config/tc-i386.h +++ b/gas/config/tc-i386.h @@ -294,6 +294,8 @@ struct i386_segment_info { last_insn_prefix } kind; } last_insn; + subsegT subseg; + struct i386_segment_info *next; }; #define TC_SEGMENT_INFO_TYPE struct i386_segment_info @@ -395,6 +397,9 @@ extern void tc_x86_frame_initial_instructions (void); #define md_elf_section_type(str,len) i386_elf_section_type (str, len) extern int i386_elf_section_type (const char *, size_t); +#define md_elf_section_change_hook i386_elf_section_change_hook +extern void i386_elf_section_change_hook (void); + #ifdef TE_SOLARIS #define md_fix_up_eh_frame(sec) i386_solaris_fix_up_eh_frame (sec) extern void i386_solaris_fix_up_eh_frame (segT); diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index 2c2543d..3917be6b 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -745,6 +745,8 @@ if [gas_32_check] then { run_dump_test "nop-6" run_dump_test "unique" + run_dump_test "lfence-subsect" + run_dump_test "property-1" if {[istarget "*-*-linux*"]} then { diff --git a/gas/testsuite/gas/i386/lfence-subsect.d b/gas/testsuite/gas/i386/lfence-subsect.d new file mode 100644 index 0000000..3bb17c3 --- /dev/null +++ b/gas/testsuite/gas/i386/lfence-subsect.d @@ -0,0 +1,18 @@ +#as: -mlfence-before-indirect-branch=all +#warning_output: lfence-section.e +#objdump: -dw +#name: -mlfence-before-indirect-branch=all w/ subsection 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 + +0+8 : +#pass diff --git a/gas/testsuite/gas/i386/lfence-subsect.s b/gas/testsuite/gas/i386/lfence-subsect.s new file mode 100644 index 0000000..b399128 --- /dev/null +++ b/gas/testsuite/gas/i386/lfence-subsect.s @@ -0,0 +1,19 @@ + .text +_start: + rep + + .subsection 2 +aux1: + nop + + .previous + call *%eax + rep + + .pushsection .text, 2 +aux2: + nop + + .popsection + ret + .p2align 2, 0xcc -- cgit v1.1