|
|
  |
C компилятор вообще и GCC в частности, вопросы начального уровня |
|
|
|
Feb 18 2010, 08:40
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Здравствуйте. Изучаю 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, или какой-то код идет в прошивку? Почему эклипс периодически при отладке заявляет, что исходник не обнаружен, хотя если нужный файл открыть в ручную, то отладчик по нему отлично шагает?
|
|
|
|
|
Feb 18 2010, 12:10
|

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

|
Цитата(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) про секции только упоминается, причем никакой конкретики. Может быть, плохо искал? Я тоже не нашел  Цитата(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 перемещался в другое место перед отладкой. Там, кажется, пишутся относительные пути.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 18 2010, 13:53
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Спасибо за ответ. Цитата(Сергей Борщ @ 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 файлы открывает нормально.
|
|
|
|
|
Feb 18 2010, 14:57
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(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;
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Feb 18 2010, 16:31
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Цитата(MrYuran @ Feb 18 2010, 17:57)  Секции, их размер и местоположение задаются обычно в скрипте линкера. Я так понимаю, что в скрипте линкера описывается только как уже созданые секции размещать, т.е. реально они создаются на этапе компиляции и информация о них содержится в файлах .o? Или их порождает уже линкер, а объектных файлах содержится только информация о том, код это или данные? Меня интересует такой момент: Есть некий ряд жестко заданных секций (например .text, .data, .bss) и хочешь-не хочешь, ты обязан описать их размещение в скрипте линкера? Если это так, то хотелось бы знать, где этот ряд можно найти и про него почитать. Или возможно никаких жестких секций нет и они все они объявляются на каком либо этапе (например, передаются линкеру в виде ключей или еще как)? Т.е. кто создает секции .text, .data, .bss?
|
|
|
|
|
Feb 18 2010, 19:16
|

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

|
Цитата(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.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 18 2010, 19:17
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Цитата(Сергей Борщ @ Feb 18 2010, 22:05)  Насчет знания стандарта не соглашусь - нужно. Ну я имел ввиду, что знание только одного стандарта вредно. А так, конечно, стандарт - это святое. В общем, большое спасибо за информацию, постепенно начинаю вникать.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|