porty 0 21 февраля, 2012 Опубликовано 21 февраля, 2012 · Жалоба Добрый день. 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: Решил уж опубликовать, раз текст почти подготовил Интересно есть ли у данного способа недостатки? Как проще решить данную проблему? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 21 февраля, 2012 Опубликовано 21 февраля, 2012 (изменено) · Жалоба const mytype name __attribute__((section("sectionname"), used)) = initial_value; Изменено 21 февраля, 2012 пользователем KnightIgor Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
porty 0 21 февраля, 2012 Опубликовано 21 февраля, 2012 · Жалоба const mytype name __attribute__((section("sectionname"), used)) = initial_value; used не работает что то меня не покидает ощущение что опять где то фразу в офф. документации пропустил и всё можно было бы сделать одной такой строкой как выше ... поэтому и спрашиваю, нормальное ли мое решение в начале темы и кто как делает? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 21 февраля, 2012 Опубликовано 21 февраля, 2012 · Жалоба Атрибут used и не должен работать на уровне линкера. Этот атрибут — для компилятора, чтобы он на этапе создания объектного файла не выкинул static-объект, к которому не видит обращений в пределах этого файла. Может понадобиться для случая, когда такой константный объект объявляется static для незабивания глобального пространства имён (и для незабивания головы придумыванием уникального имени) — без этого атрибута объект не дойдёт до линкера. А вот линкеру уже нужен KEEP() На мой взгляд — вполне подходящее решение. Можно завернуть в макрос, пихающий все такие константные объекты (хоть и структуры описателей чего-либо) в подсекции некоторой секции, заведенной специально для них. И в линкерном скрипте сделать только одну запись для всех таких констант. Сортировка констант в пределах секции — по имени файла либо по имени подсекции, которую можно использовать как «приоритет». Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 21 февраля, 2012 Опубликовано 21 февраля, 2012 (изменено) · Жалоба А вот линкеру уже нужен KEEP() Признаюсь, что я проглядел "GCC" в начале вопроса: я же работаю с KEIL. Его линкер, похоже, не выбрасывает секцию, если в нем есть переменная/константа, отмеченная как used. Изменено 21 февраля, 2012 пользователем KnightIgor Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 22 февраля, 2012 Опубликовано 22 февраля, 2012 · Жалоба Возможно, Вы просто не добрались до какой-то галочки в настройках, которая помещает каждый объект в отдельную секцию и выбрасывает те секции, к которым нет обращения. Эта функция оптимизатора (написали в одном файле кучку С-функций, из которых не все используются — выбросить неиспользуемые) вроде как не только в GCC есть, но это функция линкера. Как компилятору — и GCC достаточно used Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alx2 0 24 февраля, 2012 Опубликовано 24 февраля, 2012 · Жалоба Кстати, у линкера есть полезная опция --undefined. Она указывает линкеру считать символ неопределенным, как если бы на него была ссылка в программе. Я часто использую ее для указания линкеру прямо в командной строке, чтобы он загрузил из библиотеки молули, содержащие указанные мной символы, при том что на эти символы никто не ссылается (например набор команд встроенного в устройство шелла). Например --undefined=my_var_1 --undefined=my_var_2... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться