Сценарий компоновщика: вставьте абсолютный адрес функции в сгенерированный код
У меня есть вопрос, связанный с линкером gcc.
Я работаю со встроенными компонентами (PIC32), но компилятор и компоновщик PIC32 основан на gcc, поэтому основные вещи должны быть общими для "обычного" компоновщика gcc и компоновщика PIC32.
Чтобы сэкономить место на флэш-памяти (которого часто не хватает на микроконтроллерах), мне нужно поместить несколько крупных функций в загрузчик, и приложение должно вызывать эти функции только указателями.
Итак, мне нужно создать векторную таблицу в сгенерированном коде.
Я пытаюсь получить абсолютный адрес функции и записать его в сгенерированный код, но все еще получаю ошибки.
В приведенном ниже примере я пытаюсь получить адрес функции _formatted_write
,
Код:
.user_addr_table _USER_ADDR_TABLE_ADDR :
{
KEEP(*(.user_addr_table))
LONG((ABSOLUTE(_formatted_write))); /* _formatted_write is a name of my function */
} > user_addr_table
Линкер возвращает ошибку: "unresolvable symbol '_formatted_write' referenced in expression
".
Я заметил, что если я пишу мусор вместо _formatted_write
тогда возвращается ошибкаundefined symbol .....
", так, _formatted_write
известен линкером.
Это заставляет меня думать, что я должен выполнить некоторые дополнительные шаги, чтобы сделать его "разрешимым". Но до сих пор не знаю, как это сделать.
2 ответа
Я нашел способ использовать указатели функций, т.е.
void (*formatted_write)( int a, char * b, struct mystruct c );
затем в коде где-то при загрузке задайте адрес этой функции, т.е.
formatted_write = 0xa0000;
затем вы можете вызвать свою функцию, используя обычное соглашение.
Кроме того, вы можете использовать флаг -Wl,- just-symbols=symbols.txt при компиляции. Вы можете установить адрес ваших символов следующим образом:
formatted_write = 0xa0000;
Для случая, когда у кого-то есть такая же проблема (как у меня несколько часов назад), есть еще лучшее решение:
Пусть "bootloader.out" будет бинарным загрузчиком. Тогда мы можем генерировать с
nm -g bootloader.out | grep '^[0-9,a-e]\{8\} T' | awk '{printf "PROVIDE(%s = 0x%s);\n",$3,$1}' > bootloader.inc
файл, который мы можем включить в скрипт компоновщика приложения с
INCLUDE bootloader.inc
Компоновщик теперь знает адреса всех функций загрузчика, и мы можем ссылаться на него без фактического кода функции в приложении. Все, что нам нужно, - это объявление для каждой функции загрузчика, которую мы хотим выполнить.