调用0x16时出现分段错误

时间:2019-04-14 11:26:47

标签: linux interrupt assembly

这是我的鼻祖代码:

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

然后

[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,英特尔酷睿i5

1 个答案:

答案 0 :(得分:1)

int 0x80

intsysentersyscall指令是call指令的特殊变体:

这些指令调用一个特殊功能,即所谓的“处理程序”。

int 0x80是Linux操作系统中用于32位Linux程序的处理程序。从64位程序(您的程序显然是64位)中调用int 0x80可能有效,但也可能无效。

在64位Linux中,您使用syscall而不是int 0x80exit系统调用应(*)如下所示:

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中的处理程序。您只能从16位实模式(**)程序调用BIOS处理程序。您不能从32位程序或64位程序中调用此处理程序。


(*)不幸的是,我只为32位Linux编写了汇编程序,所以我不确定这是否正确。

(**)执行16位代码时,CPU支持两种不同的操作模式。 BIOS处理程序只能在这两种模式之一中工作。


  

等待键盘

在Linux中,没有显式的键盘功能。

您必须使用termios函数来切换stdin文件句柄(文件句柄0)的行为。在汇编器中,这将通过sys_ioctl调用来完成。

默认行为是Linux按行处理输入(例如,如果您按“ AB” +“ backspace” +“ CD” +“ enter”,Linux将向程序返回“ ACD” +“ enter”)

默认行为也是sys_read将等待直到有一些数据可用。使用termios,您可以通过以下方式更改此行为:将所有键盘按键都返回给程序和/或sys_read将不等待输入。

然后您致电sys_read来读取stdin