On Fri, Nov 28, 2025 at 10:30 AM Mathias Krause <[email protected]> wrote: > > 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]>
OK with a small test adjustment. Thanks, Uros. > --- > 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 } } */ scan-assembled-not here. > +/* { 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 >
