GCC 4.7.2优化问题

Ver*_*rax 7 c embedded optimization gcc

摘要

我正在使用最新版本的Sourcery CodeBench Lite工具链(GCC arm-none-eabi 4.7.2)将ST的USB OTG库移植到定制的STM32F4板上.

当我用-O0编译代码时,程序运行正常.当我用-O1或-O2编译时它失败了.当我说失败时,它就会停止.没有硬故障,没有(好吧,显然它有一些东西,但我没有一个模拟器用于调试和发现,我很抱歉.我的硬故障处理程序没有被调用).

细节

我正在尝试调用以下函数...

void USBD_Init(USB_OTG_CORE_HANDLE *pdev,
           USB_OTG_CORE_ID_TypeDef coreID, 
           USBD_DEVICE *pDevice,                  
           USBD_Class_cb_TypeDef *class_cb, 
           USBD_Usr_cb_TypeDef *usr_cb);
Run Code Online (Sandbox Code Playgroud)

...但它似乎没有进入功能体.(这是"砸碎"的症状吗?)

传递给此函数的结构具有以下定义:

typedef struct USB_OTG_handle
{
  USB_OTG_CORE_CFGS    cfg;
  USB_OTG_CORE_REGS    regs;
  DCD_DEV     dev;
}
USB_OTG_CORE_HANDLE , *PUSB_OTG_CORE_HANDLE;

typedef enum
{
  USB_OTG_HS_CORE_ID = 0,
  USB_OTG_FS_CORE_ID = 1
}USB_OTG_CORE_ID_TypeDef;

typedef struct _Device_TypeDef
{
  uint8_t  *(*GetDeviceDescriptor)( uint8_t speed , uint16_t *length);  
  uint8_t  *(*GetLangIDStrDescriptor)( uint8_t speed , uint16_t *length); 
  uint8_t  *(*GetManufacturerStrDescriptor)( uint8_t speed , uint16_t *length);  
  uint8_t  *(*GetProductStrDescriptor)( uint8_t speed , uint16_t *length);  
  uint8_t  *(*GetSerialStrDescriptor)( uint8_t speed , uint16_t *length);  
  uint8_t  *(*GetConfigurationStrDescriptor)( uint8_t speed , uint16_t *length);  
  uint8_t  *(*GetInterfaceStrDescriptor)( uint8_t speed , uint16_t *length);   
} USBD_DEVICE, *pUSBD_DEVICE;

typedef struct _Device_cb
{
  uint8_t  (*Init)         (void *pdev , uint8_t cfgidx);
  uint8_t  (*DeInit)       (void *pdev , uint8_t cfgidx);
 /* Control Endpoints*/
  uint8_t  (*Setup)        (void *pdev , USB_SETUP_REQ  *req);  
  uint8_t  (*EP0_TxSent)   (void *pdev );    
  uint8_t  (*EP0_RxReady)  (void *pdev );  
  /* Class Specific Endpoints*/
  uint8_t  (*DataIn)       (void *pdev , uint8_t epnum);   
  uint8_t  (*DataOut)      (void *pdev , uint8_t epnum); 
  uint8_t  (*SOF)          (void *pdev); 
  uint8_t  (*IsoINIncomplete)  (void *pdev); 
  uint8_t  (*IsoOUTIncomplete)  (void *pdev);   
  uint8_t  *(*GetConfigDescriptor)( uint8_t speed , uint16_t *length);  
  uint8_t  *(*GetUsrStrDescriptor)( uint8_t speed ,uint8_t index,  uint16_t *length);   

} USBD_Class_cb_TypeDef;

typedef struct _USBD_USR_PROP
{
  void (*Init)(void);   
  void (*DeviceReset)(uint8_t speed); 
  void (*DeviceConfigured)(void);
  void (*DeviceSuspended)(void);
  void (*DeviceResumed)(void);  

  void (*DeviceConnected)(void);  
  void (*DeviceDisconnected)(void);    

}
USBD_Usr_cb_TypeDef;
Run Code Online (Sandbox Code Playgroud)

我试图包含与此问题相关的所有源代码.如果您想查看完整的源代码,可以在此处下载:http: //www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware/stm32_f105-07_f2_f4_usb -host-device_lib.zip

解决方案试图

我试图用玩#pragma GCC optimize ("O0"),__attribute__((optimize("O0")))和宣布某些定义的volatile,但毫无效果.我宁愿只修改代码,使其与优化器完美匹配.

如何修改此代码以使其与GCC的优化器一起使用?

mfr*_*fro 2

您显示的代码似乎没有任何问题,因此这个答案会更通用。

“接近硬件”代码在未经优化的情况下正常工作并且在更高的优化级别下失败的典型错误是什么?

考虑一下-O0和之间的差异-O1/-O2:优化策略包括 - 除其他外 - 循环展开(似乎并不危险)、尝试尽可能长时间地在寄存器中保存值、消除死代码和指令重新排序。

如果没有正确声明可以随时更改的硬件寄存器,则改进的寄存器使用通常会导致更高优化级别的问题volatile(请参阅上面 PokyBrain 的评论)。优化的代码将尝试尽可能长时间地保存寄存器中的值,从而导致您的程序无法注意到硬件方面的更改。确保volatile正确声明硬件寄存器

如果您需要读取硬件寄存器以对编译器未知的硬件产生任何影响,并且不对您刚刚读取的值执行任何操作,则死代码消除可能会导致问题。如果您没有void正确声明用于读取访问的变量,这些硬件访问可能会被优化(不过编译器应该发出警告)。确保将虚拟读取投射到(void)

指令重新排序:如果您需要按特定顺序访问不同的硬件寄存器以产生所需的结果,并且如果您通过以任何方式不相关的指针来执行此操作,则编译器可以自由地对结果指令进行重新排序,因为它认为合适(即使硬件寄存器正确声明volatile)。您需要在代码中添加内存屏障以强制执行所需的访问顺序 ( __asm__ __volatile__(::: "memory");)。确保在需要的地方添加内存屏障。

尽管不太可能,但您仍然可能发现编译器错误。优化并不是一件容易的事,尤其是当它涉及到硬件时。也许值得一看 gcc bug 数据库。

如果所有这些都没有帮助,有时您将不可避免地深入研究生成的汇编代码以确保其执行应有的操作。