【问题标题】:Rewrite Intel-style assembly code into GCC inline assembly将 Intel 风格的汇编代码重写为 GCC 内联汇编
【发布时间】:2012-02-12 05:10:56
【问题描述】:

如何将此汇编代码编写为内联汇编?编译器:gcc(i586-elf-gcc)。 GAS 语法让我感到困惑。 请告诉我如何将其编写为适用于 gcc 的内联程序集。

.set_video_mode:
    mov ah,00h
    mov al,13h
    int 10h   

.init_mouse:
    mov ax,0
    int 33h

我在汇编中也有类似的。我将它们单独编写为汇编例程,以便从我的 C 程序中调用它们。我需要从 C 本身调用这些以及更多的中断。

我还需要根据我正在调用的中断例程将一些值放入一些寄存器中。请告诉我该怎么做。

我想做的就是从 C 调用中断例程。我什至可以使用 int86() 但我没有该函数的源代码。 我想要 int86() 以便我可以从 C 调用中断。

我正在开发自己的微型操作系统,因此我在调用中断或任何直接硬件访问方面没有任何限制。

【问题讨论】:

  • erm... 除非您使用 gcc 以 ELF 格式编译内核(那时您仍然需要引导加载程序),否则这不会成功,因为任何授予直接访问 BIOS 中断的操作系统(例如 MSDOS)将无法运行您的二进制文件
  • 所以这基本上是一个语法问题?
  • 我看到另一个问题:你希望你的代码以实模式(16 位)执行,其中 gcc 和 gas 将生成 32 位代码

标签: gcc assembly operating-system dos interrupt


【解决方案1】:

我尚未对此进行测试,但它应该可以帮助您入门:

void set_video_mode (int x, int y) {
  register int ah asm ("ah") = x;
  register int al asm ("al") = y;

  asm volatile ("int $0x10"
                : /* no outputs */
                : /* no inputs */
                : /* clobbers */ "ah", "al");
}

我以两个“clobbers”为例,但您需要设置正确的clobbers 列表,以便编译器知道您已覆盖寄存器值(可能没有)。

【讨论】:

  • 再看一遍……您可能需要将两个整数设为volatile 以防止编译器将它们优化掉。请注意。
  • @IsmaelLuceno 我不确定 x86 汇编器应该是什么样子(我主要将它用于 ARM)。答案的重点是C“asm”语法。我已经对其进行了编辑,使其看起来像其他一些答案。这样更好吗?
  • C asm 语法也是错误的,它甚至不能按原样编译,但是如果你修复语法细节,它最终会编译不工作的代码(实际上是 GCC 的错,但仍然......)。
  • 首先,变量上的asm只对寄存器或静态变量有效,volatile关键字必须跟在asm之后
  • 其次,GCC 对 x86 寄存器并不是很聪明,而且它做错了事,所以你必须将%ah%al 组合成%eax
【解决方案2】:

首先,请记住 GCC 尚不支持 16 位代码,因此您最终将在 16 位模式下编译 32 位代码,这非常低效但可行(例如,它被用于通过 Linux 和 SeaBIOS)。可以在每个文件的请求中通过以下方式完成:

__asm__ (".code16gcc");

较新的 GCC 版本(自 4.9 IIRC 起)支持执行相同操作的 -m16 标志。

此外,没有可用的鼠标驱动程序,除非您在内核运行 init_mouse 之前加载它。

您似乎正在使用几个 x86 DOS 中常用的 API。

asm 可以处理寄存器分配,所以代码可以简化为:

void set_video_mode(int mode)
{
    mode &= 255;
    __asm__ __volatile__ (
        "int $0x10"
        : "+a" (mode) /* %eax = mode & 255 => %ah = 0, %al = mode */
    );
}

void init_mouse(void)
{
    /* XXX it is really important to check the IDT entry isn't 0 */
    int tmp = 0;
    __asm__ __volatile__ (
        "int $0x33"
        : "+a" (tmp) /* %eax = 0*/
        :: "ebx" /* %ebx is also clobbered by DOS mouse drivers */
    );
}

asm 语句记录在 GCC 手册中,尽管可能不够深入并且缺少 x86 示例。输出(在第一个冒号之后)具有明显晦涩的语法,而其余的则更容易理解(第二个冒号指定输入,第三个冒号指定被破坏的寄存器、标志和/或内存)。

输出必须以= 为前缀,这意味着您不关心它之前可能具有的值,或者+,这意味着您也想将其用作输入。在这种情况下,我们使用它而不是输入,因为值是由中断修改的,并且不允许在破坏列表中指定输入寄存器(因为禁止编译器使用它们)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 2012-10-20
    • 2013-01-22
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    相关资源
    最近更新 更多