Перейти к содержанию
    

Yagarto Eclipse+GCC4.2.1/4.2.2 - в хидерах компилятся все функции!

Всем доброго времени суток.

Помогите пожалуйста, может кто сталкивался с подобными непонятками, буду очень признателен.

Не так давно AVRа стало маловато, решил переходить на ARM7, причем софт решил использовать свободный, чтоб так сказать все по честному. Выбор пал на YAGARTO Eclipse + GCC. До этого писал преимущественно на ассемблере, поэтому столкнулся с массой трудностей. Но постепенно все прояснялось, вот только со следующей проблемой борюсь уже 2 дня и ни сколько не продвинулся в ее решении. :wacko:

Даже появились грешные мысли воспользоваться ломаным иаром или кейлом :05:

Проблема в следующем:

решил я воспользоваться файлом "libAT91SAM7S256.h" (взял его где-то из примеров) и сразу после его подключения и последующей компиляции (ни одну из его функций я еще не использовал) размер генерируемого кода увеличился с 1К до 17К. Как выяснилось компилятся все функции независимо от того, вызывались они или нет. После "танцев с бубном, протирки монитора и постукивания по системнику" совершенно чудесным образом хидер начал компилиться как надо: только те функции которые были вызваны из main (или другой функции). :08:

На радостях я решил сделать еще один хидер назвал его "icpsr.h" и вставил содержимое из файла "isrsupport.c" из примера demo_at91sam7_blink_flash. И тут опять старая проблема! Причем "libAT91SAM7S256.h" работает правильно, а "icpsr.h" компилится весь. Приведенные выше маневры не помогли. Подскажите, плиз проблема в компиляторе или в моей голове?

Проэкт прилагается.

NEW_workspace.rar

 

ЗЫ: при установке компилятору уровня оптимизации отличного от -О0 размер кода заметно сокращается, но компилятор начинает полностью игнорировать конструкции типа:

for (k = 600000; k != 0; k-- ); как будто их не существует!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

решил я воспользоваться файлом "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")

ЗЫ: при установке компилятору уровня оптимизации отличного от -О0 размер кода заметно сокращается, но компилятор начинает полностью игнорировать конструкции типа:

for (k = 600000; k != 0; k-- ); как будто их не существует!

Правильно. Этот код ничего не делает, поэтому и выкидывается. Вы же хотели оптимизацию - вот компилятор и сократил и код, и время выполнения. Вам ведь не нравятся другие медленно работающие программы? ;) Чтобы этого не происходило, объявите k как volatile или вставьте в тело цикла что-нибудь типа asm(" nop");

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за разъяснение, но это проблему не решило.

Я поправил 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:

Но не все так хорошо:

1) "правильно" компилятся только __inline функции, остальные же по-прежнему компилятся всегда и при удалении их вызова сами они никуда из итогового кода не исчезают.

2) линкер требует прописывания секций так же для функций находящихся в хидере icpsr.h (кроме __inline функций), даже если они не вызывались.

3) а если у меня в проэкте около сотни различных функций наберется? Это ж сколько писанины в разных файлах. :wacko: А еще глобальные переменные...

Все вышеизложенное наталкивает на мысль, что решение должно быть гораздо проще.

К тому же, в первоначальном варианте, до вышеописанной правки, для эксперемента я сделал __inline все функции в файле icpsr.h, таким образом получилось два почти одинаковых файла icpsr.h и libAT91SAM7S256.h. Различие было лишь в количестве содержащихся функций. Затем я подключал эти хидеры в соседних строках одного си-файла и вызывал по одной функции из каждого файла тоже в соседних строках, при этом из файла libAT91SAM7S256.h компилировалась только вызываемая функция, а из icpsr.h все по отдельности + еще раз вызываемая на этот раз в нужном месте. Глаза поломал, но разницу между файлами (кроме количества содержащихся функций) не увидел. :unsure:

В чем может быть причина?

Да и файл libAT91SAM7S256.h поначалу тоже компилился весь, но в какой-то момент во время танцев с бубном заработал как надо, и при последующей правке всяких мелочей содержимого и проб вариантов для поиска причины, работать не перестал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я поправил Makefile, правда не совсем так, как вы указали:
Это не принципиально.

После этого линкер начал требовать прописывания секции для каждой функции и глобальной переменной.
Я тоже не большой специалист, но у меня получилось так:
  .text :
  {
    .......
    *(.text)            /* code */
    *(.text.*)          /* code */

    .............
  } > ROM

Аналогично и для данных. Приведенные выше ключи компилятора заставляют выделять отдельную секцию для каждой функции и для каждой переменной (ибо линкер по --gc-sections умеет выкидывать только секции целиком).

Все вышеизложенное наталкивает на мысль, что решение должно быть гораздо проще.
Использование шаблонного символа '*' в скрипте.
Затем я подключал эти хидеры в соседних строках одного си-файла и вызывал по одной функции из каждого файла тоже в соседних строках, при этом из файла libAT91SAM7S256.h компилировалась только вызываемая функция, а из icpsr.h все по отдельности + еще раз вызываемая на этот раз в нужном месте.
Если до понедельника никто не ответит - покомпилирую приложенный вами выше проект, помедитирую. Пока не готов дать ответ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) "правильно" компилятся только __inline функции, остальные же по-прежнему компилятся всегда и при удалении их вызова сами они никуда из итогового кода не исчезают.

А с какого бодуна они должны исчезать :)? Объектные файлы линкуются целиком.

Некоторые форматы объектников и соответственно поддерживающие их линкеры позволяют выборочную линковку, но это вымирающая (ARM IAR до перехода на elf умел ) редкость.

Читайте про библиотеки, делайте их и пользуйтесь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А с какого бодуна они должны исчезать :)? Объектные файлы линкуются целиком.

Некоторые форматы объектников и соответственно поддерживающие их линкеры позволяют выборочную линковку, но это вымирающая (ARM IAR до перехода на elf умел ) редкость.

Читайте про библиотеки, делайте их и пользуйтесь.

Создать библиотеку? Это интересно :rolleyes:

Вы, случайно ссылочкой не располагаете, где почитать про создание библиотек для ARM-GCC ?

Буду очень признателен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы, случайно ссылочкой не располагаете, где почитать про создание библиотек для ARM-GCC ?

Дык, библиотекарь неотъемлимая часть набора инструментов. В GNU он, правда странновато называется ar (архивный библиотекарь).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Дык, библиотекарь неотъемлимая часть набора инструментов. В GNU он, правда странновато называется ar (архивный библиотекарь).

Спасибо zltigo, нагуглил простое описание для GCC. Щас как раз пытаюсь сделать статическую библиотеку из icpsr.h, напишу что получится. ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Щас как раз пытаюсь сделать статическую библиотеку из icpsr.h, напишу что получится. ;)
Все же мне кажется, вы несколько не в ту сторону двигаетесь. Вы ведь не будете каждый файл компилировать в библиотеку.

1) нужно включить оптимизацию. В противном случае функции не будут инлайнится и если вы включите один заголовочник в несколько .c-файлов - получите несколько копий одной и той же функции в объектниках, с руганью на стадии линковки - линкер не знает, какую из копий использовать (он ведь не знает, что это копии)

2) все нестатические и невстраиваемые (не inline) функции из .c-файлов попадают в объектный файл при компиляции - ведь только на этапе линковки можно определить, какая функция потребуется, а какая нет.

3) линкер не знает, где начинается одна функция, а где заканчивается предыдущая, поэтому он может выкинуть только всю секцию целиком. Для этого компилятор помещает каждую функцию в отдельную секцию (-ffunction-sections). Тогда, если нет обращений к функции нет и обращений к этой секции и линкер может такую секцию выкинуть. Выкидывая секцию, линкер выкидывает функцию целиком, причем только одну. Поэтому, даже если будете пользоваться библиотеками, вам придется каждую функцию компилировать в библиотеку из отдельного исходного файла - иначе получите то же самое, что и сейчас.

4)-ffunction-sections прекрасно работает со скриптами, идущими в комплекте WinAVR. Пробовал и сборку Yagarto, тоже работает.

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Указание в скрипте линкера входных секций как *(.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();

Картина та же - исчезает только команда вызова.

Может еще каких-нибудь флажков в мэйкфайле не хватает? :laughing:

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

Вы, Сергей, абсолютно правы - уже убедился, так и есть: при вызове одной подключаются все. Слишком накладно получается каждую функцию из отдельного файла. :unsure:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Слишком накладно получается каждую функцию из отдельного файла. :unsure:

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

группы функций разбить по файлам

Значит все таки можно для создания библиотеки несколько независимых функций в один файл?

Или вы имели ввиду /основная функция + вызываемые из нее функции/ в одном файле?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Картина та же - исчезает только команда вызова.

Может еще каких-нибудь флажков в мэйкфайле не хватает? :laughing:

До меня только сегодня дошло - вы опцию, которая должны передаваться линкеру, -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 и поэтому не выкидывает неиспользуемые секции.

 

Значит все таки можно для создания библиотеки несколько независимых функций в один файл?
Можно. Указав при компиляции --ffunction-sections. Круг замкнулся :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Значит все таки можно для создания библиотеки несколько независимых функций в один файл?

Без труда - нет.

Или вы имели ввиду /основная функция + вызываемые из нее функции/ в одном файле?

Ну что-то приблизительно, как вариант.

Я имел ввиду, что совсем-уж независимые функции бывают редко и можно объединять их в группы, даже если они друг из друга не вызываются. Ну а то, что много файлов, то в общем-то сильных неудобств при нормальном редакторе с проектом, тэгами.... это вызывать не должно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Выходные файлы пусты, а объектные созданы правильно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...