From: Kyrylo Tkachov <[email protected]>
Different switch tables can reach the same case block. The CET pass
inserts an ENDBR for each table, although the destination needs only one.
This also affects dispatches that share a table.
Reuse an existing ENDBR after the destination label.
[ ubizjak: Use GET_CODE/XINT, adjust ChangeLog ]
Assisted-by: OpenAI Codex 5.6 Sol
gcc/ChangeLog:
* config/i386/i386-features.cc
(rest_of_insert_endbr_and_patchable_area):
Reuse an existing ENDBR.
gcc/testsuite/ChangeLog:
* gcc.target/i386/cet-switch-4.c: New test.
Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.
Signed-off-by: Kyrylo Tkachov <[email protected]>
Signed-off-by: Uros Bizjak <[email protected]>
Uros.
diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index 1d26aa0c336..f95bc41fb47 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -3274,6 +3274,14 @@ rest_of_insert_endbr_and_patchable_area (bool need_endbr,
dest_blk = e->dest;
insn = BB_HEAD (dest_blk);
gcc_assert (LABEL_P (insn));
+
+ /* Reuse existing ENDBR. */
+ rtx_insn *next = next_nonnote_nondebug_insn (insn);
+ if (next && NONJUMP_INSN_P (next)
+ && GET_CODE (PATTERN (next)) == UNSPEC_VOLATILE
+ && XINT (PATTERN (next), 1) == UNSPECV_NOP_ENDBR)
+ continue;
+
endbr = gen_nop_endbr ();
emit_insn_after (endbr, insn);
}
diff --git a/gcc/testsuite/gcc.target/i386/cet-switch-4.c
b/gcc/testsuite/gcc.target/i386/cet-switch-4.c
new file mode 100644
index 00000000000..53cb960f0d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-switch-4.c
@@ -0,0 +1,56 @@
+/* PR middle-end/126236 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection=branch -mcet-switch -fno-pie -fno-pic" }
*/
+/* { dg-final { scan-assembler-times "endbr32" 9 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 9 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "\[ \t]+jmp\[ \t]+\[*]" 2 } } */
+
+/* Both tables reach the same eight destinations. */
+
+void f0 (void);
+void f1 (void);
+void f2 (void);
+void f3 (void);
+void f4 (void);
+void f5 (void);
+void f6 (void);
+void f7 (void);
+
+void
+foo (unsigned x, int which)
+{
+ if (which)
+ switch (x)
+ {
+ case 0: goto a;
+ case 1: goto b;
+ case 2: goto c;
+ case 3: goto d;
+ case 4: goto e;
+ case 5: goto f;
+ case 6: goto g;
+ case 7: goto h;
+ default: return;
+ }
+ else
+ switch (x)
+ {
+ case 0: goto h;
+ case 1: goto g;
+ case 2: goto f;
+ case 3: goto e;
+ case 4: goto d;
+ case 5: goto c;
+ case 6: goto b;
+ case 7: goto a;
+ default: return;
+ }
+a: f0 (); return;
+b: f1 (); return;
+c: f2 (); return;
+d: f3 (); return;
+e: f4 (); return;
+f: f5 (); return;
+g: f6 (); return;
+h: f7 (); return;
+}