Как системные инструкции Intel могут выполняться в Linux?

#linux #assembly #x86 #segmentation-fault

#linux #сборка #x86 #ошибка сегментации

Вопрос:

Использование процессора i5 7-го поколения, nasm, ld.

Написанная с использованием регистров общего назначения и системных вызовов, программа работает в Ubuntu. Примером может служить простая программа hello world.

 global _start


section .text
    _start:

        mov eax, 0x4                ; write(int fd, char *buf, int len)
        mov ebx, 0x1                ; fd
        mov ecx, message            ; *buf
        mov edx, message_length     ; len
        int 0x80                    ; syscall

        mov eax, 0x1                ; exit(int status)
        mov ebx, 0x0                ; status
        int 0x80                    ; syscall
    



section .data
    message db "hello world", 0xA
    message_length equ $-message
  
 nasm -f elf64 -o hello_world.o hello_world.s
ld hello_world.o -o hello_world
./hello_world
  

вывод: hello_world

Однако программа, написанная с использованием системных инструкций Intel, не работает.

 global _start



section .text
    _start:
        CLI
        HLT
  
 nasm -f elf64 halt.s -o halt.o
ld halt.o -o halt
./halt
  

вывод: Segmentation fault (core dumped)

  1. Что мешает этому коду компилироваться таким образом и выполняться?
  2. Как этот код может быть скомпилирован и запущен?

Комментарии:

1. ОС предотвращает это. Задача ядра состоит в том, чтобы помешать вам выполнять действия, которые могут помешать работе системы или другим процессам, если вы не уполномочены на это. Для запуска cli и hlt вам нужно быть root и иметь права ввода-вывода

Ответ №1:

У вас есть два вопроса:

  1. Что мешает этому коду компилироваться таким образом и выполняться?

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

    Посмотрите на HLT, в описании которого указано

    Инструкция HLT является привилегированной инструкцией.

    Также посмотрите на CLI / STI, ситуация с которым сложнее (что объясняется в приведенной ниже статье и комментариях ниже), но также в основном полезна для кода режима ядра. Википедия говорит

    Во всех трех случаях только привилегированные приложения (обычно ядро ОС) могут изменять IF [Флаг прерывания]. […] CLI и STI [также] являются привилегированными инструкциями, которые вызывают общую ошибку защиты, если непривилегированное приложение пытается ее выполнить, […]

    Это должно ответить на ваш вопрос о разнице между этими двумя инструкциями и о том, почему HLT обязательно генерирует ошибку GPF (ошибка общей защиты), выполняемую в пользовательском режиме.

  2. Как этот код может быть скомпилирован и запущен?

    Единственный способ запустить этот код — в привилегированном режиме. Итак, в Windows или Linux вам придется закодировать драйвер ядра или закодировать свою собственную ОС, чтобы разумно использовать эти инструкции.

Вышесказанное относится только к защищенному режиму или длинному коду режима.
(Код реального режима всегда может изменять IF, флаг прерывания)

Комментарии:

1. CLI проверяет IOPL. Для этого вам не нужно находиться в ring0. По-видимому, вы делаете для HLT.

2. Linux дает вам iopl() . Тем не менее, это не будет работать для HLT.

3. Привилегированный пользователь в Linux может вызвать функцию iopl и установить для нее значение 3 CLI , а затем STI можно использовать и man7.org/linux/man-pages/man2/iopl.2.html . HLT хотя на него не влияет IOPL и вызовет #GP, если CPL ! = 0.

4. Майкл. Спасибо за комментарий. 🙂 Исследуя случай CPL (текущий уровень привилегий), я наткнулся на таблицу с именем GDTR. Не могли бы вы порекомендовать эмулятор для запуска этих системных инструкций?