- gcc, статическая и динамическая линковка
- Re: gcc, статическая и динамическая линковка
- Re: gcc, статическая и динамическая линковка
- Re: gcc, статическая и динамическая линковка
- Re: gcc, статическая и динамическая линковка
- Re: gcc, статическая и динамическая линковка
- Re: gcc, статическая и динамическая линковка
- Re: gcc, статическая и динамическая линковка
- Линукс статическая линковка мертва?
- 5 ответов
- статическая линковка libc
- Re: статическая линковка libc
- Re: статическая линковка libc
- Re: статическая линковка libc
- Re: статическая линковка libc
- Re: статическая линковка libc
- Re: статическая линковка libc
- Re: статическая линковка libc
- Линковка в Linux
- Table of Contents
- 1 Ссылки
- 2 Линковка
- 3 Основы
- 4 Линковщики и Загрузчики
- 5 Объектные файлы
- 6 ELF
- 6.1 Заголовки Elf
- 7 Символы и адресация символов
- 8 Линковка статических библиотек
- 9 Релокация
- 10 Динамическая линковка: разделяемые библиотеки
- 11 Загрузка разделяемой библиотеки из приложения
gcc, статическая и динамическая линковка
Необходимо слинковать С++ приложение, используя все библиотеки сппишные статически (-static), но при этом оддну свою библиотеку надо слинковать динамически. Как такое реализуется?
Re: gcc, статическая и динамическая линковка
Перспектива назначать др имена срршным статическим билиотекам др имена и собирать динамически не очень радует
Re: gcc, статическая и динамическая линковка
Re: gcc, статическая и динамическая линковка
Боюсь что так не подоидет
Re: gcc, статическая и динамическая линковка
Re: gcc, статическая и динамическая линковка
Re: gcc, статическая и динамическая линковка
Вообще говоря, так:
g++ -static -Wl,-Bdynamic -lfoo
Но ввиду того, что современный набор ГНУтых утилит полон багов и фич, не соберется. Вернее, соберется, но запускаться не будет (типа, нет такой команды).
Можешь вызвать загрузчик явно, на x86 Линуксе оно будет такое:
на x86-64 — такое:
Если не упало, (на большинстве x86-64 систем оно ссегфолтится), то заметь, что libc6 туда затащилось динамически:
/lib/ld-linux.so.2 —list ./a.out
Если ТАКОЕ тебя устраивает — что ж, можешь пинком добавить загрузчик в файл:
g++ -static -Wl,-Bdynamic -lfoo -Wl,-Bstatic -Wl,-dynamic-linker /lib/ld-linux.so.2
Полученное творение почти везде ссегфолтится или выругается на несоответствие версии libc6 или ядра.
Re: gcc, статическая и динамическая линковка
Источник
Линукс статическая линковка мертва?
Фактически, флаг gcc -static в Linux сейчас не работает. Позвольте мне процитировать из GNU libc FAQ:
2,22. Даже статически связанные программы нуждаются в некоторых общих библиотеках что не приемлемо для меня. Какие я могу сделать?
Решением является настройка glibc с —enable-статическому NSS. В этом случае вы можете создать статический двоичный файл, который будет использовать только сервисы днс и файлы (измените /etc/nsswitch.conf для этого). Вы должны явно указать ссылку на все эти услуги. Например:
Проблема с этим подходом что вы должны связать каждый статический Программа, которая использует подпрограммы NSS с все эти библиотеки.
Что касается этого факта, есть ли сейчас какой-нибудь разумный способ создать полнофункциональную статическую сборку в Linux, или статическая компоновка полностью отсутствует в Linux? Я имею в виду статическую сборку, которая:
- Ведет себя точно так же, как динамическая сборка do (static-nss с непоследовательное поведение — зло!);
- Работает над разумными вариациями среды glibc и версий Linux;
5 ответов
Что касается этого факта, есть ли сейчас какой-то разумный способ создать полнофункциональную статическую сборку в Linux, или статическая компоновка полностью не работает в Linux?
Я не знаю, где найти исторические ссылки, но да, статическая ссылка не работает в системах GNU. (Я считаю, что он умер при переходе с libc4 /libc5 на libc6 /glibc 2.x.)
Эта функция была признана бесполезной в свете:
Уязвимости безопасности. Приложение, которое было статически связано, даже не поддерживает обновление libc. Если приложение было связано в системе с уязвимостью lib, оно будет сохранено в статически связанном исполняемом файле.
Раздувание кода. Если многие статически связанные приложения запускаются в одной и той же системе, стандартные библиотеки не будут использоваться повторно, поскольку каждое приложение содержит в себе собственную копию всего. (Попробуйте du -sh /usr/lib , чтобы понять масштаб проблемы.)
Попробуйте копировать архивы списков рассылки LKML и glibc 10-15 лет назад. Я уверен, что давно я видел что-то связанное с LKML.
Я думаю, что это очень раздражает, и я считаю высокомерным называть функцию «бесполезной», потому что у нее есть проблемы, связанные с определенными вариантами использования. Самая большая проблема с подходом glibc заключается в том, что он жестко кодирует пути к системным библиотекам (gconv, а также nss), и поэтому он ломается, когда люди пытаются запустить статический двоичный файл в дистрибутиве Linux, отличном от того, для которого он был создан.
В любом случае, вы можете обойти проблему gconv, установив GCONV_PATH, чтобы он указывал на соответствующее местоположение, это позволило мне взять двоичные файлы, созданные на Ubuntu, и запустить их в Red Hat.
Статические ссылки, похоже, не очень любят в мире Linux. Вот мой дубль.
Люди, которые не видят привлекательности статического связывания, обычно работают в области ядра и операционной системы более низкого уровня. Многие разработчики * nix библиотек потратили целую жизнь на решение неизбежных проблем, связанных с попыткой связать сотню постоянно меняющихся библиотек — задача, которую они выполняют каждый день. Посмотрите на автоинструменты, если вы хотите узнать, какие из них сальто комфортно выполнять.
Но никто не должен тратить на это большую часть своего времени. Статическое связывание продвинет вас далеко от буферизации библиотеки. Разработчик может обновить зависимости своего программного обеспечения в соответствии с расписанием программного обеспечения, вместо того, чтобы быть вынужденным сделать это в момент появления новых версий библиотеки. Это важно для пользовательских приложений со сложными пользовательскими интерфейсами, которым необходимо управлять потоком многих библиотек более низкого уровня, от которых они неизбежно зависят. И именно поэтому я всегда буду фанатом статических ссылок. Если вы можете статически связывать кросс-скомпилированный переносимый код C и C ++, вы в значительной степени сделали мир устрицей, поскольку вы сможете быстрее доставлять сложное программное обеспечение на широкий круг постоянно растущих устройств мира.
В этом есть много разногласий с другой точки зрения, и приятно, что программное обеспечение с открытым исходным кодом учитывает их все.
То, что вам нужно динамически связываться со службой NSS, не означает, что вы не можете статически связываться с любой другой библиотекой. Все, что часто задаваемые вопросы говорят о том, что даже «статически» связанные программы имеют некоторые динамически связанные библиотеки. Это не говорит о том, что статическое связывание «невозможно» или «оно не работает».
Добавление других ответов:
По причинам, указанным в других ответах, это не рекомендуется для большинства дистрибутивов Linux, но на самом деле существуют дистрибутивы, созданные специально для запуска статически связанных двоичных файлов:
Из описания стали
static linux основан на отобранной вручную коллекции лучших инструментов для каждой задачи и каждого инструмента статически связаны (включая некоторые X такие клиенты, как st, surf, dwm, dmenu),
Он также нацелен на уменьшение размера двоичного файла за счет исключения glibc. и другие раздутые библиотеки GNU, где это возможно (ранние эксперименты показывают, что статически связанные двоичные файлы обычно меньше, чем их динамически связанные аналоги glibc . ). Обратите внимание, это в значительной степени вопреки тому, что Ульрих Дреппер считает статическим связыванием.
Из-за побочной выгоды, что статически связанные двоичные файлы запускаются быстрее, распределение также нацелено на повышение производительности.
Статическое связывание также помогает уменьшить зависимость.
Источник
статическая линковка libc
Расскажитие плиз как надо шаманить, чтобы libc слинковать статически с помощью gcc.
С уважением, Боронин Сергей
Re: статическая линковка libc
Я хотел бы уточнить вопрос на примере. — main.cpp void some_func (); int main() < some_func (); >— — some_func.cpp void some_func () < printf ("Hello, World. "); >; — Задача: Нужно собрать some_func.cpp в виде so, таким образом чтобы она не зависела ни от каких динамических библиотек, таких как stdc++, libc, ld libgcc и пр., иными словами нужно получить динамическую библиотеку стаически слинкованную. Тоже самое касается и main.cpp, ее тоже надо собрать статически но чтобы при этом подгружала some_func.so. Пробовал примерно так: g++ -nodefaultlibs -shared stdc++.a libc.a some_func.cpp -o some_func.so g++ -static main.cpp -o main some_func.so При запуске получаю примерно такое сообщение ./main: can’t find specified file
Что я сделал не так?
Re: статическая линковка libc
Вывод ldd твоя_программа в студию.
Re: статическая линковка libc
ldd main staticaly linked
ldd some_func.so staticaly linked
Re: статическая линковка libc
Понятно, что main не имеет шансов загрузить разделяемую библиотеку, хотя все происходящее довольно странно: я не понимаю, почему main вообще собрался.
Re: статическая линковка libc
Вообще засада какая-то.
Я использую. gcc-3.3.3 ALTLinux Master 2.4 RH 9.0
Re: статическая линковка libc
А вообще как правильно собрать этот пример?
Re: статическая линковка libc
> Расскажитие плиз как надо шаманить, чтобы libc слинковать статически с помощью gcc.
Источник
Линковка в Linux
Table of Contents
1 Ссылки
2 Линковка
Линковка это процесс компоновки различных кусков кода и данных вместе, в результате чего получается один исполняемый файл. Линковка может быть выполнена во время компиляции, во время загрузки (загрузчиком) и также во время исполнения (исполняемой программой). Раньше (конец 40-х) линковка выполнялась вручную, сейчас мы имеем программы линковщики (linkers), которые дают возможность динамической линковки разделяемых библиотек (shared libraries).
3 Основы
Пусть у нас есть два файла с кодом a.c и b.c. Чтобы скомпилировать эти два файла при помощи GCC, мы вызываем следующий код
Это вызывает следующую последовательность:
Запустить препроцессор на файле a.c и сохранить результат в промежуточный файл a.i
Запустить компилятор на a.i и сгенерировать ассемблерный код в a.s
Запустить ассемблер на a.s и сгенерировать объектный файл a.o
Работа линковщика состоит в том, чтобы получить на вход сгенерированные объектные файлы a.o и b.o и сгенерировать из них финальный исполняемый файл a.out
После этого мы можем запустить наш бинарный файл ./a.out. Оболочка командной строки вызовет функцию загрузчика, которая скопирует код и данные из исполняемого файла a.out в память, затем передаст управление в начало программы. Функция загрузчик называется execve, она загружает код и данные исполняемых объектных файлов в память, затем запускает их выполнение, прыгая на первую инструкцию.
4 Линковщики и Загрузчики
Линковщики (linkers) и загрузчики (loaders) выполняют концептуально разные, но в целом похожие задачи:
- Загрузка программ. Копирование образа программы с жёсткого диска в RAM. В некоторых случаях загрузка программы (loading) также может включать выделение дисковой памяти или отображение виртульного адресного пространства на дисковое пространство.
- Релокация (relocation). Компиляторы и ассемблеры генерируют объектный код для каждого входного модуля программы с началом адресации в нуле. Релокация — это процесс изменения адреса загрузки различных частей программы во время объединения всех секций одного типа в одну секцию. Секции кода и данных таким образом будут указывать на корректные адреса в рантайме.
- Symbol Resolution. Программы имеют внутри себя множество подпрограмм; указание одной подпрограммы на другую подпрограмму происходит через символьные таблицы. Работа линковщика — подменять указания на символ подпрограммы на указание адреса расположения подпрограммы, изменяя объектный код.
В итоге, получается что загрузчик выполняет загрузку программ; линковщик выполняет symbol resolution; оба выполняют релокацию.
5 Объектные файлы
- Перемещаемый объектный файл (relocatable object file) — содержит бинарный код и данные в форме, которая может быть скомпонована с другими перемещаемыми объектными файлами во время компиляции. В итоге получаем исполняемый объектный файл, скомпонованный из перемещаемых объектный файлов.
- Исполняемый объектный файл (executable object file) — содержат бинарный код и данные в форме, которая может быть напрямую загружена в память и выполнена.
- Разделяемый объектный файл (shared object file) — специальный тип перемещаемого объектного файла, который может быть загружен в память и слинкован динамически либо во время загрузки в память, либо во время выполнения.
Компиляторы и ассемблеры генерируют перемещаемые объектные файлы (а так же разделяемые объектные файлы). Линковщики компонуют эти объектные файлы вместе и генерируют исполняемые объектные файлы.
6 ELF
Объектные файлы разнятся в разных ОС. Первые UNIX системы использовали формат a.out. Ранние System V использовали формат COFF (common object file format). Windows NT использует разновидность формата COFF, называемую PE (portable executable); IBM использует собственный формат IBM 360. Современные UNIX системы, такие как Linux и Solaris используют формат UNIX ELF (executable and linking format).
6.1 Заголовки Elf
7 Символы и адресация символов
Каждый перемещаемый объектный файл содержит таблицу символов связанные символы. В контексте линковщика представлены следующие виды символов:
- Глобальные символы объявленые на уровне модуля — могут быть адресованы из других модулей.Все не-статические и глобальные переменные попадают в эту категорию.
- Глобальные символы адресованные в коде, но объевленные где-то вне. Все функции и переменные с модификатором extern попадают в эту категорию.
- Локальные символы объявленные и адресованные исключительно во входном модуле. Все статические функции и статические переменные попадают в эту категорию.
Линковщик разрещает адресацию символов путём соотношения каждой ссылки на символ только к одному определению символу из таблицы символов.
8 Линковка статических библиотек
- На каждый следующий входной аргумент линковщик определяет передаётся ли объектный файл или архив. Если это перемещаемый объектный файл, то линковщик добавляет его в набор O, обновляет наборы U и D и переходит к следующему входному аргументу
- Если входной аргумент архив, линковщик сканирует список членов модулей, входящих в архив, чтобы отыскать любые неразрешённые символы, находящиеся в наборе U. Если такие символы находятся, то они добавляются в список O и обновляется список U. Список D дополняется символами, найденными в архиве.
- Когда все входные аргументы пройдены, но если набор U не пуст, то линковщик сообщает об ошибке линковки и завершает свою работу. Иначе, если набор U пуст, линковщик компонует и релоцирует объектные файлы из набора O и генерирует финальный исполняемый файл.
9 Релокация
После того как линковщик разрешил адресацию всех символов, каждый адресация символа ссылается ровно на одно определение символа. В этот момент линковщик запускает процесс релокации, состоящий из двух шагов:
- Релокация секций и определения символов. Линковщик объединяет все секции одного типа в новую секцию. К примеру, линковщик объединяет все секции .data всех входных перемещаемых объектов в новую секцию .data результирующего исполняемого файла. Похожий процесс происходит для секции .code. Затем линковщик указывает текущий адрес памяти для этой сгенерированной секции. Так для каждой секции и символа. После завершения этого шага каждая инструкция и глобальная переменная в прогармме будет иметь уникальный адрес в момент загрузки.
- Релокация адресации символов внутри секций. На этом шаге линковщик изменяет адресации на символы в коде и секциях данных так, чтобы они указывали на корректный уникальный адрес в момент загрузки.
Ассемблер при релокации создаёт секции .relo.text и .relo.data, в которых содержится информация как разрешить адресацию (адрес для обращения к символу). ELF содержит в секциях релокации следующие данные:
- Смещение (offset). Для перемещаемых файлов значение смещения это смещение в байтах от начала секции до получившегося после релокации адреса.
- Символ (symbol). Индекс символа в символьной таблице.
- Тип (type). Тип релокации.
10 Динамическая линковка: разделяемые библиотеки
Статические библиотеки, описанные выше, имеют существенный недостаток. Например, возьмём стандартные функции printf и scanf. Они используются почти что в каждой программе. Пусть на системе запущено 50-100 процессов, каждый процесс содержит свою копию исполняемого кода printf и scanf — это существенный объём затраченной памяти. Разделяемые библиотеки в свою очередь направлены на исправление этого недостатка статических библиотек. Разделяемые библиотеки это объектные модули, которые могут быть загружены в память в момент исполнения программы и после слинкованы с программой. Разделяемые библиотеки (shared libraries) называют так же разделяемые объекты (shared objects). На большинстве систем UNIX они именуются с суффиксом .so; на системах HP-UX — с суфиксом .sl; на системах Microsoft они называются DLL. Чтобы собрать разделяемый объектный файл, компилятор надо вызывать со специальным флагом
Эта команда сообщает компилятору, что надо сгенерировать разделяемую библиотеку libfoo.so, собранную из объектный файлов a.o и b.o. Флаг -fPIC сообщает компилятору, что надо сгенерировать адресо-независимый код (position independent code — PIC). Теперь представим что объектный модуль bar.o зависит от a.o и b.o. В этом случае мы компилируем его так:
Эта команда создаёт исполняемый файл a.out, который будет линковаться с libfoo.so в момент загрузки. Здесь a.out не содержит в себе объектный модулей a.o и b.o, которые были бы включены в него, если бы мы использовали статическую линковку. Исполняемый файл просто содержит некоторую информацию о релокации и таблицу символов, которые позволяют адресоваться к коду и данным в libfoo.so и эта адресация будет разрешена в процессе исполнения (runtime). Таким образом, a.out это не совсем исполняемый файл, который имеет зависимость от libfoo.so. Исполняемый файл содержит секцию .interp, где содержится имя динамического линковщика (который сам является разделяемым объектом в системах Linux — ld-linux.so). Таким образом, когда исполняемый файл загружается в память, загрузчик передаёт управление динамическому линковщику. Динамический линковщик содержит некоторый код, который отображает пространство адресов динамических библиотек на пространство адресов испольняемой программы.
- Происходит релокация кода и данных из libfoo.so в область памяти
- Происходит релокация адресации в a.out на символы объявленные в libfoo.so.
В конце работы динамический линковщик передаёт контроль исполняемой программе. С этого момента местоположение разделяемого объекта зафиксировано в памяти.
11 Загрузка разделяемой библиотеки из приложения
Разделяемая библиотека может быть загружена из приложения в любой момент выполнения. Приложение может обратиться к динамическому линковщику с просьбой загрузить и прилинковать динамическую библиотеку. Linux, Solaris и другие системы поддерживают различниые функции, которые могут быть использованы для динамической загрузки разделяемых объектов. В Linux это системные вызовы dlopen, dlsym, dlclose, используемые для загрузки разделяемого объекта, поиска символа в разделяемом объекте и для закрытия разделяемого объекта.
Источник