Как я могу скомпилировать программу Rust с пользовательским llc? - PullRequest
0 голосов
/ 22 октября 2018

У меня есть пользовательский бэкэнд LLVM, и я хочу кросс-компилировать Rust для этой пользовательской цели (nostd).Я хотел бы скомпилировать программы Rust в два этапа:

  1. Использование rustc для генерации IR LLVM.
  2. Использование моих собственных opt и llc для преобразования IR LLVMв машинный код.

Я пытался использовать cargo rustc -- --emit=llvm-ir.Я получаю .ll файлы, а затем использую llc, чтобы получить .o файлы.Затем я кросс-компиляцию libcore таким же образом.Когда я пытаюсь связать все объекты вместе, это говорит мне о неопределенной ссылке.Я использовал один и тот же коммит libcore и rustc.Это кажется проблемой с версиями LLVM, но я не уверен.

1 Ответ

0 голосов
/ 31 мая 2019

Есть пара вещей, о которых вы должны знать.Наиболее важно то, что версия LLVM, которую rustc использует по умолчанию, если вы получаете ее из rustup или диспетчера пакетов дистрибутивов, является / не / актуальной версией LLVM и может фактически не быть совместимой с битовым кодом с конкретной версией llvm.Мы решили эту проблему в моем проекте, создав ржавчину из источника с флагом --llvm-root для настройки.Затем вы можете использовать rustup toolchain link, чтобы связать ваш встроенный rustc с пользовательским набором инструментов rustup.

Во-вторых, вы можете сделать файлы rustr emit .rlib, содержащие битовый код llvm вместо машинного кода, если вы используете хотя бы rustc 1.34 ипередать флаг -C linker-plugin-lto в rustc.Я также написал следующий скрипт, который может распаковать файл rlib, содержащий объектный код, и упаковать его обратно в файл rlib, содержащий битовый код llvm, если вышеуказанный подход не работает для вас.

#!/bin/bash
dir="$(mktemp -d)"
trap "rm -rf $dir" INT TERM EXIT
archive=$(realpath -m $1)
cd "$dir"
ar x "$archive"
rm ./*.rcgu.o
for file in *.bc.z; do
len=`od -An -t u4 -j 15 -N4 $file`
blen=`od -An -t u8 -j $((len+19)) -N8 $file`
tail -c+$((len+28)) $file | head -c $blen > $file.bc.gz
printf "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00" |cat - $file.bc.gz |gzip -dc > ${file%.bc.z}.o
done
rm *.bc.z
rm *.gz
rm "$archive"
llvm-ar rs "${archive}" ./*

После того, как вы получитеRlib-файлы, вы можете использовать любой инструмент llvm toolchain для них так же, как и для .a-файла, содержащего битовый код llvm.

С точки зрения выполнения окончательной ссылки, следует помнить несколько вещей.,Во-первых, rustc автоматически генерирует символы __rust_alloc, __rust_alloc_zeroed, __rust_dealloc и __rust_realloc и указывает на них либо __rg_alloc (и аналогичные __rg_ символы соответственно), что является реализацией GlobalAlloc, которая использует jemalloc bydefault или __rdl_alloc (и аналогичные __rdl_ символы соответственно), который является системным распределителем, работающим на libc malloc.Вам придется реализовать эти символы самостоятельно, если вы не используете rustc для окончательной ссылки.

Во-вторых, libstd и libcore зависят от некоторых других библиотек, с которыми вам также, вероятно, придется ссылаться.В зависимости от того, какой сегмент стандартной библиотеки вы используете, вы можете обнаружить, что требуются разные наборы библиотек, поэтому я не могу помочь вам без конкретного сообщения об ошибке, но я могу вам сказать, что список библиотек, которые мое приложениев итоге потребовалось было, по порядку: std, core, alloc, unwind, compiler_builtins, panic_abort, backtrace_sys, rustc_demangle.Если вы используете panic = unwind, вам, очевидно, придется использовать это вместо этого.Если вы обнаружите, что у вас все еще отсутствуют символы, я бы предложил использовать nm, чтобы найти библиотеку, содержащую отсутствующий символ, и выяснить, где он находится в порядке компоновщика с методом проб и ошибок.

Надеюсь, это поможет, поскольку ямы потратили немало усилий на разработку решения именно этой проблемы (хотя и не в целях кросс-компиляции).

...