【问题标题】:How to use a variable declared in C within inline assembly如何在内联汇编中使用在 C 中声明的变量
【发布时间】:2015-12-29 21:38:06
【问题描述】:

我试图弄清楚如何在下面的内联汇编代码中使用变量 ret,但我不断收到此错误:未定义对 'ret 的引用。

char getkey(void){
int ret;
asm(
"movq $0, %RAX\n\t"
"INT $0X16\n\t"
"movq %RAX, ret"
);
return ret;
}

【问题讨论】:

  • 我正在使用 gcc。我正在使用 ubuntu 操作系统。
  • 您应该查看汇编器模板并将变量作为输入(和输出参数)gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
  • 我在第一条评论中添加了指向文档的链接。
  • ret 是指令的名称;这可能是导致它失败的原因
  • 除了您没有正确使用 GCC 的内联程序集之外,此代码永远无法工作。 INT 0x16 键盘 BIOS 接口仅在实模式下工作,您无法从实模式访问 64 位寄存器(例如 RAX)。 (理论上它可以在 64 位 DOS 扩展器下工作,但据我所知不存在这样的东西。)

标签: c gcc assembly keyboardinterrupt


【解决方案1】:

您尝试执行的操作将行不通。 PC BIOS 中断,如 int 16h,仅在系统以实模式运行时可用(即在启用 MMU 之前的启动时);它们不能在 Linux 可执行文件中使用。

话虽如此,一般来说,您可以使用gcc assembler constraints 指定一个输出寄存器。例如:

asm(
    "movq $0, %RAX\n"
    "int $0x16\n"
    : "=a" (ret)
);

请注意,此代码末尾没有mov 指令! "=A" 约束告诉编译器结果将留在 A 寄存器中;它会从那里弄清楚该怎么做。 (如果你聪明的话,也有办法消除第一个mov。)

【讨论】:

  • 所以你是说我的代码,甚至你提供的代码都不起作用,因为我不能使用中断?
  • @stingraing 正确。您不能在任何比 MS-DOS 更新的操作系统中使用 BIOS 中断。
  • 那么我该如何访问bios。操作系统是如何做到的?如果我创建了一个操作系统,操作系统不能吗?这不是他们为编程语言创建库的方式吗?
  • @stingraing 你不能,也不能。现代操作系统基本上忽略了除了启动和直接与硬件接口之外的 BIOS。
  • @stingraing 当您启动 IBM-PC(假设是旧版 BIOS)时,BIOS 包含可以处理基本硬件的中断。许多人首先调用 BIOS 来获取他们的第一个玩具操作系统/引导加载程序。不幸的是,如果您使用保护模式,大多数 BIOS 不支持保护模式调用。通常,受保护模式操作系统实现与发现的硬件通信的驱动程序。这通常通过与 IO 端口(输入/输出指令系列)通信或直接读/写内存来完成。本质上是滚动你自己的设备驱动程序,BIOS 中断为你做了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 2021-05-03
  • 2019-03-14
  • 1970-01-01
相关资源
最近更新 更多