Включает в себя Linux GCC Linker - PullRequest
       7

Включает в себя Linux GCC Linker

5 голосов
/ 02 декабря 2008

Я не понимаю, как GCC работает под Linux. В исходном файле, когда я делаю:

#include <math.h>

Извлекает ли компилятор соответствующий двоичный код и вставляет ли он в скомпилированный исполняемый файл ИЛИ вставляет ли компилятор ссылку на внешний двоичный файл (а-ля Windows DLL?)

Я предполагаю, что общая версия этого вопроса такова: существует ли эквивалентная концепция библиотекам Windows в * nix?

Ответы [ 5 ]

25 голосов
/ 02 декабря 2008

Хорошо. Когда вы включаете math.h, компилятор будет читать файл, содержащий объявления функций и макросов, которые можно использовать. Если вы вызываете функцию, объявленную в этом файле ( header ), то компилятор вставляет инструкцию вызова в это место в вашем объектном файле, который будет сделан из файла, который вы компилируете (давайте назовем его test.c и объектный файл создан test.o). Он также добавляет запись в таблицу перемещений этого объектного файла:

Relocation section '.rel.text' at offset 0x308 contains 1 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0000001c  00000902 R_386_PC32        00000000   bar

Это будет запись перемещения для функциональной панели. Будет сделана запись в таблице символов, отметив, что функция еще не определена:

9: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND bar

Когда вы связываете объектный файл test.o с программой, вам нужно связать ее с математической библиотекой с именем libm.so. Расширение so аналогично расширению .dll для Windows. Это означает, что это общий объектный файл . При компиляции компилятор исправит все места, которые появляются в таблице перемещений test.o, заменив свои записи соответствующим адресом функции bar. В зависимости от того, используете ли вы совместно используемую версию библиотеки или статическую (тогда она называется libm.a), компилятор сделает это исправление после компиляции или позже, во время выполнения, когда вы фактически запускаете свою программу. Когда закончите, он вставит запись в таблицу общих библиотек, необходимых для этой программы. (можно показать с помощью readelf -d ./test):

Dynamic section at offset 0x498 contains 22 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libm.so.6]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 ... ... ...

Теперь, если вы запустите вашу программу, динамический компоновщик найдет эту библиотеку и свяжет эту библиотеку с вашим исполняемым образом. В Linux эта программа называется ld.so. Статическим библиотекам нет места в динамическом разделе, поскольку они просто связаны с другими объектными файлами, и о них забывают; с тех пор они являются частью исполняемого файла.

На самом деле все гораздо сложнее, и я также не понимаю этого в деталях. Это грубый план.

8 голосов
/ 02 декабря 2008

Здесь задействовано несколько аспектов.

Сначала заголовочные файлы . Компилятор просто включает содержимое файла в том месте, где он был включен, и ничего более. Насколько я знаю, GCC даже не обрабатывает стандартные заголовочные файлы по-другому (но я могу ошибаться).

Однако заголовочные файлы могут фактически не содержать реализацию, только ее объявление. Если реализация находится где-то еще, вы должны сообщить об этом компилятору / компоновщику. По умолчанию вы делаете это, просто передавая соответствующие библиотечные файлы компилятору или передавая имя библиотеки. Например, следующие два эквивалента (при условии, что libcurl.a находится в каталоге, где его может найти компоновщик):

gcc codefile.c -lcurl
gcc codefile.c /path/to/libcurl.a

Это говорит редактору ссылок («компоновщик») связать ваш файл кода с реализацией статической библиотеки libcurl.a (компилятор gcc фактически игнорирует эти аргументы, потому что не знает что с ними делать, и просто передает их компоновщику). Однако это называется статическое связывание . Также есть динамическое связывание , которое происходит при запуске вашей программы и происходит с .dll s в Windows (тогда как статические библиотеки соответствуют .lib файлам в Windows). Файлы динамических библиотек в Linux обычно имеют расширение .so.

Лучший способ узнать больше об этих файлах - это ознакомиться с компоновщиком GCC ld, а также с отличным набором инструментов binutils, с помощью которого вы можете редактировать / просматривать файлы библиотеки. без усилий (любые файлы с двоичным кодом, на самом деле).

2 голосов
/ 02 декабря 2008

Существует ли эквивалентная концепция библиотекам Windows в * nix?

Да, они называются «Общие объекты» или .so файлы. Они динамически связаны с вашим двоичным файлом во время выполнения. В Linux вы можете использовать команду «ldd» в вашем исполняемом файле, чтобы увидеть, с какими общими объектами связан ваш двоичный файл. Вы можете использовать ListDLL из sysinternals, чтобы выполнить то же самое в Windows.

1 голос
/ 02 декабря 2008

Есть. Включение делает текстовое включение файла заголовка (который является стандартным поведением C / C ++). То, что вы ищете, это компоновщик . Аргумент -l для gcc / g ++ сообщает компоновщику, в какую библиотеку (и) нужно добавить. Для математики (libm.so) вы должны использовать -lm. Общий шаблон:

  • исходный файл: #include
  • командная строка gcc / g ++: -lfoo
  • общая библиотека: libfoo.so

math.h - небольшая вариация на эту тему.

1 голос
/ 02 декабря 2008

Компилятору разрешено делать все, что ему угодно, при условии, что он действует так, как если бы вы включили файл. (Все известные мне компиляторы, включая GCC, просто включают файл с именем math.h.)

И нет, обычно оно не содержит определения самой функции. Это libm.so, «общий объект», похожий на Windows .DLL. Он должен быть в каждой системе, так как он является компаньоном libc.so, среды выполнения C.

Редактировать: И именно поэтому вы должны передать -lm компоновщику, если вы используете математические функции - он указывает ему связать с libm.so.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...