【问题标题】:Translate VS inline assembler to GCC inline assembler将 VS 内联汇编器翻译成 GCC 内联汇编器
【发布时间】:2019-05-11 19:23:05
【问题描述】:

我发现这个带有内联汇编代码的 C 代码:

ReadFromCMOS (unsigned char array [])
{
   unsigned char tvalue, index;

   for(index = 0; index < 128; index++)
   {
      _asm
      {
         cli             /* Disable interrupts*/
         mov al, index   /* Move index address*/
         /* since the 0x80 bit of al is not set, NMI is active */
         out 0x70,al     /* Copy address to CMOS register*/
         /* some kind of real delay here is probably best */
         in al,0x71      /* Fetch 1 byte to al*/
         sti             /* Enable interrupts*/
         mov tvalue,al
       }

       array[index] = tvalue;
   }
}

WriteTOCMOS(unsigned char array[])
{
   unsigned char index;

   for(index = 0; index < 128; index++)
   {
      unsigned char tvalue = array[index];
      _asm
      {
         cli             /* Clear interrupts*/
         mov al,index    /* move index address*/
         out 0x70,al     /* copy address to CMOS register*/
         /* some kind of real delay here is probably best */
         mov al,tvalue   /* move value to al*/
         out 0x71,al     /* write 1 byte to CMOS*/
         sti             /* Enable interrupts*/
      }
   }
}

我尝试翻译成 GNU 内联汇编器,但失败了,主要是因为 GNU 内联汇编很混乱,使用过时的 AT&T 语法并且难以使用。

给我错误的代码:

void read_cmos(unsigned char array[])
{
    unsigned char tvalue, index;
    for (index = 0; index < 128; ++index)
    {
        /* read from CMOS */
        asm ("cli; outb %1, $0x70; inb $0x71, %0; sti" : "=a"(tvalue) : "a"(index));
    }
    array[index] = tvalue;
}

【问题讨论】:

  • 我们不知道上下文,但通常您应该为clistiout 拥有(或制作)单独的函数或宏,因此您不需要使用内联汇编到处都是。
  • 我实际上正在制作一个引导加载程序。感谢@fuz,我解决了我的问题,但没有奏效,它可能会产生堆栈溢出?。
  • @konniskatt 您的困惑在哪里?或许我可以帮忙清理一下。
  • 假设一个相对简单的 ABI 用于传递参数等,我认为你最好在汇编中简单地编写这些函数! hard 部分已经提供,剩下的只是记账。结合@fuz 的答案,编译 C -> assembler,然后花时间检查、验证并可能优化结果。
  • @konniskatt 问题是您使用-std=c99 编译,其中asm 未被识别为关键字。将asm 的所有提及更改为__asm__ 以解决此问题或改用-std=gnu99。如果您 (a) 发布了您遇到的所有错误,并且 (b) 您为编译代码而键入的命令的确切顺序,这将更容易找到。我花了一段时间才找到这个。

标签: gcc assembly x86-16 inline-assembly gnu-assembler


【解决方案1】:

试试这样的:

/* read from CMOS */
asm ("cli; outb %1, $0x70; inb $0x71, %0; sti" : "=a"(tvalue) : "a"(index));

/* write to CMOS */
unsigned char i = index;
asm volatile ("cli; outb %0, $0x70; movb %1, %%al; outb %%al, $0x71; sti" : "+a"(i) : "rm"(tvalue));

请注意,为tvalue 使用额外变量是可选的。你也可以指定

"+a"(array[index])

"a"(array[index])

直接。重要的是您传递的表达式具有字节大小的类型,因此 gcc 选择 al 而不是 eax

需要将index 分配给i 以允许在不更改index 的值的情况下破坏al。这段代码应该可以工作。或者,第二组指令也可以一分为二:

asm volatile ("cli; outb %0, $0x70" :: "a"(index));
asm volatile ("outb %0, %0x71" :: "a"(tvalue));

这避免了对额外变量的需要,并在选择寄存器时为编译器提供了更大的灵活性。

【讨论】:

  • 可能值得注意的是,这段代码假定中断开始时是开启的,因为无论之前是否启用,它总是启用它们。
  • kernel/rtc.h:7:50: error: expected ')' before ':' token asm ("cli; outb %1, $0x70; inb $0x71, %0; sti" : "=a"(tvalue) : "a"(index));
  • @konniskatt 请将您的代码附加到问题中。这适用于我的机器,所以我不完全确定它有什么问题。你使用哪个编译器?
  • 我使用 i686-elf-gcc
  • @konniskatt 哪个版本?请发布您尝试编译的代码或重现问题的minimal reproducible example,以便我了解出了什么问题。
【解决方案2】:

看看(古老的)GCC-inline-assembly HOWTO(面向 i686 Linux,所以可能适合您使用),仔细检查参数传递/约束(它们允许 GCC 正确安排调用代码,通过例如将输入/输出放在使用的寄存器中)。关于内联汇编的 GCC 文档也很相关,但在我的记忆中有些不透明,更详细,详细涵盖了更多架构(但可能是最新的)。

(抱歉,无法在我的手机上放置链接。快速搜索应该会将它们作为首选。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-20
    • 2013-07-23
    • 2016-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    相关资源
    最近更新 更多