Компиляция кода GAS не обнаруживает параметр -fPIC

Я пытаюсь скомпилировать код GAS для проекта с помощью компилятора GCC gnu. Вот как я его компилирую:

gcc -c boot.s -o boot.o -fPIC

После компиляции файла kernel.c с аргументом -fPIC я пытаюсь связать его с помощью этой команды:

gcc -N -T linker.ld -o Slack\ Berry.bin -ffreestanding -nostdlib kernel.o boot.o -lgcc

Получается:

/usr/bin/ld: boot.o: relocation R_X86_64_32 against '.multiboot' can not be used when making a PIE object; recompile with -fPIC

Это заставляет меня думать, что мой код GAS не компилируется с -fPIC. Как я могу это исправить?


person Sushila Jyothi Lévêque    schedule 13.11.2018    source источник


Ответы (2)


Прежде всего, вам, вероятно, понадобится -fPIE, а не -fPIC. -fPIE позволяет компилятору генерировать более эффективный код, но может использоваться только для кода, который является частью основного исполняемого файла (не разделяемой библиотеки).

Теперь и -fPIC, и -fPIE являются флагами только для компилятора и не передаются ассемблеру. Вам нужно будет явно использовать мнемонику, специфичную для PIC, в коде сборки вместо зависимых от позиции вызовов и ветвей, например, вместо

movq $bar, %rdx

использовать

movq bar@GOTPCREL(%rip), %rdx

(обычно, чтобы получить нужный мне синтаксис, я просто запускаю gcc -fPIE -S -o- для соответствующего фрагмента C).

person yugr    schedule 14.11.2018
comment
ОП создает PIE, а не общую библиотеку; им не нужны GOT или PLT для внутренних статических символов. Единственное необходимое изменение — это lea bar(%rip), %rdx, LEA, относящийся к RIP, вместо mov $imm32, %r64. (movabs подойдет, но будет больше и обычно медленнее.) - person Peter Cordes; 14.11.2018
comment
@PeterCordes Спасибо, я сделаю обновление. Я думаю, что вопрос также должен быть обновлен. - person yugr; 14.11.2018
comment
Почему, как вы думаете, чего не хватает в вопросе? У него есть -ffreestanding -nostdlib и такие имена, как boot.o, и упоминается мультизагрузка. Также в сообщении об ошибке упоминается создание исполняемого файла PIE. Мне кажется довольно ясным, что ОП на самом деле не пытался создать общую библиотеку. (Это не первый вопрос об этом сообщении об ошибке при создании исполняемого файла из asm, поэтому я вовсе не ожидал, что вопрос будет о фактическом создании общих библиотек. Обычно это просто PIE, требующий перемещаемого в любом месте кода, ловящего людей сюрприз.) - person Peter Cordes; 14.11.2018
comment
@PeterCordes Ну, почему бы не сделать вещи более явными, если это возможно? - person yugr; 14.11.2018
comment
Я думаю, может быть. Я пропустил, что они на самом деле скомпилировали свой kernel.c с -fPIC, поэтому код, вероятно, зависит от PLT и GOT, если только они не использовали осторожно __attribute__((hidden)). Вы определенно не хотите проходить через GOT/PLT для вызовов/ссылок внутри одного и того же объекта. - person Peter Cordes; 14.11.2018
comment
@PeterCordes Да, я разработал ShlibVisibilityChecker специально для этого. К сожалению, я обнаружил, что сопровождающие пакетов обычно не очень заботятся об избавлении от ложных ссылок GOT/PLT... - person yugr; 14.11.2018

Повторная компиляция с -fPIC применяется только в том случае, если asm был сгенерирован компилятором, а не написан вручную. Это не влияет на то, как asm собирается в машинный код.

Проблема в том, что ваш исполняемый файл PIE не может быть связан с 32-битными абсолютными адресами. (Вы имели в виду сделать PIE вместо статического исполняемого файла, зависящего от позиции)?

Вам не нужен полный материал общей библиотеки для ссылки на символы в другой библиотеке или в основном исполняемом файле (например, ответ @yugr показывает, как это сделать). Ваше автономное ядро ​​может даже не иметь GOT или PLT, и определенно не должно использовать их для внутренних символов.

Единственное необходимое изменение – это lea bar(%rip), %rdx, связанный с RIP LEA вместо mov $imm32, %r/m64. (movabs подойдет, но будет больше и обычно медленнее.)

Или, если вы на самом деле собирались с -static и создали исполняемый файл, который будет загружаться по фиксированному адресу в младших 32 битах адресного пространства, вы должны использовать mov $bar, %edx для получения 5-байтовой кодировки mov $imm32, %r32 вместо 7-байтовой mov $sign_extended_imm32, %r/m64 или 7-байтовый LEA. См. также Разницу между movq и movabsq в x86-64

person Peter Cordes    schedule 14.11.2018