Перейти к содержанию
    

Перемещение функции в памяти ...

Как в C коректнее скопировать функцию из одной области памяти в другую и затем вызвать из нового местоположения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Размышления вслух... Если после компиляции си-компилятором (не известно ж

какой компилятор и что за процессор), мы получаем код, адресация переходов в котором выполнена в относительной системе, относительно текущеего адреса, тогда такую функцию в принципе можно копировать из

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как в 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();

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 max

Я правильно понял Ваш пример?

Копируемая функция source_f() переносится по адресу функции source_f_end(), вызов пересенной функции осуществляется через pointer() ?

 

Попробовал пример сунуть в VDSP4.0.

В дебуггере после memcpy() функция source_f_end() не меняет своего содержимого. В железе все то же виснет :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Компилятор в VDSP может не понимать того, что вы делаете и я больше чем увероен, что это так!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 olefil

Я по большому счету, пытаюсь перенести asm примеры с оверлеями на C. Пока не получается :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть еще одна проблема, зависящая от компилятора и оптимизации -

передача параметров в подпрограмму. Т.е. необходимо копировать не только

тело самой функции, но и кусок кода ее вызывающий, либо запихивать параметры самому в необходимые регистры/ячейки. Не надо также забывать об изменении указателя фрейма, если таковой имеется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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, значение которого должно быть равно адресу начала буфера, куда была скопирована функция.

 

А что есть в самой копируемой функции? Ведь если там есть прямые вызовы других функций и обращение к глобальным переменным, то она работать не будет. Т.к. как правило их смещения вычисляются линкером при линковке и едут непредсказуемым образом при копировании функции. Может быть в этом проблема?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть еще одна проблема, зависящая от компилятора и оптимизации -

передача параметров в подпрограмму. Т.е. необходимо копировать не только

тело самой функции, но и кусок кода ее  вызывающий, либо запихивать параметры самому в необходимые регистры/ячейки. Не надо также забывать об изменении указателя фрейма, если таковой имеется.

 

Минуточку... Есть стандартный способ передачи параметров в подпрограмму, который используется повсеместно (в проекте) одним компилятором. Поэтому нужно иметь правильный прототип функции и тогда вызов будет происходить корректно.

 

Что касается фрейма (я так понимаю, что речь идет о фрейме стека), то он вычисляется исходя из текущего значения указателя стека. А в некоторых случаях он вообще не используется (например у gcc при -fomit-frame-pointer).

 

Так что, как мне кажется, проблемы передачи параметров нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Скорее это так, проблем с передачей параметров действительно нет, но вот от компиляции конкретным оброзом внутренности программы Sharc очень сильно изменяются. И если использовать оптимизацию, то что эта функция делает, знает только компилятор.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

???

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

<Есть стандартный способ передачи параметров в подпрограмму>

А в чем он заключается?

 

через general-purpose регистры. а если параметров много - через стековый фрейм функции из которой производится вызов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня ща все платы в доработке не фига не попробовать. Но вроде код на первый взгляд правельный. Правда на счет упаковки 48-32 трудно сказать, я сейчас немного другой работой занимаюсь, но вроде похоже на правду. А че показывает VDSP, если в debugger код посмотреть. Блин у меня где-то был исходник для overley'ев копировал функции из внутренней памяти во внешнюю правда не по DMA, а через PX регистр все работало.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...