Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: GCC для ARM: Размещение неиспользуемой константы в прошивке.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Porty
Добрый день.
GCC для ARM: Размещение неиспользуемой константы в прошивке, для случая когда нужна оптимизация.

Условия:
Часто бывает необходимо какую либо служебную информацию включить внутрь прошивки такую какая будет использоваться например нестандартным прошивальшиком, или самим пользователем или ещё как, а не самой программой, т.е. внутри программы на этот блок данных ссылки нет и поэтому компилятор и компоновщик GCC их выкидывают если оптимизация включена например -О3 и включено убирание неиспользуемых данных и кода --gc-sections. Т.е. после сборки такая константа удаляются и их нет в файле прошивки. И желательно, чтоб эта константа включалась в прошивку, всего лишь включением в список компилированных си файлов дополнительного си файла. Т.е. чтобы ничего другого не писать и не дописывать уже имеющиеся исходники

Особенности - локальное отключение оптимизации не помогает, куча разных хаков описанных на stackoverfull тоже. volatile тоже не помогает. Всякие разные __attribute__ и их ухищрения тоже. Все способы не работают на АРМ, на других платформах многие работают. А так же нужна оптимизация и сборка мусора и неиспользуемых блоков кода и данных (иначе бинарник не уместится в памяти).

Решение
Почему удаляется неиспользуемая константа - всему виной --gc-sections - это ключ для компилятора который сборщику LD говорит чтоб не включал в сборку секции на которые нет ссылок из других секций. Под секцией подразумевается либо функции либо данные. Сборщик LD работает через имена секций и скрипт сборки с расширением *.ld. Через данный скрипт можно напрямую задать то как собирать и что сохранить, директива KEEP от оптимизации, т.е. те секции которые указаны в KEEP будут принудительно включены в сборку. Но данные компилятор добавляет все в одну секцию, для констант она именуется как .rodata. Для того чтоб каждая переменная/константа и тд клалась в свою секцию необходимо компилятору добавить ключ -fdata-sections
И далее добавить в *.ld файл в раздел секций инструкцию KEEP(*(.rd.const_name)) в блок .text :

Т.е. например имея необходимость принудительно невзирая на оптимизацию разместить константу const_name в флеш памяти
необходимо сделать следующее:
1. Добавить ключ -fdata-sections на стадию компиляции всего проекта или отдельному си файлу с описанием данной константы.
2. Внести в *.ld файл в раздел секций начинающийся с SECTIONS { в подраздел начинающийся с .text : { . Запись вида: KEEP(*(.rd.const_name)) в конец подсекции .text (ВАЖНО, порядок строк в данном файле задаёт порядок сборки бинарника)
3. Сделать ребилд всего проекта. Готово.

Пример:
CODE
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
SEARCH_DIR(.)
INCLUDE "memory.ld"

/* Section Definitions */
SECTIONS
{
.text :
{
KEEP(*(.isr_vector .isr_vector.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
KEEP(*(.rodata.const_name)) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
} > rom

.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > rom

.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom

. = ALIGN(4);
_etext = .;
_sidata = .;

.data : AT (_etext)
{
_sdata = .;
*(.data .data.*)
. = ALIGN(4);
_edata = . ;
} > ram

/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
_sbss = . ;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
} > ram

/* stack section */
.co_stack (NOLOAD):
{
. = ALIGN(8);
*(.co_stack .co_stack.*)
} > ram

. = ALIGN(4);
_end = . ;
}


Пока хотел спросить и формулировал как спросить понял как найти и нашол в гугле и разобрался, понадобился день. laughing.gif
Решил уж опубликовать, раз текст почти подготовил biggrin.gif

Интересно есть ли у данного способа недостатки?
Как проще решить данную проблему?
KnightIgor
const mytype name __attribute__((section("sectionname"), used)) = initial_value;
Porty
Цитата(KnightIgor @ Feb 21 2012, 18:07) *
const mytype name __attribute__((section("sectionname"), used)) = initial_value;

used не работает

что то меня не покидает ощущение что опять где то фразу в офф. документации пропустил и всё можно было бы сделать одной такой строкой как выше ... поэтому и спрашиваю, нормальное ли мое решение в начале темы и кто как делает?
ReAl
Атрибут used и не должен работать на уровне линкера.
Этот атрибут — для компилятора, чтобы он на этапе создания объектного файла не выкинул static-объект, к которому не видит обращений в пределах этого файла.
Может понадобиться для случая, когда такой константный объект объявляется static для незабивания глобального пространства имён (и для незабивания головы придумыванием уникального имени) — без этого атрибута объект не дойдёт до линкера.
А вот линкеру уже нужен KEEP()

На мой взгляд — вполне подходящее решение.
Можно завернуть в макрос, пихающий все такие константные объекты (хоть и структуры описателей чего-либо) в подсекции некоторой секции, заведенной специально для них. И в линкерном скрипте сделать только одну запись для всех таких констант. Сортировка констант в пределах секции — по имени файла либо по имени подсекции, которую можно использовать как «приоритет».
KnightIgor
Цитата(ReAl @ Feb 21 2012, 16:45) *
А вот линкеру уже нужен KEEP()

Признаюсь, что я проглядел "GCC" в начале вопроса: я же работаю с KEIL. Его линкер, похоже, не выбрасывает секцию, если в нем есть переменная/константа, отмеченная как used.
ReAl
Возможно, Вы просто не добрались до какой-то галочки в настройках, которая помещает каждый объект в отдельную секцию и выбрасывает те секции, к которым нет обращения.
Эта функция оптимизатора (написали в одном файле кучку С-функций, из которых не все используются — выбросить неиспользуемые) вроде как не только в GCC есть, но это функция линкера. Как компилятору — и GCC достаточно used
alx2
Кстати, у линкера есть полезная опция --undefined. Она указывает линкеру считать символ неопределенным, как если бы на него была ссылка в программе. Я часто использую ее для указания линкеру прямо в командной строке, чтобы он загрузил из библиотеки молули, содержащие указанные мной символы, при том что на эти символы никто не ссылается (например набор команд встроенного в устройство шелла). Например --undefined=my_var_1 --undefined=my_var_2...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.