【问题标题】:<Int 16h> BIOS interruption with GCC Assembly in Linux?<Int 16h> Linux 中 GCC 程序集的 BIOS 中断?
【发布时间】:2021-04-01 16:51:27
【问题描述】:

我正在使用 QTCreator 3.5.1 和一个虚拟操作系统,它是 Linux Mint 18.3 Cinnamon 32 位、GCC 编译器。

我必须编写一个使用中断的代码,使用汇编命令获取键盘上按下的键。

本来应该在windows上运行的代码是这样的:

#include <iostream>
unsigned char x;
int main()
{
 do {
 __asm {
 mov ah, 00h
 int 16h
 mov x, ah
 };
 std::cout <<"The pressed key code is "<< x << std::endl;
 } while (true);
}

虽然它不能在 Windows 98 上运行,在 Windows 7x32 上使用 Visual Studio 2003 编译,以及任何其他 Windows 系统,给我一个运行时错误或关闭我的系统(在 Windows 98 上)。

所以我切换到 Linux,http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html(第 7 部分)的以下汇编示例代码运行良好:

#include <iostream>
using std::cout;
int main(void)
{
        int foo = 10, bar = 15;
        __asm__ __volatile__("addl  %%ebx,%%eax"
                             :"=a"(foo)
                             :"a"(foo), "b"(bar)
                             );
        printf("foo+bar=%d\n", foo);
        return 0;
}

(为了使其正常工作,我还必须在 QT Creator Tool->Options 的“Desktop Kit”上指定编译器版本(usr/bin 中的 GCC x86 32bit)和一个工作 QT 版本,即 4.8.7,最后一个版本 5.5.1 给我一个“未正确安装,请运行 make install”错误)

虽然我很难理解中断的概念以及“int 16h”中断应该如何在带有 GCC 内联汇编的 linux 上工作,但语法是什么以及如何获得任何按下的键盘键代码?

【问题讨论】:

  • 当您使用 Qt 时(显然),使用 this 之类的东西不是更合适,而是尝试在 bios 级别捕获键盘事件(不太可能配置在不同操作系统中的相同中断)。
  • int 16h 是 BIOS 服务。它仅在实模式下工作,通常用于引导加载程序或 DOS 程序。它不能从 Windows(任何版本,除非执行 DOS 程序在这种情况下模拟服务)或 Linux(任何版本)或任何其他受保护模式的操作系统访问。
  • 练习是否指定您必须使用int 16h?还提供了哪些其他细节?您可以在 Linux 上使用内联汇编读取输入(尽管我不建议在学术练习之外这样做)。在 Windows 上,这也是可能的,但正确的调用取决于 Windows 版本。
  • @fuz,是的。这就是问题所在,我的学术练习确实指定我必须使用 int 16h
  • @IvanSilkin 尝试哄骗 Visual Studio 生成 Win16 或 DOS 应用程序。

标签: c++ linux assembly gcc bios


【解决方案1】:

int 16h 服务是 BIOS 服务。它仅在实模式下工作,通常用于引导加载程序或 DOS 程序。它不能从 Windows(任何版本,除非执行 DOS 程序在这种情况下模拟服务)或 Linux(任何版本)或任何其他受保护模式的操作系统访问。

根据 Freenode 上#winapi 上的人们的说法,可能可以从 Windows 98 上的 Win32 程序调用 int 16h,但该调用可能会在 BIOS 中产生挂起。无论如何,这对实现您的目标没有用处。

要解决您的问题,请使用 DOS 工具链(例如 ia16-gcc、Open Watcom 或旧版本的 MSVC)编写 DOS 程序,或者使用您正在编程的操作系统支持的保护模式服务。

【讨论】:

    【解决方案2】:

    对于现代系统;在引导期间,操作系统从固件中控制所有硬件,之后固件将无法使用(因为不能假定任何硬件都处于固件预期的状态)。然后操作系统启动自己的为操作系统设计的驱动程序,使用 IRQ 并与操作系统调度程序一起工作(不要浪费 CPU 时间轮询),为多 CPU 工作,并正确支持内存(并且不是t 限制为 640 KiB)。

    这意味着 BIOS 中断“int 0x16”只有在以下任一情况下才能工作:

    a) 您正在使用 20 多年前变得无关紧要的操作系统 (MS-DOS)

    b) 您使用的操作系统做了很多额外的工作来模拟 20 多年前变得无关紧要的操作系统(例如 Windows95 内置的“旧版 DOS 兼容性”,而不是任何适用于 Windows 的 Windows 可执行文件)。

    c) 您没有使用操作系统,并且计算机太旧以至于固件是 BIOS(较新的计算机切换到 UEFI)。

    我必须编写一个使用中断的代码,使用汇编命令获取键盘上按下的键。

    我会仔细检查你应该做什么。例如。 “使用中断”可能意味着“使用旧的 32 位 Linux 内核 API (int 0x80) 而不是过时的 BIOS 功能”(它可能意味着“使用过时的 PS/2 控制器芯片 IRQ(就像设备驱动程序一样)” ,或其他)。

    更具体地说;我猜你遵循了包括“在虚拟机中安装旧的 32 位版本的 Linux”的说明,因为你应该使用旧的 Linux 内核 API(“int 0x80”)来做相当于“ read(STDIN_FILENO, buffer, 1);" 汇编语言(从任何 stdin 中获取一个字节,这可能来自键盘,也可能不来自键盘,具体取决于您的可执行文件的启动/使用方式)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-22
      • 2015-07-23
      • 2016-03-15
      • 2015-04-07
      • 1970-01-01
      • 2014-06-13
      相关资源
      最近更新 更多