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

GCC для ARM: Размещение неиспользуемой константы в прошивке.

Добрый день.

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. Сделать ребилд всего проекта. Готово.

 

Пример:

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:

Решил уж опубликовать, раз текст почти подготовил :biggrin:

 

Интересно есть ли у данного способа недостатки?

Как проще решить данную проблему?

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


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

const mytype name __attribute__((section("sectionname"), used)) = initial_value;
Изменено пользователем KnightIgor

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


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

const mytype name __attribute__((section("sectionname"), used)) = initial_value;

used не работает

 

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

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


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

Атрибут used и не должен работать на уровне линкера.

Этот атрибут — для компилятора, чтобы он на этапе создания объектного файла не выкинул static-объект, к которому не видит обращений в пределах этого файла.

Может понадобиться для случая, когда такой константный объект объявляется static для незабивания глобального пространства имён (и для незабивания головы придумыванием уникального имени) — без этого атрибута объект не дойдёт до линкера.

А вот линкеру уже нужен KEEP()

 

На мой взгляд — вполне подходящее решение.

Можно завернуть в макрос, пихающий все такие константные объекты (хоть и структуры описателей чего-либо) в подсекции некоторой секции, заведенной специально для них. И в линкерном скрипте сделать только одну запись для всех таких констант. Сортировка констант в пределах секции — по имени файла либо по имени подсекции, которую можно использовать как «приоритет».

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


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

А вот линкеру уже нужен KEEP()

Признаюсь, что я проглядел "GCC" в начале вопроса: я же работаю с KEIL. Его линкер, похоже, не выбрасывает секцию, если в нем есть переменная/константа, отмеченная как used.

Изменено пользователем KnightIgor

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


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

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

Эта функция оптимизатора (написали в одном файле кучку С-функций, из которых не все используются — выбросить неиспользуемые) вроде как не только в GCC есть, но это функция линкера. Как компилятору — и GCC достаточно used

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


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

Кстати, у линкера есть полезная опция --undefined. Она указывает линкеру считать символ неопределенным, как если бы на него была ссылка в программе. Я часто использую ее для указания линкеру прямо в командной строке, чтобы он загрузил из библиотеки молули, содержащие указанные мной символы, при том что на эти символы никто не ссылается (например набор команд встроенного в устройство шелла). Например --undefined=my_var_1 --undefined=my_var_2...

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


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

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

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

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

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

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

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

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

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

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