Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: linker
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Злодей
Здравствуйте!

WinAVR, родной makefile.

main.c
Код
#include <avr/io.h>

int do_not_link_me( int arg )
{
    return arg * arg;
}

int main( void )
{
}


main.lss ( По сути листинг прошивки )
Код
int do_not_link_me( int arg )
{
  88:    88 9f           mul    r24, r24
  8a:    90 01           movw    r18, r0
  8c:    89 9f           mul    r24, r25
  8e:    30 0d           add    r19, r0
  90:    98 9f           mul    r25, r24
  92:    30 0d           add    r19, r0
  94:    11 24           eor    r1, r1
    return arg * arg;
}


Хочу так, что бы в прошивке не было неиспользуемых функций. Усердно читаю и пробую ld options...

Помогите, пожалуста, терминами ( как эту проблему правильно называть ) ну и с решением. Спасибо!
Злодей
Добавлю, что в приведённом примере функция не линкуется если её объявить static.

Что сделать, бы модули неиспользуемые не линковать? Некоторые доки вгоняют в полную печаль...
mdmitry
Уже обсуждалось на форуме, поищите, пожалуйста. Сообщения, кажется, от Сергея Борща.
Злодей
Спасибо, коллега подсказал параметры компиляции -ffunction-sections -fdata-sections и компоновки -Wl,--gc-sections.

LDFLAGS += -Wl,--gc-sections
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections

Всё Шикарно smile.gif
mdmitry
Именно они, но я их не могу запомнить.

bb-offtopic.gif Не пора ли этот вопрос в FAQ отправлять?
Злодей
Тогда сразу в -Os ... Вероятно, есть ньюансы, из-за которых их туда не добавляют?

(А то забуду) В FAQ надо отправить hex2bin и bin2hex посредством srecord krapula.gif
alx2
Цитата(Злодей @ Jun 17 2009, 18:09) *
Добавлю, что в приведённом примере функция не линкуется если её объявить static.
Хочу добавить, что иначе и быть не может: у статических объектов область видимости - файл, поэтому линкеру они не видны, он о их существовании ничего не знает (исключением, по-моему, яувляются только статические члены классов).
Цитата(Злодей @ Jun 19 2009, 03:11) *
(А то забуду) В FAQ надо отправить hex2bin и bin2hex посредством srecord
А что это и для чего?
IgorKossak
Цитата(alx2 @ Jun 19 2009, 21:16) *
у статических объектов область видимости - файл, поэтому линкеру они не видны, он о их существовании ничего не знает (исключением, по-моему, яувляются только статические члены классов).

Такие обьекты должны быть видны линкеру посредством их использования другими (нестатическими) обьектами\функциями. В примпре, приведённом у топикстартера, функция int do_not_link_me( int arg ) нигде не используется, поэтому если её обьявить статической, она справедливо будет выкинута.
aesok
Для GCC:

Единицей обработки компилятора является одна функция или переменная. Если функция или переменная объявлена как static и не используется в компилируемом файле то компилятор ее выкидывает. Если же функция или переменная используется или является глобальной, то она кладется в объектный файл в общую секцию .text (функция) и в .data или .bss (переменная) (если для них не указан атрибут section). Ключи -ffunction-sections и -fdata-sections компилятора изменяют это поведение компилятора и заставляют его в объектном файле для каждой функции и переменной создавать отдельную секцию.

Единицей обработки линкера является секция, вне зависимости от того сколько функций или переменных в этой секции находиться. По умолчанию ликер собирает все секции из входных файлов и кладет в результирующий объектный файл. Ключ --gc-sections изменет это поведение и заставляет линкер не класть в результирующий файл секции на которые нет ссылок из других секций. Секции которые обязательно должны присутствовать в результирующем файле, например секция со стартап кодом из которого вызывается функция main, описывается в скрипте линкера с помощью команды KEEP ().

Выводы.
1. Неиспользуемые stаtiс функции и переменные оптимизируются компилятором. Старайтесь использовать слово static в ваших программах это улучшает их читаемость и потенциально уменьшает размер.

2. -ffunction-sections и -fdata-sections на высоких уровнях оптимизации не включаются по двум причинам:
a) увеличение времени работы линкера, при использовании этих ключей сильно увеличивается количество секций которые должен обработать линкер.
б) в описании этих ключей есть предостережение что при их использовании возможны проблемы с отладкой. Мне не встречались сообщения с описаниями проблем для AVR платформы.

Анатолий.
alx2
Цитата(IgorKossak @ Jun 20 2009, 23:31) *
Такие обьекты должны быть видны линкеру посредством их использования другими (нестатическими) обьектами\функциями.
? Не понял. Что значит "видны посредством использования"?
Код
$ cat test2.c
static int foo(int x)
{
    return x + 5;
}

int bar(int x)
{
    return foo(x * 2);
}
$ gcc -c test2.c
$ nm -g test2.o
0000000c T bar
IgorKossak
Цитата(alx2 @ Jun 21 2009, 17:24) *
? Не понял. Что значит "видны посредством использования"?

В Вашем же примере статическая функция static int foo(int x) вызывается в int bar(int x), поэтому (если в свою очередь последняя функция также используется в приложении) линкер не должен её выкинуть.
aesok
Цитата(IgorKossak @ Jun 21 2009, 21:17) *
В Вашем же примере статическая функция static int foo(int x) вызывается в int bar(int x), поэтому (если в свою очередь последняя функция также используется в приложении) линкер не должен её выкинуть.


Только компилятор может выкидывать функции. А линкер может выкидывать только секции, вне зависимости сколько в ней функций (или переменных). Если есть ссылка хоть на одну функцию или переменную в секции то линкет оставляет всю секцию целиком. А вот сколько функций (переменных) положит компилятор в секцию управляеться ключем -ffunction-sections (-fdata-sections).

Анатолий.
IgorKossak
Да, Вы правы, оговорился. Но независимо от того, кто чем занимается, результат останется прежним.
demiurg_spb
Цитата(IgorKossak @ Jun 22 2009, 10:29) *
результат останется прежним...
Почтиsmile.gif Компилятор может также с лёгкостью заинлайнить статическую функцию.
И как такового "экземпляра" функции не будет вовсе, как пролога эпилога и call/ret.
mdmitry
Цитата(demiurg_spb @ Jun 22 2009, 18:41) *
Почтиsmile.gif Компилятор может также с лёгкостью заинлайнить статическую функцию.
И как такового "экземпляра" функции не будет вовсе, как пролога эпилога и call/ret.

объявление:
Код
static inline void __attribute__ ((always_inline)) foo(void);


тело:
Код
void foo(void)
{
....
}
demiurg_spb
Цитата(mdmitry @ Jun 22 2009, 20:05) *
объявление:...
Что Вы хотели этим сказать, что бывает атрибут always_inline? Так это в мануале прописано... Тут разговор о другом, что даже без упоминания о inline, простой статик частенько позволяет компилятору инлайнить статические функции. Всё. Конец мысли.
mdmitry
Гарантированно инлайн и никаких мыслей более
demiurg_spb
Цитата(mdmitry @ Jun 22 2009, 20:22) *
Гарантированно инлайн и никаких мыслей более
Для этих целей у меня специальный макрос заготовлен:
Код
#define INLINE __inline__ __attribute__((always_inline))
ReAl
Цитата(demiurg_spb @ Jun 22 2009, 19:26) *
Для этих целей у меня специальный макрос заготовлен:
Код
#define INLINE __inline__ __attribute__((always_inline))

И обязательно рядом
Код
#define NOINLINE __attribute__((noinline))

тоже бывает нужен.
alx2
Цитата(IgorKossak @ Jun 21 2009, 22:17) *
В Вашем же примере статическая функция static int foo(int x) вызывается в int bar(int x), поэтому (если в свою очередь последняя функция также используется в приложении) линкер не должен её выкинуть.
Верно, что не должен, но не поэтому. Как уже сказал aesok, линкер не работает с функциями. Линкер работает с секциями. Он либо включает секцию в выходной файл, либо не включает. Целью приведенного мной примера было показать, что в сгенеренном ассемблером объектном файле вообще нет глобального символа foo, таким образом, линкер вообще не узнает о существовании такой функции.
aesok
Цитата(alx2 @ Jun 23 2009, 13:29) *
Целью приведенного мной примера было показать, что в сгенеренном ассемблером объектном файле вообще нет глобального символа foo,


Нет, нету глобального символа foo, потому что функция foo статическая и ее область видимости ограничивается одним модулем.

Цитата(alx2 @ Jun 23 2009, 13:29) *
таким образом, линкер вообще не узнает о существовании такой функции.


Если компилятор не проинлайнит функцию foo, а то линкер увидет метку foo. И в даном случае при компиляции примера без оптимизации видим:

Код
$ nm  test2.o
00000000 b .bss
00000000 d .data
00000000 t .text
0000000b T _bar
00000000 t _foo



Анатолий.
alx2
Цитата(aesok @ Jun 23 2009, 23:11) *
Если компилятор не проинлайнит функцию foo, а то линкер увидет метку foo.
Код
00000000 t _foo
Так это же локальный символ - буква "t" маленькая. Разве линкер работает с локальными символами? Я почему-то считал, что он работает только с глобальными, а локальные его интересовать совершенно не должны. Это будет диверсия, если линкер удовлетворит внешнюю ссылку локальным объектом...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.