aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2023-12-15 12:42:43 +0100
committerJan Beulich <jbeulich@suse.com>2023-12-15 12:42:43 +0100
commitda374e940857fed398acccf4202b37b8a5bc8c38 (patch)
treea962ea129a94499679c6863303607e16db30d952 /gas
parentc26906716eacae672a32309865ea5cc9f3e192c5 (diff)
downloadbinutils-da374e940857fed398acccf4202b37b8a5bc8c38.zip
binutils-da374e940857fed398acccf4202b37b8a5bc8c38.tar.gz
binutils-da374e940857fed398acccf4202b37b8a5bc8c38.tar.bz2
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.
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-i386.c33
-rw-r--r--gas/config/tc-i386.h5
-rw-r--r--gas/testsuite/gas/i386/i386.exp2
-rw-r--r--gas/testsuite/gas/i386/lfence-subsect.d18
-rw-r--r--gas/testsuite/gas/i386/lfence-subsect.s19
5 files changed, 77 insertions, 0 deletions
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 <aux1>:
+#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