Решил сваять мелкую утилитку для маршрутизатора, поставил Sourcery CodeBench Lite for MIPS, от конца 2014. Из того, что размер инсталлятора — 620 метров, ожидал, что оно развернется гига в полтора-два максимум. Оно развернулось в шесть гигов и 84 тысячи файлов. От такой широты я малость офигел и полез по дереву смотреть, что и где. 90% всего объема занимает mips-linux-gnu/libc. Для чего там такие дикие объемы?
Ладно, собрал простейший "Hello, world", который в статической сборке получился аж в 700 кб, что тоже весьма удивило. Ну да, отладочная информация — добавил -g0, но размер не уменьшился. Убрал отладочные символы strip'ом — осталось 500 кб. Это действительно минимально необходимый объем кода, требуемого для вывода одной строки на консоль, или я чего-то не понимаю?
И это версия Lite — боюсь даже предположить, сколько будет занимать полная.
Re: Sourcery CodeBench - гигантомания или норма? :)
Здравствуйте, Евгений Музыченко, Вы писали:
EM> Это действительно минимально необходимый объем кода, требуемого для вывода одной строки на консоль, или я чего-то не понимаю?
Можно использовать "-fdata-sections -ffunction-sections" при компиляции
и "-Wl,--gc-sections" при линковки, тогда не используемые функции будут удалены,
но возможно для этого нужно пересобраться libc с этими ("-fdata-sections -ffunction-sections")
опциями
Re[2]: Sourcery CodeBench - гигантомания или норма? :)
Здравствуйте, Zhendos, Вы писали:
Z>Можно использовать "-fdata-sections -ffunction-sections" при компиляции Z>и "-Wl,--gc-sections" при линковки, тогда не используемые функции будут удалены,
После добавления всех перечисленных ключей размер исполняемого файла уменьшился с 700 до 650 кб, а после отрезания символов — до 550. Откуда там берется столько кода на элементарные операции? Причем замена printf на puts никакого влияния на размер не оказывает.
Кстати, что нужно сказать gcc, чтобы он изначально не добавлял символы к файлу? -g0 не помогает.
Re[3]: Sourcery CodeBench - гигантомания или норма? :)
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, Zhendos, Вы писали:
Z>>Можно использовать "-fdata-sections -ffunction-sections" при компиляции Z>>и "-Wl,--gc-sections" при линковки, тогда не используемые функции будут удалены,
ЕМ>После добавления всех перечисленных ключей размер исполняемого файла уменьшился с 700 до 650 кб, а после отрезания символов — до 550. Откуда там берется столько кода на элементарные операции? Причем замена printf на puts никакого влияния на размер не оказывает.
Потому что библиотека не собрана с "-fdata-sections -ffunction-sections",
и поэтому если puts вызывает какой-то хелпер из другого объектного файла,
то подтянется весь "другой" объектный файл с хелпером, и так по цепочке.
Вы можете посмотреть все это вручную, взять libc.a, или как там он называется,
вызвать
ar x libc.a
, извлечь кучу объектных файлов,
и линковаться последовательно, типа
grep fputs *.o
прилинковываем нужные .o файлы, потом снова на что-нибудь ругается и т.д.
На вскидку, fputs внутри использует какой-нибудь мьютекс внутри, в файле мьютексом может
быть какое-нибудь логирование ошибок, оно тянет printf, они malloc и пошло поехало,
пересоберите glibc с "-fdata-sections -ffunction-sections", думаю половину можно будет выкинуть.
ЕМ>Кстати, что нужно сказать gcc, чтобы он изначально не добавлял символы к файлу? -g0 не помогает.
Можно при линковке передать линкеру опцию --strip-all, как с "--gc-sections": "-Wl,--strip-all".
Re[4]: Sourcery CodeBench - гигантомания или норма? :)
Здравствуйте, Zhendos, Вы писали:
Z>Потому что библиотека не собрана с "-fdata-sections -ffunction-sections", Z>и поэтому если puts вызывает какой-то хелпер из другого объектного файла, Z>то подтянется весь "другой" объектный файл с хелпером, и так по цепочке.
Однако... То есть, в библиотеке все функции сложены в одну секцию, и линкер умеет цеплять только секцию целиком?
В "поганой винде" (а также в досе) еще с незапамятных времен считалось крайне дурным тоном класть более одной крупной функции в одну секцию, а компиляторы/линкеры, цепляющие функции независимо от их расположения в секциях, появились как бы не пятнадцать лет назад.
Z>Вы можете посмотреть все это вручную, взять libc.a, или как там он называется, Z>вызвать
ar x libc.a
, извлечь кучу объектных файлов, Z>и линковаться последовательно
А просто посмотреть, как функции разложены по секциям, можно?
Z>На вскидку, fputs внутри использует какой-нибудь мьютекс внутри, в файле мьютексом может Z>быть какое-нибудь логирование ошибок, оно тянет printf, они malloc и пошло поехало,
Да это-то понятно. Оно ж везде так, однако в той же винде программа из единственного printf, полностью статически собранная компилятором/линкером от MS 2012 года, имеет размер 52 кб, а из puts — 48. То есть, на порядок меньше. Отчего у меня глаза на лоб и полезли.
Z>пересоберите glibc с "-fdata-sections -ffunction-sections", думаю половину можно будет выкинуть.
То есть, такая программа будет примерно в 250 кб? Но это ведь тоже запредельно много. Отчего там код такой неимоверно толстый?
Re[5]: Sourcery CodeBench - гигантомания или норма? :)
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, Zhendos, Вы писали:
Z>>Потому что библиотека не собрана с "-fdata-sections -ffunction-sections", Z>>и поэтому если puts вызывает какой-то хелпер из другого объектного файла, Z>>то подтянется весь "другой" объектный файл с хелпером, и так по цепочке.
ЕМ>Однако... То есть, в библиотеке все функции сложены в одну секцию, и линкер умеет цеплять только секцию целиком?
Не совсем, библиотека (статическая) это архив объектных файлов,
и вот в пределах одного файла линкер (GNU ld) цепляет секцию целиком,
а не используемые объектники выкидывает.
Например, файлов в архиве /usr/lib64/libc.a у меня 1553, соотвественно
что-то он точно выкинет.
ЕМ>В "поганой винде" (а также в досе) еще с незапамятных времен считалось крайне дурным тоном класть более одной крупной функции в одну секцию, а компиляторы/линкеры, цепляющие функции независимо от их расположения в секциях, появились как бы не пятнадцать лет назад.
Ну, статическая линковка для Linux, это все-таки довольно редкий подход, все используют ".so",
и наверное поэтому такой оптимизацией никто не заморачивался.
Z>>Вы можете посмотреть все это вручную, взять libc.a, или как там он называется, Z>>вызвать
ar x libc.a
, извлечь кучу объектных файлов, Z>>и линковаться последовательно
ЕМ>А просто посмотреть, как функции разложены по секциям, можно?
Да,
objdump -h libc.a
Z>>На вскидку, fputs внутри использует какой-нибудь мьютекс внутри, в файле мьютексом может Z>>быть какое-нибудь логирование ошибок, оно тянет printf, они malloc и пошло поехало,
ЕМ>Да это-то понятно. Оно ж везде так, однако в той же винде программа из единственного printf, полностью статически собранная компилятором/линкером от MS 2012 года, имеет размер 52 кб, а из puts — 48. То есть, на порядок меньше. Отчего у меня глаза на лоб и полезли.
Ну, с gcc
printf("hello\n");
==
fputs("hello\n", stdout);
,
т.к. в компиляторе есть соотвествующая оптимизация, и все printf без параметров он заменяет на fputs.
Z>>пересоберите glibc с "-fdata-sections -ffunction-sections", думаю половину можно будет выкинуть.
ЕМ>То есть, такая программа будет примерно в 250 кб? Но это ведь тоже запредельно много. Отчего там код такой неимоверно толстый?
"Половину" это оценка с потолка, без пересборки не узнаешь.
И при сборке можно выключить скажем nscd (кэширующий демон DNS) и прочую хрень.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>В "поганой винде" (а также в досе) еще с незапамятных времен считалось крайне дурным тоном класть более одной крупной функции в одну секцию, а компиляторы/линкеры, цепляющие функции независимо от их расположения в секциях, появились как бы не пятнадцать лет назад.
Это же опенсорс. Берёте код линкера, напильник в зубы — и вперёд, и с песней!