Пользовательская компиляция binutils/ld не находит символы в архивах

В настоящее время я пытаюсь скомпилировать Clang/LLVM для голой металлической цели aarch64. Компилировать Clang было просто — на самом деле я скомпилировал для нескольких архитектур, включая arm и aarch64. Для бэкэнда я использую binutils. Поскольку binutils может работать только с одной архитектурой, я создал версии для aarch64 и arm. Снова строительство казалось простым. Я собрал binutils для aarch64, используя:

mkdir build
cd build
../configure --target=aarch64-none-elf
make

из распакованного исходного пакета binutils 2.24.

Проблема, с которой я сталкиваюсь, заключается в том, что я не могу заставить мою пользовательскую сборку ld правильно обрабатывать архивные файлы. Кажется, что он находит и открывает архивные файлы без проблем, но не может найти в них неопределенные символы при компиляции окончательного двоичного файла. Вот некоторые более конкретные детали на примере:

Создайте простой файл main.s, скомпилировав:

int foo();
int main() { return foo(); } 

с Clang и с использованием --target=aarch64 -S, т.е. для создания файла сборки для конкретной архитектуры.

Сделайте то же самое, чтобы создать foo.s, скомпилировав:

int foo() { return 0; }

Соберите оба файла .s в файлы .o, используя специальную сборку газа из binutils.

Создайте архив libfoo.a, запустив пользовательские сборки ar и ranlib из binutils, используя ar cr foo.a foo.s и ranlib libfoo.a.

Попробуйте связать два файла вместе, используя ld -L. -lfoo -o main.elf main.o.

Вывод показывает неопределенную ссылку на foo.

bar.cpp:(.text+0x14): undefined reference to `foo()'

Я могу запустить readelf на foo.a, и он выглядит прекрасно. В частности, я вижу общедоступный символ для foo. Если я запускаю ld с параметром --verbose, я вижу

attempt to open ./libfoo.a succeeded

но нет признаков того, что он нашел какие-либо символы.

Если я напрямую связываюсь с объектными файлами, то есть использую ld -o main.elf foo.o main.o, то я получаю хорошо сформированный файл elf. Кроме того, если я извлеку foo.o обратно из libfoo.a, я также смогу успешно скомпоновать извлеченный foo.o.

У кого-нибудь есть идеи, почему это может происходить? Я почти уверен, что моя сборка clang в порядке, так как выпущенные файлы сборки эффективно отделяют проблему от clang. Я также предполагаю, что собранные файлы .o в порядке. Таким образом, виновником остается только ar/ranlib или ld.

Чтобы попытаться устранить ar/ranlib как виновников, я пересобрал binutils для arm (те же шаги, но с использованием --target=arm-none-eabi). Если я интегрирую встроенные двоичные файлы ar/ranlib в заведомо исправную цепочку инструментов arm-eabi-none GCC, то они, похоже, будут работать правильно. Таким образом, мои подозрения на данный момент указывают на ld. Обратите внимание, что у меня возникает та же проблема с примером main/foo, что и выше, если я использую свою сборку Clang с сборкой binutils для рук.

Я также попытался интегрировать версию ld для руки в существующую хорошо известную цепочку инструментов GCC, но получил:

this linker was not configured to use sysroots

Нужно в этом разобраться. Это все еще немного загадочно для меня прямо сейчас. Это мешает мне проверить работоспособность сборки руки ld.

Вполне может быть, что я делаю что-то явно не так, но сейчас я этого не вижу.

Примечания:

  • Мне пришлось взломать скрипт make для binutils, чтобы добавить пару флагов -Wno-xxx. Мне нужно сделать это "правильным" способом, но я не думаю, что этот хак должен повлиять на результат.

  • Я создаю/размещаю все инструменты на OSX 10.9.4 64-бит.

ОБНОВЛЕНИЕ:

Ошибка по поводу sysroots проста. Ранее существовавшая цепочка инструментов была настроена с помощью флагов:

--with-prefix $SOME_INSTALL_DIR
--with-sysroot $SOME_INSTALL_DIR/arm-none-eabi

Если я пересоберу с ними, то смогу без проблем вставить свою ld-версию, и она будет работать. Я обрадовался, думая, что это могло быть моей ошибкой. Раньше я не запускал make install, так как на данном этапе меня не особо интересовала установка. Я подумал, что, возможно, моя новая сборка ld каким-то образом ссылалась на системные библиотеки/исполняемые файлы OSX (хотя я не уверен, на что именно она могла ссылаться, кроме, возможно, ar, т.е. если она запускает ar для обработки архивов) . Однако у меня все еще есть одна и та же проблема с версиями binutils как для arm, так и для arrach64, даже при такой настройке.


person Andrew Parker    schedule 28.07.2014    source источник


Ответы (1)


Похоже, я слишком много думал о проблеме, а также упустил что-то, чего никогда не понимал в ld. Проблема была со строкой:

 ld -L. -lfoo -o main.elf main.o

Я не знал, что ld чувствителен к порядку объектных файлов/библиотек. Неопределенная ссылка на foo() была в main.o. Я указал библиотеку libfoo.a в качестве входных данных перед разбором main.o. Это означает, что компоновщик не будет искать символ в libfoo.a, так как он уже обработал эту библиотеку. main.o должен быть указан перед, например.

ld -L. main.o -lfoo -o main.elf

Даже обертывание -lfoo с --start-group ... --end-group не решает этого.

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

Время для чашки чая!

person Andrew Parker    schedule 28.07.2014