IN指令上的段故障,内联汇编GCC

时间:2018-01-09 23:18:09

标签: linux gcc io x86 inline-assembly

我正在尝试通过内联汇编代码中的IN和OUT指令从Linux(Ubuntu)上的C访问I / O端口。执行IN或OUT指令后立即生成seg故障。

例如,这段简单的代码会生成一个seg错误:

#include <stdint.h>

int main() {

    uint8_t readvalue = 0;
    uint16_t port = 0xB3;

    asm volatile("in    %%dx, %%al\n\t"
         : "=a" (readvalue)
         : "d" (port)
    );

    return(0);

}

我编译:gcc -O2 -g

从GDB,我看到这个程序被编译成以下简单的汇编代码序列:

mov    $0xb3,%edx
in     (%dx),%al
xor    %eax,%eax
retq

在GDB中,我看到只要执行IN指令,就会发生seg故障。

完整的GDB会话:

(gdb) list 
1   #include <stdint.h>
2   
3   int main() {
4       
5       uint8_t readvalue = 0;
6       uint16_t port = 0xB3;
7            
8       asm volatile("in    %%dx, %%al\n\t"
9            : "=a" (readvalue)
10           : "d" (port)
(gdb) list
11      );
12
13      return(0);
14
15  } 
16   
(gdb) break 7
Breakpoint 1 at 0x4003e0: file tcgsmi_inonly_pure.c, line 7.
(gdb) r
Starting program: /home/emerald/tcgsmi_inonly_pure

Breakpoint 1, main () at tcgsmi_inonly_pure.c:8
8       asm volatile("in    %%dx, %%al\n\t"
(gdb) disass
Dump of assembler code for function main:
=> 0x00000000004003e0 <+0>: mov    $0xb3,%edx
   0x00000000004003e5 <+5>: in     (%dx),%al
   0x00000000004003e6 <+6>: xor    %eax,%eax
   0x00000000004003e8 <+8>: retq
End of assembler dump.
(gdb) display/i $rip
1: x/i $rip
=> 0x4003e0 <main>: mov    $0xb3,%edx
(gdb) ni
0x00000000004003e5  8       asm volatile("in    %%dx, %%al\n\t"
1: x/i $rip
=> 0x4003e5 <main+5>:   in     (%dx),%al
(gdb) ni

Program received signal SIGSEGV, Segmentation fault.
0x00000000004003e5 in main () at tcgsmi_inonly_pure.c:8
8       asm volatile("in    %%dx, %%al\n\t"
1: x/i $rip
=> 0x4003e5 <main+5>:   in     (%dx),%al

1 个答案:

答案 0 :(得分:1)

答案在OP的评论中。

不能简单地在用户模式下访问IO端口。

  1. 程序需要以root身份运行(例如使用sudo)。
  2. 在访问端口之前,需要使用ioperm()解锁它们。
  3. ioperm()的原型是:

    int ioperm(unsigned long from, unsigned long num, int turn_on);
    

    from =您要访问的端口范围的ID num =范围长度
    turn_on =非零以启用访问,零以禁用访问

    因此,在上面的示例中,调用将是:

    ioperm(0xB3,1,1);