【问题标题】:Linux NASM OUTSB SegFaultLinux NASM OUTSB SegFault
【发布时间】:2012-03-14 09:25:03
【问题描述】:

我正在尝试将字节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);

}

【问题讨论】:

    标签: linux assembly segmentation-fault nasm ioports


    【解决方案1】:

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

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

    mov al, 0xff
    out 0x378, al
    

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

    让我知道结果如何。

    【讨论】:

    • 另外一点:我刚刚修改了一些英特尔手册,显然可以将单个 I/O 端口的权限授予单个任务。这需要在操作系统中使用 TSS(任务状态段)结构,我不确定 Linux 是否对每个单独的进程都使用它。
    • 我知道。但是在这种情况下,OUTSB 使用不当,因为它会导致从肯定不在进程地址空间中的内存区域读取。
    • @Daniel 我编辑了我的帖子-该程序的 C 版本可以工作(在用户态以 root 用户身份运行时)。 outb() 函数在 sys/io.h 中定义。 static __inline void outb (unsigned char __value, unsigned short int __port) { __asm__ __volatile__ ("outb %b0,%w1": :"a" (__value), "Nd" (__port)); }
    • 感谢您的更新!显然,ioperm 以某种方式修改了任务的 I/O 权限端口映射,并允许它执行特权 I/O 指令。
    • @tMC:使用out dx,al。根据您自己的参考,在 OUT:siyobik.info/main/reference/instruction/OUT目标操作数可以是字节立即数或 DX 寄存器。使用字节立即数允许访问 I/O 端口地址 0 到 255;使用 DX 寄存器作为源操作数允许访问从 0 到 65,535 的 I/O 端口。
    猜你喜欢
    • 2012-05-02
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    • 2016-05-12
    • 2011-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多