2

我正在尝试将字节写入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 寄存器中没有任何内容?或dx==edx在 32 位?

(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

1 回答 1

4

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

其次,OUTSB将一个字节从 指定的内存位置写入ESI中的 I/O 端口DX。在这种情况下,您是在告诉处理器将数据从 location 写入端口0xff,进程肯定无法访问该端口。您可以通过简单地更改代码以使用OUT指令来简化它,因为OUTSB它更适合与REP前缀一起使用。试试这个 :

mov al, 0xff
out 0x378, al

这会将字节输出al到由立即操作数指定的 I/O 端口,在本例中为0x378

让我知道结果如何。

于 2012-02-24T00:38:32.943 回答