Я пытаюсь перенести некоторый код Linux C на Apple M1 Mac и столкнулся с проблемой с некоторой встроенной сборкой. И это ставит меня в тупик.
У меня есть следующий встроенный блок сборки:
#define TEST asm volatile(\
"adr x0, label9 \n"\
: : : "x0");
И столкнулся со следующей ошибкой:
test.c:73:5: error: unknown AArch64 fixup kind!
TEST
^
./ARM_branch_macros.h:2862:7: note: expanded from macro 'TEST'
"adr x0, label9 \n"\
^
<inline asm>:1:2: note: instantiated into assembly here
adr x0, label9
^
1 error generated.
make: *** [indirect_branch_latency.o] Error 1
Я использую следующий компилятор:
Apple clang version 12.0.0 (clang-1200.0.32.27)
Target: arm64-apple-darwin20.1.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
С помощью командной строки:
clang -c -o test.o test.c -I. -w -g -lrt -O0 -static -DARM_ASSEMBLY
Любая помощь будет принята с благодарностью!
Инструкция ADR сохраняет смещение от текущего значения PC до метки, на которую вы ссылаетесь.
Когда у вас есть инструкция, которая ссылается на символ в другом объектном файле (или в другом разделе того же объектного файла), ассемблер не может напрямую закодировать точное смещение, поскольку он не знает, как компоновщик их разместит. , но должен оставить перемещение в объектном файле, предписывая компоновщику исправить инструкцию, как только станет известно точное местоположение символа.
Я думаю, что проблема здесь просто в том, что формат объектного файла MachO (который используется на платформах Apple) не имеет типа перемещения для исправления инструкции ADR, указывающей на символ в другом месте. И даже если бы он имел это, конструкция довольно хрупкая - символ, на который он указывает, должен быть в пределах +/- 1 МБ от инструкции, ссылающейся на него - это предел, который довольно легко достичь.
Чтобы получить доступ к большему диапазону, часто используется пара инструкций ADRP+ADD, которая дает вам диапазон +/- 4 ГБ, и формат MachO поддерживает их.
Синтаксис ассемблера для них немного отличается между MachO и ELF (и COFF). Для MachO синтаксис выглядит так:
adrp x0, symbol@PAGE
add x0, x0, symbol@PAGEOFF
Или, если вы хотите загрузиться с него одновременно:
adrp x0, symbol@PAGE
ldr x1, [x0, symbol@PAGEOFF]
На платформах ELF (формат объектного файла, используемый в Linux) и COFF (Windows, при сборке сборки в стиле GNU с LLVM) синтаксис выглядит следующим образом:
adrp x0, symbol
add x0, x0, :lo12:symbol
В качестве дополнения: clang поддерживает «Подсказки по оптимизации компоновщика», которые позволяют, например, включить.
adrp
+add
в простоadr
+nop
во время компоновки, если это позволяет относительное смещение. Это делается путем присвоения обеим инструкциям метки, а затем включения директивы сборки.loh AdrpAdd L1, L2
. Информация об этой функции кажется скудной, но в источнике clang есть несколько полезных комментариев.