Re: egcs 1.0.1 miscompiles Linux 2.0.33

Andi Kleen (
25 Feb 1998 12:59:38 +0100

Jeffrey A Law <> writes:

> In message <>you write:
> > [x-posted to linux-kernel and egcs mailing lists]
> >
> > Compiling the Linux kernel 2.0.33 with haifa-enabled egcs 1.0.1 causes a
> > repeatable kernel oops for me in vortex_open() during ifconfig.
> > I had used "-O3 -fomit-frame-pointer -mcpu=pentium" as the
> > architecture-specific settings for a 586. This does not happen with
> > gcc
> Hmm, I've got a stock 2.0.33 working with the current 1.0.2 prerelease
> sources with the following options for my two x86 boxes:
> "-O2 -fomit-frame-pointer -mcpu=pentium -march=pentium"
> "-O2 -fomit-frame-pointer -mcpu=pentiumpro -march=pentiumpro"
> I didn't configure for haifa, and I also don't have 3c59x configured
> into my kernel (cuz I don't have a vortex :-)
> We're closing in on an egcs-1.0.2 release, and I'd like to nail down
> any problems of this nature asap. What can I do to help y'all
> nail this problem down?

Last time a similar problem came up (with pgcc) it was attributed to
some bad contraints in asm-i386/string.h. When I remember it right Linus
argued at this time that gcc wasn't following its own documented
behaviour so that he didn't intent to fix it in the kernel.

Maybe Linus can comment himself on the issue?

Afaik the ioport.c problem (which doesn't occur on egcs 1.0.x because
it doesn't do the ADDRESSOF optimization yet) and this string.h problem
that bites with some drivers are the only known problems that cause the
Linux kernel to be miscompiled by egcs/gcc 2.8.0

Here is a message from Gabriel Paubert with an analysis:

------------- please bite here ------------- bitte hier abbeissen ---------

Sorry if this message is long, but I think it is _very_ important. And
although it is probably more kernel related than gcc related, it is
also interesting to all linux-gcc readers IMHO.

All started with the following exception report:

On Wed, 1 Oct 1997, Oliver Teuber wrote:

> hello
> today i bought a new dec network adapter DE500-AA ...
> Sep 30 23:57:02 olibox kernel: loading device 'eth0'...
> Sep 30 23:57:02 olibox kernel: Unable to handle kernel paging request at virtual address f3344544
> Sep 30 23:57:02 olibox kernel: current->tss.cr3 = 07466000, hr3 = 07466000
> Sep 30 23:57:02 olibox kernel: *pde = 00000000
> Sep 30 23:57:02 olibox kernel: Oops: 0000
> Sep 30 23:57:02 olibox kernel: CPU: 0
> Sep 30 23:57:02 olibox kernel: EIP: 0010:[<0884df3b>]
> Sep 30 23:57:02 olibox kernel: EFLAGS: 00010206
> Sep 30 23:57:02 olibox kernel: eax: 07470ea4 ebx: 00000000 ecx: 00000005 edx: 00000005
> Sep 30 23:57:02 olibox kernel: esi: 07470ea4 edi: 33344544 ebp: 07470ea4 esp: 07470e7c
> Sep 30 23:57:02 olibox kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
> Sep 30 23:57:02 olibox kernel: Process insmod (pid: 96, process nr: 13, stackpage=07470000)
> Sep 30 23:57:02 olibox kernel: Stack: 07ce7408 00001000 00000001 07ce7408 ffffffff 00000000 0000ffff 001f81d8
> Sep 30 23:57:02 olibox kernel: 07470eac 00000000 3f3f5f5f 0000003f 08851274 0885127a 08851280 08851286
> Sep 30 23:57:02 olibox kernel: 0885128c 0884abb1 07470ee8 00001c80 07ce7408 00000000 ffffffed 07ce7408
> Sep 30 23:57:02 olibox kernel: Call Trace: [<08851274>] [<0885127a>] [<08851280>] [<08851286>] [<0885128c>] [<0884abb1>] [<0884901a>]
> Sep 30 23:57:02 olibox kernel: [register_netdev+93/228] [<08849000>] [<08850afc>] [<08850b36>] [sys_init_module+963/1028] [<08849000>] [do_no_page+0/852] [<08850afc>]
> Sep 30 23:57:02 olibox kernel: [<08850b50>] [do_page_fault+0/816] [system_call+258/320]
> Sep 30 23:57:02 olibox kernel: Code: f3 a6 74 0a 96 46 80 78 ff 00 75 ed 31 c0 85 c0 74 17 89 ee

After analysing I came to the conclusion that it occured in a strstr inlined
function. Oliver used pgcc to compile 2.0.30 and I could not reproduce the
problem with standard gcc. However the strange thing was the content
of %edi: "DE43" in ASCII. The pointed to value instead of the pointer !

Then after rambling through GCC doc (I've learnt a lot today :-)), I came
to the conclusion that this is either a bug in pgcc or, more likely
bad constraints in asm-i386/string.h. Let us have a look at the strstr
asm statement:

__asm__ __volatile__(
"cld\n\t" \
"movl %4,%%edi\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
"movl %%ecx,%%edx\n"
"1:\tmovl %4,%%edi\n\t"
"movl %%esi,%%eax\n\t"
"movl %%edx,%%ecx\n\t"
"je 2f\n\t" /* also works for empty string, see above */
"xchgl %%eax,%%esi\n\t"
"incl %%esi\n\t"
"cmpb $0,-1(%%eax)\n\t"
"jne 1b\n\t"
"xorl %%eax,%%eax\n\t"
:"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
return __res;

If I correctly understand GCC doc, nothing prevents gcc from using %edi
and %edx to compute argument %4. So I sent the following patch appended
at the end which tried to prevent this by allocating %edi as an input
parameter and used two additional scratch variables allocated by the
compiler as modified and used ("=&" constraints) parameters.

I think this is The Right Way (TM acknowledged) to declare scratch
variables for inline assembly. gcc correctly recognizes that the variable is
dead after the asm statement and does not generate any superfluous code.

The de4x5 driver now works when compiled with pgcc (and quite well
according to Oliver's report). Later I got object files he compiled
without and without my patch and they confirmed my earlier hypothesis, the
second movl %4,%%edi used %edi in its addressing mode, hence the fault.

Is it possible that many of the pgcc problems reported until now were due
to this ? (Again I think that it is not a pgcc problem, correct me if I am
wrong. I sometimes have problem understanding gcc doc [1]).

According to my findings, the following functions in asm-i386/string.h are
potential victims of this problem (should I call it a bug ?), there
might be similar problems in other files (unlikely IMHO):

strspn, strcspn, strpbrk, strstr, and strtok.

the cure is probably similar. But before starting to send a larger patch,
I would like to hear the opinion of experts on the subject :-)


[1] Could a native english speaker explain me the semantic subtleties of the
first of the following sentences :-); Intel took the pain to rewrite it
between Pentium and PPro documentation, so it must be important ;):

"The C1 flag is set to 0; otherwise, cleared to 0. The C0, C2, and C3
flags are undefined." (Intel Architecture Software Developer's Reference,
Volume 2 [24319101.pdf]. On fdecstp and fincstp instructions.)

Here is the patch, I've been trying to allow the compiler to use memory
instead of registers if it is too short on registers (eternal Intel problem),
but it has not been very successful. And BTW if I try to compile the
driver with -fpic, it apparently triggers a compiler bug :(.

--- linux-2.0.30/include/asm-i386/ Wed Oct 1 10:55:48 1997
+++ linux-2.0.30/include/asm-i386/string.h Wed Oct 1 14:18:21 1997
@@ -261,29 +261,32 @@
extern inline char * strstr(const char * cs,const char * ct)
-register char * __res;
+char * __res;
+const char *_ct;
+int len;
__asm__ __volatile__(
"cld\n\t" \
- "movl %4,%%edi\n\t"
+ "movl %%edi,%2\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
- "movl %%ecx,%%edx\n"
- "1:\tmovl %4,%%edi\n\t"
+ "movl %%ecx,%1\n"
+ "1:\tmovl %2,%%edi\n\t"
"movl %%esi,%%eax\n\t"
- "movl %%edx,%%ecx\n\t"
"je 2f\n\t" /* also works for empty string, see above */
"xchgl %%eax,%%esi\n\t"
+ "movl %1,%%ecx\n\t"
"incl %%esi\n\t"
"cmpb $0,-1(%%eax)\n\t"
"jne 1b\n\t"
"xorl %%eax,%%eax\n\t"
- :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
- :"cx","dx","di","si");
+ :"=a,a,a,a" (__res), "=&r,?m,&r,?m" (len), "=&r,&r,?m,?m" (_ct)
+ :"0,0,0,0" (0),"c,c,c,c" (0xffffffff),"S,S,S,S" (cs),"D,D,D,D" (ct)
+ :"cx","di","si");
return __res;


To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to