Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: EWARM. Cделать переход по известному адресу?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
VladislavS
Что-то совсем заработался... sad.gif
Ваяю начальный загрузчик. Основная программа лежит по адресу 0x10000000 в параллельном flash. По окончании всех действий надо просто передать на неё управление. Как?

EWARM 4.40. Процессор AT91RM9200.
Сергей Борщ
Цитата(VladislavS @ Nov 8 2007, 14:56) *
EWARM 4.40. Процессор AT91RM9200.
Код
// если C++
extern "C" void Application();
// если C
extern void Application();
int main()
{
......

   Application();
}
В .xcl добавить -DApplication=0x10000000 или в Project->Options->Linker->#define вписать Application=0x10000000.
VladislavS
Спасибо. Сработало. Как все просто когда знаешь...
Rst7
Есть еще способ (без линкера):

((void(*)(void))0x10000000)();
Николай Z
Цитата(Rst7 @ Nov 8 2007, 16:30) *
Есть еще способ (без линкера):

((void(*)(void))0x10000000)();


Дык при желании можно не только без линкера обойтись - в принципе можно даже без компилятора....

Правильнее делать то и так, как Сергей Борщ написал.
Rst7
Цитата(Николай Z @ Nov 8 2007, 16:25) *
Дык при желании можно не только без линкера обойтись - в принципе можно даже без компилятора....

Правильнее делать то и так, как Сергей Борщ написал.


А если этот адрес не константа?
Николай Z
Цитата(Rst7 @ Nov 8 2007, 17:41) *
А если этот адрес не константа?


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

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

Первое, что надо определить - а зачем вообще нужно вызывать функцию по некоему переменному адресу? У вас функции ползают по памяти что ли?

У меня обычно нет и мне трудно сообразить - зачем мне вообще нужно делать вызовы по неким переменным адресам в общем случае.
Rst7
Цитата(Николай Z @ Nov 8 2007, 17:09) *
В топе был вопрос про известный, фиксированный адрес...


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

Так чем он плох? Ничем. Так что пусть человек знает, что решений задачи несколько, есть и более универсальные.

PS Ах да, кроме всего прочего мое решение стрельнет на любом компиляторе.
aaarrr
Цитата(Николай Z @ Nov 8 2007, 18:09) *
В топе был вопрос про известный, фиксированный адрес...

Налили воды, однако smile.gif

По-моему, вариант перехода ((void(*)(void))0x10000000)(); куда как лучше извратов с линкером.
Николай Z
Цитата(aaarrr @ Nov 8 2007, 18:25) *
Налили воды, однако smile.gif

По-моему, вариант перехода ((void(*)(void))0x10000000)(); куда как лучше извратов с линкером.


Нравится - так используйте... Никто не против...
Только Вы быстро сами поймете, что чем меньше в проекте статически распределенных объектов, тем она удобнее и мобилнее и легче носится с одной архитектуры на другую.

Это вовсе не вода. Это некоторый опыт, который даже не я собирал, а в общем-то все сообщество программистов от первого компьютера и до ныненшних дней. Статические адреса и распределения памяти - это кажется удобным только в простейших случаях.

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

Так что - я ничего не имею против Вашего решения - набивайте себе шишки сами...
aaarrr
Цитата(Николай Z @ Nov 8 2007, 19:33) *
Нравится - так используйте... Никто не против...
Только Вы быстро сами поймете, что чем меньше в проекте статически распределенных объектов, тем она удобнее и мобилнее и легче носится с одной архитектуры на другую.
...

Вообще-то речь шла о передаче управления от загрузчика к основной программе, объекту по определению статическому. И каким боком тут нужен линкер? Насчет переносимости уже сказали: поменяете компилятор (и трех лет не пройдет, ага smile.gif ), и Вам придется искать другое решение.
Сергей Борщ
Цитата(aaarrr @ Nov 8 2007, 20:49) *
Насчет переносимости уже сказали: поменяете компилятор (и трех лет не пройдет, ага smile.gif ), и Вам придется искать другое решение.
Объясню, почему я пришел к такому решению. Потому что и IAR для AVR и WinAVR на конструкцию с константным указанием генерировали у меня один и тот же код - загрузку в Z и косвенный вызов. Вариант с линкером генерит честный RCALL. Это во-первых. Во-вторых. При портировании того же самого загрузчика с AVR на ARM я поменял константу в файле линкера. Констант там немного и они сгруппированы в одном месте - не нужно искать по всему исходнику. Исходник вообще не трогал - как там было Application(), так и осталось. Перейдя с IAR на WinAVR я нашел как определять символы линкеру (а это позволяет любой нормальный линкер) и снова никаких проблем. К слову, для AVR надо указывать адрес слова, хотя вся остальная адресация что у IAR, что у WinAVR идет побайтно. Что касается IAR для ARM, там тоже вызов через константу компилится во что-то не совсем красивое. Такие пироги.
VladislavS
Цитата(Rst7 @ Nov 8 2007, 18:23) *
Представим себе ситуацию, что в процессе развития этого начального загрузчика будет необходимо загружать код не только на адрес 0x10000000, но и на любой другой адрес...


Так оно и есть. Запуск кода из параллельной flash был только первым шагом. Теперь буду загружать разные приложения из DataFlash в SDRAM.

Цитата
Так чем он плох? Ничем. Так что пусть человек знает, что решений задачи несколько, есть и более универсальные.


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

Теперь после просветления никакого труда не составит сделать указатель на функцию и по нему запускать код в любом нужном месте памяти.
aaarrr
Цитата(Сергей Борщ @ Nov 8 2007, 22:36) *
Объясню, почему я пришел к такому решению. Потому что и IAR для AVR и WinAVR на конструкцию с константным указанием генерировали у меня один и тот же код - загрузку в Z и косвенный вызов. Вариант с линкером генерит честный RCALL.

По-моему, издержек в любом случае будет немного. Не такой уж частый случай.

Цитата(Сергей Борщ @ Nov 8 2007, 22:36) *
При портировании того же самого загрузчика с AVR на ARM я поменял константу в файле линкера. Констант там немного и они сгруппированы в одном месте - не нужно искать по всему исходнику. Исходник вообще не трогал - как там было Application(), так и осталось. Перейдя с IAR на WinAVR я нашел как определять символы линкеру (а это позволяет любой нормальный линкер) и снова никаких проблем.

Ну, #define еще никто не отменял, а в данном случае это будет родной define, а не опция линкера.
А если бы Вы переходили на ADS/RVDS, то проблемы бы возникли - не знаю, как протащить там подобную конструкцию, кроме как через symdefs-файл.
Сергей Борщ
Цитата(aaarrr @ Nov 9 2007, 01:03) *
По-моему, издержек в любом случае будет немного. Не такой уж частый случай.
Да. Но если без напряжения можно сделать лучше - почему бы и да? А не пытаюсь никого отговаривать. Просто мне так кажется логичнее - функция располагается в другом модуле, адрес ее фиксированный, на мой взгляд проставлять в код адрес такой функции скорее задача линкера. Да и прозрачнее как-то код смотрится - объявлена функция, явно указано, что она внешняя, и вызов. Аналогично можно объявлять и функции с параметрами, причем указывать фиктивные самодокументирующие имена параметров. Кстати, вызов IAP у LPC таким образом тоже красиво получается:
Код
// (Philips) Status Codes
enum iap_status_t
{
    CMD_SUCCESS, INVALID_CMD,
    SRC_ADDR_ERROR, DST_ADDR_ERROR, SRC_ADDR_NOT_MAPPED, DST_ADDR_NOT_MAPPED,
    COUNT_ERROR, INVALID_SECTOR, SECTOR_NOT_BLANK, SECTOR_NOT_PREPARED,
    COMPARE_ERROR, BUSY, PARAM_ERROR, ADDR_ERROR, ADDR_NOT_MAPPED,
    CMD_LOCKED, INVALID_CODE, INVALID_BAUD_RATE, INVALID_STOP_BIT, CODE_READ_PROT_ENABLED, MAX_ERROR
};

enum iap_cmd_t
{
    PREPARE = 50, COPY, ERASE, BLANK_CHECK, GET_PART_ID, GET_BOOT_VER, COMPARE, SIZE_ALIGN = 0xFFFFFFFF
};

#pragma pack    (push,4)
struct iap_command_t
{
    iap_cmd_t   Command;
    uint32_t    Param[4];
};
struct iap_result_t
{
    iap_status_t    Status;
    uint32_t        Result[4];
};
#pragma pack    (pop)
extern "C" __thumb void IAP(iap_command_t *params, iap_result_t *result);
/*
in .xcl:
// IAP routine, thumb code
-DIAP=7FFFFFF1
*/


.
Цитата(aaarrr @ Nov 9 2007, 01:03) *
Ну, #define еще никто не отменял, а в данном случае это будет родной define, а не опция линкера.
Не спорю - можно и так. Ненаказуемо smile.gif
Цитата(aaarrr @ Nov 9 2007, 01:03) *
А если бы Вы переходили на ADS/RVDS, то проблемы бы возникли - не знаю, как протащить там подобную конструкцию, кроме как через symdefs-файл.
Возможность-то наверняка есть, просто мы о ней (пока) не знаем. Хотя бы и через файл.

P.S. Мнения четко разделились на два подхода. Вот пришел бы кто-нибудь умный, вроде ReAl, и растолковал ограничения и правильность каждого решения.
singlskv
Цитата(Сергей Борщ @ Nov 9 2007, 02:29) *
P.S. Мнения четко разделились на два подхода. Вот пришел бы кто-нибудь умный, вроде ReAl, и растолковал ограничения и правильность каждого решения.
Я конечно не ReAl, но знаю один вариант, когда
вызов функции по фиксированному адресу приводит к непредсказуемым последствиям.
Это касается младших контроллеров AVR у которых все jmp и call существуют только в
версии rjmp и rcall.
Mega8:
Код
169:      ((void(*)(void))0x0000)();
+00000450:   DBF0        RCALL   PC-0x040F        Relative call subroutine

Mega128:
Код
169:      ((void(*)(void))0x0000)();
+00000489:   940E0000    CALL    0x00000000       Call subroutine


WinAVR-20060421

Может в новых версиях они чего-то и подправили...
aaarrr
Цитата(Сергей Борщ @ Nov 9 2007, 02:29) *
Да. Но если без напряжения можно сделать лучше - почему бы и да?

Чем лучше?
ИМХО, задание левых символов для линкера - это изврат. Особенно, если имеешь дело с полудюжиной разных архитектур и, соответственно, разных линкеров.

Цитата(Сергей Борщ @ Nov 9 2007, 02:29) *
Аналогично можно объявлять и функции с параметрами, причем указывать фиктивные самодокументирующие имена параметров.

То же самое легко делается дефайном:
Код
#define    func(x, y)    ((int(*)(int, int))0x10000000)((x), (y))

И объявить функцию в любом виде можно.

Цитата(Сергей Борщ @ Nov 9 2007, 02:29) *
Не спорю - можно и так. Ненаказуемо smile.gifВозможность-то наверняка есть, просто мы о ней (пока) не знаем. Хотя бы и через файл.

Нет там такой возможности - только через symdefs, который в обычной жизни не нужен.
VladislavS
Если делать на классическом С, то что-то типа того получается:

Код
typedef void (*MyFunc)(void);
MyFunc MyCode;

int main()
{
  MyCode = (MyFunc)0x10000000;
  MyCode();
}


Только вызов по всем книжкам (*MyCode)() должен быть, а работает правильно и просто MyCode().
Николай Z
Цитата(aaarrr @ Nov 9 2007, 05:22) *
ИМХО, задание левых символов для линкера - это изврат. Особенно, если имеешь дело с полудюжиной разных архитектур и, соответственно, разных линкеров.


Могу только повториться... Да можно и без линкера... и даже без компилятора, можно даже без ассемблера.... В пределе - можно вообще без процессора - все на логических схемах...

Скорее всего Вы просто плохо понимаете назначение линкера и описания make, которые как раз и отвечают за создание исполняемого кода и распределение памяти.

Зачем говорить о разных процессорах, если уже в программе main - вы себя жестко привязали к одной-единственной архитектуре наглухо практически - именно путем задания статического адреса? Причем тут тогда другие процессоры c другой архитектурой - у них точка входа почти наверняка будет в другом месте?

А вот символическое задание имен в программе - позволяет ее как раз переносить между разными архитектурами намного легче... Задача только увязать с требуемыми адресами заданными архитектурой - т.е. в make файле или как раз в параметрах линкера и нигде больше... А саму программу править уже и не надо в 99% cлучаев, если Вы в нее не запихнете еще какую-то архитектурную зависимость.
==============================================
PS: По поводу легко или нелегко- практически притча... Представьте себе у Вас в квартире - новую стену после ремонта... Новые обои - все красиво... Стоит на полу картина... Задача - повесить ее на стену.... Решаться может разными способами...
Первый способ - находите три ржавых гвоздя в сундуке... и какой попало молоток... Два вбиваете как попало в дорогую раму - сзади.... И привязываете к гвоздям кусок первого попавшегося шпагата.... Третий - криво и с трудом вгоняете в стену.... Ржавый такой гвоздь... кривой... Вешаете за шпагатину Вашу замечательную картину... Ну - нравится Вам этот самый простой способ? ведь проще не бывает... biggrin.gif
Способ второй Чтобы ничего не портить и сделать все аккуратно и красиво - идете в специальный магазин и покупаете соответствующий раме аккуратный и незаметный крепеж, специальную оснастку для его установки на раму и стену... Дома изучаете это все и аккуратно выполняете все инструкции по установке и в конце-концов картина на стене...

Мне кажется, что второй способ при его кажущейся большей сложности - правильнее первого и намного эстетичности. А часто - еще и более простой и легкий... Да еще и мобильный - ибо специальный крепеж легко и удалется и вид стены не испортит - а попробуйте без последствий вырнуть из стены 100 мм ржавый гвоздь? biggrin.gif
Rst7
Цитата(Николай Z @ Nov 9 2007, 11:56) *
Могу только повториться... Да можно и без линкера...


Не без линкера, а без использования определенных СТАТИЧЕСКИ в линкере адресов.

Цитата
Скорее всего Вы просто плохо понимаете назначение линкера и описания make, которые как раз и отвечают за создание исполняемого кода и распределение памяти.


Отлично понимаю, и в другом случае конечно по возможности определю адреса в .xcl-файле например.

Цитата
Зачем говорить о разных процессорах, если уже в программе main - вы себя жестко привязали к одной-единственной архитектуре наглухо практически - именно путем задания статического адреса? Причем тут тогда другие процессоры c другой архитектурой - у них точка входа почти наверняка будет в другом месте?


Причем тут архитектура. Понятное дело, что бутлоадер - вещь сугубо интимная со всех сторон.

Только вот вы видимо невнимательно читаете. Я (уж простите такую вольность) предположил, что автору возможно понадобится расширить функционал до вызова функции по произвольному адресу.

Вот что я написал:

Цитата(Rst7 @ Nov 8 2007, 17:23) *
Я понимаю. Представим себе ситуацию, что в процессе развития этого начального загрузчика будет необходимо загружать код не только на адрес 0x10000000, но и на любой другой адрес, который будет передаваться загрузчику (ну например в коммандной строке). Тогда придется перейти к моему варианту.


И автор топика ответил (болд мой)

Цитата(VladislavS @ Nov 8 2007, 22:01) *
Так оно и есть. Запуск кода из параллельной flash был только первым шагом. Теперь буду загружать разные приложения из DataFlash в SDRAM.
Да мне вообще стыдно за такой вопрос. Просто заклинило. Сидел побеждал размещение сегментов в памяти, копирование векторов прерываний, стартовые инициализации, флэшлоадер. Когда все вроде заработало и осталась такая мелочь как передать управление на код и пришлось воспользоваться подзатыльником.

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


Давайте, ваш удар, принц - сделайте это линкером - запускать код в любом нужном месте памяти

Так зачем вы нам тут притчи рассказываете?
Николай Z
Цитата(Rst7 @ Nov 9 2007, 14:23) *
Давайте, ваш удар, принц - сделайте это линкером - запускать код в любом нужном месте памяти

Так зачем вы нам тут притчи рассказываете?


А мы тут что - боксируем? Извините - я во-первых тут этого делать не собираюсь...
А во-ворых Вам уже все рассказали...
Не нравится подход - используйте свой...

А притча затем - что Ваше решение - как раз те самые три ржавых гвоздя.
А второе - это то что Вам рекомендовал г-н Сергей Борщ - это и есть правильное и довольно мобильное решение. Может и не идеальное - но классическое и проверенное.

Но Вы вправе ему как следовать, так и не следовать. Больше тут добавить нечего.
Rst7
Цитата(Николай Z @ Nov 9 2007, 13:44) *
А во-ворых Вам уже все рассказали...


Что именно?

Цитата
Не нравится подход - используйте свой...


Мне нравится подход. Но он стреляет только в том случае, если этот адрес - константа.

Цитата
А притча затем - что Ваше решение - как раз те самые три ржавых гвоздя.
А второе - это то что Вам рекомендовал г-н Сергей Борщ - это и есть правильное и довольно мобильное решение. Может и не идеальное - но классическое и проверенное.


Не поверите - классика - это как раз то что я написал biggrin.gif

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

В более общем случае рассмотрите вопрос загрузки выполняемых приложений на разные адреса (куда malloc вернул указатель, там и будет приложение). Как такое победить линкером?
Николай Z
Цитата(Rst7 @ Nov 9 2007, 15:12) *
Мне нравится подход. Но он стреляет только в том случае, если этот адрес - константа.

Нравится так нравится... Но Вам никто не мешает использовать вместо вашей константы зарезервированный заранее пойнтер и инициировать его перед использованием как Вам угодно.
Rst7
Цитата(Николай Z @ Nov 9 2007, 15:26) *
Нравится так нравится... Но Вам никто не мешает использовать вместо вашей константы зарезервированный заранее пойнтер и инициировать его перед использованием как Вам угодно.



Видимо я недостаточно точно сформулировал. Правильно будет звучать так -
"Мне нравится подход с указанием адреса в скрипте/параметрах линкера. Но он стреляет только в том случае, если этот адрес - константа."

Вот и я к тому же, что в варианте, предложенным мной, вполне будет работать переменная вместо константы. А у Вас?
Николай Z
Цитата(Rst7 @ Nov 9 2007, 16:30) *
Видимо я недостаточно точно сформулировал. Правильно будет звучать так -
"Мне нравится подход с указанием адреса в скрипте/параметрах линкера. Но он стреляет только в том случае, если этот адрес - константа."

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


Я начинаю подозревать что мы говорим о чем-то разном... Я о вопросе заданном в топе...
А Вы об чем?

Уточните Вашу задачу - а то я как считал так и продолжаю считать что мы обсуждаем вопрос из топа и ничего более...

Зачем надо переменную точку старта - вообще?

Цитата(Rst7 @ Nov 9 2007, 15:12) *
В более общем случае рассмотрите вопрос загрузки выполняемых приложений на разные адреса (куда malloc вернул указатель, там и будет приложение). Как такое победить линкером?


Возможно Вы собираетесь использовать что-то типа дозагрузки overlay-ев?
Если я правильно понимаю - то у Вас уже что-то работает в процессоре - ведь кто-то должен вызвать Ваш malloc(), который вам дает указатель?
Rst7
Цитата(Николай Z @ Nov 9 2007, 15:39) *
Я начинаю подозревать что мы говорим о чем-то разном... Я о вопросе заданном в топе...
А Вы об чем?


Я о том, что автор уточнил задачу чуть позже

Цитата(VladislavS @ Nov 8 2007, 22:01) *
Так оно и есть. Запуск кода из параллельной flash был только первым шагом. Теперь буду загружать разные приложения из DataFlash в SDRAM.


Так что уже 2 точки входа как минимум.

А теперь представьте себе, что автору понадобится загрузить два приложения на разные адреса, которые, например, ему вернет malloc. Как он выйдет из положения?


Цитата
Уточните Вашу задачу - а то я как считал так и продолжаю считать что мы обсуждаем вопрос из топа и ничего более...


Вы видимо хотите, чтобы уточнил автор топика, а не я. Перед мной такая задача на данный момент не стоит, а когда стояла, решалась так:
Код
typedef long TElfEntry(char *, void *,void *,void *);
long elfload(char *filename, void *param1, void *param2, void *param3){
....
....
  //выделим эту область и очистим ее
  if ((base=(char *)malloc(maxadr-minadr))==0){        //не выделяеться память под ельф
...
...
  ((TElfEntry *)(base+ehdr.e_entry-minadr))(filename,param1,param2,param3);
...


Цитата
Зачем надо переменную точку старта - вообще?
Возможно Вы собираетесь использовать что-то типа дозагрузки overlay-ев?
Если я правильно понимаю - то у Вас уже что-то работает в процессоре - ведь кто-то должен вызвать Ваш malloc(), который вам дает указатель?


Я не собираюсь. А автор топика - вполне возможно. Посему лучше использовать вариант, предложеный мной. На будущее.
zltigo
Да расшумелись sad.gif.
В общем случае несомненно (для меня smile.gif ) надо всеми силами избегать явных указаний адресов в исходниках - конткретика это дело линкера. Когда я такое "безобразие" вижу, например, для широко используемого некоторыми размещения неких конфигурационных констант, то очень расстраиваюсь smile.gif,
что вместо нормального "выхода в дверь" используют "выход в окно". Однако любое правило сильно исключениями для перехода куда-то безвозвратно в bootloader я явно отдам предпочтение действительно очевидно-классическому варианту, а не указания линкеру виртуальных имен. Причина проста - сразу видно, что "выход именно в окно", а не нечто обыденное.

А вот практический результат в виде полученного кода в одном и другом случае надо иметь ввиду.
Николай Z
Цитата(Rst7 @ Nov 9 2007, 16:46) *
А теперь представьте себе, что автору понадобится загрузить два приложения на разные адреса, которые, например, ему вернет malloc. Как он выйдет из положения?


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

malloc() не сам вызвался - его вызвала уже загруженная часть ситемы которая стартовала - раньше когда система стартовала...

Потому тут задача вглядит немного иначе:
Надо просто вызвать подпрограмму, которую вы прочли из Флэша или откуда-то еще в память, которую Вам указал вызванный malloc...

В таком случае - начальная загрузка и адрес указанный линкеру - совершенно не имеет отношения к делу... У Вас загрузка уже давно закончилась начальная и никаких переменных адресов ей не нужно...
Система у Вас уже работает... В ней ваш модуль определил место дозагрузки - вызовом malloc() и получил адрес места для размещения программы...

Замечу - я честно говоря не знаю зачем для этого malloc() использовать - но предположим пусть так, хотя это можно сделать гораздо более эффективно...

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

А вот написать кусок программы, который это делает - это уже гораздо более сложная песня...
Во FreeRTOS нету встроенного механизма работы с Оверлеями и софт для их поддержки непредусмотрен. Его надо делать самому... или исать в каких-то других системах...
VladislavS
Да ладно вам на пустом месте ругаться... Чтобы никому не было обидно я оставил вызов кода из флэшь по первому варианту (изменить её адрес всё равно не получится), а загруженный в SDRAM код по второму варианту. Работают оба варианта, а практика критерий истины.
Николай Z
Цитата(VladislavS @ Nov 9 2007, 20:53) *
Да ладно вам на пустом месте ругаться... Чтобы никому не было обидно я оставил вызов кода из флэшь по первому варианту (изменить её адрес всё равно не получится), а загруженный в SDRAM код по второму варианту. Работают оба варианта, а практика критерий истины.


Я так понимаю - что пытаюсь ответить уже совсем не на ваш вопрос... а на вопрос плавно вытекший из вашего... И я лично - вроде бы пока ни с кем не ругаюсь, а только пытаюсь понять - что у меня спросили... то ли ваш вариант, то ли еще какой... Придет автор уточнений - и скажет.. Если надо -- то мы откроем другую тему - потому что организация оверлеев в рамках FreeRTOS - меня самого сильно интересует...
VladislavS
А меня вот заинтересовал вопрос перемещаемости кода. Могу я из разных мест запускать то что IAR накомпилил? Что-то мне говорит что нет.
Николай Z
Цитата(VladislavS @ Nov 10 2007, 08:56) *
А меня вот заинтересовал вопрос перемещаемости кода. Могу я из разных мест запускать то что IAR накомпилил? Что-то мне говорит что нет.


Чтобы точно ответить на Ваш вопрос надо проанализировать объектный код, генерируемый компилятором. Я думаю и почти уверен, что ответ скорее всего будет нет, т.к. в исполняемом коде - скорее всего все переходы и вызовы подпрограмм жестко связаны с местоположением программы и не являются скорее всего перемещаемыми.

Я говорю "скорее всего" потому, что у меня нет особого желания это дело выяснять точно, а процессоры с архитектурой, которая принципиально имеет только "относительную" адресацию переходов - это достаточно большая редкость - и исполняемая программа практически всегда привязана именно к точке на которую ее настроил линкер....

Грубо говоря, если линкер настроил код для раположения с адреса 0x001000 к примеру и далее вверх, то он только при таком расположении в памяти и будет корректно работать. Стоит его переместить - ну например простой переписью хотя бы на 1-2-3-4 байта в любую сторону и он - скорее всего просто перестанет работать вообще, даже если вы правильно вызовете его новую точку входа.

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

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

Но в таком случае -- точка входа задаваемая линкером - к реализации вашего желания имеет минимальное отношение, и даже больше - она к этому вообще может не иметь ровно никакого отношения. Точка входа - это та точка через которую запускается Ваша программа после начальной инициализации и не более того. Вот потому ее делать переменной и не имеет никакого смысла. Она может быть нестандартной и лежать в необычном месте, но после линковки - она фиксирована и фиксирована раз и навсегда - до новой перелинковки.
Сергей Борщ
Цитата(VladislavS @ Nov 10 2007, 07:56) *
А меня вот заинтересовал вопрос перемещаемости кода. Могу я из разных мест запускать то что IAR накомпилил? Что-то мне говорит что нет.
Судя по описанию - может. Это задача линкера - размещать код. Опция -V позволяет генерить перемещаемый код. Более подробно - в описании линкера.
P.S. Да, это относится к версии 4.xx, пятую не смотрел.
Николай Z
Цитата(Сергей Борщ @ Nov 10 2007, 13:43) *
Судя по описанию - может. Это задача линкера - размещать код. Опция -V позволяет генерить перемещаемый код. Более подробно - в описании линкера.
P.S. Да, это относится к версии 4.xx, пятую не смотрел.


Тогда значит нужно освоить две вещи:
1) Научится делать перемещаемый код... Сделать независимые загружаемые по ходу дела модули...
2) Сотворить модуль загрузки дополнительных веток, которые в общем случае могу перекрывать друг-друга в памяти и сменять друг-друга в процессе исполнения...

И насколько я понимаю вопрошающего - его задача будет решена...
Но вот как это делать - пусть разберется сам. Я пока в ИАР-е Для STR912 этого делать не планирую и предпочитаю плоскую структуру софта и загрузки из одного-единственного модулябез каких-либо подгрузок по ходу работы...
Сергей Борщ
Цитата(Николай Z @ Nov 10 2007, 13:52) *
Я пока в ИАР-е Для STR912 этого делать не планирую и предпочитаю плоскую структуру софта и загрузки из одного-единственного модулябез каких-либо подгрузок по ходу работы...
Вы меня радуете:
Цитата(Николай Z @ Nov 9 2007, 22:27) *
потому что организация оверлеев в рамках FreeRTOS - меня самого сильно интересует...
zltigo
Цитата(Сергей Борщ @ Nov 10 2007, 12:43) *
P.S. Да, это относится к версии 4.xx, пятую не смотрел.

В пятой elf, со всеми вытекажщими из этого плюсами и минусами.


Цитата(Николай Z @ Nov 10 2007, 13:52) *
Тогда значит нужно освоить две вещи:
1) Научится делать перемещаемый код... Сделать независимые загружаемые по ходу дела модули...
2) Сотворить модуль загрузки дополнительных веток, которые в общем случае могу перекрывать друг-друга в памяти и сменять друг-друга в процессе исполнения...

Не факт, как частный случай модули могут простона ходится во Flash слинкованные, как не перемещаемые. Таким упрощенным подходом уже можно добиться полностью независимого написания и upgrade софта разными исполнителями. Во всех моих случаях использования оверлеев именно эта причина была довлеющей. Хотя с дополнительной целью повышения быстродействия в 16bit RAM, вместо медленной 70ns Flash, были реализации и загрузки перемещаемого кода.
Николай Z
Цитата(Сергей Борщ @ Nov 10 2007, 15:51) *
Цитата

(Николай Z):
Я пока в ИАР-е Для STR912 этого делать не планирую и предпочитаю плоскую структуру софта и загрузки из одного-единственного модулябез каких-либо подгрузок по ходу работы...

Вы меня радуете:
Цитата
(Николай Z @ Nov 9 2007, 22:27):
потому что организация оверлеев в рамках FreeRTOS - меня самого сильно интересует...



А Вы в чем собственно противоречие усмотрели?
Интересоваться и планировать - по моему вещи достаточно разные...

Планируют обычно то, что надо реализовать в ближайшее вермя, а знать желательно немного больше - по-моему это вполне нормально: интересоваться, но за реализацию не браться.
Меня много что интересует помимо того, что стоит в текущих планах и обязательно для реализации сейчас и сегодня(иногда еще вчера) biggrin.gif

Цитата(zltigo @ Nov 10 2007, 16:04) *
В пятой elf, со всеми вытекажщими из этого плюсами и минусами.
Не факт, как частный случай модули могут простона ходится во Flash слинкованные, как не перемещаемые. Таким упрощенным подходом уже можно добиться полностью независимого написания и upgrade софта разными исполнителями. Во всех моих случаях использования оверлеев именно эта причина была довлеющей. Хотя с дополнительной целью повышения быстродействия в 16bit RAM, вместо медленной 70ns Flash, были реализации и загрузки перемещаемого кода.


Дык никто об этом и спорить не собирается - мне кажется.
Но вопрос-то явно связан был с перемещаемыми модулями...

Да и оверлеи в общем случае могут быть и "статическими" - слинкованными как неперемещаемые, так "динамическими" - занружаемыми в произвольные свободные места, что уже потребует линковать их как перемещаемые.

Строго говоря - все это "хорошо забытая" классика, которая в современных учебниках обычно остается за кадром по причине всеобщего увлечения огромной динамической памятью в системах вроде Win*X или *NiX - виндоподобных или юниксоподобных... Боюсь, что скоро и во встроенных системах это станет совершенно неактуально, кроме как на "телегах с реактивными двигателями" вроде устаревших 8-битовых архитектур вроде 51-й...
Rst7
Особых проблем с изготовлением перемещаемого кода нет. В аттаче Нажмите для просмотра прикрепленного файла собственно простенький загрузчик эльфов, изготовленных при помощи IAR4.x (про пятый - ниже).

Сам загрузчик требует наличия функций fopen,fread,fclose,lseek,malloc,free,memset или zeromem, и специальной внешней функции IMB() - для выполнения прочистки кешей перед запуском.

Для упрощения загрузчика .xcl-файл должен представлять из себя следующее:
Код
-carm

// Declare relocation areas for code, constants and data.
-V(CODE)CODE_AREA,12
-V(DATA)DATA_AREA,12

// Place segments into the relocation areas
-Z(CODE_AREA)ELFBEGIN,DATA_ID,START,CODE,DATA_C,INITTAB,DATA_Z,DATA_N=0-FFFFFFFF
-Z(DATA_AREA)DATA_I=0-FFFFFFFF


В линкере выставляем Output Format elf/dwarf, Format variant none, Config/Override default program entry/Entry label "main", Extra Options -ynpra

Вызов функций, доступных для использования в исполняемых модулях, был сделан через swi. Описаны эти функции в файле swilib.h примерно таким методом:
Код
#pragma diag_suppress=Ta035
...
#pragma swi_number=10
__swi __arm int fopen(const char * cFileName, unsigned int iFileFlags, unsigned int iFileMode, unsigned int *ErrorNumber);
...


Код собственно вызывателя функций по их адресам из SWI могу привести, он похож на swi_handler в исходниках библиотеки иара.

Теперь собственно про пятый иар. Там конечно все уже в формате ELF, но штатный линкер не генерирует релокации. Попытка прикрутить ld от гнуся закончилась тем, что ld при генерации эльфа с релокациями просто эмитит ВСЕ релокации в выходной файл. Посему загрузчик надо дорабатывать, чтобы он понимал все возможные типы релокаций, а не только те, которые может генерить линкер от иара 4.x (этот линкер сразу обрабатывает все релокации, которые можно обработать при линковке, например BL внутри одной секции, это резко упрощает загрузчик). Ну или какой то промежуточный пререлокатор на хост-машине, который сделает это сам (но очень лениво писать smile.gif )
Николай Z
Цитата(Rst7 @ Nov 12 2007, 09:36) *
Особых проблем с изготовлением перемещаемого кода нет. В аттаче Нажмите для просмотра прикрепленного файла собственно простенький загрузчик эльфов, изготовленных при помощи IAR4.x (про пятый - ниже).

Сам загрузчик требует наличия функций fopen,fread,fclose,lseek,malloc,free,memset или zeromem, и специальной внешней функции IMB() - для выполнения прочистки кешей перед запуском.

Для упрощения загрузчика .xcl-файл должен представлять из себя следующее:
Код
-carm

// Declare relocation areas for code, constants and data.
-V(CODE)CODE_AREA,12
-V(DATA)DATA_AREA,12

// Place segments into the relocation areas
-Z(CODE_AREA)ELFBEGIN,DATA_ID,START,CODE,DATA_C,INITTAB,DATA_Z,DATA_N=0-FFFFFFFF
-Z(DATA_AREA)DATA_I=0-FFFFFFFF


В линкере выставляем Output Format elf/dwarf, Format variant none, Config/Override default program entry/Entry label "main", Extra Options -ynpra

Вызов функций, доступных для использования в исполняемых модулях, был сделан через swi. Описаны эти функции в файле swilib.h примерно таким методом:
Код
#pragma diag_suppress=Ta035
...
#pragma swi_number=10
__swi __arm int fopen(const char * cFileName, unsigned int iFileFlags, unsigned int iFileMode, unsigned int *ErrorNumber);
...


Код собственно вызывателя функций по их адресам из SWI могу привести, он похож на swi_handler в исходниках библиотеки иара.

Теперь собственно про пятый иар. Там конечно все уже в формате ELF, но штатный линкер не генерирует релокации. Попытка прикрутить ld от гнуся закончилась тем, что ld при генерации эльфа с релокациями просто эмитит ВСЕ релокации в выходной файл. Посему загрузчик надо дорабатывать, чтобы он понимал все возможные типы релокаций, а не только те, которые может генерить линкер от иара 4.x (этот линкер сразу обрабатывает все релокации, которые можно обработать при линковке, например BL внутри одной секции, это резко упрощает загрузчик). Ну или какой то промежуточный пререлокатор на хост-машине, который сделает это сам (но очень лениво писать smile.gif )


Мне все-таки кажется, что прежде чем обсуждать способы решения, надо для начала поставить правильно задачу. Иначе средства решения превращаются в самоцель и могут стать слишком сложными.

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

А мы тут уже кинулись зачем-то разрешать задачку запуска любой ветки оверлея с произвольного адреса... Резонно спросить - а зачем это вообще нужно в достаточно простых встроенных приложениях?
zltigo
Цитата(Rst7 @ Nov 12 2007, 08:36) *
Особых проблем ....

Спасибо за информацию по V5 - очень пригодится.


Цитата(Николай Z @ Nov 13 2007, 11:37) *
Резонно спросить - а зачем это вообще нужно в достаточно простых встроенных приложениях?

Знания никогда не помешают, вот мы их и накапливаем.
Николай Z
Цитата(zltigo @ Nov 13 2007, 12:51) *
Знания никогда не помешают, вот мы их и накапливаем.


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

Здесь же имеет смысл решать вполне конкретные задачи, но для этого нету исходной постановки задачи. Потому я и задаю все время озин и тот же вопрос - а для чего это надо...
Эффективность конкретного решения всегда выше, чем решение вообще в общем случае...
zltigo
Цитата(Николай Z @ Nov 13 2007, 14:30) *
Давно описанных способов реализации динамической загрузки более чем достаточно есть в литературе...

Ну в какой 'литературе' описан нюанс поведения линкера от V5.10 IAR при попытке сваять загружаемый модуль?
Цитата
Здесь же имеет смысл решать вполне конкретные задачи...

Вот чистой конкретикой Rst7 и поделился.
Rst7
Цитата
А мы тут уже кинулись зачем-то разрешать задачку запуска любой ветки оверлея с произвольного адреса... Резонно спросить - а зачем это вообще нужно в достаточно простых встроенных приложениях?


А что Вам так не нравится? Почему бы не скрестить какой-нибудь RTOS с загрузкой выполняемых файлов? Найдется ниша и такому применению, особенно с учетом того, что линукс часто тяжеловат для "достаточно простых встроенных приложений"

Цитата
Но вот только ведь они давно уже никакие не сакральные...


А тут никто на тайное знание и не претендует. Просто делюсь наработкой. Или нельзя?

Цитата
Давно описанных способов реализации динамической загрузки более чем достаточно есть в литературе...


Вы когда нибудь заглядывали в исходник загрузчика исполняемых файлов от никса? Там же черт ногу сломит wink.gif А тут все просто, для начинающих.
alexander55
Цитата(Rst7 @ Nov 14 2007, 09:57) *
А тут никто на тайное знание и не претендует. Просто делюсь наработкой. Или нельзя?
Вы когда нибудь заглядывали в исходник загрузчика исполняемых файлов от никса? Там же черт ногу сломит wink.gif А тут все просто, для начинающих.

Вы все правильно сделали, не терзайте себя сомнениями. smile.gif
Это полезная информация особенно, если делать что-нибудь типа КПК.
Николай Z
Цитата(zltigo @ Nov 13 2007, 15:49) *
Ну в какой 'литературе' описан нюанс поведения линкера от V5.10 IAR при попытке сваять загружаемый модуль?

Вот чистой конкретикой Rst7 и поделился.


А я не об ньюансах линкера... Я об организации оверлеев. Это никак не зависит от конкретной тулзы и может быть реализовано на любой из имеющихся в наличии. Просто большими или меньшими усилиями.

Тулза - это всего лишь инструмент - его свойства знать полезно, но решают не свойства тулзы, а цели которые надо достичь.

За конкретику - спасибо - она несомнено никому не мешает, а может и кому-то поможет.
Теперь остается только понять зачем она и куда ее применить..
Собственно мои сомнения скорее всего в том, что в топе задан несколько иной вопрос и товарищ(в топе) просто не то ищет, что ему реально было нужно... Но это как бы мои сомнения.
VladislavS
Не, вопрос я задал вполне конкретный и получил ответ (даже два), который мне помог. А потом уже вопрос трансформировался, когда проект дальше продвинулся.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.