#c #linux #static-linking
#c #linux #статическое связывание
Вопрос:
Я создаю очень простую программу на c для использования в Linux, и я хотел бы знать, возможно ли создать только один большой двоичный файл, содержащий все зависимости, которые будут работать в любой системе Linux.
Если я правильно понимаю, любой компилятор превращает исходный код в машинные инструкции, но поскольку часто существуют общие части кода, которые можно повторно использовать в разных программах, большинство программ зависят от других библиотек.
Однако, если у меня есть исходный код для всех моих зависимостей, я должен иметь возможность скомпилировать двоичный файл таким образом, чтобы ничего не требовалось от системы? Смогу ли я запускать материал, скомпилированный на 64-битной системе, в 32-битной системе?
Комментарии:
1. Вы собираетесь создавать 64-битный двоичный файл? Если это так, 32-разрядные системы не могут запускать 64-разрядный код.
2. Рассматривали ли вы возможность сделать свою программу свободной ? Это облегчило бы многие проблемы….
3. Обратите внимание, что libc каким-то образом зависит от версии ядра. Итак, ваше утверждение в целом неверно (но вполне верно на практике)
4. @nos, я предполагаю, что мне нужен только 64-битный двоичный файл, если мне нужно использовать более 3 гигабайт оперативной памяти в одном процессе? тогда мне подойдет 32 бит.
5. @Bob ну, это зависит от типа вашего процессора. Запуск 32-разрядного приложения на 64-разрядном процессоре означает, что оно должно запускаться под эмулятором, который работает медленнее, чем выполнение собственных инструкций процессора
Ответ №1:
Короче говоря: возможно.
Более длинный ответ:
Это зависит. Вы не можете, например, запустить 64-разрядный двоичный файл в 32-разрядной системе, это просто невозможно. Да, это одно и то же семейство процессоров, но в 64-разрядной системе в два раза больше регистров, которые также имеют в два раза больше регистров. Какой 32-разрядный процессор будет «возвращать» значение тех битов и регистров, которых нет в аппаратном обеспечении процессора? Это просто не сработает. Некоторые инструкции также полностью меняют смысл, поэтому система действительно должна быть «правильной» для скомпилированного кода, иначе она не будет работать — к счастью, Linux проверит это и просто откажется, если это неправильно.
Вы можете СОЗДАТЬ 32-разрядный двоичный файл в 64-разрядной системе (при условии, что у вас есть все нужные библиотеки и т. Д., Установленные Как для 64-, Так и для 32-разрядных версий и т. Д.).
Аналогично, если вы попытаетесь запустить код ARM на процессоре x86 или код MIPS на процессоре ARM, у него просто нет шансов на работу, потому что фактические инструкции совершенно разные (или они будут нарушать некоторые патенты / авторские права или аналогичные, потому что наборы команд процессора содержат части, которые являются»защищенная интеллектуальная собственность» почти во всех случаях — поэтому дизайнеры должны убедиться, что они НЕ делают «то же самое, что и чужой дизайн»). Как и для 32-разрядных и 64-разрядных версий, у вас просто не будет возможности запустить здесь неправильный двоичный файл, он просто не будет работать.
Иногда есть небольшие различия, например, код ARM может быть скомпилирован с «жесткой» или «мягкой» плавающей запятой. Если код скомпилирован для жесткого float, а в ОС нет нужной поддержки, он не будет запускать двоичный файл. Что еще хуже, если вы скомпилируете на x86 для инструкций SSE и попытаетесь запустить на процессоре, отличном от SSE, код просто завершится сбоем [если вы специально не создаете код для «проверки наличия SSE и отображения ошибки, если ее нет»].
Итак, если у вас есть двоичный файл, который соответствует вышеуказанным критериям, система Linux имеет тенденцию немного меняться между выпусками, и в разных дистрибутивах есть тонкие «исправления», которые меняют ситуацию. В большинстве случаев они полностью безопасны (они исправляют какой-то неясный угловой случай, который кто-то обнаружил во время тестирования, но общее поведение, не связанное с углом, является «нормальным»). Однако, если вы перейдете с версии Linux 2.2 на версию Linux 3.15, между двумя версиями будут некоторые существенные различия, и двоичный файл из старого вполне может быть несовместим с более новым (и почти наверняка наоборот) — трудно точно знать, какие версии инесовместимы. В близких версиях он должен работать нормально, если вы специально не полагаетесь на какую-то функцию, которая присутствует только в одном (в конце концов, время от времени в ядро Linux добавляются новые вещи). Здесь ответ «возможно».
Обратите внимание, что выше также приведена ваша реализация среды выполнения C и C , поэтому, если у вас есть «новая» библиотека времени выполнения C или C , которая использует функцию X ядра Linux, и попробуйте запустить ее на более старом ядре, до того, как функция X была реализована (или работает правильно для данного случаясреда выполнения C или C пытается его использовать).
Статическое связывание действительно является хорошим способом УМЕНЬШИТЬ зависимость разных версий. И хороший способ сделать ваш двоичный файл огромным, что может помешать людям его загружать.
Гораздо лучший способ решить эту проблему — сделать код с открытым исходным кодом, тогда вы просто распространяете свой исходный код и список «минимальных требований» и позволяете другим людям разбираться с ним, требующим перекомпиляции.
Комментарии:
1. Итак, будет ли программа работать, зависит от того, совместимы ли функции ядра, используемые при компиляции, с системой, в которой она запущена?
2. Да, это основной фактор, когда мы преодолеваем «аппаратную совместимость» (например, 32-разрядную или 64-разрядную, SSE или нет и т. Д.)
3. Сохраняется ли обратная совместимость в ядрах? Могу ли я просто скомпилировать старое 32-битное 2. * ядро и ожидать, что оно будет работать на любом 32 или 64-битном 2. * ядре?
4. Существует стремление сохранить обратную совместимость, но нет абсолютной гарантии. Я видел, как вещи переходили с одной версии на другую. Однако на работе я регулярно запускаю программы на 3.4, 3.9 и 3.11 с одним и тем же (статически связанным) двоичным файлом. Таким образом, он может работать — в значительной степени это зависит от того, что именно делает код.
5. Я работаю в ARM, и кто-то из нашего юридического отдела недавно сказал мне, что у них есть патенты, защищающие набор команд. Однако это может быть не весь набор команд, а только его части. Суть в том, что вы не можете (тривиально) просто создать полностью совместимый процессор без какого-либо сотрудничества с оригинальным производителем — если только процессор не достаточно старый, чтобы срок действия таких прав истек. Я внесу правку, чтобы уточнить.
Ответ №2:
На практике это зависит от «достаточно простого». Если вы используете C 11, вы быстро обнаружите, что библиотеки C 11 зависят от современных версий libc. В свою очередь, они поставляются только с современными дистрибутивами Linux. Я не знаю ни о каком дистрибутиве Linux с «долгосрочной поддержкой», который сегодня (июнь 2014) поставляется с поддержкой libc для GCC 4.8
Ответ №3:
Короткий ответ — нет, по крайней мере, без серьезного взлома.
В разных дистрибутивах Linux может быть разный связующий код между пользовательским пространством и ядром. Например, hello world, казалось бы, без зависимостей, созданный из ubuntu, не может быть выполнен под CentOS.
РЕДАКТИРОВАТЬ: Спасибо за комментарий. Я перепроверяю это, и причина в том, что я использую 32-разрядную виртуальную машину. Извините за путаницу. Однако, как отмечалось выше, эмпирическое правило заключается в том, что даже один и тот же дистрибутив Linux может иногда нарушать совместимость для развертывания исправления ошибок, поэтому вывод остается в силе.
Комментарии:
1. Я буквально только что запустил hello world, построенный без специальных флагов на xubuntu 14 на centos 6.5.
2. Действительно? Я делал это не один раз, поэтому я немного смущен, при каких обстоятельствах это НЕ работает.
3. Может быть, это имеет значение, если я запускаю centos на виртуальной машине? Я добавил вывод в исходное сообщение.
4. Я использовал это как в baremetal, так и в виртуальной машине. Виртуальная машина сама по себе не должна изменять время выполнения ОС как таковое — если это так, это не «настоящая виртуальная машина». (И вам пришлось бы перекомпилировать код для виртуальной машины и baremetal той же ОС, что было бы довольно болезненно)
5. @Mats Petersson, извините, я думал, вы говорили мне, что это не должно работать. Итак, наконец, можно запустить hello world из ubuntu на centos.