Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Стартап и скрипт линкера из CMSIS для Sourcery CodeBench
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Страницы: 1, 2
koluna
Всем привет!

Помогите разобраться, пожалуйста.
Стартап и скрипт взял из CMSIS 3.01 (\Device\ARM\ARMCM3\Source\GCC): gcc_arm.ld, startup_ARMCM3.S (приложил к теме).
Подцепляю к простейшему тестовому проекту.
При сборке линкер ругался сначала на отсутствие libnosys.a (ее действительно нет в дистрибе компилятора) - убрал ее из списка в скрипте. Ошибка пропала.
Но так и не нашел, что это за либа, для чего нужна и почему ее нет...
Потом линкер ругался на отсутствие "_start". Странно, откуда эта метка в стартапе и почему так называется? Поставил вместо нее "main" - все собралось. Ошибок нет.
Но осадок сомнения остался - уже две ошибки в этих двух файлах... кто знает, что там еще? Надеялся, что все заработает "из коробки".
Пока не зашивал, не уверен в работоспособности, будем пробовать.
Насколько можно верить этим файлам? Что еще в них придется корректировать (ну, кроме размеров RAM, ROM, размеров стека и кучи)?
Непомнящий Евгений
Я в свое время сам писал и скрипт и стартап. Чем-то меня смсисовские не устроили.

Кстати, неясно зачем там асм. Для кортексов стартап прекрасно пишется на С...
koluna
Цитата(Непомнящий Евгений @ Jun 6 2013, 12:22) *
Я в свое время сам писал и скрипт и стартап. Чем-то меня смсисовские не устроили.


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

Что, неужели "коробочные" файлы так плохи и никто их не использует?
koluna
Кто-нибудь выскажет свое мнение?
Или мир разделился на два лагеря: одни пишут скрипты/стартапы сами, другие используют среды программирования с уже имеющимися скриптами/стартапами и не заморачиваются? sm.gif

Еще стартапы есть в стандартной библиотеке периферии от STM. Правда при сборке с ними ошибок гораздо больше.
И нет почему-то скриптов линкера...
_Артём_
Цитата(koluna @ Jun 6 2013, 14:58) *
И нет почему-то скриптов линкера...

Скрипты должны быть - иначе как собрать откомпилированный код?
koluna
Цитата(_Артём_ @ Jun 6 2013, 21:32) *
Скрипты должны быть - иначе как собрать откомпилированный код?


Ясное дело, что где-то они есть - без них никак!
Я говорю о другом. В комплекте с SPL их нет. Стартапы есть, а скриптов нет.
Поэтому взял все из CMSIS. Но при сборке возникли ошибки.
Поправил. Заработало. Пока не зашивал. Не уверен в работоспособности полученного кода из-за скрипта и стартапа. Не знаю какие там могут быть ошибки еще - вот и спрашиваю у опытных людей.
Кто-нибудь использовал эти самые файлы из комплекта CMSIS с минимальными изменениями (и какими)?
AHTOXA
Попробуйте скрипты и стартап от scmRTOS. Я точно знаю, что они рабочиеsm.gif
koluna
AHTOXA, спасибо большое!
Но мне хотелось бы все-таки получить ответы на свои вопросы касательно файлов из CMSIS sm.gif

Кстати, какими основными принципами надо руководствоваться при написании стартапов (для Ассемблера и Си)?
koluna
AHTOXA, есть вопросы по Вашему стартапу, прошу помочь разобраться sm.gif

Строки 12-23.
Что это? Где определено? В доке на компилятор не нашел.

Строки 207-454.
(intfunc)((unsigned long)&_estack) - для чего это вначале таблицы векторов?

Строки 465-487.
Тут, вроде, более менее понятно.
Инициализируем инициализируемые переменные своими значениями, инициализируем нулями неинициализируемые переменные, инициализируем железо (что конкретно только не понятно пока), инициализируем внешнюю память, если она есть, вызываем конструкторы.
init_HW() - это что-то типа SystemInit() из system_stm32f10x.c в SPL?
Вызов init_HW() до вызова конструкторов т. к., конструкторы могут работать с железом?
Видимо в scmRTOS есть реализованная функция init_HW()? sm.gif

AHTOXA
Цитата(koluna @ Jun 7 2013, 20:44) *
Строки 12-23.
Что это? Где определено? В доке на компилятор не нашел.

Это переменные из линкерного скрипта. Границы секций.
Цитата(koluna @ Jun 7 2013, 20:44) *
Строки 207-454.
(intfunc)((unsigned long)&_estack) - для чего это вначале таблицы векторов?

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

Цитата(koluna @ Jun 7 2013, 20:44) *
Строки 465-487.
Тут, вроде, более менее понятно.
Инициализируем инициализируемые переменные своими значениями, инициализируем нулями неинициализируемые переменные, инициализируем железо (что конкретно только не понятно пока), инициализируем внешнюю память, если она есть, вызываем конструкторы.
init_HW() - это что-то типа SystemInit() из system_stm32f10x.c в SPL?
Вызов init_HW() до вызова конструкторов т. к., конструкторы могут работать с железом?
Видимо в scmRTOS есть реализованная функция init_HW()? sm.gif

Да, всё именно так. Просто сначала я придумал название init_HW(), а потом в ST придумали SystemInit() sm.gif Можете заменить одно на другое.
(Если что, то функцию init_HW() можно посмотреть здесь).
koluna
Цитата(AHTOXA @ Jun 7 2013, 20:59) *
Это переменные из линкерного скрипта. Границы секций.


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

Не совсем понятно что это. Вроде, одно и тоже... но зачем тогда два идентификатора?
Код
extern unsigned long _etext;
extern unsigned long _sidata;


Тут правильно?
Код
extern unsigned long _sdata; // Начало секции размещения инициализированных данных (RAM)
extern unsigned long _edata; // Ее конец
extern unsigned long _sbss; // Начало секции размещения неициализированных данных (RAM)
extern unsigned long _ebss; // Ее конец
extern unsigned long _estack; // Конец стека (конец RAM)
extern unsigned long __ctors_start__; // Начало секции размещения конструкторов (FLASH)
extern unsigned long __ctors_end__; // Ее конец
extern unsigned long __dtors_start__; // Начало секции размещения деструкторов (FLASH)
extern unsigned long __dtors_end__; // Ее конец


Код
Ну, у нас таблица указателей на функции,  а первый элемент в ней - адрес стека. Приходится преобразовывать тип, чтобы компилятор не ругался.


С преобразованием-то понятно, а вот с тем что первый элемент адрес стека - нет, видимо, так для ARM надо. Перечитаю про прерывания sm.gif

Спасибо большое за консультации.
В общем, параллельно надо в скрипт линкера вникать sm.gif
AHTOXA
Цитата(koluna @ Jun 8 2013, 01:53) *
Кстати, это именно переменные, которые определяются в скрипте и глобальны для всей программы?

Да. Линкер знает их адреса (из скрипта). В любом месте программы вы можете объявить переменную с таким именем. (Здесь нам нужна не сама переменная, а её адрес. Хотя я видел, как в линкерном скрипте объявляли регистры процессора. В этом нет особого смысла, но это возможноsm.gif ).

Цитата(koluna @ Jun 8 2013, 01:53) *
Не совсем понятно что это. Вроде, одно и тоже... но зачем тогда два идентификатора?
Код
extern unsigned long _etext;
extern unsigned long _sidata;

Там есть какой-то перечень предопределённых имён, которые нужны встроенным стартапам. Так что в скрипте объявляются разные возможные варианты, например, end и __end. Памяти они не занимают, так что не жалко.

Цитата(koluna @ Jun 8 2013, 01:53) *
Тут правильно?

Да, всё так.
koluna
Цитата(AHTOXA @ Jun 8 2013, 01:39) *
Да. Линкер знает их адреса (из скрипта). В любом месте программы вы можете объявить переменную с таким именем. (Здесь нам нужна не сама переменная, а её адрес. Хотя я видел, как в линкерном скрипте объявляли регистры процессора. В этом нет особого смысла, но это возможноsm.gif ).


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

Цитата
Там есть какой-то перечень предопределённых имён, которые нужны встроенным стартапам. Так что в скрипте объявляются разные возможные варианты, например, end и __end. Памяти они не занимают, так что не жалко.


А где, кстати, перечень? Может быть так много имен для совместимости?
AHTOXA
Цитата(koluna @ Jun 10 2013, 18:41) *
Кстати, а для чего в программе могут понадобиться такие переменные?

Ну мало ли. Например, end/_end/__end часто используются менеджерами кучи.
Цитата(koluna @ Jun 10 2013, 18:41) *
А где, кстати, перечень? Может быть так много имен для совместимости?

Не уверен, что этот перечень где-то формализован. Скорее, это происходит так: перестаёт компилироваться каким-то компилятором программа - добавляем ещё одну переменную.
В общем, не надо особо с этим заморачиваться, основную идею поняли, заработало - и нормуль. Если вдруг понадобится что-то специфическое, то тогда уже погружаться, даsm.gif
koluna
Цитата(AHTOXA @ Jun 10 2013, 22:56) *
Ну мало ли. Например, end/_end/__end часто используются менеджерами кучи.
Не уверен, что этот перечень где-то формализован. Скорее, это происходит так: перестаёт компилироваться каким-то компилятором программа - добавляем ещё одну переменную.


Понятно, спасибо sm.gif
Разбираюсь с линкером потихонечку.
Будут и по нему вопросы sm.gif
koluna
Вопросы по Вашему скрипту.

Зачем вообще придумали так много разных секций? Где узнать назначение каждой секции?
Секции .text, .data, .bss, .isr_vector понятно для чего.
.ARM.exidx для чего?

Код
/* higher address of the user mode stack */
PROVIDE ( _estack = ALIGN(ORIGIN(RAM) + LENGTH(RAM) - 8 ,8) );


Зачем тут PROVIDE()?
Если в программе уже определен символ _estack, то линкер использует его. А если символ не определен, но есть ссылки на него, то линкер сам создаст этот символ. Так?
Не понял что тут с выравниванием и зачем так...

Код
.isr_vector :
{
    . = ALIGN(4);
    KEEP(*(.isr_vector))
    . = ALIGN(4);
} > FLASH


Зачем тут эти выравнивания?
Зачем вообще во всем скрипте так много выравниваний?
KEEP(), как я понимаю, нужен для того, чтобы при линковке с --gc-sections линкер не отбросил секцию .isr_vector?
Не совсем понятно как он чистит мусор.

Код
._usrstack :
{
    . = ALIGN(4);
    _susrstack = .;
    . = . + _Minimum_Stack_Size;
    . = ALIGN(4);
    _eusrstack = .;
} >RAM


_Minimum_Stack_Size, это размер стека?
_susrstack и _eusrstack могут использоваться программой для отслеживания переполнения стека?

Код
/* remove the debugging information from the standard libraries */
DISCARD :
{
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
}


Как я понимаю, все входные секции, перечисленные в выходной секции DISCARD не попадают в выходной файл. Здесь - все секции из перечисленных файлов.
А почему в комментарии это названо отладочной информацией? Что-то я не понимаю, мы же используем эти библиотеки, а если мы их используем, то не мешает ли выше перечисленное?!
Или получается так, что ранее мы уже включили все нужное нам из этих библиотек в выходной файл (секции .text, .data, .bss) и все что остается - нам не нужно?

Код
/* Stabs debugging sections.  */
.stab          0 : { *(.stab) }
...


Почему мы все располагаем по адресу "0"?
AHTOXA
Ничего себе, сколько вопросовsm.gif
Сразу предупреждаю, так глубоко я не копал, так что не на все вопросы у меня есть ответы.
Цитата(koluna @ Jun 12 2013, 20:58) *
Зачем вообще придумали так много разных секций? Где узнать назначение каждой секции?
Секции .text, .data, .bss, .isr_vector понятно для чего.
.ARM.exidx для чего?

Это что-то связанное с обработкой исключений. Хотя мы отключаем эту обработку, всё равно что-то иногда пролазит. Короче, без этой секции какой-то из линкеров не собирал.
Цитата(koluna @ Jun 12 2013, 20:58) *
Код
/* higher address of the user mode stack */
PROVIDE ( _estack = ALIGN(ORIGIN(RAM) + LENGTH(RAM) - 8 ,8) );


Зачем тут PROVIDE()?
Если в программе уже определен символ _estack, то линкер использует его. А если символ не определен, но есть ссылки на него, то линкер сам создаст этот символ. Так?
Не понял что тут с выравниванием и зачем так...

Да, так. Если мы сильно захотим, то можем в программе задать свой адрес для _estack.
Выравнивание на 8 байт - это требование ARM EABI. Без этого бывают трудноуловимые глюки.
Цитата(koluna @ Jun 12 2013, 20:58) *
Зачем тут эти выравнивания?
Зачем вообще во всем скрипте так много выравниваний?
KEEP(), как я понимаю, нужен для того, чтобы при линковке с --gc-sections линкер не отбросил секцию .isr_vector?
Не совсем понятно как он чистит мусор.

Выравнивания полезныsm.gif Я не помню, зачем они в каждом конкретном случае, но хуже от них точно не будет.
Лично наблюдал приличное уменьшение времени переключения контекста scmRTOS при добавлении выравнивания функции переключения контекста.
Мусор чистит очень просто. То, что KEEP - оставляет, далее строит дерево вызовов. Всё, что не вызывается из того, что KEEP - выкидывается.
Цитата(koluna @ Jun 12 2013, 20:58) *
Код
._usrstack :
{
    . = ALIGN(4);
    _susrstack = .;
    . = . + _Minimum_Stack_Size;
    . = ALIGN(4);
    _eusrstack = .;
} >RAM


_Minimum_Stack_Size, это размер стека?
_susrstack и _eusrstack могут использоваться программой для отслеживания переполнения стека?

Здесь простейшая проверка, что перед _eusrstack у нас останется _Minimum_Stack_Size свободного места. Если не останется, то линкер ругнётся.
Цитата(koluna @ Jun 12 2013, 20:58) *
Как я понимаю, все входные секции, перечисленные в выходной секции DISCARD не попадают в выходной файл. Здесь - все секции из перечисленных файлов.
А почему в комментарии это названо отладочной информацией? Что-то я не понимаю, мы же используем эти библиотеки, а если мы их используем, то не мешает ли выше перечисленное?!
Или получается так, что ранее мы уже включили все нужное нам из этих библиотек в выходной файл (секции .text, .data, .bss) и все что остается - нам не нужно?

Да, всё полезное из этих файлов мы уже забрали выше.
Цитата(koluna @ Jun 12 2013, 20:58) *
Код
/* Stabs debugging sections.  */
.stab          0 : { *(.stab) }
...


Почему мы все располагаем по адресу "0"?

Тут ничего не скажу, не знаю. Этот кусок есть во всех скриптах, которые я видел, поэтому он, наверное, нуженsm.gif
koluna
Цитата(AHTOXA @ Jun 12 2013, 22:45) *
Ничего себе, сколько вопросовsm.gif
Сразу предупреждаю, так глубоко я не копал, так что не на все вопросы у меня есть ответы.


Я посмотрел на скрипт внимательно, почитал доку на линкер и понял, что надо позадавать еще вопросов sm.gif

Цитата
Это что-то связанное с обработкой исключений. Хотя мы отключаем эту обработку, всё равно что-то иногда пролазит. Короче, без этой секции какой-то из линкеров не собирал.


Зачем вообще она нужна для ARM? Почему ее полностью не отключат изначально? Или тулчейн один и на мелкие процы, и на крупные процы, а на крупных обработка исключений в ходу, в отличие от мелких?

Цитата
Да, так. Если мы сильно захотим, то можем в программе задать свой адрес для _estack.


Ууу... что, может понадобиться?

Цитата
Выравнивание на 8 байт - это требование ARM EABI. Без этого бывают трудноуловимые глюки.


Ветку почитаем, спасибо. Пруфлинк можно про выравнивание, пожалуйста?

Цитата
Выравнивания полезныsm.gif Я не помню, зачем они в каждом конкретном случае, но хуже от них точно не будет.


Дырки в памяти образуются wink.gif И большое количество команд выравнивания вводит в ступор: не понимаешь для чего это и почему именно так и нужно ли вообще...
А хочется все понимать...

Цитата
Лично наблюдал приличное уменьшение времени переключения контекста scmRTOS при добавлении выравнивания функции переключения контекста.


Может, связано с выборкой команд? Ну там... ARM-инструкции (32 бита), THUMB-инструкции (16 бит)... т. е., адрес расположеня должен почему-то быть кратным 4 или 2 байтам...

Цитата
Мусор чистит очень просто. То, что KEEP - оставляет, далее строит дерево вызовов. Всё, что не вызывается из того, что KEEP - выкидывается.


Т. е., то, на что есть ссылки в коде и то, что обрамлено KEEP оставляется, все остальное - выкидывается?

Цитата
Здесь простейшая проверка, что перед _eusrstack у нас останется _Minimum_Stack_Size свободного места. Если не останется, то линкер ругнётся.


Код
._usrstack :
{
    . = ALIGN(4);
    _susrstack = .;
    . = . + _Minimum_Stack_Size;
    . = ALIGN(4);
    _eusrstack = .;
} >RAM


Как я понимаю, эта секция - последнее, что будет размещено в RAM. И, если не хватит места для ее размещения, то линкер об этом сообщит?
Фактически мы проверям (на этапе линковки), что размер стека будет не менее чем _Minimum_Stack_Size?
А во время выполнения программы? wink.gif
Стек ведь может переполниться...

Цитата
Да, всё полезное из этих файлов мы уже забрали выше.


Как я понимаю, это влияет на размер бинаря. А еще что на размер влияет? sm.gif
Встречал где-то, что многие сталкиваются с "раздуванием" бинаря при использовании Си++, но сам пока не изучал вопрос.
AHTOXA
Цитата(koluna @ Jun 13 2013, 13:40) *
Зачем вообще она нужна для ARM? Почему ее полностью не отключат изначально? Или тулчейн один и на мелкие процы, и на крупные процы, а на крупных обработка исключений в ходу, в отличие от мелких?

GCC один на все, видимо есть места, где эти исключения никак не выпилить при портировании.
Цитата(koluna @ Jun 13 2013, 13:40) *
Ууу... что, может понадобиться?

Ну мало ли. Возможность не помешаетsm.gif
Цитата(koluna @ Jun 13 2013, 13:40) *
Ветку почитаем, спасибо. Пруфлинк можно про выравнивание, пожалуйста?

Дык, там же, во втором сообщении темы: Eight-byte Stack Alignment
Цитата(koluna @ Jun 13 2013, 13:40) *
Т. е., то, на что есть ссылки в коде и то, что обрамлено KEEP оставляется, все остальное - выкидывается?

Да.
Цитата(koluna @ Jun 13 2013, 13:40) *
Как я понимаю, эта секция - последнее, что будет размещено в RAM. И, если не хватит места для ее размещения, то линкер об этом сообщит?
Фактически мы проверям (на этапе линковки), что размер стека будет не менее чем _Minimum_Stack_Size?
А во время выполнения программы? wink.gif
Стек ведь может переполниться...

Ну, время выполнения - это уж никак не забота линкераsm.gif
Цитата(koluna @ Jun 13 2013, 13:40) *
Как я понимаю, это влияет на размер бинаря. А еще что на размер влияет? sm.gif
Встречал где-то, что многие сталкиваются с "раздуванием" бинаря при использовании Си++, но сам пока не изучал вопрос.

Не бинаря, а elf. При прошивке вся эта ботва всё равно выкидывается.
Насчёт раздувания при использовании Си++ - не замечал такого. Если не подцепились исключения, то всё очень компактно получается.
Непомнящий Евгений
Цитата(koluna @ Jun 13 2013, 11:40) *
Зачем вообще она нужна для ARM? Почему ее полностью не отключат изначально? Или тулчейн один и на мелкие процы, и на крупные процы, а на крупных обработка исключений в ходу, в отличие от мелких?

Мне вот пригодилась кое-где. Хотите отключить вообще - наверное можно и так собрать тулчейн, просто зачем?


Цитата
Т. е., то, на что есть ссылки в коде и то, что обрамлено KEEP оставляется, все остальное - выкидывается?

Есть флаги компиляции, которые заведуют разбиением на секции - -ffunction-sections, --fdata-sections и флаг линкера --gc-sections

Цитата
А во время выполнения программы? wink.gif
Стек ведь может переполниться...

А во время выполнения программы - нужны динамические проверки. К примеру в конце стека размещаем некий паттерн, а потом периодически проверяем, что паттерн не затерт...

Цитата
Встречал где-то, что многие сталкиваются с "раздуванием" бинаря при использовании Си++, но сам пока не изучал вопрос.


Я столкнулся sm.gif
Включение исключений добавляют несколько десятков килобайт, включение rtti - дает накладные расходы на каждый тип с виртуальными функциями. Использование чего-то вроде iostream - дает еще порядка 150 килобайт sm.gif А это включение происходит в потрохах стандартной библиотеки при включении исключений. Так как исключения мне были нужны, пришлось немного подхачить libc++.

Ну а дальше - как обычно, чем больше кода, тем больше размер. При этом надо учитывать, что какой-то код генерится автоматически - вроде инстанцирования шаблонов.

Итого, если отключить rtti и исключения - оверхеда по сравнению с С нет. Если включить и использовать stl - тут уже надо сравнивать с аналогичным рукопашным кодом на С. Ну и мозг надо не выключать sm.gif
koluna
Вот здесь зачем выравнивание перед таблицей векторов?
Ведь по адресу 0 должен сохраняться указатель начального адреса стека, но он уже включен в таблицу из .isr_vector.

Код
.isr_vector :
{
    . = ALIGN(4);
    KEEP(*(.isr_vector))
    . = ALIGN(4);
} > FLASH


По VMA и LMA тоже не все понятно.
Как я понял, LMA - это адрес расположения секции в ROM, а VMA - расположения в RAM?
Используется только при создании образа в ROM для инициализации инициализированных переменных в RAM?

Код
.text.align :
{
    . = ALIGN(8);
    _etext = .;
    _sidata = _etext;        /* start of initialized data label */
} > FLASH

.data : AT ( _sidata )        /* AT makes the LMA follow on in the binary image */
{
    . = ALIGN(4);
    _sdata = .;                /* start of .data label */
    KEEP( *(.data) )
    KEEP( *(.data.*) )
    . = ALIGN(4);
    _edata = .;                /* end of .data label */
} > RAM


Т. е., выше перечисленное следует понимать как-то так.
Размещаем образ для ининицилизации переменных после чудной секции .ARM.exidx (опять с непонятным выравниванием на 8) во FLASH. Тут у нас используется LMA.
Размещаем данные (хотя, наверное, не размещаем, а резервируем место для размещения) с выравниванием 4 (т. е., от начала RAM адрес расположения переменных будет 4) в RAM. Тут у нас используется VMA.

Кстати, зачем .data обертывать в KEEP()? В этих секциях ведь находятся данные, на которые мы ссылаемся, поэтому линкер не должен их выбрасывать при чистке мусора. Или я чего-то не допонял sad.gif

Код
KEEP(SORT(*)(.init_array))


Какой смысл в сортировке файлов при размещении статических конструкторов?
Сергей Борщ
QUOTE (koluna @ Jun 13 2013, 21:41) *
Вот здесь зачем выравнивание перед таблицей векторов?
Ведь по адресу 0 должен сохраняться указатель начального адреса стека, но он уже включен в таблицу из .isr_vector.
Считайте это перестраховкой. Чтобы когда захочется эту программу использовать с загрузчиком и адрес начала региона будет задан не 0 и, возможно, не кратным 4, программа продолжала собираться в рабочее состояние. Чтобы в варианте с загрузчиком, добавление секции перед этой .isr_vector не ломало программу.
QUOTE (koluna @ Jun 13 2013, 21:41) *
По VMA и LMA тоже не все понятно.
Как я понял, LMA - это адрес расположения секции в ROM, а VMA - расположения в RAM?

Да.
QUOTE (koluna @ Jun 13 2013, 21:41) *
Используется только при создании образа в ROM для инициализации инициализированных переменных в RAM?
Чаще всего - да. Также используется для загружаемых в ОЗУ функций.
QUOTE (koluna @ Jun 13 2013, 21:41) *
Кстати, зачем .data обертывать в KEEP()? В этих секциях ведь находятся данные, на которые мы ссылаемся, поэтому линкер не должен их выбрасывать при чистке мусора.
Верно. Антоха что-то намудрил. и .data : AT ( _sidata ) тоже не лучший вариант. Предпочитаю
CODE
.data :
{
   ......
} > RAM AT > FLASH


QUOTE (koluna @ Jun 13 2013, 21:41) *
Какой смысл в сортировке файлов при размещении статических конструкторов?
кто-то может использовать для задания порядка вызова конструкторов. Т.е. Объект ADC будет создан до объекта UART. Но по секркту - это рудимент от найденного в интернете образца скрипта wink.gif Не мешает.
AHTOXA
Цитата(koluna @ Jun 14 2013, 00:41) *
Вот здесь зачем выравнивание перед таблицей векторов?
Ведь по адресу 0 должен сохраняться указатель начального адреса стека, но он уже включен в таблицу из .isr_vector.

Ох, дались вам эти выравниванияsm.gif Если мы 0 выровняем на 4, то останется 0, так что дырки не будет. А вот если мы будем размещать .isr_vector где-то в другом месте, то выравнивание необходимо.
Цитата(koluna @ Jun 14 2013, 00:41) *
По VMA и LMA тоже не все понятно.
Как я понял, LMA - это адрес расположения секции в ROM, а VMA - расположения в RAM?
Используется только при создании образа в ROM для инициализации инициализированных переменных в RAM?

Да, всё верно.
Цитата(koluna @ Jun 14 2013, 00:41) *
Размещаем данные (хотя, наверное, не размещаем, а резервируем место для размещения) с выравниванием 4 (т. е., от начала RAM адрес расположения переменных будет 4) в RAM.

Нет, выравнивание на 4 - это не то же самое, что отступ на 4:) Если начало ОЗУ выровнено на 4 (а обычно так и есть), то никакого отступа не будет.
Цитата(koluna @ Jun 14 2013, 00:41) *
Кстати, зачем .data обертывать в KEEP()? В этих секциях ведь находятся данные, на которые мы ссылаемся, поэтому линкер не должен их выбрасывать при чистке мусора. Или я чего-то не допонял sad.gif

Тут я не помню, если честно. Вроде бы это я боролся с LTO. И вроде бы, без этого линкер что-то выкидывал нужное. Но точно не помню, могу и соврать.
Цитата(koluna @ Jun 14 2013, 00:41) *
Какой смысл в сортировке файлов при размещении статических конструкторов?

Удобно, чтоб по алфавиту вызывались.

Цитата(Сергей Борщ @ Jun 14 2013, 01:12) *
Верно. Антоха что-то намудрил. и .data : AT ( _sidata ) тоже не лучший вариант. Предпочитаю
Код
.data :
{
   ......
} > RAM AT > FLASH

С KEEP() я написал выше, хотя может и правда намудрилsm.gif А чем хуже вариант с ".data : AT ( _sidata )" ? Мне он кажется как-то понятнее по записи.
Terminator
Цитата(Сергей Борщ @ Jun 14 2013, 02:12) *
Верно. Антоха что-то намудрил. и .data : AT ( _sidata ) тоже не лучший вариант. Предпочитаю
Код
.data :
{
   ......
} > RAM AT > FLASH

А как, при такой записи, определить по какому адресу FLASH эти данные расположились?

Цитата(Сергей Борщ @ Jun 14 2013, 02:12) *
Цитата(koluna)
Какой смысл в сортировке файлов при размещении статических конструкторов?

кто-то может использовать для задания порядка вызова конструкторов. Т.е. Объект ADC будет создан до объекта UART. Но по секркту - это рудимент от найденного в интернете образца скрипта wink.gif Не мешает.

Если SORT убрать, то будут вызываться в порядке появления в cpp файле?
koluna
Цитата(Сергей Борщ @ Jun 13 2013, 23:12) *
кто-то может использовать для задания порядка вызова конструкторов. Т.е. Объект ADC будет создан до объекта UART. Но по секркту - это рудимент от найденного в интернете образца скрипта wink.gif Не мешает.


Вот смотрю я доку на линкер и не понимаю (Sourcery Codebench)...

Цитата
SORT is an alias for SORT_BY_NAME.

Ну тут понятно.

В доке все время упоминается синтаксис вида:
Код
...
SORT_BY_NAME(.text*)
...
SORT_BY_NAME (SORT_BY_NAME (wildcard section pattern))
....


Т. е., SORT обрамляет шаблон секций.
А в скрипте - SORT обрамляет шаблон файлов:
Код
...
SORT(*)(.init_array)
...


И, мне, например, непонятно из всего прочитанного/увиденного, толи только файлы будут сортироваться по имени, толи всетаки сначала файлы а внутри них и содержимое секций...

В моем понимании надо делать как-то так:
Код
...
SORT( *( .init_array ) )
...


Ну, или так:
Код
...
*( SORT( .init_array ) )
...


Цитата(Terminator @ Jun 14 2013, 05:51) *
А как, при такой записи, определить по какому адресу FLASH эти данные расположились?


Видимо, линкер разместит эти данные во FLASH сразу за предыдущей секцией, размещенной во FLASH.

Цитата
The load address is specified by the AT or AT>
keywords. Specifying a load address is optional.
The AT keyword takes an expression as an argument. This specifies the exact load address
of the section. The AT> keyword takes the name of a memory region as an argument. See
Section 3.7 [MEMORY], page 63. The load address of the section is set to the next free
address in the region, aligned to the section’s alignment requirements.
koluna
Цитата(AHTOXA @ Jun 13 2013, 23:48) *
Ох, дались вам эти выравниванияsm.gif Если мы 0 выровняем на 4, то останется 0, так что дырки не будет. А вот если мы будем размещать .isr_vector где-то в другом месте, то выравнивание необходимо.

...

Нет, выравнивание на 4 - это не то же самое, что отступ на 4:) Если начало ОЗУ выровнено на 4 (а обычно так и есть), то никакого отступа не будет.


Ааа... понял... выравнивание и отступ - разные вещи sm.gif
Если счетчик позиций == 0, ALIGN( 4 ) == 0.
Если счетчик позиций == 3, ALIGN( 4 ) == 4.
Если счетчик позиций == 4, ALIGN( 4 ) == 4.
Если счетчик позиций == 5, ALIGN( 4 ) == 8.
Если счетчик позиций == 7, ALIGN( 4 ) == 8.
И т. д.

Ну а отступ, это было бы что-то вроде: ". += <отступ>;"

Выравнивание начала ОЗУ на 4 тоже требование ARM EABI, как и выравнивание начала стека на 8 байт?

Так, т. е., выравнивание таблицы векторов, начала стека и начала ОЗУ - обязательные требования, получается?

Исходя из скрипта, куча начинается сразу за неинициализированными данными и растет вверх навстречу стеку?
Чтобы стек и куча не пересеклись используются менеджеры кучи?
AHTOXA
Цитата(koluna @ Jun 15 2013, 00:25) *
Ааа... понял... выравнивание и отступ - разные вещи sm.gif

Даsm.gif
Цитата(koluna @ Jun 15 2013, 00:25) *
Выравнивание начала ОЗУ на 4 тоже требование ARM EABI, как и выравнивание начала стека на 8 байт?

Нет, я такого требования не припоминаю. Скорее, это сделано для удобства инициализации данных (чтоб копировать данные по слову).
Цитата(koluna @ Jun 15 2013, 00:25) *
Так, т. е., выравнивание таблицы векторов, начала стека и начала ОЗУ - обязательные требования, получается?

Начала стека - да. Начала ОЗУ - нет (вроде). А вот с таблицей векторов на самом деле требования гораздо жестче. Нужно выравнивать на ближайшую степень двойки, большую размера таблицы векторов. Так что мы недовыравнивалиsm.gif
Цитата(koluna @ Jun 15 2013, 00:25) *
Исходя из скрипта, куча начинается сразу за неинициализированными данными и растет вверх навстречу стеку?
Чтобы стек и куча не пересеклись используются менеджеры кучи?

Да, всё так.
Сергей Борщ
QUOTE (AHTOXA @ Jun 13 2013, 22:48) *
А чем хуже вариант с ".data : AT ( _sidata )" ? Мне он кажется как-то понятнее по записи.
Тем, что если захочется добавить еще одну секцию между .text и .data - то придется заводить еще один символ, аналогичный _sidata и вписывать его сюда вместо _sidata. В случае же "AT > " ничего этого делать не нужно, все происходит автоматически.

QUOTE (Terminator @ Jun 14 2013, 04:51) *
А как, при такой записи, определить по какому адресу FLASH эти данные расположились?

CODE
   __data_load_start = LOADADDR(.data);
   __data_load_end = __data_load_start + SIZEOF(.data);


QUOTE (AHTOXA @ Jun 13 2013, 22:48) *
Если SORT убрать, то будут вызываться в порядке появления в cpp файле?
Да. А для разных единиц компиляции порядок не определен. Вот для этого и делается сортировка по именам файлов (спасибо koluna, что обратил внимание). Сортировать по именам секций смысла нет, ибо все конструкторы помещаются в одну секцию, сортировать нечего.
AHTOXA
Цитата(Сергей Борщ @ Jun 15 2013, 01:50) *
Тем, что если захочется добавить еще одну секцию между .text и .data - то придется заводить еще один символ, аналогичный _sidata и вписывать его сюда вместо _sidata. В случае же "AT > " ничего этого делать не нужно, все происходит автоматически.
Код
   __data_load_start = LOADADDR(.data);
   __data_load_end = __data_load_start + SIZEOF(.data);

А, точно! Вот значит почему я в скрипте для F4 сделал с "AT > " -- чтоб не заводить ещё один символ для ramfunc. Хорошая болезнь - склерозsm.gif (Но символ _sidata всё-таки вручную там завёл, не подумал про LOADADDR()).
Цитата(Сергей Борщ @ Jun 15 2013, 01:50) *
Цитата(AHTOXA @ Jun 14 2013, 01:48) *
Если SORT убрать, то будут вызываться в порядке появления в cpp файле?

Да. А для разных единиц компиляции порядок не определен.

Это не я спрашивал, а Terminator sm.gif
koluna
Цитата(AHTOXA @ Jun 14 2013, 23:19) *
Начала стека - да. Начала ОЗУ - нет (вроде). А вот с таблицей векторов на самом деле требования гораздо жестче. Нужно выравнивать на ближайшую степень двойки, большую размера таблицы векторов. Так что мы недовыравнивалиsm.gif


Недовыравнивали - ошибка? wink.gif
Т. е., первый ". = ALIGN(4);" в секции должен выравнивать по-другому?
Хитрые там вычисления какие-то и зависят от количества векторов почему-то...

Кстати, выравненное смещение этим самым хитрым образом нужно записать в регистр VTOR, как я понимаю.
Где осуществляется запись? В стартапе и в init_HW() не нашел. Или используется значение по умолчанию?


Проекты с данным скриптом нормально собираются в Sourcery CodeBench?
Какими компиляторами собирается без проблем?

Кстати, точка входа, как я понимаю для проекта с данным скриптом будет - первый байт в секции .text?
AHTOXA
Цитата(koluna @ Jun 15 2013, 16:27) *
Недовыравнивали - ошибка? wink.gif

Давайте лучше применим терминологию Сергея Борща, и скажем: "недомудрил" sm.gif
То есть, скрипт рассчитан на размещение приложения по умолчанию, но в нём были приняты некоторые меры для более лёгкой его адаптации для приложений, загружаемых по другим адресам. И меры эти - оказались недостаточными.
Цитата(koluna @ Jun 15 2013, 16:27) *
Т. е., первый ". = ALIGN(4);" в секции должен выравнивать по-другому?
Хитрые там вычисления какие-то и зависят от количества векторов почему-то...

Насколько я понял, это необходимо, чтобы адрес любого вектора из таблицы своими старшими битами совпадал с VTOR. Типа, контроллер прерываний вычисляет адрес вектора как VTOR | (номер_прерывания * 4).
Но у меня чисто теоретические познания в этой области, я не писал загрузчиков и приложений под них. Надеюсь, Сергей Борщ что-нибудь добавит.
Цитата(koluna @ Jun 15 2013, 16:27) *
Кстати, выравненное смещение этим самым хитрым образом нужно записать в регистр VTOR, как я понимаю.
Где осуществляется запись? В стартапе и в init_HW() не нашел. Или используется значение по умолчанию?

Да, по умолчанию.
Цитата(koluna @ Jun 15 2013, 16:27) *
Проекты с данным скриптом нормально собираются в Sourcery CodeBench?
Какими компиляторами собирается без проблем?

Sourcery я давно не проверял, старыми собиралось нормально. Недавно проверял с Yagarto - работало. А сам на постоянной основе использую kgp и gcc-arm-embedded, которую здесь ещё называют Linaro (что не совсем верно, имхо).
Цитата(koluna @ Jun 15 2013, 16:27) *
Кстати, точка входа, как я понимаю для проекта с данным скриптом будет - первый байт в секции .text?

Точка входа будет вот такая:
Код
    ENTRY(Reset_Handler)
koluna
Цитата(AHTOXA @ Jun 15 2013, 14:57) *
Давайте лучше применим терминологию Сергея Борща, и скажем: "недомудрил" sm.gif
То есть, скрипт рассчитан на размещение приложения по умолчанию, но в нём были приняты некоторые меры для более лёгкой его адаптации для приложений, загружаемых по другим адресам. И меры эти - оказались недостаточными.


Давайте применим sm.gif
Все хорошо, спасибо Вам и всем окружающим!
Достаточно полезная беседа получается!

Цитата
Насколько я понял, это необходимо, чтобы адрес любого вектора из таблицы своими старшими битами совпадал с VTOR. Типа, контроллер прерываний вычисляет адрес вектора как VTOR | (номер_прерывания * 4).
Но у меня чисто теоретические познания в этой области, я не писал загрузчиков и приложений под них. Надеюсь, Сергей Борщ что-нибудь добавит.


Подождем sm.gif

Цитата
Точка входа будет вот такая:
Код
    ENTRY(Reset_Handler)


Из доки на линкер.
Цитата
3.4.1 Setting the Entry Point

There are several ways to set the entry point. The linker will set the entry point by trying
each of the following methods in order, and stopping when one of them succeeds:
• the ‘-e’ entry command-line option;
• the ENTRY(symbol ) command in a linker script;
• the value of a target specific symbol, if it is defined; For many targets this is start,
but PE and BeOS based systems for example check a list of possible entry symbols,
matching the first one found.
• the address of the first byte of the ‘.text’ section, if present;
• The address 0.


Как я понимаю, наш случай - предпоследний?
Так... а по логике вещей при включении должно генерироваться прерывание сброса, где мы как раз и попадаем в Reset_Handler().
Ну а зачем тогда команда ENTRY и вообще разговоры об этом?


Кстати, атрибуты регионов здесь зачем?
Цитата
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 4K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K
}


Как я понимаю, если линкер встречает входную секцию, которая не замаплена на выходную секцию, то он создаст выходную секцию с именем входной секции и подберет регион памяти для ее расположения с участием этих атрибутов?
AHTOXA
Цитата(koluna @ Jun 16 2013, 01:56) *
Как я понимаю, наш случай - предпоследний?

Нет. Потому что в начале секции .text у нас лежит начальный стек. В принципе, всё работало и без строчки
ENTRY(Reset_Handler)
в скрипте. Но отладка при этом глючила.
Зачем нужны атрибуты регионов - я не задумывался, есть и есть sm.gif
Сергей Борщ
QUOTE (AHTOXA @ Jun 15 2013, 13:57) *
Но у меня чисто теоретические познания в этой области, я не писал загрузчиков и приложений под них. Надеюсь, Сергей Борщ что-нибудь добавит.
Из описания VTOR:
QUOTE
Bits 29:11 TBLOFF[29:9]: Vector table base offset field.
It contains bits [29:9] of the offset of the table base from memory address 0x00000000. When
setting TBLOFF, you must align the offset to the number of exception entries in the vector table.
The minimum alignment is 128 words.
Собственно тут все сказано: выравнивание должно быть на 128 байт.
QUOTE (koluna @ Jun 15 2013, 22:56) *
Как я понимаю, наш случай - предпоследний?
Нет. Но в двух словах: программа будет работать в железе и без строчки ENTRY(), ибо старт с вектора по адресу 0x00000004 в процессоре прибит гвоздями. Эта строка (в приведенном AHTOXой виде) нужна отладчику, ибо он не умеет (пока) брать стартовый адрес из таблицы векторов, а пытается, по старинке, считать код команды по адресу 0. А у Cortex там лежит начальное значение указателя стека и получается конфуз.

QUOTE (koluna @ Jun 15 2013, 22:56) *
Кстати, атрибуты регионов здесь зачем?

QUOTE
К программисту подходит сынишка:
- Папа, почему солнышко каждый день встает на востоке, а садится на западе?
- Что, правда?
- Да.
- Каждый день?
- Да.
- По-другому было когда нибудь?
- Нет.
- О! Вот это работает - не трогай.
sm.gif
AHTOXA
Цитата(Сергей Борщ @ Jun 16 2013, 04:03) *
Собственно тут все сказано: выравнивание должно быть на 128 байт.

Понятно, то есть, вариативность в описании от АРМовцев - это для производителей проца. А ST сделал жёстко 128 слов, убрав ещё пару младших битов у VTOR. С точки зрения написания линкерных скриптов это хорошо: надо просто поменять выравнивание с 4 на 512:)
Цитата(Сергей Борщ @ Jun 16 2013, 04:03) *
работает - не трогай.

Именно! beer.gif
Сергей Борщ
QUOTE (AHTOXA @ Jun 16 2013, 01:33) *
128 слов
Да, виноват, ошибся. 128 слов, 512 байт.
Да я вам больше скажу: они там сами никак не определятся. На картинке замаскированы 9 бит, а полностью описание звучит так:
QUOTE
Bits 29:11 TBLOFF[29:9]: Vector table base offset field.
It contains bits [29:9] of the offset of the table base from memory address 0x00000000. When
setting TBLOFF, you must align the offset to the number of exception entries in the vector table.
The minimum alignment is 128 words. Table alignment requirements mean that bits[8:0] of the
table offset are always zero.
Bit 29 determines whether the vector table is in the code or SRAM memory region.
0: Code
1: SRAM
Note: Bit 29 is sometimes called the TBLBASE bit.
Bits 10:0 Reserved, must be kept cleared
Так все-таки 29:11 или 29:9? Судя по последующим "Bits 10:0" маскируются 11 бит и выравнивание должно быть на 2048 байт. "Ребус, краксворд!".
koluna
Цитата(AHTOXA @ Jun 16 2013, 00:26) *
Нет. Потому что в начале секции .text у нас лежит начальный стек. В принципе, всё работало и без строчки
ENTRY(Reset_Handler)


Код
    .text :
    {
        __ctors_start__ = .;
        KEEP(SORT(*)(.init_array))  /* eabi uses .init_array for static constructor lists */
        __ctors_end__ = .;

        __dtors_start__ = .;
        __dtors_end__ = .;
        
        . = ALIGN(4);
        *(.text)                   /* remaining code */
        *(.text.*)
        *(.rodata)                 /* read-only data (constants) */
        *(.rodata*)

        *(.eh_frame_hdr)
        *(.eh_frame)
        *(.ARM.extab* .gnu.linkonce.armextab.*)
        *(.gcc_except_table)
        *(.eh_frame_hdr)
        *(.eh_frame)

        *(.glue_7)
        *(.glue_7t)
        . = ALIGN(4);
    } > FLASH


Так, я где здесь начальный стек? sm.gif Вижу конструкторы вначале.
AHTOXA
Цитата(koluna @ Jun 16 2013, 13:25) *
Так, я где здесь начальный стек? sm.gif Вижу конструкторы вначале.

А, ну да. Тогда тем более не "предпоследний случай".
AHTOXA
Цитата(Сергей Борщ @ Jun 16 2013, 05:15) *
Так все-таки 29:11 или 29:9? Судя по последующим "Bits 10:0" маскируются 11 бит и выравнивание должно быть на 2048 байт. "Ребус, краксворд!".

В PM0214 (Programming manual для F4) всё однозначно:
Цитата
Bits 29:9 TBLOFF: Vector table base offset field.
Bits 8:0 Reserved, must be kept cleared

Видимо была опечатка в предыдущих PM.
koluna
О счетчике позиций.

Может быть вот это:
Код
__exidx_start = .;
.ARM.exidx :
{
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;


было бы правильнее сделать так:
Код
.ARM.exidx :
{
    __exidx_start = .;
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    __exidx_end = .;
} > FLASH


Есть определенные сомнения после прочтения документации.

Цитата
The GNU Linker
3.10.5 The Location Counter
...
Setting symbols to the value of the location counter outside of an output section statement
can result in unexpected values if the linker needs to place orphan sections.
...
Сергей Борщ
QUOTE (koluna @ Jun 17 2013, 17:51) *
было бы правильнее сделать так:
Похоже, что так.
AHTOXA
Вот ведь дилемма... С одной стороны, "возможны проблемы", а с другой - "работает - не трогай!" sm.gif

Да, надо поправить.
koluna
Не совсем разобрался с адресацией: абсолютная и относительная.
Как я понял, вне описания секций адресация абсолютная, внутри описания секций - относительная.
Вот в чем проблема. Если внутри секций мы присваиваем значение счетчика позиций (или просто число) какому-нибудь символу, то присваевается относительный адрес (адрес относительно начала секции).

Код
__ctors_start__ = .;
__ctors_end__ = .;
_sdata = .;
_edata = .;
_sbss = .;
_ebss = .;


Потом в программе (в первую очередь в стартапе) мы используем эти символы.
Но адреса-то они содержат относительные! Программе, как я понимаю, нужны абсолютные адреса?
AHTOXA
Цитата(koluna @ Jun 18 2013, 17:02) *
Вот в чем проблема. Если внутри секций мы присваиваем значение счетчика позиций (или просто число) какому-нибудь символу, то присваевается относительный адрес (адрес относительно начала секции).

Нет. Это адрес в выходной секции (в нашем случае это FLASH или RAM):
Цитата
koluna
Цитата(AHTOXA @ Jun 18 2013, 17:00) *
Нет. Это адрес в выходной секции (в нашем случае это FLASH или RAM):


Знаю. Но тогда это что значит?

Цитата
Note: . actually refers to the byte offset from the start of the current containing object. Normally this is the SECTIONS statement, whose start address is 0, hence . can be used as an absolute address. If . is used inside a section description however, it refers to the byte offset from the start of that section, not an absolute address
koluna
Пока так и не понял, "--gc-sections" работает без "-ffunction-sections и -fdata-sections"?
Ну поместит компилятор при использовании ключей "-ffunction-sections и -fdata-sections" каждую функцию в ".text.имя_функции", и каждую переменную (глобальную или статическую) в ".data.имя_переменной" (".bss.имя_переменной") и что дальше?
Или линкер не может отбросить при оптимизации функции и просто переменные, которые не используются в программе, т. е., он может отбросить только секции, в которые компилятор и помещает функции/переменные при использовании ключей "-ffunction-sections и -fdata-sections"?
AHTOXA
Цитата(koluna @ Jun 18 2013, 19:25) *
Знаю. Но тогда это что значит?

А фиг его знает. Либо меня подводит мой англицкий, либо там написана неправда. sm.gif
Но по факту точка - это адрес в области, куда помещается секция. Может быть, дело в ">"? Там примеры без ">".
Цитата(koluna @ Jun 18 2013, 21:52) *
Или линкер не может отбросить при оптимизации функции и просто переменные, которые не используются в программе, т. е., он может отбросить только секции, в которые компилятор и помещает функции/переменные при использовании ключей "-ffunction-sections и -fdata-sections"?

Да, линкер умеет отбрасывать только секции.
koluna
Цитата(AHTOXA @ Jun 18 2013, 20:58) *
А фиг его знает. Либо меня подводит мой англицкий, либо там написана неправда. sm.gif
Но по факту точка - это адрес в области, куда помещается секция. Может быть, дело в ">"? Там примеры без ">".


Вот и я сомневаюсь... предлагаю подождать Сергея sm.gif

Цитата
Да, линкер умеет отбрасывать только секции.


В итоге.
Секции, перечисленные в команде KEEP() не отбрасываются линкером при чистке мусора (актуально при компиляции с опциями “-ffunction-sections”, “-fdata-sections” и одновременной линковке с опцией “--gc-sections”). При компиляции с опциями “-ffunction-sections” и “-fdata-sections” компилятор помещает каждую функцию и переменную в отдельную секцию вида “.text.имя”, “.data.имя”, “.bss.имя”. Далее, при линковке с опцией “--gc-sections”, линкером отбрасываются все эти входные секции, на которые нет ссылок в программе (нет ссылок на функции и переменные, содержащиеся в них), кроме помеченых KEEP().
Правильно? sm.gif
AHTOXA
Да, всё так.
Сергей Борщ
QUOTE (koluna @ Jun 18 2013, 20:43) *
Вот и я сомневаюсь... предлагаю подождать Сергея sm.gif
Я пас.

QUOTE (koluna @ Jun 18 2013, 20:43) *
Правильно? sm.gif
Да.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.