Actions

icon Post
text/html Subscribe
text/html Unsubscribe

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[arm-gnu] Compiler bug using GCC 4.x.x


  • To: "Mark Mitchell" <mark@xxxxxxxxxxxxxxxx>
  • Subject: [arm-gnu] Compiler bug using GCC 4.x.x
  • From: "Remy Bohmer" <linux@xxxxxxxxxx>
  • Date: Tue, 16 Sep 2008 19:27:56 +0200

Hello Mark,

I am using gcc version 4.2.3 (Sourcery G++ Lite 2008q1-126) and I have
discovered a compiler bug which seems to be related to '__attribute__
((packed))' and the code optimiser of GCC 4.x.x.

I have tested several versions of (CodeSourcery) GCC Lite, and the
first versions that delivers somewhat working code is an older GCC 3.x
version (gcc version 3.4.2 (release) (CodeSourcery ARM Q3D 2004) )

Attached I have put a piece of code stripped out of U-boot where I was
debugging this problem.
I stripped it down to the little piece of code that shows the bug.

What happens:
We compile the code with this commandline:
arm-none-linux-gnueabi-gcc -g  -Os -fno-strict-aliasing -Wall -c -o usb.o usb.c

The resulting object code uses register 'r3' as loop counter for the
variable 'i' in the routine usb_set_maxpacket().
BUT: This register is used later on for other purposes, resulting in a
corrupt loop counter 'i'.

The code is optimised which -Os, however, other -O levels generate
different, but also buggy object code as well.

I also attached a file which shows a workaround which I am currently
using for this bug.

Any idea how to get this bug fixed in future versions of GCC?


Kind Regards,

Remy Bohmer
/*
 *
 * this source is stripped OUT of the U-boot source tree to be able to 
 * show a compiler bug...
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 */

/* Endpoint descriptor */
struct usb_endpoint_descriptor {
        unsigned char  dummy[2];
        unsigned char  bEndpointAddress;
        unsigned char  bmAttributes;
        unsigned short wMaxPacketSize;
        unsigned char  dummy2[3];
} __attribute__ ((packed)); /* Packed is not necessary for showing the bug here */

struct usb_interface_descriptor {
        unsigned char  dummy[4];
        unsigned char  bNumEndpoints;
        unsigned char  dummy2[7];
        struct usb_endpoint_descriptor ep_desc[16];
};

/* Device descriptor */
struct usb_device_descriptor {
        unsigned char  dummy[18];
} __attribute__ ((packed));

/* Configuration descriptor information.. */
struct usb_config_descriptor {
        unsigned char  dummy[4];
        unsigned char  bNumInterfaces;
	unsigned char  dummy2[2];
        unsigned char  bmAttributes;
	unsigned char  dummy3[2];
        struct usb_interface_descriptor if_desc[8];
} __attribute__ ((packed));

struct usb_device {
	char dummy[124];
        int epmaxpacketin[16];          /* INput endpoint specific maximums */
        int epmaxpacketout[16];         /* OUTput endpoint specific maximums */

        int dummy2;                   /* selected config number */
        struct usb_device_descriptor descriptor; /* Device Descriptor */
        struct usb_config_descriptor config; /* config descriptor */
};

/*
 * set the max packed value of all endpoints in the given configuration
 */
int usb_set_maxpacket(struct usb_device *dev)
{
	int i,ii,b;
	struct usb_endpoint_descriptor *ep;

	for(i=0; i<dev->config.bNumInterfaces;i++) {
		for(ii=0; ii<dev->config.if_desc[i].bNumEndpoints; ii++) {
			ep = &dev->config.if_desc[i].ep_desc[ii];
			b=ep->bEndpointAddress & 0x0f;

			if((ep->bmAttributes & 0x03)==0) {	/* Control => bidirectional */
				dev->epmaxpacketout[b] = ep->wMaxPacketSize;
				dev->epmaxpacketin [b] = ep->wMaxPacketSize;
			}
			else {
				if ((ep->bEndpointAddress & 0x80)==0) { /* OUT Endpoint */
					if(ep->wMaxPacketSize > dev->epmaxpacketout[b]) {
						dev->epmaxpacketout[b] = ep->wMaxPacketSize;
					}
				}
				else  { /* IN Endpoint */
					if(ep->wMaxPacketSize > dev->epmaxpacketin[b]) {
						dev->epmaxpacketin[b] = ep->wMaxPacketSize;
					}
				} /* if out */
			} /* if control */
		} /* for each endpoint */
	}
	return 0;
}

/* EOF */

Attachment: usb.objdump
Description: Binary data

/*
 *
 * this source is stripped OUT of the U-boot source tree to be able to 
 * show a compiler bug...
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 */

/* Endpoint descriptor */
struct usb_endpoint_descriptor {
        unsigned char  dummy[2];
        unsigned char  bEndpointAddress;
        unsigned char  bmAttributes;
        unsigned short wMaxPacketSize;
        unsigned char  dummy2[3];
} __attribute__ ((packed)); /* Packed is not necessary for showing the bug here */

struct usb_interface_descriptor {
        unsigned char  dummy[4];
        unsigned char  bNumEndpoints;
        unsigned char  dummy2[7];
        struct usb_endpoint_descriptor ep_desc[16];
};

/* Device descriptor */
struct usb_device_descriptor {
        unsigned char  dummy[18];
} __attribute__ ((packed));

/* Configuration descriptor information.. */
struct usb_config_descriptor {
        unsigned char  dummy[4];
        unsigned char  bNumInterfaces;
	unsigned char  dummy2[2];
        unsigned char  bmAttributes;
	unsigned char  dummy3[2];
        struct usb_interface_descriptor if_desc[8];
} __attribute__ ((packed));

struct usb_device {
	char dummy[124];
        int epmaxpacketin[16];          /* INput endpoint specific maximums */
        int epmaxpacketout[16];         /* OUTput endpoint specific maximums */

        int dummy2;                   /* selected config number */
        struct usb_device_descriptor descriptor; /* Device Descriptor */
        struct usb_config_descriptor config; /* config descriptor */
};

/* The routine usb_set_maxpacket_ep() is extracted from the loop of routine
 * usb_set_maxpacket(), because the optimizer of GCC 4.x chokes on this routine
 * when it is inlined in 1 single routine. What happens is that the register r3
 * is used as loop-count 'i', but gets overwritten later on.
 * This is clearly a compiler bug, but it is easier to workaround it here than
 * to update the compiler (Occurs with at least several GCC 4.{1,2},x
 * CodeSourcery compilers like e.g. 2007q3, 2008q1, 2008q3 lite editions on ARM)
 */
static void  __attribute__((noinline))
usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep)
{
       int b;

       b = ep->bEndpointAddress & 0x0f;

       if ((ep->bmAttributes & 0x03) == 0) {
               /* Control => bidirectional */
               dev->epmaxpacketout[b] = ep->wMaxPacketSize;
               dev->epmaxpacketin [b] = ep->wMaxPacketSize;
       } else {
               if ((ep->bEndpointAddress & 0x80) == 0) {
                       /* OUT Endpoint */
                       if (ep->wMaxPacketSize > dev->epmaxpacketout[b]) {
                               dev->epmaxpacketout[b] = ep->wMaxPacketSize;
                       }
               } else {
                       /* IN Endpoint */
                       if (ep->wMaxPacketSize > dev->epmaxpacketin[b]) {
                               dev->epmaxpacketin[b] = ep->wMaxPacketSize;
                       }
               } /* if out */
       } /* if control */
}

/*
 * set the max packed value of all endpoints in the given configuration
 */
int usb_set_maxpacket(struct usb_device *dev)
{
      int i, ii;

      for (i = 0; i < dev->config.bNumInterfaces; i++)
              for (ii = 0; ii < dev->config.if_desc[i].bNumEndpoints; ii++)
                      usb_set_maxpacket_ep(dev,
                                        &dev->config.if_desc[i].ep_desc[ii]);
      return 0;
}
/* EOF */