Ошибка компиляции gcc со встроенной сборкой: несоответствие типа операнда для ljmp

По какой-то причине следующая встроенная сборка (стиль AT & T / gcc) не работает на недавно установленном 64-разрядном компьютере Debian GNU / Linux; он компилируется и корректно работает на других машинах:

static void INIT_CODE kernel_entry (void) NORETURN;

void _start(void)
{
    // ...other code here...

    asm ("ljmp   %0, %1"
         :
         : "n" (SELECTOR_KERNEL_CODE),
         "p" (&kernel_entry));
}

static void INIT_CODE kernel_entry(void)
{
    // ...
}

Я получаю следующую ошибку компиляции с gcc 7 и 8:

$ gcc-7 -o init.o -Wall -Wextra -Wshadow -Wpointer-arith -Waggregate-return \
    -Wredundant-decls -Winline -Werror -Wcast-align -Wsign-compare -Wmissing-declarations \
    -Wmissing-noreturn -pipe -O0 -fno-builtin -fno-asynchronous-unwind-tables \
    -funsigned-char   -g -fomit-frame-pointer -ffreestanding   -DPACKAGE_NAME=\"storm\" \
    -DPACKAGE_VERSION=\"0.5.1+\" \
    -DREVISION=\"`git rev-list HEAD --max-count 1 --abbrev-commit`\" \
    -DCREATOR=\"`whoami`@`hostname -s`\" --std=gnu99 -Wbad-function-cast \
    -Wmissing-prototypes -Wnested-externs   -Wstrict-prototypes -m32 -I../include \
    -I.. -I. -c init.c 
init.c: Assembler messages:
init.c:151: Error: operand type mismatch for `ljmp'

Я также попытался посмотреть код сборки (скомпилировать с -S), и это имеет смысл, почему он не компилируется:

#NO_APP
        leal    kernel_entry@GOTOFF(%eax), %eax
#APP
# 151 "init.c" 1
        ljmp   $8, %eax
# 0 "" 2

Так не пойдет; инструкция ljmp принимает только два постоянных операнда (т.е. не %eax в качестве второго операнда).

Итак, как я могу заставить gcc это понять? Нужно ли менять pограничение аргумента? Я уже пытался изменить его на n, но вместо этого получаю эту ошибку:

init.c: In function ‘_start’:
init.c:151:5: warning: asm operand 1 probably doesn’t match constraints
     asm ("ljmp   %0, %1"
     ^~~
init.c:151:5: error: impossible constraint in ‘asm’

Спасибо заранее.

Это выглядит подозрительно, как будто у вас включен PIE (возможно, по умолчанию). Попробуйте добавить переключатели -fno-PIC -fno-pic -no-pie в некоторой комбинации. gcc.godbolt.org работает, если я не добавлю -fPIC или -fpic.

Jester 13.09.2018 00:43

Большое спасибо @Jester - добавление -fno-PIC или -fno-pic действительно помогает. Отправлю последующий ответ с более подробной информацией.

Per Lundberg 13.09.2018 21:23
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
1 024
1

Ответы 1

Как предполагается в комментарии, оказалось, что проблема в том, что мой gcc по умолчанию использует ПОС:

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 8.2.0-5' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 8.2.0 (Debian 8.2.0-5) 

Проблема здесь в флаге --enable-default-pie; по умолчанию он включает режим PIC / PIE.

По-видимому, многие дистрибутивы Linux (включая Debian) по умолчанию перешли на позиционно-независимый код из соображений безопасности: https://wiki.debian.org/Harpting/PIEByDefaultTransition

Обходной путь для такого кода (который действительно не работает в позиционно-независимом режиме) - добавить -fno-pic в список аргументов компилятора - это дает нам следующий вывод asm, который работает намного лучше:

# 0 "" 2
        .loc 1 151 0
# 151 "init.c" 1
        ljmp   $8, $kernel_entry
# 0 "" 2

При сборке $kernel_entry может быть разрешен как константа времени компиляции => может быть сгенерирован действительный машинный код для этой инструкции.

Лучшее решение IMHO - создать кросс-компилятор ELF для i686, i386 или x86-64 и набор инструментов и прекратить использование собственного компилятора хоста для работы OSDev.

Michael Petch 13.09.2018 21:37

@MichaelPetch действительно лучше в некоторых аспектах, но большой недостаток: это делает его более неудобным для людей, желающих внести свой вклад в вашу ОС для хобби, поскольку им также нужен тот же кросс-компилятор. Вот почему я сейчас выбрал этот подход - в целом работает нормально. Теперь, если бы кто-то сделал "чистый" пакет .deb кросс-компилятора gcc, это, конечно, было бы круто ...

Per Lundberg 14.09.2018 20:49

Другие вопросы по теме