Ошибка сегментации при вызове 0x16 - PullRequest
0 голосов

Вот часть моего кода нации:

extern printf

%macro print 2
        mov  rdi, %1
        mov  rsi, %2
        mov  rax, 0
        call printf
%endmacro

section .data

        msg1:   db 'Nasm', 0
        len1:   equ $ - msg1
        fmts:   db "%s", 10, 0 ; printf format string 
        fmti:   db "%d", 10, 0

section .bss           ;Uninitialized data
   num resb 5

section  .text
        global main    ; declaring for gcc
main:
        push    rbp            ; save rbp

        print   fmts, msg1
        xor     ah, ah
        int     0x16
        print   fmti, [num]

exit:
        leave
        mov     rax,1       ;system call number (sys_exit)
        int     0x80        ;call kernel

Выход:

[b@l .K]$ nasm test.asm -f elf64 -o test.o && gcc test.o -o test && ./test
Nasm
Segmentation fault (core dumped)

Когда я заменяю:

        print   fmts, msg1
        print   fmti, [num]
        xor     ah, ah
        int     0x16

1010 * тогда *

[b@l .K]$ nasm test.asm -f elf64 -o test.o && gcc test.o -o test && ./test
Nasm
0
Segmentation fault (core dumped)

int 0x80 работает очень хорошо, но 0x16 сокрушает мой код. Я на fedora 29, Intel Core i5

1 Ответ

1 голос
/ 14 апреля 2019
int 0x80

Инструкции int, sysenter и syscall являются специальными вариантами инструкции call:

Эти инструкции вызывают специальную функцию, так называемый «обработчик».

int 0x80 - это обработчик в операционной системе Linux, предназначенный для 32-битных программ Linux. Вызов int 0x80 из 64-битных программ (и ваша программа, очевидно, является 64-битной) может работать, но может также не работать.

В 64-битном Linux вы используете syscall вместо int 0x80. Системный вызов exit должен (*) выглядеть следующим образом:

mov $60, %rax  # In 64-bit Linux sys_exit is 60, not 1
mov $0, %rdi   # Exit code; this would be %ebx in 32-bit Linux
syscall

int 0x16 - это обработчик в BIOS. Вы можете вызывать обработчики BIOS только из 16-битных программ реального режима (**). Вы не можете вызвать этот обработчик ни из 32-, ни из 64-битных программ.


(*) К сожалению, я написал программы на ассемблере только для 32-битного Linux, поэтому я не уверен, что это правильно.

(**) CPU поддерживает два разных режима работы при выполнении 16-битного кода. Обработчики BIOS будут работать только в одном из этих двух режимов.


ждать клавиатуры

В Linux нет явных функций клавиатуры.

Вы должны использовать функции termios, чтобы переключить поведение дескриптора файла stdin (дескриптор файла 0). В ассемблере это будет сделано вызовом sys_ioctl.

По умолчанию Linux обрабатывает ввод по линии (например, если вы нажмете «AB» + «backspace» + «CD» + «enter», Linux вернет «ACD» + «enter» программе) .

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

Затем вы звоните sys_read, чтобы прочитать с stdin.

...