This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

gcc optimizer bug


Gcc compiles following piece of C code: (completed source file is attached)

        u_short *ptr;
        int sum, oddbyte;

        oddbyte = 0; 
        *((u_char *) &oddbyte) = *(u_char *) ptr;
        sum += oddbyte;

into compiled into (%esi = ptr, %ecx = sum)

0x28067038 <TcpChecksum+80>:    movb   (%esi),%al
0x2806703a <TcpChecksum+82>:    addl   %eax,%ecx

note that higher bytes of %eax are not cleared.

This machine is a P5 133Mhz PC running FreeBSD-current, and here is
gcc -v --save-temps output:

Using builtin specs.
gcc version egcs-2.91.66 19990314 (egcs-1.1.2 release)
 /usr/libexec/cpp -lang-c -v -undef -D__GNUC__=2 -D__GNUC_MINOR__=91 -Di386 -Dunix -D__FreeBSD__=4 -D__FreeBSD_cc_version=400002 -D__i386__ -D__unix__ -D__FreeBSD__=4 -D__FreeBSD_cc_version=400002 -D__i386 -D__unix -Acpu(i386) -Amachine(i386) -Asystem(unix) -Asystem(FreeBSD) -D__OPTIMIZE__ -D__ELF__ a.c a.i
GNU CPP version egcs-2.91.66 19990314 (egcs-1.1.2 release) (i386 FreeBSD/ELF)
#include "..." search starts here:
#include <...> search starts here:
 /usr/include
End of search list.
 /usr/libexec/cc1 a.i -quiet -dumpbase a.c -O -version -o a.s
GNU C version egcs-2.91.66 19990314 (egcs-1.1.2 release) (i386-unknown-freebsd) compiled by GNU C version egcs-2.91.66 19990314 (egcs-1.1.2 release).
 /usr/libexec/elf/as -v -o a.o a.s
GNU assembler version 2.9.1 (i386-unknown-freebsdelf), using BFD version 2.9.1
 /usr/libexec/elf/ld -m elf_i386 -dynamic-linker /usr/libexec/ld-elf.so.1 -o a /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/libdata/gcc -L/usr/libexec/elf -L/usr/libexec a.o /usr/lib/libgcc.a -lc /usr/lib/libgcc.a /usr/lib/crtend.o /usr/lib/crtn.o

The complete C source file. pkt is an actual tcp packet captured by tcpdump
which has a bad tcp checksum generated by TcpChecksum().

#include <sys/types.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

u_short pkt[] = {
	0x4510, 0x0051, 0x3f17, 0x4000, 0x3f06, 0xc9ca, 0xcfca, 0x49aa,
	0xcfca, 0x4976, 0x040c, 0x0015, 0x5e7a, 0x8495, 0xb73b, 0xbf64,
	0x8018, 0x43e0, 0xf71c, 0x0000, 0x0101, 0x080a, 0x0000, 0x410a,
	0x0000, 0x7e28, 0x504f, 0x5254, 0x2032, 0x3037, 0x2c32, 0x3032,
	0x2c37, 0x332c, 0x3137, 0x302c, 0x3232, 0x392c, 0x3231, 0x340d,
	0x0a00,
};

#define	NPKT	(sizeof(pkt)/sizeof(pkt[0]))

extern u_short TcpChecksum(struct ip *);

main()
{
	int i;
	int sum;
	u_short buf[NPKT];

	for (i = 0; i < NPKT; i++)
		buf[i] = htons(pkt[i]);
	sum = TcpChecksum((struct ip *)buf);
	printf("sum = %x, %x\n", sum, sum % 0xffff);

#if 0
	sum = htons(pkt[4] & 0xff);
	for (i = 6; i < NPKT; i++) {
		sum += htons(pkt[i]);
	}
	sum += htons(pkt[1] - 0x14);
	printf("sum = %x, %x\n", sum, sum % 0xffff);
#endif
}

u_short 
TcpChecksum(struct ip *pip)
{
    u_short *ptr;
    struct tcphdr *tc;
    int nhdr, ntcp, nbytes;
    int sum, oddbyte;

    nhdr = pip->ip_hl << 2;
    ntcp = ntohs(pip->ip_len) - nhdr;

    tc = (struct tcphdr *) ((char *) pip + nhdr);
    ptr = (u_short *) tc;
    
/* Add up TCP header and data */
    nbytes = ntcp;
    sum = 0;
    while (nbytes > 1)
    {
        sum += *ptr++;
        nbytes -= 2;
    }
    if (nbytes == 1)
    {
        oddbyte = 0;
        *((u_char *) &oddbyte) = *(u_char *) ptr;
        sum += oddbyte;
    }

/* "Pseudo-header" data */
    ptr = (u_short *) &(pip->ip_dst);
    sum += *ptr++;
    sum += *ptr;
    ptr = (u_short *) &(pip->ip_src);
    sum += *ptr++;
    sum += *ptr;
    sum += htons((u_short) ntcp);
    sum += htons((u_short) pip->ip_p);

/* Roll over carry bits */
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);

/* Return checksum */
    return((u_short) ~sum);
}



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]