【发布时间】:2019-10-27 17:14:24
【问题描述】:
我不得不完全改写这个问题及其标题,因为我最初的分析结果是错误的(感谢所有提示和建议!)。问题的旧标题是:
GCC -O3 搞乱二进制文件并产生数据垃圾
事实证明它与优化级别无关,我也不确定数据是否垃圾。
无论如何,这些是我正在使用的 SDK 代码的相关 sn-ps。我显然不能在这里发布整个 SDK 代码。
首先我有两个常量:
static const usb_device_controller_interface_struct_t s_UsbDeviceEhciInterface = {
USB_DeviceEhciInit, USB_DeviceEhciDeinit, USB_DeviceEhciSend,
USB_DeviceEhciRecv, USB_DeviceEhciCancel, USB_DeviceEhciControl};
和
static const usb_device_class_map_t s_UsbDeviceClassInterfaceMap[] = {
{USB_DeviceCdcAcmInit, USB_DeviceCdcAcmDeinit, USB_DeviceCdcAcmEvent, kUSB_DeviceClassTypeCdc},
{(usb_device_class_init_call_t)NULL, (usb_device_class_deinit_call_t)NULL, (usb_device_class_event_callback_t)NULL,
(usb_device_class_type_t)0},
};
在我的 main.c 中,看似无关,有这个 sn-p:
if (kStatus_USB_Success != error)
{
usb_echo("kUSB_DeviceCdcEventSetControlLineState error!");
}
现在,如果我使用-O3 编译,应用程序在访问s_UsbDeviceEhciInterface 时崩溃,使用-O0 时应用程序在访问s_UsbDeviceClassInterfaceMap 时崩溃。
似乎都涉及到第三个代码 sn-p。
使用-O3,反汇编中的数据对于s_UsbDeviceEhciInterface如下所示:
000066b4 <s_UsbDeviceEhciInterface>:
66b4: 00000479 0000145d 00001499 000014a5 y...]...........
66c4: 000014ad 00001685 4253556b 7665445f ........kUSB_Dev
66d4: 43656369 76456364 53746e65 6f437465 iceCdcEventSetCo
66e4: 6f72746e 6e694c6c 61745365 65206574 ntrolLineState e
66f4: 726f7272 00000021 rror!...
而s_UsbDeviceClassInterfaceMap 似乎根本不存在。
使用-O0,反汇编中的数据对于s_UsbDeviceEhciInterface如下所示:
00009164 <s_UsbDeviceEhciInterface>:
9164: 000018b5 00001999 00006ebb 00006eed .........n...n..
9174: 00001a21 00001c35 !...5...
对于s_UsbDeviceClassInterfaceMap:
0000917c <s_UsbDeviceClassInterfaceMap>:
917c: 00007eb1 00007f49 00002985 00000002 .~..I....)......
...
919c: 00007071 4253556b 7665445f 43656369 qp..kUSB_DeviceC
91ac: 76456364 53746e65 6f437465 6f72746e dcEventSetContro
91bc: 6e694c6c 61745365 65206574 726f7272 lLineState error
91cc: ffff0021 !...
在映射文件中,我们可以看到两次 main.c 数据跟随 const - 正如反汇编所暗示的那样。对于-O3:
.rodata.s_UsbDeviceEhciInterface
0x00000000000066b4 0x18 ./usb/device/source/usb_device_dci.o
.rodata.USB_DeviceCdcVcomCallback.str1.4
0x00000000000066cc 0x30 ./source/main.o
对于-O0:
.rodata.s_UsbDeviceEhciInterface
0x0000000000009164 0x18 ./usb/device/source/usb_device_dci.o
.rodata.s_UsbDeviceClassInterfaceMap
0x000000000000917c 0x20 ./usb/device/class/usb_device_class.o
.rodata 0x000000000000919c 0x32 ./source/main.o
回顾一下:从 main.c 访问常量字符串之前的常量时,应用程序总是崩溃
我尝试启动编译器警告,但在 SDK 代码中只得到一些未使用的参数。
为了完整起见,这是原始问题:
过时(见上文)
所以,我有这个代码:
static const usb_device_controller_interface_struct_t s_UsbDeviceEhciInterface = {
USB_DeviceEhciInit, USB_DeviceEhciDeinit, USB_DeviceEhciSend,
USB_DeviceEhciRecv, USB_DeviceEhciCancel, USB_DeviceEhciControl};
在其他地方,在另一个看似无关的文件中,我有这个 sn-p:
if (kStatus_USB_Success != error)
{
usb_echo("kUSB_DeviceCdcEventSetControlLineState error!");
}
现在,访问s_UsbDeviceEhciInterface 会使应用程序崩溃。查看反汇编文件,我发现以下内容:
00006674 <s_UsbDeviceEhciInterface>:
6674: 00000479 0000145d 00001499 000014a5 y...]...........
6684: 000014ad 00001685 4253556b 7665445f ........kUSB_Dev
6694: 43656369 76456364 53746e65 6f437465 iceCdcEventSetCo
66a4: 6f72746e 6e694c6c 61745365 65206574 ntrolLineState e
66b4: 726f7272 00000021 rror!...
这似乎是两个不相关的代码部分的组合!
如果我删除第二个代码 sn-p 访问 s_UsbDeviceEhciInterface 再次工作。然后反汇编看起来像这样,这更有意义:
000042b4 <s_UsbDeviceEhciInterface>:
42b4: 00000479 00000b0d 00000b49 00000b55 y.......I...U...
42c4: 00000b5d 00000d35 ]...5...
这仅在我使用 -O3 优化时发生。当我切换到-O0 时,一切似乎又好了。
这是怎么发生的?有没有办法在仍然使用-O3 的同时防止这种情况发生?
编辑:我刚刚意识到-O0 也会发生这种情况,只是在数据的另一部分。也许我搞砸了我的链接器脚本?
【问题讨论】:
-
请尝试获取代码的反汇编输出,而不是查看原始的十六进制转储。
-
无法帮助您,因为您只提供了一小部分代码。毫无疑问,您有一个代码错误,它不显示为 -O0,而只显示为 -O3。贴一个完整的代码示例...
-
打开编译器警告。 GCC 可能正在消除死代码路径。
-
我刚刚意识到它也发生在 -O0 上,只是在不同的地方。我会尝试打开我的编译器警告,谢谢@JL2210
-
@Someprogrammerdude :“原始十六进制转储”是数据对象,而不是代码。