移植 AT&T inline-asm inb / outb 包装器以与 gcc -masm=intel 一起使用

2024-01-24

我目前正在开发 x86 操作系统。我尝试实现 inb 函数here https://wiki.osdev.org/Inline_Assembly/Examples它给了我Error: Operand type mismatch for `in'.

这也可能与outb or io_wait.

我正在使用英特尔语法(-masm=intel),我不知道该怎么办。

Code:

#include <stdint.h>
#include "ioaccess.h"

uint8_t inb(uint16_t port)
{
    uint8_t ret;
    asm volatile ( "inb %1, %0"
                   : "=a"(ret)
                   : "Nd"(port) );
    return ret;
}

对于 AT&T 语法,这确实有效。


对于 outb ,在反转操作数后我遇到了不同的问题:

void io_wait(void)
{
    asm volatile ( "outb $0x80, %0" : : "a"(0) );
}

Error: operand size mismatch for `out'


If you need to use -masm=intel you will need to insure that your inline assembly is in Intel syntax. Intel syntax is dst, src (AT&T syntax is reverse). This somewhat related answer https://stackoverflow.com/a/54961862/3857942 has some useful information on some differences between NASM's Intel variant1 (not GAS's variant) and AT&T syntax:

有关如何将 NASM Intel 语法转换为 GAS 的 AT&T 语法的信息,请参阅此堆栈溢出答案 https://stackoverflow.com/a/54961862/3857942,并且其中提供了很多有用的信息IBM 文章 https://www.ibm.com/developerworks/library/l-gas-nasm/index.html.

[snip]

一般来说,最大的区别是:

  • 对于 AT&T 语法,源位于左侧,目标位于右侧,而 Intel 则相反。
  • 使用 AT&T 语法,寄存器名称前面带有一个%
  • 对于 AT&T 语法,立即值前面带有一个$
  • 内存操作数可能是最大的区别。 NASM用途[段:disp+base+index*scale]而不是 GAS 的语法段:disp(基数,索引,比例).

您代码中的问题是源操作数和目标操作数必须与您使用的原始 AT&T 语法相反。这段代码:

asm volatile ( "inb %1, %0"
               : "=a"(ret)
               : "Nd"(port) );

需要是:

asm volatile ( "inb %0, %1"
               : "=a"(ret)
               : "Nd"(port) );

关于您的更新:问题是在英特尔语法中,立即值没有前面加上$。这一行有问题:

asm volatile ( "outb $0x80, %0" : : "a"(0) );

它应该是:

asm volatile ( "outb 0x80, %0" : : "a"(0) );

如果你有一个合适的outb函数你可以这样做:

#include <stdint.h>
#include "ioaccess.h"

uint8_t inb(uint16_t port)
{
    uint8_t ret;
    asm volatile ( "inb %0, %1"
                   : "=a"(ret)
                   : "Nd"(port) );
    return ret;
}

void outb(uint16_t port, uint8_t byte)
{
    asm volatile ( "outb %1, %0"
                   :
                   : "a"(byte),
                     "Nd"(port) );
}

void io_wait(void)
{
    outb (0x80, 0);
}

稍微复杂一点的版本,支持 AT&T 和 Inteldialects https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html:

asm 模板中的多种汇编语言在 x86 等目标上, GCC 支持多种汇编语言。 -masm 选项控制 GCC 使用哪种方言作为内联汇编器的默认方言。这 -masm 选项的目标特定文档包含以下列表 支持的方言,以及默认方言(如果选项为) 未指定。理解这些信息可能很重要,因为 使用一种方言编译时可以正常工作的汇编代码 如果使用另一个编译可能会失败。请参阅 x86 选项。

如果您的代码需要支持多种汇编语言(例如 例如,如果您正在编写需要支持的公共标头 各种编译选项),使用这种形式的构造:

{ 方言0 |方言1 |方言2...}

在 x86 和 x86-64 目标上有两种方言。 Dialect0 是 AT&T 语法,Dialect1 是 Intel 语法。这些功能可以这样重新设计:

#include <stdint.h>
#include "ioaccess.h"

uint8_t inb(uint16_t port)
{
    uint8_t ret;
    asm volatile ( "inb {%[port], %[retreg] | %[retreg], %[port]}"
                   : [retreg]"=a"(ret)
                   : [port]"Nd"(port) );
    return ret;
}

void outb(uint16_t port, uint8_t byte)
{
    asm volatile ( "outb {%[byte], %[port] | %[port], %[byte]}"
                   :
                   : [byte]"a"(byte),
                     [port]"Nd"(port) );
}

void io_wait(void)
{
    outb (0x80, 0);
}

我还给了约束符号名称而不是使用%0 and %1使内联汇编更易于阅读和维护。从 GCC 文档来看,每个约束的形式如下:

[ [asmSymbolicName] ] 约束 (cvariablename)

Where:

asm符号名

指定操作数的符号名称。通过将名称括在方括号中来引用汇编器模板中的名称(即“%[Value]”)。名称的范围是包含定义的 asm 语句。任何有效的 C 变量名称都是可接受的,包括周围代码中已定义的名称。同一 asm 语句中的两个操作数不能使用相同的符号名称。

当不使用 asmSymbolicName 时,请使用汇编器模板中操作数列表中操作数的(从零开始)位置。例如,如果有三个输出操作数,则在模板中使用“%0”表示第一个,“%1”表示第二个,“%2”表示第三个。

This version should work2 whether you compile with -masm=intel or -masm=att options


脚注

  • 1Although NASM Intel dialect and GAS's (GNU Assembler) Intel syntax are similar there are some differences. One is that NASM Intel syntax uses [segment:disp+base+index*scale] where a segment can be specified inside the [] and GAS's Intel syntax requires the segment outside with segment:[disp+base+index*scale].
  • 2Although the code will work, you should place all these basic functions in the ioaccess.h file directly and eliminate them from the .c file that contains them. Because you placed these basic functions in a separate .c file (external linkage) the compiler can't optimize them as well as it could. You can modify the functions to be of type static inline and place them in the header directly. The compiler will then have the ability to optimize the code by removing function calling overhead and reduce the need for extra loads and stores. You will want to compile with optimizations higher than -O0. Consider -O2 or -O3.
  • Special Notes Regarding OS Development:
    1. 有许多玩具操作系统(示例、教程和even代码上操作系统开发维基 https://wiki.osdev.org/Main_Page)不适用于优化。很多失败都是因为坏/差的内联汇编 https://gcc.gnu.org/wiki/DontUseInlineAsm或使用未定义的行为。内联汇编应该作为最后的手段。如果您的内核没有在优化的情况下运行,那么它可能不是编译器中的错误(有可能,只是不太可能)。
    2. 请注意 @PeterCordes 答案中有关可能触发 DMA 读取的端口访问的建议。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

移植 AT&T inline-asm inb / outb 包装器以与 gcc -masm=intel 一起使用 的相关文章

  • 每个托管线程是否都有自己对应的本机线程?

    我想知道是否在 Net 中创建托管线程 通过调用Thread Start 导致在后台创建一个本机线程 那么托管线程是否有对应的本机线程呢 如果是 当托管线程等待或睡眠时 是否意味着相应的本机线程也在等待或睡眠 是的 NET 线程映射到所有当
  • 使用 std::packaged_task/std::exception_ptr 时,线程清理程序报告数据争用

    我遇到了线程清理程序 TSan 的一些问题 抱怨某些生产代码中的数据争用 其中 std packaged task 通过将它们包装在 std function 中而移交给调度程序线程 对于这个问题 我简化了它在生产中的作用 同时触发 TSa
  • 如何在 .NET Framework 2.0 中模拟“Func<(Of <(TResult>)>) 委托”?

    我尝试使用这个类代码项目文章 http www codeproject com KB threads AsyncVar aspx在 VB NET 和 NET Framework 2 0 中 除了这一行之外 所有内容似乎都可以编译Privat
  • 如何在c++中读取pcap文件来获取数据包信息?

    我想用 C 编写一个程序来读取 pcap 文件并获取数据包的信息 例如 len sourc ip flags 等 现在我找到了如下代码 我认为它会帮助我获取信息 但是我有一些疑问 首先我想知道应该将哪个库添加到我的程序中 然后什么是 pca
  • 如何将非静态类成员“std::bind”绑定到 Win32 回调函数“WNDPROC”?

    我正在尝试将非静态类成员绑定到标准WNDPROC http msdn microsoft com en us library ms633573 aspx功能 我知道我可以通过将类成员设为静态来简单地做到这一点 但是 作为一名 C 11 ST
  • ClickOnce 应用程序错误:部署和应用程序没有匹配的安全区域

    我在 IE 中使用 FireFox 和 Chrome 的 ClickOnce 应用程序时遇到问题 它工作正常 异常的详细信息是 PLATFORM VERSION INFO Windows 6 1 7600 0 Win32NT Common
  • 单个对象的 Monogame XNA 变换矩阵?

    我读过一些解释 XNA Monogame 变换矩阵的教程 问题是这些矩阵应用于 SpriteBatch Begin matrix 这意味着所有 Draw 代码都将被转换 如何将变换矩阵应用于单个可绘制对象 就我而言 我想转换滚动背景 使其自
  • 获取两个工作日之间的天数差异

    这听起来很简单 但我不明白其中的意义 那么获取两次之间的天数的最简单方法是什么DayOfWeeks当第一个是起点时 如果下一个工作日较早 则应考虑在下周 The DayOfWeek 枚举 http 20 20 5B1 5D 3a 20htt
  • 使用接口有什么好处?

    使用接口有什么用 我听说它用来代替多重继承 并且还可以用它来完成数据隐藏 还有其他优点吗 哪些地方使用了接口 程序员如何识别需要该接口 有什么区别explicit interface implementation and implicit
  • 将 Word 文档另存为图像

    我正在使用下面的代码将 Word 文档转换为图像文件 但是图片显得太大 内容不适合 有没有办法渲染图片或将图片保存到合适的尺寸 private void btnConvert Click object sender EventArgs e
  • 是否有实用的理由使用“if (0 == p)”而不是“if (!p)”?

    我倾向于使用逻辑非运算符来编写 if 语句 if p some code 我周围的一些人倾向于使用显式比较 因此代码如下所示 if FOO p some code 其中 FOO 是其中之一false FALSE 0 0 0 NULL etc
  • 我可以使用 moq Mock 来模拟类而不是接口吗?

    正在经历https github com Moq moq4 wiki Quickstart https github com Moq moq4 wiki Quickstart 我看到它 Mock 一个接口 我的遗留代码中有一个没有接口的类
  • DbContext 和 ObjectContext 有什么区别

    From MSDN 表示工作单元和存储库模式的组合 使您能够查询数据库并将更改分组在一起 然后将这些更改作为一个单元写回存储 DbContext在概念上类似于ObjectContext 我虽然DbContext只处理与数据库的连接以及针对数
  • 如何禁用 fread() 中的缓冲?

    我正在使用 fread 和 fwrite 读取和写入套接字 我相信这些函数用于缓冲输入和输出 有什么方法可以在仍然使用这些功能的同时禁用缓冲吗 Edit 我正在构建一个远程桌面应用程序 远程客户端似乎 落后于服务器 我不知道可能是什么原因
  • 等待进程释放文件

    我如何等待文件空闲以便ss Save 可以用新的覆盖它吗 如果我紧密地运行两次 左右 我会得到一个generic GDI error
  • “接口”类似于 boost::bind 的语义

    我希望能够将 Java 的接口语义与 C 结合起来 起初 我用过boost signal为给定事件回调显式注册的成员函数 这非常有效 但后来我发现一些函数回调池是相关的 因此将它们抽象出来并立即注册所有实例的相关回调是有意义的 但我了解到的
  • 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

    我已经启动了一个 MQTT 服务器 就像this https github com chkr1011 MQTTnet tree master例子 该代码托管在 ASP Net Core 2 0 应用程序中 但我尝试过控制台应用程序 但没有成
  • 按 Esc 按键关闭 Ajax Modal 弹出窗口

    我已经使用 Ajax 显示了一个面板弹出窗口 我要做的是当用户按 Esc 键时关闭该窗口 这可能吗 如果有人知道这一点或以前做过这一点 请帮助我 Thanks 通过以下链接 您可以通过按退出按钮轻松关闭窗口 http www codepro
  • WebSocket安全连接自签名证书

    目标是一个与用户电脑上安装的 C 应用程序交换信息的 Web 应用程序 客户端应用程序是 websocket 服务器 浏览器是 websocket 客户端 最后 用户浏览器中的 websocket 客户端通过 Angular 持久创建 并且
  • 当从finally中抛出异常时,Catch块不会被评估

    出现这个问题的原因是之前在 NET 4 0 中运行的代码在 NET 4 5 中因未处理的异常而失败 部分原因是 try finallys 如果您想了解详细信息 请阅读更多内容微软连接 https connect microsoft com

随机推荐