MyTetra Share
Делитесь знаниями!
Как в языке Си вызвать функцию, для которой известен адрес вызова в виде числа
Время создания: 17.02.2022 17:12
Автор: intrea
Текстовые метки: язык, Си, C, адрес, функция, вызвать, embedding, машинный код
Раздел: Компьютер - Программирование - Язык C (Си)
Запись: xintrea/mytetra_syncro/master/base/1645107136euxp0gl4ty/text.html на raw.github.com

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




1

2

3

4

5

6

__attribute__( ( naked ) )

void jump_to_funct(uint32_t stack, uint32_t func)

{

__set_MSP(stack);

(*(void (*)())(func))();

}



Что здесь происходит? Перед прототипом функции jump_to_funct прописан атрибут naked, благодаря которому компилятор для данной функции не будет создавать пролог и эпилог. То есть, код данной функции будет содержать только команды, которые получатся в результате компиляции строки 4 и 5.


В функцию jump_to_func передаются два числа. Первое число - это адрес вершины стека. Второе число - это адрес функции, т. е. адрес первой машинной команды вызываемой функции.


На строке 4 происходит вызов инстрикт-функции __set_MSP(stack). Данная функция установит указатель стека на значение, переданное в переменной stack. Пременная stack содержит адрес в виде беззнакового целочислоительного числа.


В строке 5 происходит вызов функции, расположенной по адресу func, причем этот адрес так же задается просто в виде беззнакового целочислительного числа.


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


Проинициализировать значения stack и func можно следующим образом:



void main_start()

{

uint32_t *boot_from = (uint32_t*)MAIN_RUN_FROM;


if (((boot_from[0] >> 24) != (SRAM_BASE >> 24)) &&

((boot_from[0] >> 24) != (CCMDATARAM_BASE >> 24)))

return send_str("SRAM ERROR\r");


if (((boot_from[1] >> 24) != (FLASH_BASE >> 24)) && (boot_from[1] > MAIN_RUN_FROM))

return send_str("FLASH ERROR\r");


send_str("CONTEXT OK\r\r");

usart_deinit();

RCC_DeInit();


jump_to_func(boot_from[0], boot_from[1]);

}



В данном случае предполагается, что данный код вызывается до функции main(). По-сути, данный код вызывает функцию main() по указанному адресу. Полный код похожего проекта можно посмотреть на GitHub:



https://github.com/Mirn/Boot_F4_fast_uart/blob/master/src/sfu_commands.c



Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования