调用0x16时出现分段错误

问题描述 投票:0回答:1

这是我的nasm代码:

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上

linux interrupt assembly
1个回答
1
投票
int 0x80

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

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

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

在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”+“退格”+“CD”+“输入”,Linux将返回“ACD”+“输入”程序)。

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

然后你打电话给sys_readstdin读。

© www.soinside.com 2019 - 2024. All rights reserved.