Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Yagarto Eclipse+GCC4.2.1/4.2.2 - в хидерах компилятся все функции!
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
injen-d
Всем доброго времени суток.
Помогите пожалуйста, может кто сталкивался с подобными непонятками, буду очень признателен.
Не так давно AVRа стало маловато, решил переходить на ARM7, причем софт решил использовать свободный, чтоб так сказать все по честному. Выбор пал на YAGARTO Eclipse + GCC. До этого писал преимущественно на ассемблере, поэтому столкнулся с массой трудностей. Но постепенно все прояснялось, вот только со следующей проблемой борюсь уже 2 дня и ни сколько не продвинулся в ее решении. wacko.gif
Даже появились грешные мысли воспользоваться ломаным иаром или кейлом 05.gif
Проблема в следующем:
решил я воспользоваться файлом "libAT91SAM7S256.h" (взял его где-то из примеров) и сразу после его подключения и последующей компиляции (ни одну из его функций я еще не использовал) размер генерируемого кода увеличился с 1К до 17К. Как выяснилось компилятся все функции независимо от того, вызывались они или нет. После "танцев с бубном, протирки монитора и постукивания по системнику" совершенно чудесным образом хидер начал компилиться как надо: только те функции которые были вызваны из main (или другой функции). 08.gif
На радостях я решил сделать еще один хидер назвал его "icpsr.h" и вставил содержимое из файла "isrsupport.c" из примера demo_at91sam7_blink_flash. И тут опять старая проблема! Причем "libAT91SAM7S256.h" работает правильно, а "icpsr.h" компилится весь. Приведенные выше маневры не помогли. Подскажите, плиз проблема в компиляторе или в моей голове?
Проэкт прилагается.
Нажмите для просмотра прикрепленного файла

ЗЫ: при установке компилятору уровня оптимизации отличного от -О0 размер кода заметно сокращается, но компилятор начинает полностью игнорировать конструкции типа:
for (k = 600000; k != 0; k-- ); как будто их не существует!
Сергей Борщ
Цитата(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-- ); как будто их не существует!
Правильно. Этот код ничего не делает, поэтому и выкидывается. Вы же хотели оптимизацию - вот компилятор и сократил и код, и время выполнения. Вам ведь не нравятся другие медленно работающие программы? wink.gif Чтобы этого не происходило, объявите k как volatile или вставьте в тело цикла что-нибудь типа asm(" nop");
injen-d
Спасибо за разъяснение, но это проблему не решило.
Я поправил 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)
                         ...

Проэкт начал компилиться без ошибок. biggrin.gif
Но не все так хорошо:
1) "правильно" компилятся только __inline функции, остальные же по-прежнему компилятся всегда и при удалении их вызова сами они никуда из итогового кода не исчезают.
2) линкер требует прописывания секций так же для функций находящихся в хидере icpsr.h (кроме __inline функций), даже если они не вызывались.
3) а если у меня в проэкте около сотни различных функций наберется? Это ж сколько писанины в разных файлах. wacko.gif А еще глобальные переменные...
Все вышеизложенное наталкивает на мысль, что решение должно быть гораздо проще.
К тому же, в первоначальном варианте, до вышеописанной правки, для эксперемента я сделал __inline все функции в файле icpsr.h, таким образом получилось два почти одинаковых файла icpsr.h и libAT91SAM7S256.h. Различие было лишь в количестве содержащихся функций. Затем я подключал эти хидеры в соседних строках одного си-файла и вызывал по одной функции из каждого файла тоже в соседних строках, при этом из файла libAT91SAM7S256.h компилировалась только вызываемая функция, а из icpsr.h все по отдельности + еще раз вызываемая на этот раз в нужном месте. Глаза поломал, но разницу между файлами (кроме количества содержащихся функций) не увидел. unsure.gif
В чем может быть причина?
Да и файл libAT91SAM7S256.h поначалу тоже компилился весь, но в какой-то момент во время танцев с бубном заработал как надо, и при последующей правке всяких мелочей содержимого и проб вариантов для поиска причины, работать не перестал.
Сергей Борщ
Цитата(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 все по отдельности + еще раз вызываемая на этот раз в нужном месте.
Если до понедельника никто не ответит - покомпилирую приложенный вами выше проект, помедитирую. Пока не готов дать ответ.
zltigo
Цитата(injen-d @ Jan 12 2008, 21:01) *
1) "правильно" компилятся только __inline функции, остальные же по-прежнему компилятся всегда и при удалении их вызова сами они никуда из итогового кода не исчезают.

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

Создать библиотеку? Это интересно rolleyes.gif
Вы, случайно ссылочкой не располагаете, где почитать про создание библиотек для ARM-GCC ?
Буду очень признателен.
zltigo
Цитата(injen-d @ Jan 12 2008, 21:56) *
Вы, случайно ссылочкой не располагаете, где почитать про создание библиотек для ARM-GCC ?

Дык, библиотекарь неотъемлимая часть набора инструментов. В GNU он, правда странновато называется ar (архивный библиотекарь).
injen-d
Цитата(zltigo @ Jan 12 2008, 23:46) *
Дык, библиотекарь неотъемлимая часть набора инструментов. В GNU он, правда странновато называется ar (архивный библиотекарь).

Спасибо zltigo, нагуглил простое описание для GCC. Щас как раз пытаюсь сделать статическую библиотеку из icpsr.h, напишу что получится. wink.gif
Сергей Борщ
Цитата(injen-d @ Jan 12 2008, 22:50) *
Щас как раз пытаюсь сделать статическую библиотеку из icpsr.h, напишу что получится. wink.gif
Все же мне кажется, вы несколько не в ту сторону двигаетесь. Вы ведь не будете каждый файл компилировать в библиотеку.
1) нужно включить оптимизацию. В противном случае функции не будут инлайнится и если вы включите один заголовочник в несколько .c-файлов - получите несколько копий одной и той же функции в объектниках, с руганью на стадии линковки - линкер не знает, какую из копий использовать (он ведь не знает, что это копии)
2) все нестатические и невстраиваемые (не inline) функции из .c-файлов попадают в объектный файл при компиляции - ведь только на этапе линковки можно определить, какая функция потребуется, а какая нет.
3) линкер не знает, где начинается одна функция, а где заканчивается предыдущая, поэтому он может выкинуть только всю секцию целиком. Для этого компилятор помещает каждую функцию в отдельную секцию (-ffunction-sections). Тогда, если нет обращений к функции нет и обращений к этой секции и линкер может такую секцию выкинуть. Выкидывая секцию, линкер выкидывает функцию целиком, причем только одну. Поэтому, даже если будете пользоваться библиотеками, вам придется каждую функцию компилировать в библиотеку из отдельного исходного файла - иначе получите то же самое, что и сейчас.
4)-ffunction-sections прекрасно работает со скриптами, идущими в комплекте WinAVR. Пробовал и сборку Yagarto, тоже работает.

Указание в скрипте линкера входных секций как *(.text.*) не помогло?
injen-d
Цитата
Указание в скрипте линкера входных секций как *(.text.*) не помогло?

Еще как помогло! smile.gif
Правда файл 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();
Картина та же - исчезает только команда вызова.
Может еще каких-нибудь флажков в мэйкфайле не хватает? laughing.gif
Цитата
Поэтому, даже если будете пользоваться библиотеками, вам придется каждую функцию компилировать в библиотеку из отдельного исходного файла - иначе получите то же самое, что и сейчас.

Вы, Сергей, абсолютно правы - уже убедился, так и есть: при вызове одной подключаются все. Слишком накладно получается каждую функцию из отдельного файла. unsure.gif
zltigo
Цитата(injen-d @ Jan 13 2008, 12:33) *
Слишком накладно получается каждую функцию из отдельного файла. unsure.gif

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

Значит все таки можно для создания библиотеки несколько независимых функций в один файл?
Или вы имели ввиду /основная функция + вызываемые из нее функции/ в одном файле?
Сергей Борщ
Цитата(injen-d @ Jan 13 2008, 12:33) *
Картина та же - исчезает только команда вызова.
Может еще каких-нибудь флажков в мэйкфайле не хватает? laughing.gif
До меня только сегодня дошло - вы опцию, которая должны передаваться линкеру, -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. Круг замкнулся smile.gif
zltigo
Цитата(injen-d @ Jan 13 2008, 13:02) *
Значит все таки можно для создания библиотеки несколько независимых функций в один файл?

Без труда - нет.
Цитата
Или вы имели ввиду /основная функция + вызываемые из нее функции/ в одном файле?

Ну что-то приблизительно, как вариант.
Я имел ввиду, что совсем-уж независимые функции бывают редко и можно объединять их в группы, даже если они друг из друга не вызываются. Ну а то, что много файлов, то в общем-то сильных неудобств при нормальном редакторе с проектом, тэгами.... это вызывать не должно.
injen-d
Цитата
До меня только сегодня дошло - вы опцию, которая должны передаваться линкеру, -Wl,--gc-sections (это одна опция), поместили в CFLAGS и передаете компилятору. А ее надо поместить в LDFLAGS, ибо при линковке вы в качестве флагов используете именно ее (точнее, у вас она названа LFLAGS, но в документации на GNU make ее рекомендуется называть LDFLAGS)

Вобще-то, насколько я понял из документации (в школе учил французский biggrin.gif ), -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)

Выходные файлы пусты, а объектные созданы правильно.
Сергей Борщ
Цитата(injen-d @ Jan 13 2008, 13:47) *
Выходные файлы пусты, а объектные созданы правильно.
Люкс! Теперь осталось в вашем скрипте сделать KEEP() для сегмента, в котором располагаются вектора. Т.е. надо вектора (в crt.s) поместить в отдельную секцию, обозвав ее, скажем, vectors:
Код
/* GNU assembler controls  */
.vectors                                    /* all assembler code that follows will go into .vectors section     */
.arm                                    /* compile for 32-bit ARM instruction set                         */
.align                                    /* align section on 32-bit boundary                                 */

/* ============================================================ */
/*                         VECTOR TABLE                              */
/*                                                                */
/*    Must be located in FLASH at address 0x00000000                */
/*                                                                */
/*    Easy to do if this file crt.s is first in the list             */
/*    for the linker step in the makefile, e.g.                    */
/*                                                                */
/*        $(LD) $(LFLAGS) -o main.out  crt.o main.o                */
/*                                                                */
/* ============================================================ */

_vec_reset:        b           _init_reset                /* RESET vector - must be at 0x00000000    */
_vec_undef:        b           AT91F_Undef_Handler        /* Undefined Instruction vector            */
_vec_swi:        b           _vec_swi                /* Software Interrupt vector            */
_vec_pabt:        b           AT91F_Pabt_Handler        /* Prefetch abort vector                */
_vec_dabt:        b           AT91F_Dabt_Handler        /* Data abort vector                    */
_vec_rsv:        nop                                 /* Reserved vector                        */
_vec_irq:        b           AT91F_Irq_Handler        /* Interrupt Request (IRQ) vector        */
_vec_fiq:        b            AT91F_Default_FIQ_handler    /*Fast interrupt request (FIQ) vector    */

.text     /* place remaining code to .text section */
и в скрипте линкера сделать
Код
SECTIONS
{
    . = 0;                                /* set location counter to address zero  */
    
    .text :                                /* collect all sections that should go into FLASH after startup  */
    {
        KEEP(*(.vectors))
        *(.text)                        /* all .text sections (code)  */



Цитата(injen-d @ Jan 13 2008, 13:47) *
Вобще-то, насколько я понял из документации (в школе учил французский biggrin.gif ), -Wl, - означает "передать следующий флаг линкеру".
Да, вы поняли правильно. Так линкер должен эту -Wl получить, т.е. она должна быть передана gcc при линковке (в цели main.out), а у вас ее получал компилятор в целях *.o
injen-d
Добавил:
Код
. = 0x0000000;
         .text : { KEEP(*crt.o (.text)) }>CODE =0
         .text :
         ...
(скрипт уже не тот, что в представленном проэкте)
О, чудо!!! ВСЕ ЗАРАБОТАЛО!!! 08.gif
Даже из созданной библиотеки libicpsr.a линкуется только используемая функция, хотя я ее (библиотеку) сделал из одного файла!
Истина восторжествовала!
Огромное спасибо zltigo, но особенное вам, Сергей!
ЗЫ: был бы в Риге - поставил бы пиво и, возможно даже, расцеловал бы от счастья! biggrin.gif
Сергей Борщ
Цитата(injen-d @ Jan 13 2008, 14:44) *
О, чудо!!! ВСЕ ЗАРАБОТАЛО!!! 08.gif
ЗдОрово. Когда будете переходить на С++, не забудьте сделать KEEP() для секций конструкторов и деструкторов статических объектов *(ctors.*) и *(dtors.*). Вы можете уже сейчас добавить эти строчки в скрипт линкера - пока конструкторов и деструкторов нет, они ни на что влиять не будут. Зато потом можно будет избежать лишней головной боли.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.