Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: C компилятор вообще и GCC в частности
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Dopler
Здравствуйте.
Изучаю GCC (на платформе AVR32). Раньше программировать на C для контроллеров не приходилось, поэтому возникает много общих вопросов о том, как это все устроено. Более-менее изучил документацию на make и ld. Малость
освоился в Eclipse. А вот с компилятором много не понятного. Документация читается тяжело. В "Using the GNU Compiler Collection" описаны по большей части ключи да разные режимы работы. "GNU Compiler Collection Internals"
для меня пока сложен, я почти не понимаю, о чем речь.
1. Как устроена C программа, т.е. какие минимальные действия нужно выполнить для инициализации окружения: инициализировать стек и кучу, обнулить глобальные переменные, что еще?
2. Если создать примитивный проект с пустой функцией main, то gcc подключает стандартный стартап, в итоге в выходном .elf файле появляется ряд секций.
Не понятно, какие из этих секций порождает компилятор, а какие описаны в стартовом коде. И вообще где почитать, какие секции для работы C программы обязательны (как они называются, что в них размещается).
В документации на GCC (gccint.pdf) про секции только упоминается, причем никакой конкретики. Может быть, плохо искал?
3. Во всех Atmelo'вских примерах и при компиляции и при компоновке вызывается avr32-gcc.exe, причем параметры конкретно линкеру передаются через Wl. Почему не принято вызывать, например, линкер на прямую, зачем в этом
случае прослойка в виде gcc.exe?
4. Используется ли динамическая память в контроллерах (malloc и free), и если используется, то как реализуется менеджер памяти?
5. Что такое отладочная информация (которая включается ключом -g)? Это просто ссылки на файлы с исходным кодом в итоговом elf, или какой-то код идет в прошивку? Почему эклипс периодически при отладке заявляет, что исходник не обнаружен, хотя если нужный файл открыть в ручную, то отладчик по нему отлично шагает?
Сергей Борщ
Цитата(Dopler @ Feb 18 2010, 10:40) *
"GNU Compiler Collection Internals" для меня пока сложен, я почти не понимаю, о чем речь.
Он вам пока не нужен. Пока вы не захотите что-то подправить в самом компиляторе или портировать его для нового процессора.
Цитата(Dopler @ Feb 18 2010, 10:40) *
1. Как устроена C программа, т.е. какие минимальные действия нужно выполнить для инициализации окружения: инициализировать стек и кучу, обнулить глобальные переменные, что еще?
Скопировать начальные значения в инициализированные глобальные и статические переменные, вызвать конструкторы(для С++), вызвать собственно main(). После возврата из main() вызвать деструкторы(для С++), закрыть файлы(если они есть), освободить память кучи, отдать управление операционной системе(если она есть) или бесконечный цикл. Все это называется C-startup код. Не знаю, как для AVR32, для AVR он уже есть готовый библиотечный, для ARM без ОС он подключается к проекту отдельным ассемблерным файлом. Обычно носит название crt???.S или gcrt???.S
Цитата(Dopler @ Feb 18 2010, 10:40) *
2. Если создать примитивный проект с пустой функцией main, то gcc подключает стандартный стартап, в итоге в выходном .elf файле появляется ряд секций.
Не понятно, какие из этих секций порождает компилятор, а какие описаны в стартовом коде. И вообще где почитать, какие секции для работы C программы обязательны (как они называются, что в них размещается).
О! Значит библиотечный стартап есть и до возникновения острой необходимости можете о нем не думать. Можете смело рассчитывать, что на момент запуска main() все проинициализировано в соответствии со стандартом. Основных секций три: .text = это программный код, .bss - неинициализированные явно глобальные и статические переменые (те, которые обнуляются) и в последних версиях gcc сюда попадают явно проинициализированные нулем переменные. .data - это проинициализированные глобальные и статические переменные. В секции .rodata хранятся константы. .debug_*, .stabs.* - отладочная информация. Вроде ничего важного не забыл. Возможны еще какие-то секции специфичные для конкретной архитектуры.
Цитата(Dopler @ Feb 18 2010, 10:40) *
В документации на GCC (gccint.pdf) про секции только упоминается, причем никакой конкретики. Может быть, плохо искал?
Я тоже не нашел sad.gif
Цитата(Dopler @ Feb 18 2010, 10:40) *
3. Во всех Atmelo'вских примерах и при компиляции и при компоновке вызывается avr32-gcc.exe, причем параметры конкретно линкеру передаются через Wl. Почему не принято вызывать, например, линкер на прямую, зачем в этом случае прослойка в виде gcc.exe?
Она знает кучу параметров по умолчанию, которые в противном случае пришлось бы указывать вручную. Для AVR, например, в зависимости от выбранного типа процессора она компилятору определяет кучу служебных символов (__HAS_RAMPZ и подобные), а линкеру подставляет нужный скрипт, нужный файл стартапа. В общем - полезно. В makefile, опять же, вам надо указать путь только к этой программе а она уже сама найдет и нужный препроцессор и компилятор и ассемблер и линкер.
Цитата(Dopler @ Feb 18 2010, 10:40) *
4. Используется ли динамическая память в контроллерах (malloc и free), и если используется, то как реализуется менеджер памяти?
Если надо - используется. Конкретную реализацию надо смотреть в потрохах библиотеки (clib, newlib или какая там для AVR32), но с точки зрения программы они все работают так, как описано в стандарте С.
Цитата(Dopler @ Feb 18 2010, 10:40) *
5. Что такое отладочная информация (которая включается ключом -g)? Это просто ссылки на файлы с исходным кодом в итоговом elf, или какой-то код идет в прошивку? Почему эклипс периодически при отладке заявляет, что исходник не обнаружен, хотя если нужный файл открыть в ручную, то отладчик по нему отлично шагает?
Это информация и о строках исходного файла соответствующих конкретным ассемблерным командам, и об адресах и типах данных (в том числе и о структурах, классах, и т.д). Эклипс может не находить исходники если elf перемещался в другое место перед отладкой. Там, кажется, пишутся относительные пути.
Dopler
Спасибо за ответ.
Цитата(Сергей Борщ @ Feb 18 2010, 15:10) *
О! Значит библиотечный стартап есть и до возникновения острой необходимости можете о нем не думать.

Да, в библиотеках стартап есть (но без исходников, объектный файл). Atmel также предлагает так называемый Sowtware Framework - набор исходных кодов для работы с периферией, там же есть и crt0.x (асемблер здесь .x).
Не думать о нем мне не позволяет религия, при первой компиляции проект с пустым main откомпилился в прошивку 8 kB размером. Очень интересно, чего он туда напихал. Да и вообще для полноценной работы нужно хорошо знать инструментарий, знания только стандарта C для разработки под контроллеры на мой взгляд явно не достаточно (а может даже и вредно, народ, зачастую, не знает примитивных вещей, а уже Программирует!)

Цитата
Основных секций три: .text = это программный код, .bss - неинициализированные явно глобальные и статические переменые (те, которые обнуляются) и в последних версиях gcc сюда попадают явно проинициализированные нулем переменные. .data - это проинициализированные глобальные и статические переменные. В секции .rodata хранятся константы. .debug_*, .stabs.* - отладочная информация. Вроде ничего важного не забыл. Возможны еще какие-то секции специфичные для конкретной архитектуры.

По поводу секций мне не совсем ясно именно откуда они берутся. Т.е. они где-то объявляются в исходниках (или в библиотеках) или жестко вшиты в компилятор? Например, если подключается стандартный стартап, то появляются секции .init и .fini. Это порождение компилятора, или он где-то были объявлены, типа:
Код
.section  .text, "ax", @progbits


Цитата
Она знает кучу параметров по умолчанию, которые в противном случае пришлось бы указывать вручную. Для AVR, например, в зависимости от выбранного типа процессора она компилятору определяет кучу служебных символов (__HAS_RAMPZ и подобные), а линкеру подставляет нужный скрипт, нужный файл стартапа. В общем - полезно.

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

Цитата
Это информация и о строках исходного файла соответствующих конкретным ассемблерным командам, и об адресах и типах данных (в том числе и о структурах, классах, и т.д).

Т.е. именно в исполняемый код (в прошивку) ничего не добавляется? Т.е. если из эльфа выдирать hex, то он будет одинаковых размеров что с ключом -g, что без него?

Цитата
Эклипс может не находить исходники если elf перемещался в другое место перед отладкой. Там, кажется, пишутся относительные пути.

Не открывает автоматически асемблерные файлы (*.x), C файлы открывает нормально.
MrYuran
Цитата(Dopler @ Feb 18 2010, 16:53) *
Спасибо за ответ.

По поводу секций мне не совсем ясно именно откуда они берутся. Т.е. они где-то объявляются в исходниках (или в библиотеках) или жестко вшиты в компилятор?

Секции, их размер и местоположение задаются обычно в скрипте линкера.
Можно, правда, задать свою в опциях линкера и ссылаться на неё в тексте программы
Например, в makefile указываем
LDFLAGS += -Wl,--section-start -Wl,.seg_a=0x1080
а потом в тексте ссылаемся:
#define __SEG_A__ __attribute__((section(".seg_a"), used))
...
static stFlashData const __SEG_A__ FlashData = FACTORY_SETTINGS;
Dopler
Цитата(MrYuran @ Feb 18 2010, 17:57) *
Секции, их размер и местоположение задаются обычно в скрипте линкера.


Я так понимаю, что в скрипте линкера описывается только как уже созданые секции размещать, т.е. реально они создаются на этапе компиляции и информация о них содержится в файлах .o?
Или их порождает уже линкер, а объектных файлах содержится только информация о том, код это или данные?
Меня интересует такой момент:
Есть некий ряд жестко заданных секций (например .text, .data, .bss) и хочешь-не хочешь, ты обязан описать их размещение в скрипте линкера? Если это так, то хотелось бы знать, где этот ряд можно найти и про него почитать.
Или возможно никаких жестких секций нет и они все они объявляются на каком либо этапе (например, передаются линкеру в виде ключей или еще как)?
Т.е. кто создает секции .text, .data, .bss?
Сергей Борщ
Цитата(Dopler @ Feb 18 2010, 15:53) *
Не думать о нем мне не позволяет религия, при первой компиляции проект с пустым main откомпилился в прошивку 8 kB размером. Очень интересно, чего он туда напихал.
avr32-objdump -xD file.elf > file.lst
Цитата(Dopler @ Feb 18 2010, 15:53) *
Да и вообще для полноценной работы нужно хорошо знать инструментарий, знания только стандарта C для разработки под контроллеры на мой взгляд явно не достаточно (а может даже и вредно, народ, зачастую, не знает примитивных вещей, а уже Программирует!)
Ваш подход заслуживает уважения. Насчет знания стандарта не соглашусь - нужно.
Цитата(Dopler @ Feb 18 2010, 15:53) *
По поводу секций мне не совсем ясно именно откуда они берутся. Т.е. они где-то объявляются в исходниках (или в библиотеках) или жестко вшиты в компилятор? Например, если подключается стандартный стартап, то появляются секции .init и .fini. Это порождение компилятора, или он где-то были объявлены, типа:
Код
.section  .text, "ax", @progbits
Что-то объявлено в исходниках, что-то (отладочную информацию) порождает компилятор.
Цитата(Dopler @ Feb 18 2010, 15:53) *
Т.е. в gcc.exe просто жестко вшиты некоторые таблицы соответствия имени процессора и его стандартных библиотечных файлов? А как-нибудь можно посмотреть, что этот gcc вызывает и с какими ключами?
avr32-gcc -dumpspecs, а содержимое расписано внутри исходников gcc.
Цитата(Dopler @ Feb 18 2010, 15:53) *
Т.е. именно в исполняемый код (в прошивку) ничего не добавляется? Т.е. если из эльфа выдирать hex, то он будет одинаковых размеров что с ключом -g, что без него?
Да, именно так.


Цитата(Dopler @ Feb 18 2010, 18:31) *
Я так понимаю, что в скрипте линкера описывается только как уже созданые секции размещать, т.е. реально они создаются на этапе компиляции и информация о них содержится в файлах .o?
Или их порождает уже линкер, а объектных файлах содержится только информация о том, код это или данные?
Линкер только размещает секции. Сам он никаких секций не создает. При желании может выкинуть лишние (читайте про ключи -ffunction-section, -fdata-section компилятора, --gc-section линкера).
Цитата(Dopler @ Feb 18 2010, 18:31) *
Есть некий ряд жестко заданных секций (например .text, .data, .bss) и хочешь-не хочешь, ты обязан описать их размещение в скрипте линкера? Если это так, то хотелось бы знать, где этот ряд можно найти и про него почитать.
Глубоко копаете... Что-то есть в документации binutils, в описании bfd. Что-то применительно к avr - в описании avr-libc. Что-то в комментариях самих скриптов. Что-то в форумах.
Цитата(Dopler @ Feb 18 2010, 18:31) *
Т.е. кто создает секции .text, .data, .bss?
Эти секции создает компилятор (или ассемблер). Линкер только укладывает секции в конкретные адреса памяти. Описание линкера идет в комплекте документации binutils.
Dopler
Цитата(Сергей Борщ @ Feb 18 2010, 22:05) *
Насчет знания стандарта не соглашусь - нужно.

Ну я имел ввиду, что знание только одного стандарта вредно. А так, конечно, стандарт - это святое.

В общем, большое спасибо за информацию, постепенно начинаю вникать.
Сергей Борщ
Цитата(Dopler @ Feb 18 2010, 15:53) *
Не открывает автоматически асемблерные файлы (*.x), C файлы открывает нормально.
В makefile в целях ассемблирования (или в ASMFLAGS) не указан ключ генерации отладочной информации -Wa,-gdwarf2. Или, как долгое время для обычных avr, ассемблер просто не умеет генерировать такую отладочную информацию.
dch
Я чего то вот здесь почитал и мне сразу полегчало, во всяком случае CASC мне пригодился:
http://vak.ru/doku.php/proj
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.