|
|
  |
Стартап и скрипт линкера из CMSIS для Sourcery CodeBench |
|
|
|
Jun 6 2013, 08:09
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Всем привет! Помогите разобраться, пожалуйста. Стартап и скрипт взял из CMSIS 3.01 (\Device\ARM\ARMCM3\Source\GCC): gcc_arm.ld, startup_ARMCM3.S (приложил к теме). Подцепляю к простейшему тестовому проекту. При сборке линкер ругался сначала на отсутствие libnosys.a (ее действительно нет в дистрибе компилятора) - убрал ее из списка в скрипте. Ошибка пропала. Но так и не нашел, что это за либа, для чего нужна и почему ее нет... Потом линкер ругался на отсутствие "_start". Странно, откуда эта метка в стартапе и почему так называется? Поставил вместо нее "main" - все собралось. Ошибок нет. Но осадок сомнения остался - уже две ошибки в этих двух файлах... кто знает, что там еще? Надеялся, что все заработает "из коробки". Пока не зашивал, не уверен в работоспособности, будем пробовать. Насколько можно верить этим файлам? Что еще в них придется корректировать (ну, кроме размеров RAM, ROM, размеров стека и кучи)?
Прикрепленные файлы
GCC.zip ( 3.82 килобайт )
Кол-во скачиваний: 14
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 6 2013, 08:42
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(Непомнящий Евгений @ Jun 6 2013, 12:22)  Я в свое время сам писал и скрипт и стартап. Чем-то меня смсисовские не устроили. Да я бы и сам написал, если бы знал как  Хочется разобраться, но времени пока нет. Поэтому решил начать с более простого - подключить имеющиеся файлы. Что, неужели "коробочные" файлы так плохи и никто их не использует?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 6 2013, 11:58
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Кто-нибудь выскажет свое мнение? Или мир разделился на два лагеря: одни пишут скрипты/стартапы сами, другие используют среды программирования с уже имеющимися скриптами/стартапами и не заморачиваются?  Еще стартапы есть в стандартной библиотеке периферии от STM. Правда при сборке с ними ошибок гораздо больше. И нет почему-то скриптов линкера...
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 6 2013, 18:27
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(_Артём_ @ Jun 6 2013, 21:32)  Скрипты должны быть - иначе как собрать откомпилированный код? Ясное дело, что где-то они есть - без них никак! Я говорю о другом. В комплекте с SPL их нет. Стартапы есть, а скриптов нет. Поэтому взял все из CMSIS. Но при сборке возникли ошибки. Поправил. Заработало. Пока не зашивал. Не уверен в работоспособности полученного кода из-за скрипта и стартапа. Не знаю какие там могут быть ошибки еще - вот и спрашиваю у опытных людей. Кто-нибудь использовал эти самые файлы из комплекта CMSIS с минимальными изменениями (и какими)?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 7 2013, 14:44
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
AHTOXA, есть вопросы по Вашему стартапу, прошу помочь разобраться  Строки 12-23. Что это? Где определено? В доке на компилятор не нашел. Строки 207-454. (intfunc)((unsigned long)&_estack) - для чего это вначале таблицы векторов? Строки 465-487. Тут, вроде, более менее понятно. Инициализируем инициализируемые переменные своими значениями, инициализируем нулями неинициализируемые переменные, инициализируем железо (что конкретно только не понятно пока), инициализируем внешнюю память, если она есть, вызываем конструкторы. init_HW() - это что-то типа SystemInit() из system_stm32f10x.c в SPL? Вызов init_HW() до вызова конструкторов т. к., конструкторы могут работать с железом? Видимо в scmRTOS есть реализованная функция init_HW()?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 7 2013, 16:59
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(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()?  Да, всё именно так. Просто сначала я придумал название init_HW(), а потом в ST придумали SystemInit()  Можете заменить одно на другое. (Если что, то функцию init_HW() можно посмотреть здесь).
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 7 2013, 19:53
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(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 надо. Перечитаю про прерывания  Спасибо большое за консультации. В общем, параллельно надо в скрипт линкера вникать
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 7 2013, 21:39
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(koluna @ Jun 8 2013, 01:53)  Кстати, это именно переменные, которые определяются в скрипте и глобальны для всей программы? Да. Линкер знает их адреса (из скрипта). В любом месте программы вы можете объявить переменную с таким именем. (Здесь нам нужна не сама переменная, а её адрес. Хотя я видел, как в линкерном скрипте объявляли регистры процессора. В этом нет особого смысла, но это возможно  ). Цитата(koluna @ Jun 8 2013, 01:53)  Не совсем понятно что это. Вроде, одно и тоже... но зачем тогда два идентификатора? Код extern unsigned long _etext; extern unsigned long _sidata; Там есть какой-то перечень предопределённых имён, которые нужны встроенным стартапам. Так что в скрипте объявляются разные возможные варианты, например, end и __end. Памяти они не занимают, так что не жалко. Цитата(koluna @ Jun 8 2013, 01:53)  Тут правильно? Да, всё так.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 10 2013, 12:41
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(AHTOXA @ Jun 8 2013, 01:39)  Да. Линкер знает их адреса (из скрипта). В любом месте программы вы можете объявить переменную с таким именем. (Здесь нам нужна не сама переменная, а её адрес. Хотя я видел, как в линкерном скрипте объявляли регистры процессора. В этом нет особого смысла, но это возможно  ). Кстати, а для чего в программе могут понадобиться такие переменные? Цитата Там есть какой-то перечень предопределённых имён, которые нужны встроенным стартапам. Так что в скрипте объявляются разные возможные варианты, например, end и __end. Памяти они не занимают, так что не жалко. А где, кстати, перечень? Может быть так много имен для совместимости?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 10 2013, 18:56
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(koluna @ Jun 10 2013, 18:41)  Кстати, а для чего в программе могут понадобиться такие переменные? Ну мало ли. Например, end/_end/__end часто используются менеджерами кучи. Цитата(koluna @ Jun 10 2013, 18:41)  А где, кстати, перечень? Может быть так много имен для совместимости? Не уверен, что этот перечень где-то формализован. Скорее, это происходит так: перестаёт компилироваться каким-то компилятором программа - добавляем ещё одну переменную. В общем, не надо особо с этим заморачиваться, основную идею поняли, заработало - и нормуль. Если вдруг понадобится что-то специфическое, то тогда уже погружаться, да
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 11 2013, 07:46
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(AHTOXA @ Jun 10 2013, 22:56)  Ну мало ли. Например, end/_end/__end часто используются менеджерами кучи. Не уверен, что этот перечень где-то формализован. Скорее, это происходит так: перестаёт компилироваться каким-то компилятором программа - добавляем ещё одну переменную. Понятно, спасибо  Разбираюсь с линкером потихонечку. Будут и по нему вопросы
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 12 2013, 14:58
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Вопросы по Вашему скрипту. Зачем вообще придумали так много разных секций? Где узнать назначение каждой секции? Секции .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"?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 12 2013, 18:45
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Ничего себе, сколько вопросов  Сразу предупреждаю, так глубоко я не копал, так что не на все вопросы у меня есть ответы. Цитата(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? Не совсем понятно как он чистит мусор. Выравнивания полезны  Я не помню, зачем они в каждом конкретном случае, но хуже от них точно не будет. Лично наблюдал приличное уменьшение времени переключения контекста 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"? Тут ничего не скажу, не знаю. Этот кусок есть во всех скриптах, которые я видел, поэтому он, наверное, нужен
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 13 2013, 07:40
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(AHTOXA @ Jun 12 2013, 22:45)  Ничего себе, сколько вопросов  Сразу предупреждаю, так глубоко я не копал, так что не на все вопросы у меня есть ответы. Я посмотрел на скрипт внимательно, почитал доку на линкер и понял, что надо позадавать еще вопросов  Цитата Это что-то связанное с обработкой исключений. Хотя мы отключаем эту обработку, всё равно что-то иногда пролазит. Короче, без этой секции какой-то из линкеров не собирал. Зачем вообще она нужна для ARM? Почему ее полностью не отключат изначально? Или тулчейн один и на мелкие процы, и на крупные процы, а на крупных обработка исключений в ходу, в отличие от мелких? Цитата Да, так. Если мы сильно захотим, то можем в программе задать свой адрес для _estack. Ууу... что, может понадобиться? Цитата Выравнивание на 8 байт - это требование ARM EABI. Без этого бывают трудноуловимые глюки. Ветку почитаем, спасибо. Пруфлинк можно про выравнивание, пожалуйста? Цитата Выравнивания полезны  Я не помню, зачем они в каждом конкретном случае, но хуже от них точно не будет. Дырки в памяти образуются  И большое количество команд выравнивания вводит в ступор: не понимаешь для чего это и почему именно так и нужно ли вообще... А хочется все понимать... Цитата Лично наблюдал приличное уменьшение времени переключения контекста 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? А во время выполнения программы?  Стек ведь может переполниться... Цитата Да, всё полезное из этих файлов мы уже забрали выше. Как я понимаю, это влияет на размер бинаря. А еще что на размер влияет? Встречал где-то, что многие сталкиваются с "раздуванием" бинаря при использовании Си++, но сам пока не изучал вопрос.
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 13 2013, 08:36
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(koluna @ Jun 13 2013, 13:40)  Зачем вообще она нужна для ARM? Почему ее полностью не отключат изначально? Или тулчейн один и на мелкие процы, и на крупные процы, а на крупных обработка исключений в ходу, в отличие от мелких? GCC один на все, видимо есть места, где эти исключения никак не выпилить при портировании. Цитата(koluna @ Jun 13 2013, 13:40)  Ууу... что, может понадобиться? Ну мало ли. Возможность не помешает  Цитата(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? А во время выполнения программы?  Стек ведь может переполниться... Ну, время выполнения - это уж никак не забота линкера  Цитата(koluna @ Jun 13 2013, 13:40)  Как я понимаю, это влияет на размер бинаря. А еще что на размер влияет? Встречал где-то, что многие сталкиваются с "раздуванием" бинаря при использовании Си++, но сам пока не изучал вопрос. Не бинаря, а elf. При прошивке вся эта ботва всё равно выкидывается. Насчёт раздувания при использовании Си++ - не замечал такого. Если не подцепились исключения, то всё очень компактно получается.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 13 2013, 08:43
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(koluna @ Jun 13 2013, 11:40)  Зачем вообще она нужна для ARM? Почему ее полностью не отключат изначально? Или тулчейн один и на мелкие процы, и на крупные процы, а на крупных обработка исключений в ходу, в отличие от мелких? Мне вот пригодилась кое-где. Хотите отключить вообще - наверное можно и так собрать тулчейн, просто зачем? Цитата Т. е., то, на что есть ссылки в коде и то, что обрамлено KEEP оставляется, все остальное - выкидывается? Есть флаги компиляции, которые заведуют разбиением на секции - -ffunction-sections, --fdata-sections и флаг линкера --gc-sections Цитата А во время выполнения программы?  Стек ведь может переполниться... А во время выполнения программы - нужны динамические проверки. К примеру в конце стека размещаем некий паттерн, а потом периодически проверяем, что паттерн не затерт... Цитата Встречал где-то, что многие сталкиваются с "раздуванием" бинаря при использовании Си++, но сам пока не изучал вопрос. Я столкнулся Включение исключений добавляют несколько десятков килобайт, включение rtti - дает накладные расходы на каждый тип с виртуальными функциями. Использование чего-то вроде iostream - дает еще порядка 150 килобайт  А это включение происходит в потрохах стандартной библиотеки при включении исключений. Так как исключения мне были нужны, пришлось немного подхачить libc++. Ну а дальше - как обычно, чем больше кода, тем больше размер. При этом надо учитывать, что какой-то код генерится автоматически - вроде инстанцирования шаблонов. Итого, если отключить rtti и исключения - оверхеда по сравнению с С нет. Если включить и использовать stl - тут уже надо сравнивать с аналогичным рукопашным кодом на С. Ну и мозг надо не выключать
|
|
|
|
|
Jun 13 2013, 18:41
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Вот здесь зачем выравнивание перед таблицей векторов? Ведь по адресу 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()? В этих секциях ведь находятся данные, на которые мы ссылаемся, поэтому линкер не должен их выбрасывать при чистке мусора. Или я чего-то не допонял  Код KEEP(SORT(*)(.init_array)) Какой смысл в сортировке файлов при размещении статических конструкторов?
Сообщение отредактировал koluna - Jun 13 2013, 18:42
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 13 2013, 19:12
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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. Но по секркту - это рудимент от найденного в интернете образца скрипта  Не мешает.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 13 2013, 19:48
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(koluna @ Jun 14 2013, 00:41)  Вот здесь зачем выравнивание перед таблицей векторов? Ведь по адресу 0 должен сохраняться указатель начального адреса стека, но он уже включен в таблицу из .isr_vector. Ох, дались вам эти выравнивания  Если мы 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()? В этих секциях ведь находятся данные, на которые мы ссылаемся, поэтому линкер не должен их выбрасывать при чистке мусора. Или я чего-то не допонял  Тут я не помню, если честно. Вроде бы это я боролся с LTO. И вроде бы, без этого линкер что-то выкидывал нужное. Но точно не помню, могу и соврать. Цитата(koluna @ Jun 14 2013, 00:41)  Какой смысл в сортировке файлов при размещении статических конструкторов? Удобно, чтоб по алфавиту вызывались. Цитата(Сергей Борщ @ Jun 14 2013, 01:12)  Верно. Антоха что-то намудрил. и .data : AT ( _sidata ) тоже не лучший вариант. Предпочитаю Код .data : { ...... } > RAM AT > FLASH С KEEP() я написал выше, хотя может и правда намудрил  А чем хуже вариант с ".data : AT ( _sidata )" ? Мне он кажется как-то понятнее по записи.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 14 2013, 01:51
|

Местный
  
Группа: Участник
Сообщений: 209
Регистрация: 7-12-04
Из: Томск
Пользователь №: 1 382

|
Цитата(Сергей Борщ @ Jun 14 2013, 02:12)  Верно. Антоха что-то намудрил. и .data : AT ( _sidata ) тоже не лучший вариант. Предпочитаю Код .data : { ...... } > RAM AT > FLASH А как, при такой записи, определить по какому адресу FLASH эти данные расположились? Цитата(Сергей Борщ @ Jun 14 2013, 02:12)  Цитата(koluna) Какой смысл в сортировке файлов при размещении статических конструкторов? кто-то может использовать для задания порядка вызова конструкторов. Т.е. Объект ADC будет создан до объекта UART. Но по секркту - это рудимент от найденного в интернете образца скрипта  Не мешает. Если SORT убрать, то будут вызываться в порядке появления в cpp файле?
|
|
|
|
|
Jun 14 2013, 13:41
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(Сергей Борщ @ Jun 13 2013, 23:12)  кто-то может использовать для задания порядка вызова конструкторов. Т.е. Объект ADC будет создан до объекта UART. Но по секркту - это рудимент от найденного в интернете образца скрипта  Не мешает. Вот смотрю я доку на линкер и не понимаю (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.
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 14 2013, 18:25
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(AHTOXA @ Jun 13 2013, 23:48)  Ох, дались вам эти выравнивания  Если мы 0 выровняем на 4, то останется 0, так что дырки не будет. А вот если мы будем размещать .isr_vector где-то в другом месте, то выравнивание необходимо. ... Нет, выравнивание на 4 - это не то же самое, что отступ на 4:) Если начало ОЗУ выровнено на 4 (а обычно так и есть), то никакого отступа не будет. Ааа... понял... выравнивание и отступ - разные вещи  Если счетчик позиций == 0, ALIGN( 4 ) == 0. Если счетчик позиций == 3, ALIGN( 4 ) == 4. Если счетчик позиций == 4, ALIGN( 4 ) == 4. Если счетчик позиций == 5, ALIGN( 4 ) == 8. Если счетчик позиций == 7, ALIGN( 4 ) == 8. И т. д. Ну а отступ, это было бы что-то вроде: ". += <отступ>;" Выравнивание начала ОЗУ на 4 тоже требование ARM EABI, как и выравнивание начала стека на 8 байт? Так, т. е., выравнивание таблицы векторов, начала стека и начала ОЗУ - обязательные требования, получается? Исходя из скрипта, куча начинается сразу за неинициализированными данными и растет вверх навстречу стеку? Чтобы стек и куча не пересеклись используются менеджеры кучи?
Сообщение отредактировал koluna - Jun 14 2013, 18:14
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 14 2013, 19:19
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(koluna @ Jun 15 2013, 00:25)  Ааа... понял... выравнивание и отступ - разные вещи  Да  Цитата(koluna @ Jun 15 2013, 00:25)  Выравнивание начала ОЗУ на 4 тоже требование ARM EABI, как и выравнивание начала стека на 8 байт? Нет, я такого требования не припоминаю. Скорее, это сделано для удобства инициализации данных (чтоб копировать данные по слову). Цитата(koluna @ Jun 15 2013, 00:25)  Так, т. е., выравнивание таблицы векторов, начала стека и начала ОЗУ - обязательные требования, получается? Начала стека - да. Начала ОЗУ - нет (вроде). А вот с таблицей векторов на самом деле требования гораздо жестче. Нужно выравнивать на ближайшую степень двойки, большую размера таблицы векторов. Так что мы недовыравнивали  Цитата(koluna @ Jun 15 2013, 00:25)  Исходя из скрипта, куча начинается сразу за неинициализированными данными и растет вверх навстречу стеку? Чтобы стек и куча не пересеклись используются менеджеры кучи? Да, всё так.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 14 2013, 19:50
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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, что обратил внимание). Сортировать по именам секций смысла нет, ибо все конструкторы помещаются в одну секцию, сортировать нечего.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 15 2013, 05:43
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Сергей Борщ @ 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. Хорошая болезнь - склероз  (Но символ _sidata всё-таки вручную там завёл, не подумал про LOADADDR()). Цитата(Сергей Борщ @ Jun 15 2013, 01:50)  Цитата(AHTOXA @ Jun 14 2013, 01:48)  Если SORT убрать, то будут вызываться в порядке появления в cpp файле? Да. А для разных единиц компиляции порядок не определен. Это не я спрашивал, а Terminator
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 15 2013, 10:27
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(AHTOXA @ Jun 14 2013, 23:19)  Начала стека - да. Начала ОЗУ - нет (вроде). А вот с таблицей векторов на самом деле требования гораздо жестче. Нужно выравнивать на ближайшую степень двойки, большую размера таблицы векторов. Так что мы недовыравнивали  Недовыравнивали - ошибка?  Т. е., первый ". = ALIGN(4);" в секции должен выравнивать по-другому? Хитрые там вычисления какие-то и зависят от количества векторов почему-то... Кстати, выравненное смещение этим самым хитрым образом нужно записать в регистр VTOR, как я понимаю. Где осуществляется запись? В стартапе и в init_HW() не нашел. Или используется значение по умолчанию? Проекты с данным скриптом нормально собираются в Sourcery CodeBench? Какими компиляторами собирается без проблем? Кстати, точка входа, как я понимаю для проекта с данным скриптом будет - первый байт в секции .text?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 15 2013, 10:57
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(koluna @ Jun 15 2013, 16:27)  Недовыравнивали - ошибка?  Давайте лучше применим терминологию Сергея Борща, и скажем: "недомудрил"  То есть, скрипт рассчитан на размещение приложения по умолчанию, но в нём были приняты некоторые меры для более лёгкой его адаптации для приложений, загружаемых по другим адресам. И меры эти - оказались недостаточными. Цитата(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)
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 15 2013, 19:56
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(AHTOXA @ Jun 15 2013, 14:57)  Давайте лучше применим терминологию Сергея Борща, и скажем: "недомудрил"  То есть, скрипт рассчитан на размещение приложения по умолчанию, но в нём были приняты некоторые меры для более лёгкой его адаптации для приложений, загружаемых по другим адресам. И меры эти - оказались недостаточными. Давайте применим  Все хорошо, спасибо Вам и всем окружающим! Достаточно полезная беседа получается! Цитата Насколько я понял, это необходимо, чтобы адрес любого вектора из таблицы своими старшими битами совпадал с VTOR. Типа, контроллер прерываний вычисляет адрес вектора как VTOR | (номер_прерывания * 4). Но у меня чисто теоретические познания в этой области, я не писал загрузчиков и приложений под них. Надеюсь, Сергей Борщ что-нибудь добавит. Подождем  Цитата Точка входа будет вот такая: Код 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 } Как я понимаю, если линкер встречает входную секцию, которая не замаплена на выходную секцию, то он создаст выходную секцию с именем входной секции и подберет регион памяти для ее расположения с участием этих атрибутов?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 15 2013, 22:03
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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 К программисту подходит сынишка: - Папа, почему солнышко каждый день встает на востоке, а садится на западе? - Что, правда? - Да. - Каждый день? - Да. - По-другому было когда нибудь? - Нет. - О! Вот это работает - не трогай.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 15 2013, 23:15
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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 байт. "Ребус, краксворд!".
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 16 2013, 07:25
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(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 Так, я где здесь начальный стек?  Вижу конструкторы вначале.
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 16 2013, 19:48
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Сергей Борщ @ 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.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 17 2013, 14:51
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
О счетчике позиций. Может быть вот это: Код __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. ...
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 18 2013, 11:02
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Не совсем разобрался с адресацией: абсолютная и относительная. Как я понял, вне описания секций адресация абсолютная, внутри описания секций - относительная. Вот в чем проблема. Если внутри секций мы присваиваем значение счетчика позиций (или просто число) какому-нибудь символу, то присваевается относительный адрес (адрес относительно начала секции). Код __ctors_start__ = .; __ctors_end__ = .; _sdata = .; _edata = .; _sbss = .; _ebss = .; Потом в программе (в первую очередь в стартапе) мы используем эти символы. Но адреса-то они содержат относительные! Программе, как я понимаю, нужны абсолютные адреса?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 18 2013, 13:25
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(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 - Jun 18 2013, 15:27
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 18 2013, 16:58
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(koluna @ Jun 18 2013, 19:25)  Знаю. Но тогда это что значит? А фиг его знает. Либо меня подводит мой англицкий, либо там написана неправда.  Но по факту точка - это адрес в области, куда помещается секция. Может быть, дело в ">"? Там примеры без ">". Цитата(koluna @ Jun 18 2013, 21:52)  Или линкер не может отбросить при оптимизации функции и просто переменные, которые не используются в программе, т. е., он может отбросить только секции, в которые компилятор и помещает функции/переменные при использовании ключей "-ffunction-sections и -fdata-sections"? Да, линкер умеет отбрасывать только секции.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 18 2013, 17:43
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(AHTOXA @ Jun 18 2013, 20:58)  А фиг его знает. Либо меня подводит мой англицкий, либо там написана неправда.  Но по факту точка - это адрес в области, куда помещается секция. Может быть, дело в ">"? Там примеры без ">". Вот и я сомневаюсь... предлагаю подождать Сергея  Цитата Да, линкер умеет отбрасывать только секции. В итоге. Секции, перечисленные в команде KEEP() не отбрасываются линкером при чистке мусора (актуально при компиляции с опциями “-ffunction-sections”, “-fdata-sections” и одновременной линковке с опцией “--gc-sections”). При компиляции с опциями “-ffunction-sections” и “-fdata-sections” компилятор помещает каждую функцию и переменную в отдельную секцию вида “.text.имя”, “.data.имя”, “.bss.имя”. Далее, при линковке с опцией “--gc-sections”, линкером отбрасываются все эти входные секции, на которые нет ссылок в программе (нет ссылок на функции и переменные, содержащиеся в них), кроме помеченых KEEP(). Правильно?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 18 2013, 18:37
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Мучает меня вопрос по секциям все-таки... .init_array - конструкторы EABI. .ctors - конструкторы не EABI. Для совместимости лучше использовать в скрипте и то и другое? .dtors Деструкторы. EABI? Нет? Все?  Это зачем? .comment .line
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 18 2013, 19:44
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(koluna @ Jun 19 2013, 00:37)  .init_array - конструкторы EABI. .ctors - конструкторы не EABI. Для совместимости лучше использовать в скрипте и то и другое? Можно использовать. Насчёт "лучше" - не уверен. Зачем поддерживать такие старые компиляторы? Цитата(koluna @ Jun 19 2013, 00:37)  .dtors Деструкторы. EABI? Нет? Все?  Деструкторы нам не нужны. Поэтому мы их игнорируем, где бы они не были размещены. Цитата(koluna @ Jun 19 2013, 00:37)  Это зачем? .comment .line Не знаю, и знать не хочу!
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 19 2013, 07:41
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(AHTOXA @ Jun 18 2013, 23:44)  Можно использовать. Насчёт "лучше" - не уверен. Зачем поддерживать такие старые компиляторы? Насколько старые? Просто встречаю в других скриптах... видимо, авторы не особо задумывались над этим... Цитата Деструкторы нам не нужны. Поэтому мы их игнорируем, где бы они не были размещены. И деструкторы тоже встречаю в других скриптах... Ну, да... по сути и не нужны деструкторы для глобальных и статических объектов. Но вдруг у кого-то фантазия проснется и он решит вызвать деструктор?  Цитата Не знаю, и знать не хочу!  А вот я хочу, это бодрит  Со счетчиком позиций вопрос пока открыт
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 19 2013, 08:04
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(koluna @ Jun 19 2013, 13:41)  Насколько старые? Емнимс, уже года три-четыре как перешли на eabi. Цитата(koluna @ Jun 19 2013, 13:41)  Но вдруг у кого-то фантазия проснется и он решит вызвать деструктор?  Вызвать вручную -- без проблем. Та секция отвечает за автоматический вызов деструкторов при завершении программы. Цитата(koluna @ Jun 19 2013, 13:41)  А вот я хочу, это бодрит  Мне кажется, что вы уже достаточно прокачали свой уровень по скрипту и стартапу, и уже можно смело двигаться дальше  Цитата(koluna @ Jun 19 2013, 13:41)  Со счетчиком позиций вопрос пока открыт  По факту всё работает как надо. Скорее всего либо мы что-то не так поняли в описании, либо там (в описании) ошибка.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 19 2013, 09:44
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Цитата(AHTOXA @ Jun 19 2013, 12:04)  Емнимс, уже года три-четыре как перешли на eabi. Теперь все поддерживаемые (развиваемые) в данный момент компиляторы компиляторы стали EABI? Цитата Вызвать вручную -- без проблем. Та секция отвечает за автоматический вызов деструкторов при завершении программы. А, ну да... Если хотим автоматом, то используем в скрипте входные секции ".dtors*" (мапим входные куда-нибудь в ".text", наверняка даже с KEEP()). Создаем символы, указывающие на начало и конец области размещения деструкторов в этих секциях, а потом в стартапе после вызова main() в цикле вызываем все деструкторы по указателю, используя выше определенные символы... Кстати, в ".ctors" (для EABI ".init_array") помещаются только конструкторы по умолчанию, а остальные конструкторы попадают в ".text*"? А деструкторы-то куда компилятор пихает? По аналогии с конструкторами в ".dtors*"? Цитата По факту всё работает как надо. Скорее всего либо мы что-то не так поняли в описании, либо там (в описании) ошибка. Вот-вот... не понятно... Кстати, зачем такой префикс жуткий "arm-none-eabi-"? И что вообще означает "none-eabi"? Похоже на "не EABI", но ведь компилятор мой однозначно EABI! Читал, что такой префикс придумали, чтобы отличать от других компиляторов. Но неужели нельзя было придумать что-нибудь покороче и попроще, без двусмысленности?
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 19 2013, 10:02
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (koluna @ Jun 19 2013, 12:44)  Кстати, в ".ctors" (для EABI ".init_array") помещаются только конструкторы по умолчанию, а остальные конструкторы попадают в ".text*"? Поскольку конструкторы являются кодом - они помещаются в .text В .init_array и .ctors в нужном порядке помещаются указатели на них. Собственно вот код их вызова, по нему все понятно: CODE extern void(* const __ctors_start__[])(); extern void(* const __ctors_end__[])(); ... /* Call constructors */ void(* const *ctor)(); for( ctor = __ctors_start__; ctor < __ctors_end__; ) (*ctor++)(); QUOTE (koluna @ Jun 19 2013, 12:44)  Кстати, зачем такой префикс жуткий "arm-none-eabi-"? И что вообще означает "none-eabi"? Это два префикса. -none и -eabi. Гляньте сюда.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 19 2013, 14:10
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Судя по всему для EABI, по аналогии с конструкторами (".init_array"), для деструкторов используется ".fini_array". Вот на эту тему: http://electronix.ru/forum/index.php?showt...=79902&st=0.
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 19 2013, 18:30
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Что такое common-символы (секция COMMON)? Из доки на линкер толком не понял. Это к вопросу зачем нужно делать *(COMMON). Цитата В некоторых форматах объектных файлов общие символы (common) не привязаны к конкретной секции, поэтому линкер, считает, что они находятся в секции COMMON. Следовательно, чтобы использовать эти символы необходимо применить выражение вида *(COMMON). Но что такое "общие символы (common)" - не раскрывается
Сообщение отредактировал koluna - Jun 20 2013, 08:29
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 20 2013, 16:26
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
И все-таки хотелось бы немного поговорить и о скрипте из моего первого поста (скрипт и стартап в архиве). Без этого тема не будет для меня закрыта. Уж извините меня  Код /* Library configurations */ GROUP(libgcc.a libc.a libm.a libnosys.a) Это, как я понял, для того, чтобы в командной строке библиотеки не подключать. Что за библиотека "libnosys.a", которой нет? Насколько она нужна? CODE .text : { KEEP(*(.isr_vector)) *(.text*)
KEEP(*(.init)) KEEP(*(.fini))
/* .ctors */ *crtbegin.o(.ctors) *crtbegin?.o(.ctors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) *(SORT(.ctors.*)) *(.ctors)
/* .dtors */ *crtbegin.o(.dtors) *crtbegin?.o(.dtors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) *(SORT(.dtors.*)) *(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*)) } > FLASH Выравнивания для таблицы векторов здесь нет. Как я понимаю, выравнивание в стартапе. Но на 2, а не на 512 байт. Хотя скрипт ведь не заточен конкретно под STM... Рудименты "*(.ctors) и *(.dtors)" от не EABI-компиляторов достались, судя по всему? Для чего "crtbegin", "crtend"? В скрипте от scmRTOS этого нет. Так и не понял, нужны ли входные секции ".eh_frame" и ".eh_framehdr" или нет... Что-то для этих исключений сделано много непонятных секций... что вызывает уйму вопросов... а исключения в основном не используются... CODE .data : AT (__etext) { __data_start__ = .; *(vtable) *(.data*)
. = ALIGN(4); /* preinit data */ PROVIDE_HIDDEN (__preinit_array_start = .); KEEP(*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4); /* init data */ PROVIDE_HIDDEN (__init_array_start = .); KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4); /* finit data */ PROVIDE_HIDDEN (__fini_array_start = .); KEEP(*(SORT(.fini_array.*))) KEEP(*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4); /* All data end */ __data_end__ = .;
} > RAM Вот тут секция "vtable" используется, нужна ли она все-таки или нет? Помню, находил сообщение, где Сергей Борщ писал о том, что у него без этой секции все работает (таблица виртуальных функций помещается в ".rodata"). Входные секции ".preinit_array", ".init_array.*", ".fini_array.*", содержащие указатели на конструкторы, деструкторы (и что еще для ".preinit_array"?) размещаются в RAM. Наверное, это добавляет быстродействия, но заметно убавляет RAM, если объектов много... так что, лучше бы их было разместить во FLASH? Выходные секции ".heap" и ".stack_dummy" создаются для того, чтобы на этапе линковки уже быть уверенным в том, что хватит места для стека и кучи (просто предполагаем, что для стека и кучи нам потребуется столько-то байт)? Такое ощущение, что скрипт нужно допиливать
Сообщение отредактировал IgorKossak - Jun 21 2013, 12:07
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
--------------------
Благодарю заранее!
|
|
|
|
|
Jun 21 2013, 20:50
|
Профессионал
    
Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061

|
Посмотрел у себя файлы crt* в папках компилятора: Код find /home/koluna/soft/arm/arm-2013.05/ -name crt* /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/crtn.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/crti.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/thumb2/crtn.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/thumb2/crti.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/thumb2/crtbegin.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/thumb2/crtend.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/armv6-m/crtn.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/armv6-m/crti.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/armv6-m/crtbegin.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/armv6-m/crtend.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/thumb/crtn.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/thumb/crti.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/thumb/crtbegin.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/thumb/crtend.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/crtbegin.o /home/koluna/soft/arm/arm-2013.05/lib/gcc/arm-none-eabi/4.7.3/crtend.o Вот, нагуглилось: http://gcc.gnu.org/onlinedocs/gccint/Initialization.htmlhttp://l4u-00.jinr.ru/usoft/WWW/www_debian.../elf/node4.htmlПравильно ли я понимаю, что файлы эти отвечают только за вызов конструкторов и деструкторов (формирование функций _init(), _fini())? В конечном итоге получается что-то типа этого (обработчик сброса в стандартном стартапе): Код void Reset_Handler( void ) { _init();
ИнициализацияЖелеза();
main();
_fini(); }
Сообщение отредактировал koluna - Jun 21 2013, 22:11
--------------------
Благодарю заранее!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|