Linux NASM OUTSB SEGFULT
我正在尝试将字节Linux NASM OUTSB SEGFULT,linux,assembly,segmentation-fault,nasm,ioports,Linux,Assembly,Segmentation Fault,Nasm,Ioports,我正在尝试将字节0xff写入位于0x378的并行端口。它编译和链接时不会出现问题,但在OUTSB指令中会出现故障 section .text global _start _err_exit: mov eax, 1 mov ebx, 1 int 80h _start: mov eax, 101 ; ioperm mov ebx,
0xff
写入位于0x378
的并行端口。它编译和链接时不会出现问题,但在OUTSB
指令中会出现故障
section .text
global _start
_err_exit:
mov eax, 1
mov ebx, 1
int 80h
_start:
mov eax, 101 ; ioperm
mov ebx, 0x378 ; Parallel port addr
mov ecx, 2 ; number of bytes to 'unlock'
mov edx, 1 ; enable
int 80h
mov esi, 0xff
mov dx, 0x378
outsb
mov eax, 1 ; exit
mov ebx, 0
int 80h
如果我使用GDB单步执行,并在OUTSB
指令之前检查寄存器,那么DX寄存器中看起来没有任何内容?还是32位的dx
=edx
(gdb) info registers
eax 0x0 0
ecx 0x2 2
edx 0x378 888
ebx 0x378 888
esp 0xffffd810 0xffffd810
ebp 0x0 0x0
esi 0xff 255
edi 0x0 0
eip 0x8048090 0x8048090 <_start+36>
eflags 0x246 [ PF ZF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x0 0
该代码存在许多问题。首先,您似乎忘记了
OUTSB
是一条特权指令,即只有在调用进程具有环0访问权限时才能执行,即它是内核代码的一部分。据我所知,Linux中唯一可以访问特权指令的代码是内核本身及其加载的模块。当您试图从非特权代码段执行特权指令时,所有其他进程都会给您一个分段故障
(实际上是CPU发出的一般保护故障
)。不过,我不知道调用ioperm
syscall如何影响这一点
其次,OUTSB
将一个字节从ESI
指定的内存位置写入DX
中的I/O端口。在本例中,您告诉处理器从位置0xff
将数据写入端口,而进程肯定无法访问该端口。您可以通过简单地将代码更改为使用OUT
指令来简化这一过程,因为OUTSB
与REP
前缀一起使用。试试这个:
mov al, 0xff
out 0x378, al
这会将al
中的字节输出到立即数操作数指定的I/O端口,在本例中为0x378
让我知道结果如何。该代码存在许多问题。首先,您似乎忘记了
OUTSB
是一条特权指令,即只有在调用进程具有环0访问权限时才能执行,即它是内核代码的一部分。据我所知,Linux中唯一可以访问特权指令的代码是内核本身及其加载的模块。当您试图从非特权代码段执行特权指令时,所有其他进程都会给您一个分段故障
(实际上是CPU发出的一般保护故障
)。不过,我不知道调用ioperm
syscall如何影响这一点
其次,OUTSB
将一个字节从ESI
指定的内存位置写入DX
中的I/O端口。在本例中,您告诉处理器从位置0xff
将数据写入端口,而进程肯定无法访问该端口。您可以通过简单地将代码更改为使用OUT
指令来简化这一过程,因为OUTSB
与REP
前缀一起使用。试试这个:
mov al, 0xff
out 0x378, al
这会将al
中的字节输出到立即数操作数指定的I/O端口,在本例中为0x378
让我知道结果如何。另一个注意事项:我刚刚修订了一些英特尔手册,显然可以将各个I/O端口的权限授予各个任务。这需要在操作系统中使用TSS(任务状态段)结构,我不确定Linux是否在每个进程中都使用它。但是
OUTSB
在这种情况下使用不当,因为它会导致从进程地址空间之外的内存区域进行读取。@Daniel我编辑了我的帖子-程序的C版本可以工作(在userland中以root用户身份运行时)。sys/io.h
中定义了outb()
函数<代码>静态uuu内联void outb(无符号字符值,无符号短整数端口){uuuu asm_uuuuuvolatile_uuu(“outb%b0,%w1”)::“a”(uuu值),“Nd”(uuu端口))感谢更新!显然,ioperm
以某种方式修改了任务的I/O权限端口映射,并允许它执行特权I/O指令。@tMC:useout dx,al
。根据您自己的引用,on OUT::目标操作数可以是字节立即数或DX寄存器。使用字节立即数允许访问I/O端口地址0到255;使用DX寄存器作为源操作数,可以访问0到65535之间的I/O端口。另一方面,我刚刚修订了一些英特尔手册,显然可以将各个I/O端口的权限授予各个任务。这需要在操作系统中使用TSS(任务状态段)结构,我不确定Linux是否在每个进程中都使用它。但是OUTSB
在这种情况下使用不当,因为它会导致从进程地址空间之外的内存区域进行读取。@Daniel我编辑了我的帖子-程序的C版本可以工作(在userland中以root用户身份运行时)。sys/io.h
中定义了outb()
函数<代码>静态uuu内联void outb(无符号字符值,无符号短整数端口){uuuu asm_uuuuuvolatile_uuu(“outb%b0,%w1”)::“a”(uuu值),“Nd”(uuu端口))感谢更新!显然,ioperm
以某种方式修改了任务的I/O权限端口映射,并允许它执行特权I/O指令。@tMC:useout dx,al
。根据您自己的引用,on OUT::目标操作数可以是字节立即数或DX寄存器。使用字节立即数允许访问I/O端口地址0到255;使用DX寄存器作为源操作数可以访问0到65535之间的I/O端口。