Неопределенная ссылка при связывании файла .o с файлом .elf - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть файл .o, скомпилированный из проекта C , который ссылается на функцию с именем init_static_pools. Я использую objdump -t, чтобы показать информацию о его символах:

00000000 UND 00000000 init_static_pools

Согласно этому потоку , UND просто говорит: " Мне нужен кто-то еще, чтобы предоставить мне эту функцию ".

Поэтому я связал этот файл .o с файлом .elf,который содержит определение init_static_pools. objdump -t показывает, что символ действительно в этом файле:

00004dcf g F .text 00000048 init_static_pools

В соответствии с этим потоком флаги g и F означают, что это глобальная функция . Я думаю, это означает, что эта функция может быть статически связана .

Я попытался связать файл .o и .elf с командной строкой ниже:

/ usr / bin / c ++ -m32 -rdynamic unittest1.o -o unittest1 target.elf lib / libgtest.a lib / libgtest_main.a -lpthread

Я получил ошибку ниже:

unittest1.cc :(. Text + 0x2d): неопределенная ссылка на `init_static_pools '

Функциятолько в файле .so, почему он не может быть связан?

Может ли это быть связано с различными механизмами разрешения символов между динамической и статической связью? Потому что я использую objdump -f и вижу, что target.elf является динамическим объектом. Как показано ниже:

target.elf: формат файла elf32-i386

архитектура: i386, флаги 0x00000150:

HAS_SYMS, DYNAMIC , D_PAGED

начальный адрес 0x00001144

ADD 1 - 9:17 AM 11/6/2019

На основании комментария @ EmployedRussian , Я пробовал readelf.

Для target.elf он содержит только 1 строку, говоря:

486: 00004dcf 72 FUNC GLOBAL DEFAULT 13 init_static_pools

Для unittest1.o он содержит 2 строки:

0000002d 0000fb04 R_386_PLT32 00000000 init_static_pools

и

251: 00000000 0 NOTYPE GLOBAL DEFAULT UND init_static_pools

А для завершения их заголовки:

target.elf:

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x1144
  Start of program headers:          52 (bytes into file)
  Start of section headers:          246936 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         43
  Section header string table index: 42

unittest1.o:

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          36988 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         262
  Section header string table index: 261

Пока что я не могу пока определить причину сбоя связи. К счастью, я только что нашел series на компоновщике Ian Lance Taylor . Надеюсь, что это может просветить меня. Но это займет некоторое время.

ADD 2 - 10:33 AM 11/6/2019

Основываясь на ответе @ EmployedRussian, я попробовал следующие команды:

nm    target.elf | grep init_static_pools
nm -D target.elf | grep init_static_pools

Как и подозревал @EmployedRussian, вторая командная строка не имеет вывода. Это означает, что target.elf не экспортирует init_static_pools в свою таблицу динамических символов, и это делает символ непригодным для ссылки из-за пределов target.elf.

Ниже приведены некоторые связанные флагик связыванию target.elf:

-Wl,-T zephyr/linker.cmd  (this is quite long, but it seems to be mostly layout info)

-Wl,-Map=target_prebuilt.map

-Wl,--whole-archive

-Wl,--gc-sections

-Wl,--build-id=none

-Wl,--sort-common=descending

-Wl,--sort-section=alignment

-ldl

-lm

Или я должен также проверить флаги компиляции?

И я нашел - export-all-symbols , - export-dynamic , - gc-keep-export опции, я их пробую.

Кажется, --export-all-symbols игнорируется. Я предполагаю, что это предназначено для DLL.

Я положил --export-dynamic и --gc-keep-exported вместе, и сборка может пройти. Но nm -D все еще показывает следующее сообщение:

target.elf: без символов

ADD 3 - 11:16 11/6/2019

Статья о динамической таблице символов (.dynsym) и таблице символов (.symtab). https://blogs.oracle.com/solaris/inside-elf-symbol-tables-v2

Некоторая цитата:

Фактически, во времена, предшествующие разделяемым библиотекам и динамическим связям, ни одна из них не была необходима во время выполнения. Был один, неразмещаемыйтаблица символов (разумно названная "symtab"). Когда в систему было добавлено динамическое связывание, первоначальные разработчики столкнулись с выбором: сделать выделенную symtab или предоставить вторую меньшую выделяемую копию. Символы, необходимые во время выполнения, представляют собой небольшое подмножество от общего числа, поэтому вторая таблица символов экономит виртуальную память в процессе выполнения. Это важное соображение. Следовательно, вторая таблица символов была изобретена для динамического связывания и, следовательно, названа "dynsym".

Итак, я думаю, что .dynsym предназначен для динамического связывания во время выполнения . Но я думаю, что ожидаю, что мои unittest1.o и target.elf будут статически связаны во время сборки .

Так что это подводит меня к следующему вопросу: Могу ли я статически ссылаться на файл .ELF? В Windows я обычно статически связываюсь с файлом .lib, а не с .DLLфайл. Файл .ELF здесь больше похож на .DLL. И, кстати, мой процесс сборки также генерирует файл libtarget.a. Стоит ли использовать его вместо target.elf?

К сожалению, я пробовал nm -t и readelf -s на libtarget.a, ни один из них не показывает существования init_static_pools.

BTWЕсли вы знаете что-то о моей проблеме, не стесняйтесь, напишите намек. Спасибо!

1 Ответ

1 голос
/ 06 ноября 2019

Для target.elf он содержит только одну строку, говоря:
486: 00004dcf 72 FUNC GLOBAL DEFAULT 13 init_static_pools

К сожалению, этого все еще недостаточно, чтобы точно сказать, что происходит.

Чтобы точно сказать, выполните эти две команды:

nm    target.elf | grep init_static_pools
nm -D target.elf | grep init_static_pools

Я подозреваю, что первая команда выдаст вывод, а вторая - нет.

Если этов этом случае target.elf - это , а не , экспортирующий init_static_pools в свою динамическую таблицу символов, и это делает символ непригодным для ссылки из-за пределов target.elf.

Что касается того, какВы закончили тем, что этот символ не был экспортирован, я могу только догадываться (так как вы не предоставили команду ссылки, используемую для его связывания). Скорее всего, вы используете скрипт компоновщика, который его скрывает.

...