]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
x86: last-insn recording should be per-subsection
authorJan Beulich <jbeulich@suse.com>
Fri, 15 Dec 2023 11:42:43 +0000 (12:42 +0100)
committerJan Beulich <jbeulich@suse.com>
Fri, 15 Dec 2023 11:42:43 +0000 (12:42 +0100)
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
gas/config/tc-i386.h
gas/testsuite/gas/i386/i386.exp
gas/testsuite/gas/i386/lfence-subsect.d [new file with mode: 0644]
gas/testsuite/gas/i386/lfence-subsect.s [new file with mode: 0644]

index 6a349f2ccc59b1f38ee561ae8235c19e64e3f4c4..aa26f5ce034bc13dceb77f97f4c1c4a5e887cccd 100644 (file)
@@ -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)
index 6d6f0b93681f2e2cfc66fe0c4861acf4d6d63253..3cb0c784819b6d993932c4a6085b124051c712cf 100644 (file)
@@ -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);
index 2c2543daa145c8aa71ca4d5bcde168dea8790663..3917be6be70c146aa92c3e7384351a3544722749 100644 (file)
@@ -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 (file)
index 0000000..3bb17c3
--- /dev/null
@@ -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 (file)
index 0000000..b399128
--- /dev/null
@@ -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