When generating 16-bit code via -m16, the NOP mcount code generation
emits a 5-byte NOP. However, that is neither a valid i8086 instruction
(long NOPs are PentiumPro+), nor would it get decoded as a 5-byte
instruction. It's a 4-byte 'nopw 0(%si)' followed by a zero byte. The
latter causes the following instruction to get misinterpreted as some
form of ADD.

Fix this by emiting a 3-byte no-op 'lea 0(%si)' instead which makes it
compatible with systems lacking long NOP support.

Add a test for this and change the existing one accordingly.

gcc/ChangeLog:

        * config/i386/i386.cc (x86_print_call_or_nop): Fix 16-bit NOP
        generation.

gcc/testsuite/ChangeLog:

        * gcc.target/i386/nop-mcount-m16.c: New test.
        * gcc.target/i386/nop-mcount.c: Adapt to test for 5-byte NOP.

Signed-off-by: Mathias Krause <[email protected]>
---
I ran into this bug while trying to abuse '-pg -mnop-mcount' to force
gcc to generate a proper stack frame even for leaf functions to ease
backtracing:

https://lore.kernel.org/kvm/[email protected]/

 gcc/config/i386/i386.cc                        | 12 +++++++++---
 gcc/testsuite/gcc.target/i386/nop-mcount-m16.c | 13 +++++++++++++
 gcc/testsuite/gcc.target/i386/nop-mcount.c     |  6 +++---
 3 files changed, 25 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/nop-mcount-m16.c

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 722c1713a6d3..db43045753bf 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -23767,9 +23767,15 @@ x86_print_call_or_nop (FILE *file, const char *target,
                       const char *label)
 {
   if (flag_nop_mcount || !strcmp (target, "nop"))
-    /* 5 byte nop: nopl 0(%[re]ax,%[re]ax,1) */
-    fprintf (file, "%s" ASM_BYTE "0x0f, 0x1f, 0x44, 0x00, 0x00\n",
-            label);
+    {
+      if (TARGET_16BIT)
+       /* 3 byte no-op: lea 0(%si), %si */
+       fprintf (file, "%s" ASM_BYTE "0x8d, 0x74, 0x00\n", label);
+      else
+       /* 5 byte nop: nopl 0(%[re]ax,%[re]ax,1) */
+       fprintf (file, "%s" ASM_BYTE "0x0f, 0x1f, 0x44, 0x00, 0x00\n",
+                label);
+    }
   else if (!TARGET_PECOFF && flag_pic)
     {
       gcc_assert (flag_plt);
diff --git a/gcc/testsuite/gcc.target/i386/nop-mcount-m16.c 
b/gcc/testsuite/gcc.target/i386/nop-mcount-m16.c
new file mode 100644
index 000000000000..9d019cff5adb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/nop-mcount-m16.c
@@ -0,0 +1,13 @@
+/* Test -mnop-mcount for 16-bit code to generate a 3-byte NOP */
+/* { dg-do compile { target { *-*-linux* && nonpic } } } */
+/* { dg-require-effective-target mfentry } */
+/* { dg-options "-pg -mfentry -mnop-mcount -m16" } */
+/* { dg-final { scan-assembler-not "__fentry__" } } */
+/* { dg-final { scan-assembler-times "0x0f, 0x1f, 0x44, 0x00, 0x00" 0 } } */
+/* { dg-final { scan-assembler-times "0x8d, 0x74, 0x00" 1 } } */
+extern void foobar(char *);
+
+void func(void)
+{
+  foobar ("Hello world\n");
+}
diff --git a/gcc/testsuite/gcc.target/i386/nop-mcount.c 
b/gcc/testsuite/gcc.target/i386/nop-mcount.c
index ee3c97f3a57c..35cfef0bc9d7 100644
--- a/gcc/testsuite/gcc.target/i386/nop-mcount.c
+++ b/gcc/testsuite/gcc.target/i386/nop-mcount.c
@@ -1,8 +1,9 @@
 /* Test -mnop-mcount */
 /* { dg-do compile { target { *-*-linux* && nonpic } } } */
 /* { dg-require-effective-target mfentry } */
-/* { dg-options "-Wno-old-style-definition -pg -mfentry -mrecord-mcount 
-mnop-mcount" } */
+/* { dg-options "-pg -mfentry -mrecord-mcount -mnop-mcount" } */
 /* { dg-final { scan-assembler-not "__fentry__" } } */
+/* { dg-final { scan-assembler-times "0x0f, 0x1f, 0x44, 0x00, 0x00" 3 } } */
 /* Origin: Andi Kleen */
 extern void foobar(char *);
 
@@ -18,8 +19,7 @@ void func2(void)
     foobar ("Hello world");
 }
 
-void func3(a)
-char *a;
+void func3(char *a)
 {
   foobar("Hello world");
 }
-- 
2.47.3

Reply via email to