From: Jan Beulich Date: Fri, 15 Dec 2023 11:42:43 +0000 (+0100) Subject: x86: last-insn recording should be per-subsection X-Git-Tag: binutils-2_42~559 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=da374e940857fed398acccf4202b37b8a5bc8c38;p=thirdparty%2Fbinutils-gdb.git 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. --- diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 6a349f2ccc5..aa26f5ce034 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 6d6f0b93681..3cb0c784819 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 2c2543daa14..3917be6be70 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 00000000000..3bb17c3d500 --- /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 00000000000..b3991280b11 --- /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