LINUX.ORG.RU

Как сжать linux-бинарник (запускаемый файл)

 , , ,


1

2

Написал в Lazarus простенькое приложение, но после конпиляции запускаемый файл получился слишком большой - размер 20Мб.

Чтобы уменьшить выходной размер, как советуют в интернете, в свойствах проекта (Проект - Параметры проекта) включил 4 опции компилятора:

1) Вкладка Генерация кода: установить флажок "Умная компоновка" (-СХ);
2) Вкладка Компоновка: установить флажок "Умная компоновка" (-ХХ);
3) Вкладка Компоновка: установить флажок "Использовать внешний файл отладочных символов GDB" (-Xg);
4) Вкладка Компоновка: установить флажок "Вырезать символы из исполняемого файла" (-Xs);
5) Вкладка Компоновка: снять флажок "Выдавать номера строк в ошибках времени выполнения"(-gl).

Кроме того, можно поставил галочку «использовать текущие параметры по умолчанию для новых проектов», чтобы Lazarus запомнил эти настройки для следующих проектов.

После компилирования бинарь стал размером 4Мб. Вроде неплохо.

Затем утилита strip вырезала еще немного отладочной информации:

strip --strip-all ./mybinary

Дальше я попробовал сжать zip`ом, размер стал 1,7Мб, но файл перестал быть запускаемым (это логично).

Внимание вопрос: есть ли в линуксе какие-то утилиты, сжимающие запускаемый файл, но так, чтобы он при этом оставался запускаемым (аналог виндового UPX)?

UPD. Нашлись команды сжатия:

upx -k -9 ./mybinary
gzexe ./mybinary

Теперь второй вопрос: не скажется ли upx/gzexe на кроссплатформенности/совместимости? Ну например на i386 работает, а на x64 уже нет, или наоборот. Какая из них принесет меньше подобных проблем?

UPD2. Обновил пост, чтобы он остался в истории как мануал.
(Кстати, все опции и утилиты актуальны и для уменьшения exe-файлов в Windows)
И да, upx лучше не использовать, всё остальное - желательно.
Также рекомендую подробный мануал по рантайму, статическому и динамическому связыванию.

★★★★★

Последнее исправление: Novator (всего исправлений: 5)

Оказывается, upx есть и под linux. Установил, сжал, получилось 1,5Мб - это очень хороший результат. Причем, визуально на скорость запуска не повлияло (около 1 сек).

Думаю, лучше уже быть не может.

Novator ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Да, нашел. А вот ещё вопрос: может ли upx как-то сказаться на кроссплатформенности/совместимости? Ну например на i386 работает, а на x64 уже нет, или наоборот. Не создаст ли это каких-нибудь дополнительных проблем?

Novator ★★★★★
() автор топика
Последнее исправление: Novator (всего исправлений: 1)
Ответ на: комментарий от anonymous

Причем, визуально на скорость запуска не повлияло (около 1 сек).

Раньше это только увеличивало скорость запуска, так как загрузить 1.5 метра с диска и распаковать было быстрее чем загрузить 20 метров с медленного диска.

V1KT0P ★★
()
Ответ на: комментарий от saahriktu

Тоже работает, но размер чуть больше - 1,7Мб.
Запускается примерно так же, за 1 сек.

Novator ★★★★★
() автор топика
Ответ на: комментарий от AnDoR

Пробовал. Если DEBUG у компилятора выключен, то strip уже не влияет, размер остается прежний.

Novator ★★★★★
() автор топика
Ответ на: комментарий от Novator

Твои пользователи узнают что ты мудак, а так конечно пакеры отличная идея.

anonymous
()
Ответ на: комментарий от V1KT0P

Это что за лажовые бинарники с таким соотношением? Ну и потом в рантайме будет +25мб памяти на каждый файл, а так-то конечно ничего.

anonymous
()

Кстати оп, попробуй пробить в нём дырки, а то вдруг у тебя там ПУСТОТЫ на 2 мегабайта, что типично для дельфи программистов (хотя там из мусора не только пустоты конечно, я видел этот ваш паскаль в дисассемблере).

anonymous
()

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

kickass
()

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

При сжатии исполняемого файла КАЖДЫЙ запуск потребует чтения и распаковки, а также память для хранения сразу ВСЕГО кода, при каждом запуске приложения, и хранится этот код будет для каждого экземпляра приложения.

Так что не страдайте х-ней.

slovazap ★★★★★
()
Ответ на: комментарий от SR_team

современные кути

Ты icu не забудь, мегабайт 10-30. а там и хромиум подоспеет, ещё соточка. Нода там, ещё порядка 20. И остальное по мелочи. Другое дело, что паскаль всего предоставляемого таким рантаймом не умеет, там реально привет мир по сравнению будет.

anonymous
()
Ответ на: комментарий от slovazap

По ситуации. Иногда влезть в флеш важнее чем экономить оперативку

Dark_SavanT ★★★★★
()
Ответ на: современные кути от anonymous

Другое дело, что паскаль всего предоставляемого таким рантаймом не умеет, там реально привет мир по сравнению будет.

Вы хотели сказать, что не всякой программе на Паскале нужен такой мощный рантайм, который в неё вкомпиливается? Ну так. И такое не только в Паскале. Тоже самое, например, с тем же Go. Однако, везде по-разному.

Скомпилировал сейчас хелловорлд на Паскале. Получилось 180632 байт. С опциями "-XX -Xg -Xs" получилось 26480 байт. Последний вариант gzexe пожал до 12948 байт. И это x86_64 вариант.

А теперь соберём хелловорлд на Go. Получается 1859889 байт (1,8 Мб). После strip'а бинарник похудел до 1226184 байт (1,2 Мб). gzexe ужал его до 468276 байт.

saahriktu ★★★★★
()
Ответ на: комментарий от saahriktu

На ассеммблере вообще 680 байт для i386 бинарника и 952 байта для x86_64

(Из какой-то книжки или туториала, не помню)

;Листинг 01 - минимальная программа для Linux на NASM
;Приемы оптимизации не применяются для упрощения кода

;On the amd64 64 bit:
;1) nasm -felf64 prog01.asm -o prog0164.o
;   ld prog0164.o -o prog0164
;2) ld -m elf_i386 -s -o prog01.o file  (or ld -m elf_i386 -o prog01.o prog01)

global _start

_start:

;syscall's numbers are here:
;/usr/include/x86_64-linux-gnu/asm/unistd_64.h
;
; eax -4 - man 2 write
; ebx -1 - stdout
; ecx - buf*
; edx - buf length
mov eax, 4
mov ebx, 1
mov ecx, msg
mov edx, msglen
int 0x80

mov eax, 1
mov ebx, 0
int 0x80

section .data

msg: db "Linux rulez 4ever",0x0A,0
msglen equ $-msg
anonymous_incognito ★★★★★
()
Последнее исправление: anonymous_incognito (всего исправлений: 1)
Ответ на: комментарий от anonymous_incognito

com бинарник для доса (исполняемый вендами) единицы байт. dos rulez?

anonymous
()
Ответ на: комментарий от anonymous_incognito

А на C 6240 байт без отладочной информации. При этом для многих и C сложен, поскольку позволяет выстрелить себе в ногу. Куда уж им ещё более низкоуровневый ассемблер. Тем более, что чем ниже уровень тем более трудоёмкий процесс разработки. Так что, высокоуровневые языки, такие как, например, Паскаль, тоже нужны.

saahriktu ★★★★★
()
Ответ на: комментарий от saahriktu

Я не понимаю что ты хочешь сказать, проще ассемблера языка не существует. Ты имел в виду если уж на простом как тапок си можно накосячить, то на ещё более простом и примитивном ассемблере уж точно? Поэтому нужны сложные, нелогичные и отрицающие любой здравый смысл языки, такие, как паскаль?

anonymous
()
Ответ на: комментарий от anonymous

«архитектурная простота» != «простота для человека».

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

saahriktu ★★★★★
()
Ответ на: комментарий от saahriktu

В ассемблере и подавно так нельзя

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

anonymous
()
Ответ на: комментарий от slovazap

страницы будут закэшированы, значит при повторном запуске файла код уже будет в памяти.
При сжатии исполняемого файла КАЖДЫЙ запуск потребует чтения и распаковки, а также память для хранения сразу ВСЕГО кода, при каждом запуске приложения, и хранится этот код будет для каждого экземпляра приложения.

Запустил 3 обычных экземпляра (который 4Мб, несжатый), lxtask показал такой расход:

Память:
RSS 14,5/всего 97,8
RSS 14,5/всего 97,8
RSS 14,5/всего 97,8

Потом запустил 3 раза сжатый файл (сжат upx до 1,5Мб):

Память:
RSS 17,1/всего 97,8
RSS 17,1/всего 97,8
RSS 17,1/всего 97,8

Т.е. сжатый действительно по RSS расходует чуть больше (общий объем такой же), но ненамного. А при многократном запуске несжатого выигрыша нет - экземпляры точно также дублируются в памяти.

Novator ★★★★★
() автор топика
Ответ на: комментарий от MrClon

простенькое приложение
4Мб

Чёт как то…

Это же GUI приложение, не консольное.

Сравни с каким-нибудь «электроном», «культёй» или «гытыкой», я думаю у них по 20Мб будет без дебагов, и плюс ещё куча зависимостей (для культи мегабайт 100, как я полагаю).

Здесь же голый бинарь, не требующий никаких библиотек, кроме базового X11 или Win32 ему ничего не нужно.

Novator ★★★★★
() автор топика
Последнее исправление: Novator (всего исправлений: 1)
Ответ на: комментарий от Novator

--strip-all --remove-section=.comment --remove-section=.note.gnu.gold-version и тд

anonymous
()
Ответ на: комментарий от slovazap

Васянам вендовозным бесполезно объяснять.

anonymous
()
Ответ на: комментарий от anonymous_incognito

int 0x80

В нормальном сгенерённом компилятором коде используется инструкция syscall. Вот почему крыворуких мартышек нельзя допускать к ассемблерному коду.

anonymous
()
Ответ на: комментарий от SR_team

Почитай уже мурзилку по x86-64 архитектуре. 32бит регистры zero-extend-ятся до 64битных.

anonymous
()
Ответ на: комментарий от saahriktu

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

Помнится, был такой весёлый треш, как HiASM. Там код вообще писать не надо, всё исключительно мышевозное «соединим выход одного блока со входом другого».

devl547 ★★★★★
()
Последнее исправление: devl547 (всего исправлений: 1)
Ответ на: комментарий от SR_team

Нету, но на практике так и будет.

anonymous
()
Ответ на: комментарий от grem

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

anonymous
()
Ответ на: комментарий от anonymous

Ещё как делают (или таскают рантайм с собой), если поставляется в бинарном виде, чтобы запускалось на ряде дистрибутивов с разными версиями gcc из одного и того же бинарника. Как ещё ты сделаешь бинарника, который будет работать одновременно на debian 7 и fedora 29?

Тот же фрипаскаль для запуска собранных им прог не требует наличия в системе установленного рантайм (возможно, оно и к лучшему). А если бы требовал, тебе легче было б от того, что с системе его либы ещё больше места занимали?

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 1)
Ответ на: комментарий от grem

Что значит ещё больше? Так и так выходит они есть, только в диначическом случае в одном расшареном экземпляре.

anonymous
()
Ответ на: комментарий от anonymous

Больше значит, что не только не слинкованные библиотеки лежат, а также не подключенные модули.

А насчёт c++, как ещё обеспечить запуск проги собранной просредством icc или pgi c++ compiler в окружении, где их нет?

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 2)

не скажется ли upx/gzexe на кроссплатформенности/совместимости?

1. Скажется на времени запуска и потреблении памяти.
2. Всякие ClamAV и прочие антивирусы часто сжатые UPX'ом бинарники помечают как подозрительные и не дают запускать их.

ИМХО, если есть возможность не использовать UPX, лучше его не использовать. Дроч на освобождение лишних байтиков при размере бинаря в 4MB вызывает удивление.

P.S. strip можно вызывать с флагом -s. И есть ещё sstrip.

EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 2)
Ответ на: комментарий от EXL

Strip с этим флагом и вызывал, при отключенных DEBUG-опциях компилятора, strip -s даёт какие-то копейки, т.е. грубо говоря, вместо 4Мб получается 3.9Мб, а после сжатия вместо 1.6Мб получается 1.5Мб.

Насчет антивирусов в винде понял. Но, получается, бинарники линя можно почти смело сжимать при необходимости :)

Novator ★★★★★
() автор топика
Ответ на: комментарий от grem

как ещё обеспечить запуск проги собранной просредством icc или pgi c++ compiler в окружении, где их нет?

Не знаю что насчёт pgi, но

Intel does not ship an implementation of the C++ standard library

Так что так же будет использовать libstdc++ и нормально работать, имхо конечно, так как Intel компилятора у меня нет и никогда не было...

fsb4000 ★★★★★
()
Ответ на: комментарий от Novator

Я сталкивался с тем, что на некоторых платформах бинарники пожатые UPX'ом отказывались запускаться. Но на x86/x86_64 я думаю всё будет нормально.

EXL ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.