用于 x86 输入/输出端口 I/O 的 C inline asm 操作数大小不匹配

Posted

技术标签:

【中文标题】用于 x86 输入/输出端口 I/O 的 C inline asm 操作数大小不匹配【英文标题】:C inline asm for x86 in / out port I/O has operand-size mismatch 【发布时间】:2018-09-16 14:46:54 【问题描述】:

我正在关注 youtube 上的教程,他说需要用 C 编写一些 asm 代码(我的汇编不太好),所以我只是处理了整个代码:

unsigned char inPortB (unsigned int _port) 
    unsigned char rv;
    __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
    return rv;

void outPortB (unsigned int _port, unsigned char _data) 
    __asm__ __volatile__ ("outb %1, %0" : :  "dN" (_port), "a" (_data));

但是当我编译我得到这个错误:

operand type mismatch for 'in'
operand type mismatch for 'out'

我该如何解决?

【问题讨论】:

如果您在 Linux 上编码,请考虑使用来自<sys/io.h>inb()outb() 函数。 @toohonestforthissite :出于性能原因,Linux 有 sys_ioplsys_ioperm 系统调用,允许以 root 权限运行的用户空间程序直接访问在 x86 平台上运行的 Linux 上的端口(通过 IO 权限过程的 TSS)。在用户模式下运行的 XServer 可能会依赖它来进行 8514 图形输出。 @toohonestforthissite sys_ioplsys_ioperm 告诉 x86 Linux(假设一个以 root 权限运行)inout 指令将允许在 Linux 用户模式下直接访问端口 (ring3)不会引起#GP。 x86 硬件在任务状态段中具有 IO 特权位图或 CPLin 和out 端口指令(以及所有相关的端口指令)在特定端口(或所有端口)上作为非特权指令运行。 @G.Sliepen :这似乎是个好主意,但在查看了该标题中的 GLIBC 代码(甚至是他们在 GIT 中拥有的最新版本)之后,这对我来说太严重了在实际项目中考虑。当我打开 sys/io.h 并查看代码时,我感到非常震惊。无论你做什么,都不要在优化的情况下编译它。 @MichaelPetch:哦,我只查看inb 的定义,而不是rep-string 版本。是的,这太可怕了!您应该在之前的评论中说,只有那些不安全,因为他们的 inboutb 定义没有任何问题,这就是这个问题的 OP 正在使用的。 【参考方案1】:

端口号需要在dx 中,这是一个 16 位寄存器。要使 gcc 生成对 dx 的引用,而不是像处理代码那样生成 edx,您需要为 _port 提供 16 位类型,例如unsigned short:

unsigned char inPortB (unsigned short _port) 
    unsigned char rv;
    __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
    return rv;

这应该可以解决您的问题。

【讨论】:

以上是关于用于 x86 输入/输出端口 I/O 的 C inline asm 操作数大小不匹配的主要内容,如果未能解决你的问题,请参考以下文章

可以在x86汇编中使用IN(以及INS,INSB等)指令块吗?

汇编 输入输出指令

X86 I/O端口

6. ioremap() 函数解析

内核request_mem_region 和 ioremap的理解

内核request_mem_region 和 ioremap的理解