ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Вторник
23 апреля
1219633
VVB (30.06.2022 16:54, просмотров: 6456)
Прошу помощи зала по GCC 

Пилю проект на NUC9xx+FreeRTOS+lwIP1.4.1 на GCC10. Вылезла проблема на высоких уровнях оптимизации (-O2, -O3): некоторые переменные меняются неправильно. То есть считывание переменной и её сравнение с ожидаемым результатом даёт сбой.

С кэшами разобрался, дело не в них.


Решил включить -O1 и последовательно подключать все опции для достижения -O2. Оказалось, опция "-ftree-pre" приводит к сбою.

Пошёл дальше: выяснил исходник, для которого включение опции "-ftree-pre" приводит к сбою. Это оказался исходник lwIP src/core/netif.c.

Пошёл дальше: сравнил карту памяти для сбойной прошивки и для работающей без сбоя (прошивки отличаются только наличием опции компилятора "-ftree-pre" для netif.c). Удивился результату сравнения карты памяти, конкретно: различие имеется всего в одном месте, в невыровненном по слову адресе переменной.


Карта памяти для сбойной прошивки выглядит следующим образом:

 .bss           0x00000000001820a8        0x9 objs/debug/./lwIP/1.4.1/lwip/src/core/netif.o
                0x00000000001820a8                netif_list
                0x00000000001820ac                netif_default
 .bss           0x00000000001820b1        0x1 objs/debug/./lwIP/1.4.1/lwip/src/core/pbuf.o
                0x00000000001820b1                pbuf_free_ooseq_pending
 *fill*         0x00000000001820b2        0x2 
 .bss           0x00000000001820b4        0x4 objs/debug/./lwIP/1.4.1/lwip/src/core/raw.o

Карта памяти для работающей прошивки выглядит следующим образом:

 .bss           0x00000000001820a8        0xc objs/debug/./lwIP/1.4.1/lwip/src/core/netif.o
                0x00000000001820a8                netif_list
                0x00000000001820b0                netif_default
 .bss           0x00000000001820b4        0x1 objs/debug/./lwIP/1.4.1/lwip/src/core/pbuf.o
                0x00000000001820b4                pbuf_free_ooseq_pending
 *fill*         0x00000000001820b5        0x3 
 .bss           0x00000000001820b8        0x4 objs/debug/./lwIP/1.4.1/lwip/src/core/raw.o

В модуле netif.c имеется три переменных, объявленных в следующем порядке:

struct netif *netif_list;
struct netif *netif_default;
static u8_t netif_num;

В модуле pbuf.c имеется одна переменая:

volatile u8_t pbuf_free_ooseq_pending;

Видно, что линкер размещает переменные модулей netif.o и pbuf.o друг за другом.

Но в работающей прошивке линкер размещает переменную netif_num модуля netif.o в 4 байтах, и следующая размещаемая переменная pbuf_free_ooseq_pending модуля pbuf.o размещается по адресу, выровненному по границам слова.

А в неработающей прошивке линкер размещает переменную netif_num модуля netif.o в 1 байте, не производит выравнивания по границе слова при размещении переменных следущющего модуля, и следующая размещаемая переменная pbuf_free_ooseq_pending модуля pbuf.o размещается по адресу, не выровненному по границам слова.


Догадку проверил просто: изменил тип переменной netif_num с u8_t на u32_t (для обеспечения размещения переменной pbuf_free_ooseq_pending по выровненному адресу), и сбойная прошивка начала работать без сбоя.


Отсюда вопросы:

1. почему линкер не выравнивает переменные, размера меньше чем слово, по адресу, кратному слову?

2. как заставить линкер производить выравнивание адреса размещения переменных внутри одного модуля по границам слова, хотя бы для ускорения доступа к этим переменным?

3. как заставить линкер производить выравнивание адреса размещения переменных при переходе к другому модулю?

4. что за херня? как эта дурацкая опция влияет на генерирование кода с невыровненным адресом переменных модулей?

5. предполагаю, что имеется ошибка в GCC: работающий код может думать, что переменная размещена по выровненному адресу, а реально она находится по невыровненному