|
Yagarto Eclipse+GCC4.2.1/4.2.2 - в хидерах компилятся все функции!, Это такая "особенность" или я ... ? |
|
|
|
Jan 11 2008, 19:40
|

Частый гость
 
Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250

|
Всем доброго времени суток. Помогите пожалуйста, может кто сталкивался с подобными непонятками, буду очень признателен. Не так давно AVRа стало маловато, решил переходить на ARM7, причем софт решил использовать свободный, чтоб так сказать все по честному. Выбор пал на YAGARTO Eclipse + GCC. До этого писал преимущественно на ассемблере, поэтому столкнулся с массой трудностей. Но постепенно все прояснялось, вот только со следующей проблемой борюсь уже 2 дня и ни сколько не продвинулся в ее решении. Даже появились грешные мысли воспользоваться ломаным иаром или кейлом Проблема в следующем: решил я воспользоваться файлом "libAT91SAM7S256.h" (взял его где-то из примеров) и сразу после его подключения и последующей компиляции (ни одну из его функций я еще не использовал) размер генерируемого кода увеличился с 1К до 17К. Как выяснилось компилятся все функции независимо от того, вызывались они или нет. После "танцев с бубном, протирки монитора и постукивания по системнику" совершенно чудесным образом хидер начал компилиться как надо: только те функции которые были вызваны из main (или другой функции).  На радостях я решил сделать еще один хидер назвал его "icpsr.h" и вставил содержимое из файла "isrsupport.c" из примера demo_at91sam7_blink_flash. И тут опять старая проблема! Причем "libAT91SAM7S256.h" работает правильно, а "icpsr.h" компилится весь. Приведенные выше маневры не помогли. Подскажите, плиз проблема в компиляторе или в моей голове? Проэкт прилагается.
NEW_workspace.rar ( 802.72 килобайт )
Кол-во скачиваний: 154ЗЫ: при установке компилятору уровня оптимизации отличного от -О0 размер кода заметно сокращается, но компилятор начинает полностью игнорировать конструкции типа: for (k = 600000; k != 0; k-- ); как будто их не существует!
--------------------
- Бендер, ты же робот, зачем тебе пить пиво? - Незачем! Я могу бросить в любой момент!
|
|
|
|
|
Jan 11 2008, 21:17
|

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

|
Цитата(injen-d @ Jan 11 2008, 21:40)  решил я воспользоваться файлом "libAT91SAM7S256.h" (взял его где-то из примеров) и сразу после его подключения и последующей компиляции (ни одну из его функций я еще не использовал) размер генерируемого кода увеличился с 1К до 17К. Дело в том, что на уровне оптимизации -O0 выключено встраивание функций, и квалификатор __inline не работает. Поэтому включите оптимизацию хотя бы -O1, а лучше всего -Os. Чтобы любые неиспользуемые функции не подлинковывалисть в выходной файл, добавьте в makefile Код CFLAGS += -ffunction-sections -fdata-sections # to remove dead code, if any, at link time LDFLAGS += -Wl,--gc-sections #remove dead code ("garbage collection") Цитата(injen-d @ Jan 11 2008, 21:40)  ЗЫ: при установке компилятору уровня оптимизации отличного от -О0 размер кода заметно сокращается, но компилятор начинает полностью игнорировать конструкции типа: for (k = 600000; k != 0; k-- ); как будто их не существует! Правильно. Этот код ничего не делает, поэтому и выкидывается. Вы же хотели оптимизацию - вот компилятор и сократил и код, и время выполнения. Вам ведь не нравятся другие медленно работающие программы?  Чтобы этого не происходило, объявите k как volatile или вставьте в тело цикла что-нибудь типа asm(" nop");
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 12 2008, 19:01
|

Частый гость
 
Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250

|
Спасибо за разъяснение, но это проблему не решило. Я поправил Makefile, правда не совсем так, как вы указали: Код CFLAGS += -ffunction-sections -fdata-sections # to remove dead code, if any, at link time LDFLAGS += -Wl,--gc-sections #remove dead code ("garbage collection") я исправил на: Код CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections в соответствии с "GNAT User’s Guide For gcc version 4.2.2" Цитата 7.3.2 Compilation options The operation of eliminating the unused code and data from the final executable is directly performed by the linker. In order to do this, it has to work with objects compiled with the following options: ‘-ffunction-sections’ ‘-fdata-sections’. These options are usable with C and Ada files. They will place respectively each function or data in a separate section in the resulting object file. Once the objects and static libraries are created with these options, the linker can perform the dead code elimination. You can do this by setting the ‘-Wl,--gc-sections’ option to gcc command or in the ‘-largs’ section of gnatmake. This will create the final executable, without including the code and data determined as never accessed. Note that objects compiled without the ‘-ffunction-sections’ and ‘-fdata-sections’ options can still be linked with the executable. However, no dead code elimination will be performed on those objects (they will be linked as is). The GNAT static library is now compiled with -ffunction-sections and -fdata-sections. This allows you to eliminate the unused code of the GNAT library from your executable. После этого линкер начал требовать прописывания секции для каждой функции и глобальной переменной. После срочного изучения основ написания скриптов для линкера родились следующие строки: Код .text : /* collect all sections that should go into FLASH after startup */ { /* *(.text) /* all .text sections (code) */ *(.text.main) *(.text.USART0_setup) *(.text.uart0_putc) *(.text.Usart_c_irq_handler) *(.text.LowLevelInit) *(.text.blinker) ... Проэкт начал компилиться без ошибок. Но не все так хорошо: 1) "правильно" компилятся только __inline функции, остальные же по-прежнему компилятся всегда и при удалении их вызова сами они никуда из итогового кода не исчезают. 2) линкер требует прописывания секций так же для функций находящихся в хидере icpsr.h (кроме __inline функций), даже если они не вызывались. 3) а если у меня в проэкте около сотни различных функций наберется? Это ж сколько писанины в разных файлах.  А еще глобальные переменные... Все вышеизложенное наталкивает на мысль, что решение должно быть гораздо проще. К тому же, в первоначальном варианте, до вышеописанной правки, для эксперемента я сделал __inline все функции в файле icpsr.h, таким образом получилось два почти одинаковых файла icpsr.h и libAT91SAM7S256.h. Различие было лишь в количестве содержащихся функций. Затем я подключал эти хидеры в соседних строках одного си-файла и вызывал по одной функции из каждого файла тоже в соседних строках, при этом из файла libAT91SAM7S256.h компилировалась только вызываемая функция, а из icpsr.h все по отдельности + еще раз вызываемая на этот раз в нужном месте. Глаза поломал, но разницу между файлами (кроме количества содержащихся функций) не увидел. В чем может быть причина? Да и файл libAT91SAM7S256.h поначалу тоже компилился весь, но в какой-то момент во время танцев с бубном заработал как надо, и при последующей правке всяких мелочей содержимого и проб вариантов для поиска причины, работать не перестал.
|
|
|
|
|
Jan 12 2008, 19:35
|

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

|
Цитата(injen-d @ Jan 12 2008, 21:01)  Я поправил Makefile, правда не совсем так, как вы указали: Это не принципиально. Цитата(injen-d @ Jan 12 2008, 21:01)  После этого линкер начал требовать прописывания секции для каждой функции и глобальной переменной. Я тоже не большой специалист, но у меня получилось так: Код .text : { ....... *(.text) /* code */ *(.text.*) /* code */
............. } > ROM Аналогично и для данных. Приведенные выше ключи компилятора заставляют выделять отдельную секцию для каждой функции и для каждой переменной (ибо линкер по --gc-sections умеет выкидывать только секции целиком). Цитата(injen-d @ Jan 12 2008, 21:01)  Все вышеизложенное наталкивает на мысль, что решение должно быть гораздо проще. Использование шаблонного символа '*' в скрипте. Цитата(injen-d @ Jan 12 2008, 21:01)  Затем я подключал эти хидеры в соседних строках одного си-файла и вызывал по одной функции из каждого файла тоже в соседних строках, при этом из файла libAT91SAM7S256.h компилировалась только вызываемая функция, а из icpsr.h все по отдельности + еще раз вызываемая на этот раз в нужном месте. Если до понедельника никто не ответит - покомпилирую приложенный вами выше проект, помедитирую. Пока не готов дать ответ.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 12 2008, 19:44
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(injen-d @ Jan 12 2008, 21:01)  1) "правильно" компилятся только __inline функции, остальные же по-прежнему компилятся всегда и при удалении их вызова сами они никуда из итогового кода не исчезают. А с какого бодуна они должны исчезать  ? Объектные файлы линкуются целиком. Некоторые форматы объектников и соответственно поддерживающие их линкеры позволяют выборочную линковку, но это вымирающая (ARM IAR до перехода на elf умел ) редкость. Читайте про библиотеки, делайте их и пользуйтесь.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jan 12 2008, 19:56
|

Частый гость
 
Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250

|
Цитата(zltigo @ Jan 12 2008, 22:44)  А с какого бодуна они должны исчезать  ? Объектные файлы линкуются целиком. Некоторые форматы объектников и соответственно поддерживающие их линкеры позволяют выборочную линковку, но это вымирающая (ARM IAR до перехода на elf умел ) редкость. Читайте про библиотеки, делайте их и пользуйтесь. Создать библиотеку? Это интересно Вы, случайно ссылочкой не располагаете, где почитать про создание библиотек для ARM-GCC ? Буду очень признателен.
|
|
|
|
|
Jan 12 2008, 22:39
|

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

|
Цитата(injen-d @ Jan 12 2008, 22:50)  Щас как раз пытаюсь сделать статическую библиотеку из icpsr.h, напишу что получится.  Все же мне кажется, вы несколько не в ту сторону двигаетесь. Вы ведь не будете каждый файл компилировать в библиотеку. 1) нужно включить оптимизацию. В противном случае функции не будут инлайнится и если вы включите один заголовочник в несколько .c-файлов - получите несколько копий одной и той же функции в объектниках, с руганью на стадии линковки - линкер не знает, какую из копий использовать (он ведь не знает, что это копии) 2) все нестатические и невстраиваемые (не inline) функции из .c-файлов попадают в объектный файл при компиляции - ведь только на этапе линковки можно определить, какая функция потребуется, а какая нет. 3) линкер не знает, где начинается одна функция, а где заканчивается предыдущая, поэтому он может выкинуть только всю секцию целиком. Для этого компилятор помещает каждую функцию в отдельную секцию (-ffunction-sections). Тогда, если нет обращений к функции нет и обращений к этой секции и линкер может такую секцию выкинуть. Выкидывая секцию, линкер выкидывает функцию целиком, причем только одну. Поэтому, даже если будете пользоваться библиотеками, вам придется каждую функцию компилировать в библиотеку из отдельного исходного файла - иначе получите то же самое, что и сейчас. 4)-ffunction-sections прекрасно работает со скриптами, идущими в комплекте WinAVR. Пробовал и сборку Yagarto, тоже работает. Указание в скрипте линкера входных секций как *(.text.*) не помогло?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 13 2008, 10:33
|

Частый гость
 
Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250

|
Цитата Указание в скрипте линкера входных секций как *(.text.*) не помогло? Еще как помогло! Правда файл crt.s перестал линковаться (вместо ассемблерных команд непонятные значения, занимающие тот же объем в итоговом файле). Но после вставки скрипта из примеров для WinARM и небольших в нем исправлений, все заработало. В main.dmp вижу: Код 0010047c <EnableFIQ>: 10047c: e10f0000 mrs r0, CPSR 100480: e3c03040 bic r3, r0, #64; 0x40 100484: e129f003 msr CPSR_fc, r3 100488: e12fff1e bx lr Disassembly of section .text.EnableIRQ:
0010048c <EnableIRQ>: 10048c: e10f0000 mrs r0, CPSR 100490: e3c03080 bic r3, r0, #128; 0x80 100494: e129f003 msr CPSR_fc, r3 100498: e12fff1e bx lr Disassembly of section .text.RestoreIRQ:
0010049c <RestoreIRQ>: 10049c: e10f2000 mrs r2, CPSR 1004a0: e2000080 and r0, r0, #128; 0x80 1004a4: e3c23080 bic r3, r2, #128; 0x80 1004a8: e1833000 orr r3, r3, r0 1004ac: e129f003 msr CPSR_fc, r3 1004b0: e1a00002 mov r0, r2 1004b4: e12fff1e bx lr таким образом каждая функция расположена в своей секции, уровни оптимизации пробовал разные, в данном случае -Оs. Все функции на месте, хотя я вызываю только EnableIRQ() один раз в main.c. Пробовал комментировать вызовы функций, находящихся в USART_setup.c в частности USART0_setup(); Картина та же - исчезает только команда вызова. Может еще каких-нибудь флажков в мэйкфайле не хватает? Цитата Поэтому, даже если будете пользоваться библиотеками, вам придется каждую функцию компилировать в библиотеку из отдельного исходного файла - иначе получите то же самое, что и сейчас. Вы, Сергей, абсолютно правы - уже убедился, так и есть: при вызове одной подключаются все. Слишком накладно получается каждую функцию из отдельного файла.
--------------------
- Бендер, ты же робот, зачем тебе пить пиво? - Незачем! Я могу бросить в любой момент!
|
|
|
|
|
Jan 13 2008, 11:02
|

Частый гость
 
Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250

|
Цитата группы функций разбить по файлам Значит все таки можно для создания библиотеки несколько независимых функций в один файл? Или вы имели ввиду /основная функция + вызываемые из нее функции/ в одном файле?
--------------------
- Бендер, ты же робот, зачем тебе пить пиво? - Незачем! Я могу бросить в любой момент!
|
|
|
|
|
Jan 13 2008, 11:25
|

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

|
Цитата(injen-d @ Jan 13 2008, 12:33)  Картина та же - исчезает только команда вызова. Может еще каких-нибудь флажков в мэйкфайле не хватает?  До меня только сегодня дошло - вы опцию, которая должны передаваться линкеру, -Wl,--gc-sections (это одна опция), поместили в CFLAGS и передаете компилятору. А ее надо поместить в LDFLAGS, ибо при линковке вы в качестве флагов используете именно ее (точнее, у вас она названа LFLAGS, но в документации на GNU make ее рекомендуется называть LDFLAGS): Код main.out: $(OBJECTS) test.cmd @ echo "..linking" $(LD) $(LFLAGS) -o main.out $(OBJECTS) libc.a libm.a libgcc.a чего-то я стормозил вчера в 21.35. У вас линкер не получает --gc-sections и поэтому не выкидывает неиспользуемые секции. Цитата(injen-d @ Jan 13 2008, 13:02)  Значит все таки можно для создания библиотеки несколько независимых функций в один файл? Можно. Указав при компиляции --ffunction-sections. Круг замкнулся
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 13 2008, 11:28
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(injen-d @ Jan 13 2008, 13:02)  Значит все таки можно для создания библиотеки несколько независимых функций в один файл? Без труда - нет. Цитата Или вы имели ввиду /основная функция + вызываемые из нее функции/ в одном файле? Ну что-то приблизительно, как вариант. Я имел ввиду, что совсем-уж независимые функции бывают редко и можно объединять их в группы, даже если они друг из друга не вызываются. Ну а то, что много файлов, то в общем-то сильных неудобств при нормальном редакторе с проектом, тэгами.... это вызывать не должно.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jan 13 2008, 11:47
|

Частый гость
 
Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250

|
Цитата До меня только сегодня дошло - вы опцию, которая должны передаваться линкеру, -Wl,--gc-sections (это одна опция), поместили в CFLAGS и передаете компилятору. А ее надо поместить в LDFLAGS, ибо при линковке вы в качестве флагов используете именно ее (точнее, у вас она названа LFLAGS, но в документации на GNU make ее рекомендуется называть LDFLAGS) Вобще-то, насколько я понял из документации (в школе учил французский  ), -Wl, - означает "передать следующий флаг линкеру". Однако попробовал переименовать на LDFLAGS и т. д. В итоге: LDFLAGS = --gc-sections -Map main.map -T test.cmd после компиляции ошибок нет, но: Код TOTAL SIZE: arm-elf-size -t main.out text data bss dec hex filename 0 0 0 0 0 main.out 0 0 0 0 0 (TOTALS) Выходные файлы пусты, а объектные созданы правильно.
--------------------
- Бендер, ты же робот, зачем тебе пить пиво? - Незачем! Я могу бросить в любой момент!
|
|
|
|
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0
|
|
|