#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. ОС предотвращает это. Задача ядра состоит в том, чтобы помешать вам выполнять действия, которые могут помешать работе системы или другим процессам, если вы не уполномочены на это. Для запуска
cli
иhlt
вам нужно быть root и иметь права ввода-вывода
Ответ №1:
У вас есть два вопроса:
-
Что мешает этому коду компилироваться таким образом и выполняться?
Ничто не мешает его сборке, потому что это допустимый код.
Причина, по которой он не запускается / выдает ошибку сегментации, заключается в том, что вы пытаетесь выполнить инструкции, требующие определенных привилегий в пользовательском режиме.Посмотрите на HLT, в описании которого указано
Инструкция HLT является привилегированной инструкцией.
Также посмотрите на CLI / STI, ситуация с которым сложнее (что объясняется в приведенной ниже статье и комментариях ниже), но также в основном полезна для кода режима ядра. Википедия говорит
Во всех трех случаях только привилегированные приложения (обычно ядро ОС) могут изменять IF [Флаг прерывания]. […] CLI и STI [также] являются привилегированными инструкциями, которые вызывают общую ошибку защиты, если непривилегированное приложение пытается ее выполнить, […]
Это должно ответить на ваш вопрос о разнице между этими двумя инструкциями и о том, почему HLT обязательно генерирует ошибку GPF (ошибка общей защиты), выполняемую в пользовательском режиме.
-
Как этот код может быть скомпилирован и запущен?
Единственный способ запустить этот код — в привилегированном режиме. Итак, в Windows или Linux вам придется закодировать драйвер ядра или закодировать свою собственную ОС, чтобы разумно использовать эти инструкции.
Вышесказанное относится только к защищенному режиму или длинному коду режима.
(Код реального режима всегда может изменять IF, флаг прерывания)
Комментарии:
1. CLI проверяет IOPL. Для этого вам не нужно находиться в ring0. По-видимому, вы делаете для HLT.
2. Linux дает вам
iopl()
. Тем не менее, это не будет работать для HLT.3. Привилегированный пользователь в Linux может вызвать функцию
iopl
и установить для нее значение 3CLI
, а затемSTI
можно использовать и man7.org/linux/man-pages/man2/iopl.2.html .HLT
хотя на него не влияет IOPL и вызовет #GP, если CPL ! = 0.4. Майкл. Спасибо за комментарий. 🙂 Исследуя случай CPL (текущий уровень привилегий), я наткнулся на таблицу с именем GDTR. Не могли бы вы порекомендовать эмулятор для запуска этих системных инструкций?