fk0, легенда (18.04.2013 20:34, просмотров: 352) ответил fk0 на Как бы на этапе компиляции, для функции printf, осуществить такую транформацию: все printf("blablabla %s bla %d bla %f...", ...) заменить на printf("%x %s %d %f", OLDFORMAT, ...), где OLDFORMAT ссылается на оригинальную строку формата... Т.е. это
Практические результаты. Дано: проект на PIC24 объёмом чуть выше 256кБайт (т.е. в контроллер не влезает). После применения данной методики объём занятой программной памяти сократился на ~14.4кБайта (на 5.6%) и уместился в прошивку. На первый взгляд всё работает. Экономия, как видно, не очень существенная.
Объём строк не включённых в прошивку ввиду применения методики: 684 строки, 14.3кБайта. Следует учесть, что в программной памяти PIC24 каждые 2 байта строки займут 3 байта программной памяти (т.е. экономия 21.5кБайт). Но к прошивке добавилось 1368 байт "описателей строк" (2052 байт в памяти программ) плюс программная память для специфического вывода данных -- порядка 5кБайт. В итоге экономии всего на 14.4кБайт.
На других архитектурах, с более компактным расположением строк в программной памяти (ARM, например), экономия была бы ещё меньше, чем достигнутые 5.6% на PIC24. Ввиду чего, считаю, подобная методика оправдана при объёмах программной памяти более 256кБайт, при меньших объёмах экономии не будет, скорей наоборот, объём занимаемой памяти увеличится. Для "среднего проекта". Для проектов где очень много выводимой информации (строк) экономия может быть существенно больше и методика, возможно, оправдана при меньших объёмах программной памяти. На AVR при использовании данной методики можно получить существенную экономию оперативной памяти (если применяется компилятор GCC, т.к. строковые константы при работе программы располагаются в ОЗУ).
Отличия рабочего проекта от публикуемых тут исходников -- макрос XSTR:
#define XSTR(str) ({ /* XXX: can be used only in functions */ \
static const char __xstr[] __attribute__((section("xstr"),space(psv))) = str; \
static const char *__xsref __attribute__((section("xsref"),space(psv))) = __xstr; \
(const char*)&__xsref; \
})
Вместо строки ("xxxx...") используется макрос(XSTR("xxxx...")). Макрос допустимо использовать только в теле функции. Макрос размещает строку в отдельном сегменте (который в итоге не попадает в ПЗУ микроконтроллера). И размещает в ПЗУ микроконтроллера адрес строки (в незагружаемом сегменте). А возвращаете, вместо адреса строки, адрес описателя (__xsref), содержащего адрес строки в незагружаемом сегменте... Почему так: сами строки занимают достаточно много адресного пространства. И в адресном пространстве 16-битного процессора для них просто не остаётся места (там располагаются другие объекты со своими адресами). А вот описатели занимают всего 2 байта на строку. Такой метод занимает лишние 2 байта на строку в программной памяти, но значительно меньше использует адресного пространства (иначе секцию xstr просто негде расположить так, чтобы она не пересекалась с чем-то другим -- ведь программа различает "волшебные строки" именно по факту того, что адрес располагается в специальной секции -- в данном случае "xsref", а "xstr" в памяти отсутствует и нужна для программы на PC).
Какие выявлены интересные особенности такой методики: не стоит применять макрос XSTR() к __FILE__ -- при множественном использовании __FILE__ в пределах одного объектного файла в нём будет только одна строка с именем файла. Макрос же хотя и переместит имя файла за пределы ПЗУ контроллера, но при этом породит отдельную строку с именем __FILE__ в каждом месте использования (см. текст макроса -- это понятно почему), и при каждом использовании потратит 2 байта описателя строки. И в сумме даст больший объём занимаемой программной памяти, чем при расположении __FILE__ в ПЗУ как есть (в виде строки). То же, в принципе, касается любого случая, когда выводится многократно одинаковая короткая строка. Но практически, кроме __FILE__, такие случаи редки.
Также компилятор C30 странно воспринимает (не воспринимает толком?) ключевое слово OVERLAY в линкер скрипте. Пришлось довольствоваться NOLOAD и расположением секции xstr в адресах за пределами программно памяти (чтоб не было пересечений). В процессе компиляции из полученного *.cof с помощью objcopy извлекается секция xstr (с убиранием атрибута NOLOAD и сменой LMA на 0), затом с помошью bin2hex из комплекта компилятора переводится в hex, затем в bin который используется программой на PC для декодирования сообщений...
[ZX]