Сбой приложения при доступе к конкретным данным в разделе .rodata - PullRequest
0 голосов
/ 27 октября 2019

Мне пришлось перефразировать этот вопрос и его название полностью, потому что мой первоначальный анализ оказался неверным ( спасибо за все подсказки и предложения!) . Старый заголовок вопроса звучал так:

GCC -O3 портит двоичный файл и производит мусор данных

Как оказалось, он не имеет ничего общего с уровнями оптимизациии я не уверен, что данные также являются мусором.

В любом случае, это соответствующие фрагменты кода SDK, который я использую. Я не могу опубликовать весь код 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, по-видимомуне имеет отношения, есть этот фрагмент:

if (kStatus_USB_Success != error)
{
    usb_echo("kUSB_DeviceCdcEventSetControlLineState error!");
}

Теперь, , если я компилирую с -O3, приложение вылетает при доступе к s_UsbDeviceEhciInterface, с -O0 приложение вылетает при обращении к s_UsbDeviceClassInterfaceMap.

Оба раза кажется, что задействован третий фрагмент кода.

С -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

Напомним: приложение всегда аварийно завершает работу при обращении к константе, предшествующей константной строке, из основного.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!");
}

Теперь доступ к 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!...

, представляющее собой комбинацию двух не связанных между собой частей кода!

Если удалить второй фрагмент кода, доступ к s_UsbDeviceEhciInterface работаеточередной раз. В этом случае разборка выглядит следующим образом:

000042b4 <s_UsbDeviceEhciInterface>:
    42b4:   00000479 00000b0d 00000b49 00000b55     y.......I...U...
    42c4:   00000b5d 00000d35                       ]...5...

Это происходит только тогда, когда я использую оптимизацию -O3. Когда я переключаюсь на -O0, все снова кажется нормальным.

Как это происходит и есть ли способ предотвратить это, все еще используя -O3?

РЕДАКТИРОВАТЬ: я только что понял, что это происходитс -O0 также, просто в другой части данных. Может я испортил свой скрипт компоновщика?

1 Ответ

2 голосов
/ 27 октября 2019

Примечание. Это не объяснение вашего сбоя, а попытка объяснить предполагаемый мусор данных.

Кажется, ваша разборка сделана из окончательного исполняемого файла. В этом файле все константы собраны и добавлены в раздел rodata. Статическая и константная структура s_UsbDeviceEhciInterface являются данными только для чтения, поскольку строковый литерал, который вы нашли сразу после него.

Разница между ними заключается в том, что у первого есть пользовательское имя s_UsbDeviceEhciInterface,а последний нет. Вот почему при разборке имя отображается в качестве начальной метки, но не для строки.

Вы можете создать файл карты (опция -Map для компоновщика) и просмотреть несколько объектов и их размещение.

Итак, no , -O3 не генерирует мусор данных.

Поскольку вы обнаружили, что -O0 также приводит к сбоям, вам необходимо исследовать в другом направлении. Подумайте о переполнении разделов, висячих указателях, неинициализированных переменных и так далее. Поднимите все уровни предупреждений до максимума!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...