2012-02-23 65 views
2

我正在尝试将字节0xff写入并口0x378。它编译和链接没有问题,但段错误在OUTSB指令。Linux NASM OUTSB SegFault

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任何注册看?或dx == edx in 32bit?

(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 

我在这里做错了什么?

(在OUTS指令信息:http://siyobik.info/main/reference/instruction/OUTS%2FOUTSB%2FOUTSW%2FOUTSD


编辑:

程序的C版作品:

int main(int argc, char *argv[]) 
{ 
    int addr = 0x378; 
    int result = ioperm(addr,5,1); 

    outb(0xff, addr); 

} 

回答

4

有一些问题与代码。首先,你似乎忘记了OUTSB是一条特权指令,即它只有在调用进程具有ring 0访问时才能执行,即它是内核代码的一部分。据我所知,Linux中唯一可以访问特权指令的代码是内核本身以及它加载的模块。当您尝试从非特权代码段执行特权指令时,所有其他进程将给您一个Segmentation fault(实际上是由CPU发送信号的General Protection Fault)。不过,我不知道如何调用ioperm系统调用。

其次,OUTSB将一个字节从ESI指定的存储位置写入DX的I/O端口。在这种情况下,您告诉处理器将数据写入端口0xff的端口,该进程肯定无法访问该端口。只需更改代码以使用OUT指令即可简化该操作,因为OUTSB更适用于REP前缀。尝试:

mov al, 0xff 
out 0x378, al 

al输出字节通过立即操作数中指定的I/O端口,在这种情况下0x378

让我知道结果如何。

+0

另一个说明:我只是修改了一些英特尔手册,显然可以将单个I/O端口的权限授予单个任务。这需要在操作系统中使用TSS(任务状态段)结构,我不确定Linux是否将它用于每个单独的进程。 – 2012-02-24 00:44:19

+0

'OUT'与'OUTS *'一样享有特权,将另一个替换为另一个不会解决主要问题。 – 2012-02-24 00:48:02

+1

我知道。但在这种情况下,'OUTSB'使用不当,因为它会导致从内存区域读取,这绝对不在进程的地址空间中。 – 2012-02-24 06:22:57