|
Перемещение функции в памяти ..., Нужен совет |
|
|
|
Mar 24 2005, 10:01
|
Частый гость
 
Группа: Свой
Сообщений: 119
Регистрация: 4-03-05
Пользователь №: 3 067

|
Размышления вслух... Если после компиляции си-компилятором (не известно ж какой компилятор и что за процессор), мы получаем код, адресация переходов в котором выполнена в относительной системе, относительно текущеего адреса, тогда такую функцию в принципе можно копировать из одного места памяти в другое. Дальше, получить адрес функции в си не проблема - просто указатель на функцию. Остается проблема, как узнать длинну кода занимаемого функцией. Если длинна изместна, то поидее можно копировать в выделенный буфер, например memcpy, ну а далее вызывать по новому указателю...
|
|
|
|
|
Mar 24 2005, 10:05
|

Гуру
     
Группа: Админы
Сообщений: 3 621
Регистрация: 18-10-04
Из: Москва
Пользователь №: 904

|
Цитата(3.14 @ Mar 24 2005, 12:35) Как в C коректнее скопировать функцию из одной области памяти в другую и затем вызвать из нового местоположения. Абсолютно корректно это сделать не получится, т.к. этот вопрос не предусмотрен стандартом, но можно сделать следующее: Объявить две функции - копируемую и еще одну, вспомогательную: Код static void source_f() { .... }
static void source_f_end() { } После этого в программе можно объявить буфер и скопировать туда нужную функцию и вызвать ее: Код typedef void (*call_pointer)(void) char buffer[ desired ]; call_pointer pointer; memcpy( buffer, source_f, (size_t)(source_f_end - source_f) ); pointer = (call_pointer)buffer; pointer(); но подобный метод накладывает сильные ограничения на то, что может быть написано в копируемой функции. Так, например, если в ней есть вызовы других функций, то необходимо изменить их непосредственные вызовы на вызовы по указателям, переданным вызываемой функции. И т.д.
--------------------
BR, Makc В недуге рождены, вскормлены тленом, подлежим распаду. (с) У.Фолкнер.
|
|
|
|
|
Mar 24 2005, 11:18
|
Частый гость
 
Группа: Свой
Сообщений: 146
Регистрация: 8-12-04
Пользователь №: 1 407

|
От части этот механизм представлен в оверлеях, когда несколько функций могут занимать одно и то же место в памяти, это решает вопрос маленькой памяти, а копирование кода, точно не к чму не приведет, правда некоторые функции можно переносить таким образом, но только те которые представленны в понятном asm эквиваленте, т.е если там нет каких либо видов оптимизаии и вызовов функции по косвенному смещению от точки вызова. Тут конечно можно примеров много написать чего можно, а чего нельзя, но лучше таких вариантов с кодом не проделывать, а иначе программа может начать вести себя совершенно не вероятным образом.
|
|
|
|
|
Mar 24 2005, 11:20
|

Их либе дих ...
     
Группа: СуперМодераторы
Сообщений: 2 010
Регистрация: 6-09-04
Из: Russia, Izhevsk
Пользователь №: 609

|
2 max Я правильно понял Ваш пример? Копируемая функция source_f() переносится по адресу функции source_f_end(), вызов пересенной функции осуществляется через pointer() ? Попробовал пример сунуть в VDSP4.0. В дебуггере после memcpy() функция source_f_end() не меняет своего содержимого. В железе все то же виснет
--------------------
Усы, борода и кеды - вот мои документы :)
|
|
|
|
|
Mar 24 2005, 11:53
|

Гуру
     
Группа: Админы
Сообщений: 3 621
Регистрация: 18-10-04
Из: Москва
Пользователь №: 904

|
Цитата(3.14 @ Mar 24 2005, 14:20) 2 max Я правильно понял Ваш пример? Копируемая функция source_f() переносится по адресу функции source_f_end(), вызов пересенной функции осуществляется через pointer() ? Попробовал пример сунуть в VDSP4.0. В дебуггере после memcpy() функция source_f_end() не меняет своего содержимого. В железе все то же виснет  Не совсем так. При решении этой задачи есть две проблемы: 1. Определение размеров копируемой функции. 2. Вызов функции из того места, куда она была скопирована. 1. Для решения этой проблемы вводится функция source_f_end(), которая будет лежать после копируемой функции, т.е. адрес source_f_end - это адрес следующего байта после тела копируемой функции. Таким образом, разность source_f_end - source_f нам даст размер копируемой функции. 2. Функцию копируем в объявленный буфер. Поэтому функция source_f_end и не должна изменить своего содержимого - это только маркер. Буфер для копирования лучше объявить не локальным, а глобальным, тогда будет меньше проблем, т.к. не все процессоры умеют исполнять код из стека. Вызов осуществляется через pointer, значение которого должно быть равно адресу начала буфера, куда была скопирована функция. А что есть в самой копируемой функции? Ведь если там есть прямые вызовы других функций и обращение к глобальным переменным, то она работать не будет. Т.к. как правило их смещения вычисляются линкером при линковке и едут непредсказуемым образом при копировании функции. Может быть в этом проблема?
--------------------
BR, Makc В недуге рождены, вскормлены тленом, подлежим распаду. (с) У.Фолкнер.
|
|
|
|
|
Mar 24 2005, 11:57
|

Гуру
     
Группа: Админы
Сообщений: 3 621
Регистрация: 18-10-04
Из: Москва
Пользователь №: 904

|
Цитата(bve @ Mar 24 2005, 14:51) Есть еще одна проблема, зависящая от компилятора и оптимизации - передача параметров в подпрограмму. Т.е. необходимо копировать не только тело самой функции, но и кусок кода ее вызывающий, либо запихивать параметры самому в необходимые регистры/ячейки. Не надо также забывать об изменении указателя фрейма, если таковой имеется. Минуточку... Есть стандартный способ передачи параметров в подпрограмму, который используется повсеместно (в проекте) одним компилятором. Поэтому нужно иметь правильный прототип функции и тогда вызов будет происходить корректно. Что касается фрейма (я так понимаю, что речь идет о фрейме стека), то он вычисляется исходя из текущего значения указателя стека. А в некоторых случаях он вообще не используется (например у gcc при -fomit-frame-pointer). Так что, как мне кажется, проблемы передачи параметров нет.
--------------------
BR, Makc В недуге рождены, вскормлены тленом, подлежим распаду. (с) У.Фолкнер.
|
|
|
|
|
Mar 24 2005, 13:06
|

Их либе дих ...
     
Группа: СуперМодераторы
Сообщений: 2 010
Регистрация: 6-09-04
Из: Russia, Izhevsk
Пользователь №: 609

|
2 maks <1. Для решения этой проблемы вводится функция source_f_end(), которая будет лежать после копируемой функции...> В VDSP такая фишка не проходит, он в памяти располагает не по объявлению а по вызову. Еще имеется специфика ADSP, регистры имеют разрядность 40 бит, ширина инструкций 48 бит. В моем случае копируемая функция находится в SDRAM, разрядность данных 32 разряда, надо упаковывать в 48 бит. <Есть стандартный способ передачи параметров в подпрограмму> А в чем он заключается? Я решил сделать так, фунции которые будут копироваться в место исполнения общатся с внешней (програмной) средой будут посредством глобального массива аргументов, элементы которого для определенных функций будут являться входными и выходными параметрами. 2 olefil В общем, взял пример fft_ovly2 Вот кусок менеджера оверлеев отвечающий за DMA передачу Код i8 = runAddresses; i0 = liveAddresses; r0=0; // Disable DMA dm(DMAC0) = r0; // Set DMA external pointer to overlay live address r0=dm(m0,i0); dm(EIEP0)=r0;\ // Set DMA internal pointer to overlay run address r0=pm(m8,i8); dm(IIEP0)=r0;\ i0=runWordSize; // Number of words stored in internal memory // Most likely the word size will be 48 bits // for instructions. // Set DMA external modifier r0=1; dm(EMEP0)=r0; i8=liveWordSize; // Number of words stored in external memory // Most likely the word size will be 32 or16 // bits for external storage. // Set DMA internal modify to 1 dm(IMEP0)=r0; // Set DMA internal count to Overlay run size. r0=dm(m0,i0); dm(CEP0)=r0; // Set DMA external count to Overlay live size. r0=pm(m8,i8); dm(ECEP0)=r0; // DMA enabled, instruction word, Master, 48-32 packing r0=0x2e1; dm(DMAC0)=r0; Переписал это на C Код *pDMAC0=0; *pEIEP0=pointerDest; *pIIEP0=pointerTarget; *pEMEP0=1; *pIMEP0=1; *pCEP0=0x20; *pECEP0=0x20; *pDMAC0=0x2e1; Размер функции в которую копируется 1kword. Копируемая функция размером 10word. Разместил копируемую функцию во внутренней памяти, содержимое первых шести слов : Код 043ff8000000 0f0200000008 ad02fffffffe 10010000c009 013e00001012 11000000c009 Далее разместил копируемую функцию в SDRAM, после завершения работы DMA, содержимое скопированной функции: Код 00000000F800 00000008043F 0F020000FFFE AD02FFFF0000 0000C0090000 000010121001 ???
--------------------
Усы, борода и кеды - вот мои документы :)
|
|
|
|
|
Mar 24 2005, 13:20
|
Группа: Новичок
Сообщений: 8
Регистрация: 3-01-05
Пользователь №: 1 791

|
Цитата(3.14 @ Mar 24 2005, 16:06) <Есть стандартный способ передачи параметров в подпрограмму> А в чем он заключается? через general-purpose регистры. а если параметров много - через стековый фрейм функции из которой производится вызов.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|