Предотвратить удаление функции GCC LTO

Я работаю с GCC-ARM-Embedded и FreeRTOS. FreeRTOS имеет функцию vTaskSwitchContext(), которая используется только в некотором встроенном коде на ассемблере.

Проблема в том, что когда я использую LTO, GCC не учитывает встроенный ассемблерный код и считает, что функция не используется, поэтому удаляет ее. Затем компоновщик дает сбой, потому что вызов функции во встроенном коде ассемблера не может быть разрешен.

Я бы применил __attribute__((used)), но не хочу трогать код FreeRTOS (он сгенерирован STM32CubeMX).

Я попытался поместить это в свой код, но на самом деле GCC достаточно умен, чтобы не позволить этому работать:

if(false)
    vTaskSwitchContext();

Есть ли способ сообщить GCC в другом исходном файле или через параметр, что эту функцию не следует удалять?

Пример

// file1.c
void vTaskSwitchContext( void )
{
    ...
}

// file2.c
void xPortPendSVHandler( void )
{
    __asm volatile
    (
    ...
    "   isb                                 \n"
    "   bl vTaskSwitchContext               \n"
    "   mov r0, #0                          \n"
    ...
    );
}

person Jan Hieber    schedule 15.07.2016    source источник
comment
Я удивляюсь, как это может произойти. Компоновщик видит объектные файлы и их внешние ссылки. Не должно иметь значения, ссылается ли символ из кода C или из встроенного ассемблера.   -  person undur_gongor    schedule 15.07.2016
comment
@undur_gongor: LTO многое меняет и в целом может преподнести сюрприз. Компоновщик на самом деле не видит объектные файлы и внешние ссылки, скорее, компоновщик действует как внешний интерфейс для внутреннего интерфейса компилятора, а затем связывает результаты из внутреннего интерфейса компилятора.   -  person Dietrich Epp    schedule 15.07.2016


Ответы (4)


Попробуйте вызвать функцию из отдельной функции с пометкой used.

void dummyFunction(void) __attribute__((used));

// Never called.
void dummyFunction(void) {
    vTaskSwitchContext();
}
person Dietrich Epp    schedule 15.07.2016

Вы можете добавить -Wl,--undefined=vTaskSwitchContext к своему LDFLAGS.

person user1273684    schedule 04.05.2018

По какой-то причине решение, которое предложил Дитрих, мне не подошло. Я использую DAVE 4 от Infineon (в основном eclipse с причудливым плагином для генерации кода для их линейки микроконтроллеров XMC), что может быть причиной того, что он не работает. Мне пришлось звонить vTaskSwitchContext() после vTaskStartScheduler():

int main(){

    initializationCode();

    vTaskStartScheduler();

    //Code never reaches here
    vTaskSwitchContext();
}
person Chi    schedule 22.06.2019

Если ваша версия FreeRTOS уже использует макрос portDONT_DISCARD для vTaskSwitchContext(), вы можете определить portDONT_DISCARD в своем собственном portmacro.h

#define portDONT_DISCARD __attribute__((used))

По существу резервное копирование https://github.com/FreeRTOS/FreeRTOS-Kernel/commit/07e672c426d0e2a3fea56cae /а>

person t-8ch    schedule 29.03.2021