C 访问.rodata节中的特定数据时,应用程序崩溃
我不得不完全重新表述这个问题及其标题,因为我最初的分析结果是错误的(感谢所有的提示和建议!)。问题的旧标题是: GCC-O3将二进制文件弄乱并产生数据垃圾 事实证明,这与优化级别无关,我也不确定数据是否是垃圾 总之,这些是我正在使用的SDK代码的相关片段。显然,我不能在这里发布整个SDK代码 首先,我有两个常数:C 访问.rodata节中的特定数据时,应用程序崩溃,c,gcc,arm,embedded,C,Gcc,Arm,Embedded,我不得不完全重新表述这个问题及其标题,因为我最初的分析结果是错误的(感谢所有的提示和建议!)。问题的旧标题是: GCC-O3将二进制文件弄乱并产生数据垃圾 事实证明,这与优化级别无关,我也不确定数据是否是垃圾 总之,这些是我正在使用的SDK代码的相关片段。显然,我不能在这里发布整个SDK代码 首先,我有两个常数: static const usb_device_controller_interface_struct_t s_UsbDeviceEhciInterface = { USB_D
static const usb_device_controller_interface_struct_t s_UsbDeviceEhciInterface = {
USB_DeviceEhciInit, USB_DeviceEhciDeinit, USB_DeviceEhciSend,
USB_DeviceEhciRecv, USB_DeviceEhciCancel, USB_DeviceEhciControl};
及
在我的main.c中,似乎不相关,有以下片段:
if (kStatus_USB_Success != error)
{
usb_echo("kUSB_DeviceCdcEventSetControlLineState error!");
}
if (kStatus_USB_Success != error)
{
usb_echo("kUSB_DeviceCdcEventSetControlLineState error!");
}
现在,如果我使用-O3
编译,应用程序在访问s_-UsbDeviceEhciInterface
时崩溃,使用-O0
则应用程序在访问s_-usbdevicelclasseinterfacemap
时崩溃
这两次似乎都涉及到第三个代码段
对于-O3
,反汇编中的数据对于s_usbdeviceehcii接口来说如下所示:
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!...
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 !...
对于-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};
在其他地方,在另一个看似无关的文件中,我有一个片段:
if (kStatus_USB_Success != error)
{
usb_echo("kUSB_DeviceCdcEventSetControlLineState error!");
}
if (kStatus_USB_Success != error)
{
usb_echo("kUSB_DeviceCdcEventSetControlLineState error!");
}
现在,访问s_usbdeviceehcii界面
会使应用程序崩溃。查看反汇编文件,我发现以下内容:
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!...
这仅在我使用-O3
优化时发生。当我切换到-O0
时,一切似乎又恢复了正常
这种情况是如何发生的?在仍然使用-O3
的情况下,有没有办法防止这种情况发生
编辑:我刚刚意识到它也发生在-O0
中,只是在数据的另一部分。也许我弄糟了我的链接器脚本?注意:这不是对崩溃的解释,而是试图解释假定的数据垃圾
您的反汇编似乎是从最终的可执行文件进行的。在该文件中,收集所有常量并将其附加到rodata
部分。静态和常量结构s_UsbDeviceEhciInterface
显然是只读数据,正如您在它后面找到的字符串文字一样
两者的区别在于前者有一个用户定义的名称,s_UsbDeviceEhciInterface
,后者没有。这就是为什么反汇编将名称显示为起始标签,但不显示字符串的起始标签
您可以生成一个映射文件(链接器的选项-map
),并查看多个对象及其位置
因此,no,-O3
不会产生数据垃圾
由于您发现-O0
也会导致崩溃,因此需要从另一个方向进行调查。考虑部分溢出、悬空指针、未初始化变量等等。将所有警告级别提高到最大值 注意:这不是对崩溃的解释,而是试图解释假定的数据垃圾
您的反汇编似乎是从最终的可执行文件进行的。在该文件中,收集所有常量并将其附加到rodata
部分。静态和常量结构s_UsbDeviceEhciInterface
显然是只读数据,正如您在它后面找到的字符串文字一样
两者的区别在于前者有一个用户定义的名称,s_UsbDeviceEhciInterface
,后者没有。这就是为什么反汇编将名称显示为起始标签,但不显示字符串的起始标签
您可以生成一个映射文件(链接器的选项-map
),并查看多个对象及其位置
因此,no,-O3
不会产生数据垃圾
由于您发现-O0
也会导致崩溃,因此需要从另一个方向进行调查。考虑部分溢出、悬空指针、未初始化变量等等。将所有警告级别提高到最大值 请尝试获取代码的反汇编输出,而不是查看原始十六进制转储。这不可能帮助您,因为您只提供了代码的一小部分。毫无疑问,您有一个代码错误,它不会为-O0显示,而只为-O3显示。发布完整的代码示例…打开编译器警告。GCC可能正在消除一个死代码路径。我刚刚意识到-O0也会发生这种情况,只是在另一个地方。我将尝试打开我的编译器警告,谢谢@JL2210@Someprogrammerdude:原始十六进制转储是数据对象,而不是代码。请尝试获取代码的反汇编输出,而不是查看原始十六进制转储。由于您只提供了代码的一小部分,因此无法为您提供帮助。毫无疑问,您有一个代码错误,它不会为-O0显示,而只为-O3显示。发布完整的代码示例…打开编译器警告。GCC可能正在消除一个死代码路径。我刚刚意识到-O0也会发生这种情况,只是在另一个地方。我将尝试打开我的编译器警告,谢谢@JL2210@Someprogrammerdude:原始十六进制转储文件是数据对象,不是代码。感谢您的解释,我将查看映射文件并提高所有警告级别。我发现有趣的是,对于-O0
来说,同样的事情发生在另一个常数上。不过,您是对的,对我来说,它可能看起来像垃圾,因为其中一个数据结构没有用户定义的名称。不管怎样,我会继续调查的。可能是某种溢出。感谢您的解释,我将查看地图文件并提高所有警告级别。我觉得很有趣
000042b4 <s_UsbDeviceEhciInterface>:
42b4: 00000479 00000b0d 00000b49 00000b55 y.......I...U...
42c4: 00000b5d 00000d35 ]...5...